Compare commits

..

137 Commits

Author SHA1 Message Date
Sukchan Lee
5fad2f0e5c Release 0.3.5 2018-03-06 12:43:34 +00:00
James Park
e69cea9b5b Ignore UCS2 bit to encode UIA 2018-03-05 11:02:36 -08:00
Sukchan Lee
6f9e45a332 Modify the security capability length (#27)
If octet 5 is included, then also octet 6 shall be included and octet 7
may be included.
2018-03-03 14:18:33 +09:00
Sukchan Lee
9357381839 Fix the bug of secuirty capability in security command (#27) 2018-03-03 14:10:24 +09:00
Sukchan Lee
84e7f50b3f update test code (#22) 2018-02-27 12:01:01 +09:00
Sukchan Lee
2bc92c5ac8 fix the indentation
* VIM
set sw=4
set ts=4
set expandtab

* Limited with 80 Column
2018-02-27 11:59:08 +09:00
Sukchan Lee
2429a4e363 fix the presentmask and change default configuration (#22) 2018-02-27 11:56:10 +09:00
Sukchan Lee
dab0f3ef3a Merge pull request #22 from medeiros405/master 2018-02-27 11:08:55 +09:00
medeiros405
144548f4c0 src/mme/emm_handler.c 2018-02-26 13:48:26 -03:00
medeiros405
1f44efbc3d src/mme/emm_handler.c 2018-02-26 13:46:28 -03:00
medeiros405
02712a38e6 src/mme/emm_handler.c
src/mme/mme_context.c
src/mme/mme_context.h
support/config/mme.conf.in
2018-02-25 18:33:36 -03:00
Sukchan Lee
888cbfbdb8 S1-reset encoder/decoder is added 2018-02-22 22:52:59 +09:00
Sukchan Lee
cdf7fb94bf S1-Setup failure is added 2018-02-22 22:23:16 +09:00
Sukchan Lee
e4989c7aa3 fix the README.md 2018-02-22 11:27:38 +09:00
Sukchan Lee
5365893c34 Release 0.3.4 2018-02-22 02:17:11 +00:00
Sukchan Lee
3c65414135 Release 0.3.4 2018-02-22 02:14:31 +00:00
Sukchan Lee
80bcfcf646 Release 0.3.4 2018-02-22 02:10:52 +00:00
Sukchan Lee
7e460fbcb4 dput is added 2018-02-22 10:47:21 +09:00
Sukchan Lee
62fe796d41 fix check.sh 2018-02-22 09:51:38 +09:00
Sukchan Lee
0104543f7d add manpage for dev 2018-02-22 00:48:42 +09:00
Sukchan Lee
39c30cb908 fix it 2018-02-22 00:32:11 +09:00
Sukchan Lee
c09b272e53 fix the base image for docker-dev 2018-02-22 00:30:28 +09:00
Sukchan Lee
92d8bde84a change dependency docker-dev 2018-02-22 00:18:31 +09:00
Sukchan Lee
e2bb5706fa update Dockerfile 2018-02-21 23:55:44 +09:00
Sukchan Lee
d74afc5bc7 for old version gcc compiler, we fix the size of child_desc in TLV message library 2018-02-21 14:48:41 +00:00
Sukchan Lee
c8a65b6b18 add other OS for docker 2018-02-21 23:20:48 +09:00
Sukchan Lee
f5582c97b5 NULL-pointer sgw_ue context is accessed (#18) 2018-02-21 17:29:47 +09:00
Sukchan Lee
b8cc130bf5 update check.sh 2018-02-21 14:35:46 +09:00
Sukchan Lee
12d65e92d1 re-arrange package between base and dev 2018-02-21 14:11:41 +09:00
Sukchan Lee
2904284405 Dockerfile cache invalidating for nextepc build 2018-02-21 13:16:11 +09:00
Sukchan Lee
f1b0cd5748 Merge branch 'master' of https://github.com/acetcom/nextepc 2018-02-21 12:35:19 +09:00
Sukchan Lee
91c9586561 update docker configuration 2018-02-21 12:35:05 +09:00
Sukchan Lee
05cfcf4cc3 Override configuration if DB_URI environment variable is existed 2018-02-21 03:25:48 +00:00
Sukchan Lee
c827701824 update it 2018-02-20 23:57:06 +09:00
Sukchan Lee
5fcc7e2ee6 runtime is testedwq 2018-02-20 23:49:24 +09:00
Sukchan Lee
bd1dff2dc5 missing files 2018-02-20 22:47:56 +09:00
Sukchan Lee
f1ad0b11ae change network configuration for docker 2018-02-20 22:29:46 +09:00
Sukchan Lee
9a86d4cb7c Initial Proposal for Docker (#16) 2018-02-20 19:36:34 +09:00
Sukchan Lee
38cccb8a85 move new directory 2018-02-17 15:15:17 +09:00
Sukchan Lee
2d72eaa24d Docker for MongoDB and WebUI recommended by Issue (#16) 2018-02-17 14:47:06 +09:00
Sukchan Lee
f915820f3a network script update for linux 2018-02-15 16:59:27 +09:00
Sukchan Lee
1009ac5e47 add masquerading for Mac OS X 2018-02-14 20:09:04 +09:00
Sukchan Lee
536138457e fix the warning for Mac OS X 2018-02-14 10:22:36 +09:00
Sukchan Lee
730053cef4 update README.md 2018-02-14 10:07:20 +09:00
Sukchan Lee
4a01623d6e update README.md 2018-02-14 00:34:14 +09:00
Sukchan Lee
0cf0e73bf9 update README.md 2018-02-14 00:33:18 +09:00
Sukchan Lee
87e7992450 update docker README.md 2018-02-14 00:29:22 +09:00
Sukchan Lee
75aaf632b8 Dockerfile updated 2018-02-13 23:48:44 +09:00
Sukchan Lee
5c3c99acda update Dockerfile for including Web User Interface 2018-02-13 17:16:17 +09:00
Sukchan Lee
081170a86e add template Dockerfile for NextEPC 2018-02-13 16:15:11 +09:00
Sukchan Lee
c9b4a20223 Release v0.3.3 2018-02-13 04:50:34 +00:00
Sukchan Lee
926e73e87d We use deb-systemd-invoke instead of systemdctl (#16) 2018-02-13 03:38:33 +00:00
Sukchan Lee
61f796d341 update README.md 2018-02-12 22:11:27 +09:00
Sukchan Lee
03715c84be update README.md 2018-02-12 21:47:36 +09:00
Sukchan Lee
72d28286ea update README.md 2018-02-12 21:23:12 +09:00
Sukchan Lee
c2d68cf4b6 update it 2018-02-12 16:43:05 +09:00
Sukchan Lee
e99f6c7789 update README 2018-02-12 08:48:05 +09:00
Sukchan Lee
340b3cb69c Release v0.3.3 Update 2018-02-11 16:10:22 +00:00
Sukchan Lee
5d8231e6c2 Relase v0.3.3 2018-02-11 23:43:55 +09:00
Sukchan Lee
1e5313c230 fix the compile error in CentOS 2018-02-11 12:07:09 +00:00
Sukchan Lee
d488bc3ed7 fix the conflict between PDN disconnect and Detach Request 2018-02-10 23:59:03 +09:00
Sukchan Lee
0de9185545 change debug level 2018-02-10 17:08:51 +09:00
Sukchan Lee
9563e49f48 update nextepc-pgwd.service for systemd-networkd (#16) 2018-02-10 06:53:38 +00:00
Sukchan Lee
881196cde2 Debian package update for docker issue (#16)
* Previously, pgwtun is setup with ifupdown package.
* Now, we'll use the systemd-networkd.
2018-02-10 11:15:39 +09:00
Sukchan Lee
c096cce571 update print-out 2018-02-09 23:14:30 +09:00
Sukchan Lee
3c33206dee update comment 2018-02-09 16:43:28 +09:00
Sukchan Lee
382c52a481 clear sgw s1u path if delete session response is received 2018-02-09 16:26:55 +09:00
Sukchan Lee
f904b63053 Authentication failure should be handled based on EMM_CAUSE(#17)
* Synch failure(EMM_CAUSE:21)
  - Re-authorization. Send authentication request again.

* MAC failure(EMM_CAUSE:20)
  - Send Authentication Reject
  - Send UE Context Release Command

* Non-EPS authentication failure(EMM_CAUSE:26)
  - Send Authentication Reject
  - Send UE Context Release Command

* Others
  - Send Authentication Reject
  - Send UE Context Release Command
2018-02-07 14:12:40 +09:00
Sukchan Lee
7769ded65a remove installcheck 2018-02-06 03:45:08 +00:00
Sukchan Lee
0170166b6b update docker manual 2018-02-06 12:32:39 +09:00
Sukchan Lee
935e81f9c9 test directory re-factor 2018-02-06 12:18:11 +09:00
Sukchan Lee
9fbcb45171 testsuite is added. (refer to libosmocom) 2018-02-06 11:59:49 +09:00
Sukchan Lee
c9596d82f7 add cleanfiles 2018-02-05 14:29:13 +00:00
Sukchan Lee
598b711c01 make check is added. 2018-02-05 23:21:37 +09:00
Sukchan Lee
f9096d55f5 for make check, sample configuration is added 2018-02-05 22:45:14 +09:00
Sukchan Lee
0e87056e2e share common files for test programs 2018-02-05 20:57:06 +09:00
Sukchan Lee
ad10c84ffe volte test configuration is updated 2018-02-05 17:26:20 +09:00
Sukchan Lee
7b99cc7d7c Changes default IP configuration (#14)
* NextEPC will not use 127.0.0.1 address for Diameter and GTP-U

* MME
  S1AP: Auto-Detect
  GTP-C: Auto-Detect
  DIAMETER: 127.0.0.2

* SGW
  GTP-C: 127.0.0.2
  GTP-U: Auto-Detect

* PGW
  GTP-C: Both 127.0.0.3 and [::1]
  GTP-U: Both 127.0.0.3 and [::1]
  DIAMETER: 127.0.0.3

* HSS
  DIAMETER: 127.0.0.4

* PCRF
  DIAMETER: 127.0.0.5
2018-02-05 08:08:41 +00:00
Sukchan Lee
75cc9bbb47 update bearer context status in tracking area update 2018-02-04 23:48:49 +09:00
Sukchan Lee
3a57990cbc T3402 is redundant. Remove it in Attach/TAU Accept 2018-02-04 23:41:44 +09:00
Sukchan Lee
14ef938fb9 SGW sends End Marker if GTP Node changes. Previously, ULI's cell ID 2018-02-04 23:15:20 +09:00
Sukchan Lee
5c1a3d54e3 rename it 2018-02-04 17:05:30 +09:00
Sukchan Lee
2defa5c868 add simualtor for the active flag 2018-02-04 16:58:56 +09:00
Sukchan Lee
4371084af4 Tracking Area Update with considering Initial UE message and active flag 2018-02-04 16:01:09 +09:00
Sukchan Lee
c0d4f25717 tracking area update request's active flag 2018-02-04 13:12:26 +09:00
Sukchan Lee
aacaa83eea rollback paging check routine 2018-02-03 23:44:04 +09:00
Sukchan Lee
de04e1de45 introduce ECM_IDLE and ECM_CONNECTED 2018-02-03 23:23:50 +09:00
Sukchan Lee
95551de5f9 tracking area update is handling based on UE ECM status 2018-02-03 22:55:05 +09:00
Sukchan Lee
bb4339de2a rename it 2018-02-03 18:29:32 +09:00
Sukchan Lee
831b3e8985 Error Indication is added 2018-02-03 11:48:15 +09:00
Sukchan Lee
f37b3cbfd3 rollback it 2018-02-03 09:18:22 +09:00
Sukchan Lee
23998862f2 update it 2018-02-03 08:49:46 +09:00
Sukchan Lee
e72d79a328 rollback it 2018-02-03 04:18:31 +09:00
Sukchan Lee
66d16ae1bb update it 2018-02-03 03:44:14 +09:00
Sukchan Lee
00178ff65e fix the bug in X2 handover TAI/E_CGI 2018-02-03 02:08:43 +09:00
Sukchan Lee
582c771605 fix the bug : TAU after S1 Handover 2018-02-03 02:00:38 +09:00
Sukchan Lee
52a1e05f41 change warn to trace level 5 2018-02-02 23:36:03 +09:00
Sukchan Lee
c293bef05a add IP address log if No TEID 2018-02-02 21:29:02 +09:00
Sukchan Lee
ebddb2ad9f rename it 2018-02-02 21:09:37 +09:00
Sukchan Lee
7c2dd5e462 add simulator for S1 holding timer 2018-02-02 20:32:13 +09:00
Sukchan Lee
f61233e627 update it 2018-02-02 19:59:26 +09:00
Sukchan Lee
b97597ae7c change S1 release scheme with holding timer(30sec) 2018-02-02 19:37:36 +09:00
Sukchan Lee
57f3baa273 UE-initiated detach_request is handled in every EMM-state 2018-02-02 15:59:21 +09:00
Sukchan Lee
d944bca038 context(tai, e_cgi) transfer during S1-handover 2018-02-02 15:30:25 +09:00
Sukchan Lee
857a250e4f add to trace for testing tracking area update 2018-02-02 13:46:49 +09:00
Sukchan Lee
34986be707 rollback implicit S1 release 2018-02-02 04:26:01 +09:00
Sukchan Lee
cb7132a2fa fix the bug 2018-02-02 04:20:02 +09:00
Sukchan Lee
5397cfd2d8 Send UE Context Release Command instead of Implicit S1 release 2018-02-02 02:48:55 +09:00
Sukchan Lee
0cd0221b29 rollback conflict between service request and downlink notification 2018-02-01 23:21:20 +09:00
Sukchan Lee
8bd186adad tracking area update accept with ue context release command 2018-02-01 23:06:35 +09:00
Sukchan Lee
4e5d156a6a ECM-IDLE/CONNECTED state is added in MME Context Library 2018-02-01 22:48:59 +09:00
Sukchan Lee
c9e44579d8 refine code 2018-02-01 21:38:59 +09:00
Sukchan Lee
4648dc05d5 log update 2018-02-01 16:54:52 +09:00
Sukchan Lee
ca79c05fe6 Update TAU Accept & Initial Context Setup Failure 2018-02-01 16:39:42 +09:00
Sukchan Lee
b040214364 add U-plane TEID trace log 2018-02-01 14:07:01 +09:00
Sukchan Lee
c3afd65ff3 fix the bug for FSM library 2018-02-01 11:56:01 +09:00
Sukchan Lee
f4baa62209 explicit S1 release for initial contexgt setup failure 2018-01-31 06:24:23 +00:00
Sukchan Lee
03cf945f95 fix the memroy leak in SGW Downlink Notification Ack 2018-01-31 15:01:13 +09:00
Sukchan Lee
01d7f157ff modify release access bearer regardless ue context release request's cause 2018-01-31 12:54:59 +09:00
Sukchan Lee
e49e1d2331 Use explict S1 release for initial context setup failure 2018-01-30 22:14:12 +09:00
Sukchan Lee
67393d0160 Implicit S1 Release immediately if Older S1 context is found. 2018-01-30 22:10:28 +09:00
Sukchan Lee
7ca9ead4b9 refine code 2018-01-30 21:57:19 +09:00
Sukchan Lee
3f7c3d3041 Prevent GUTI re-allocation for every attach_request 2018-01-30 07:25:42 +09:00
Sukchan Lee
cf6df20ad7 refine code 2018-01-29 13:44:25 +00:00
Sukchan Lee
b77c9b8ff6 refine code 2018-01-29 22:38:53 +09:00
Sukchan Lee
795ecc8cf8 Implicit S1 Release 2018-01-29 19:10:54 +09:00
Sukchan Lee
b704e94efa fix the memory leak t3413 paging timer in MME_UE Context 2018-01-29 16:47:07 +09:00
Sukchan Lee
ae6e747e52 ECM_IDLE/CONNECTED is introduced 2018-01-29 14:48:51 +09:00
Sukchan Lee
60cfbed747 Update state machine 2018-01-28 22:08:53 +09:00
Sukchan Lee
597fcfbad9 rollback implict S1 release 2018-01-28 16:13:48 +09:00
Sukchan Lee
762431cb6f GUTI is suppressed in Attach accept if GUTI is not changed. 2018-01-28 15:32:45 +09:00
Sukchan Lee
21a130bc16 Implicitly S1 release without sending UE context release command 2018-01-28 15:08:52 +09:00
Sukchan Lee
5774aeb62d Change Cause value in UE Context Release Command 2018-01-28 14:11:17 +09:00
Sukchan Lee
7b2355a40f MME_UE Context is not deleted even thought Detach Request(switch-off case) 2018-01-28 13:50:21 +09:00
Sukchan Lee
28237ea6af clean security context if KSI is INVALID(7) 2018-01-26 09:08:50 +09:00
Sukchan Lee
09969e859d update log 2018-01-26 07:10:41 +09:00
Sukchan Lee
9451928786 remove INVALID ASSERT in SGW 2018-01-26 06:52:30 +09:00
149 changed files with 3791 additions and 8528 deletions

14
.gitignore vendored
View File

@@ -5,6 +5,7 @@
*.la
*.conf
.deps
.dirstamp
.libs
# generated files
@@ -33,9 +34,16 @@ Makefile
Makefile.in
m4
# autotest
test/package.m4
test/atconfig
test/testsuite
test/testsuite.dir/
test/testsuite.log
# executables
lib/core/test/testcore
test/volte/testvolte
test/testvolte
test/testepc
nextepc-mmed
nextepc-pcrfd
@@ -58,3 +66,7 @@ debian/nextepc-sgw
debian/nextepc-pgw
debian/nextepc-pcrf
debian/nextepc-hss
# webui
webui/.next/
webui/node_modules/

408
README.md
View File

@@ -16,7 +16,7 @@ NextEPC contains the PCRF (Policy and Charging Rules Function), which controls t
Installation
============
This post will guide you on how to get installed **NextEPC** with your environment. To date, NextEPC has been tested on GNU/Linux distributions(Debian, Ubuntu, CentOS, Fedora, OpenSUSE), FreeBSD, and Mac OS X.
This post will guide you on how to get installed **NextEPC** with your environment. To date, NextEPC has been tested on GNU/Linux distributions(Debian, Ubuntu, CentOS, Fedora), FreeBSD, and Mac OS X.
@@ -24,14 +24,16 @@ This post will guide you on how to get installed **NextEPC** with your environme
To get the latest Ubuntu version, please visit the official Ubuntu website: [https://www.ubuntu.com/download/](https://www.ubuntu.com/download/).
* ### Install with a Package Manager
* ### MME, SGW, PGW, HSS, and PCRF
The Nextepc package is available on the recent versions of Ubuntu.
The NextEPC package is available on the recent versions of Ubuntu.
```bash
sudo apt-get update
sudo apt-get -y install software-properties-common
sudo add-apt-repository ppa:acetcom/nextepc
sudo apt-get update
sudo apt-get install nextepc
sudo apt-get -y install nextepc
```
This will create a virtual network interface named as *pgwtun*. It is automatically removed by uninstalling NextEPC.
@@ -44,12 +46,43 @@ pgwtun Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
...
```
The NextEPC service is registered in `systemd` environment, and is started automatically during the installation phase. The service names are *nextepc-mmed*, *nextepc-sgwd*, *nextepc-pgwd*, *nextepc-hssd*, and *nextepc-pcrfd*. You can use the `systemctl` command to control specific services.
```bash
sudo systemctl status nextepc-mmed (Check the service status)
sudo systemctl stop nextepc-mmed (Stop the service)
sudo systemctl disable nextepc-mmed (Will not be started after rebooting)
sudo systemctl enable nextepc-mmed (Will be started after rebooting)
sudo systemctl start nextepc-mmed (Start the service)
sudo systemctl restart nextepc-mmed (Stop and start)
```
* ### Web User Interface
The LTE user subcription information of NextEPC is stored and maintained by [Mongo DB](https://www.mongodb.com/). To manage the subscriber information, [Mongo DB client](https://docs.mongodb.com/ecosystem/tools/) is required, and this client can connect to the DB URI [_mongodb://localhost/nextepc_].
NextEPC provides an alternative management interface for customers to manage their subscriber information in an easy way, that is **Web User Interface**. The following shows how to install the Web UI of NextEPC.
```bash
sudo apt-get -y install curl
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
curl -sL http://nextepc.org/static/webui/install | sudo -E bash -
```
The service name is *nextepc-webui*, and it will be running on _http://localhost:3000_.
```bash
sudo systemctl start nextepc-webui
```
* ### Uninstall NextEPC
```bash
sudo apt-get purge nextepc-core
curl -sL http://nextepc.org/static/webui/uninstall | sudo -E bash -
sudo apt-get purge nextepc*
```
You may need to remove manually /var/log/nextepc unless it is empty.
@@ -58,26 +91,223 @@ sudo rm -Rf /var/log/nextepc
```
## Debian, CentOS, Fedora, OpenSUSE, FreeBSD, and Mac OS X
## CentOS, Fedora, FreeBSD, and Mac OS X
For these OS, you should build NextEPC from the code. First clone this [repository](https://github.com/acetcom/nextepc.git) and then follow instructions described in the [documentation](http://nextepc.org/docs/).
* ### [FreeBSD](http://nextepc.org/docs/build/1-freebsd)
* ### [Mac OS X](http://nextepc.org/docs/build/2-macosx)
* ### [CentOS](http://nextepc.org/docs/build/3-centos)
* ### [Fedora](http://nextepc.org/docs/build/4-fedora)
* ### [Ubuntu](http://nextepc.org/docs/build/5-ubuntu)
* ### [CentOS](http://nextepc.org/docs/build/1-centos)
* ### [Fedora](http://nextepc.org/docs/build/2-fedora)
* ### [FreeBSD](http://nextepc.org/docs/build/3-freebsd)
* ### [Mac OS X](http://nextepc.org/docs/build/4-macosx)
Build
=====
Since NextEPC is an open source project, you can build and use this program directly from source code. If you have already installed it with a package manager, or are not interested in learning the source code, you can skip this guide and proceed to the next [configuration guide](http://nextepc.org/guides/3-configuration).
Note that this guide is based on Ubuntu 16.04.3(Zenial) Distribution.
## Prerequisites
NextEPC requires MongoDB and TUN device. If you have previously installed NextEPC according to the [Installation Guide](http://nextepc.org/guides/1-installation), they was configured at that time. So, you can skip this step.
Install Mongo DB with Package Manager.
```bash
sudo apt-get -y install mongodb
sudo systemctl start mongodb (if '/usr/bin/mongod' is not running)
```
To run NextEPC with least privilege, TUN device permission should be a `crw-rw-rw-`(666). Otherwise, you need to run nextepc daemon with root privilege. If the permission is not `crw-rw-rw-`(666), you may need to install `udev` package. Nevertheless, if the permission do not change , you can run nextepc with root privileges or change the permission using `chmod 666 /dev/net/tun`.
```bash
ls -al /dev/net/tun
crw-rw---- 1 root 28 10, 200 Feb 11 05:13 /dev/net/tun
sudo apt-get install udev
sudo systemctl start systemd-udevd (if '/lib/systemd/systemd-udevd' is not running)
```
Write the configuration file for the TUN deivce.
```bash
sudo sh -c "cat << EOF > /etc/systemd/network/99-nextepc.netdev
[NetDev]
Name=pgwtun
Kind=tun
EOF"
```
Craete the TUN device. Interface name will be `pgwtun`.
```
sudo systemctl enable systemd-networkd
sudo systemctl restart systemd-networkd
sudo apt-get -y install net-tools
ifconfig pgwtun
```
Then, you need to check *IPv6 Kernel Configuration*. Although you can skip this process, we recommend that you set this up to support IPv6-enabled UE.
```bash
sysctl -n net.ipv6.conf.pgwtun.disable_ipv6
(if the output is 0 and IPv6 is enabled, skip the followings)
sudo sh -c "echo 'net.ipv6.conf.pgwtun.disable_ipv6=0' > /etc/sysctl.d/30-nextepc.conf"
sudo sysctl -p /etc/sysctl.d/30-nextepc.conf
```
You are now ready to set the IP address on TUN device. If IPv6 is disabled for TUN device, please remove `Address=cafe::1/64` from below.
```bash
sudo sh -c "cat << EOF > /etc/systemd/network/99-nextepc.network
[Match]
Name=pgwtun
[Network]
Address=45.45.0.1/16
Address=cafe::1/64
EOF"
```
Check the TUN(pgwtun) device again.
```
sudo systemctl restart systemd-networkd
ifconfig pgwtun
```
## MME, SGW, PGW, HSS, and PCRF
Install the depedencies for building the source
```bash
sudo apt-get -y install autoconf libtool gcc pkg-config git flex bison libsctp-dev libgnutls28-dev libgcrypt-dev libssl-dev libmongoc-dev libbson-dev libyaml-dev
```
Git clone and compile
```bash
acetcom@nextepc:~$ git clone https://github.com/acetcom/nextepc
ccetcom@nextepc:~$ cd nextepc
acetcom@nextepc:~/nextepc$ autoreconf -iv
acetcom@nextepc:~/nextepc$ ./configure --prefix=`pwd`/install
acetcom@nextepc:~/nextepc$ make -j `nproc`
acetcom@nextepc:~/nextepc$ make install
```
We provide a program that checks whether the installation is correct. After running the wireshark, select `loopback` interface, filter `s1ap || diameter || gtpv2 || gtp` and run `./test/testepc`. You can see the virtually created packets. [[testepc.pcapng]](http://nextepc.org/static/pcapng/testepc.pcapng)
Note that you should stop all nextepc daemons before running test program if you have already installed it with a package manage.
```bash
(if nextepc-daemons are running)
sudo systemctl stop nextepc-mmed
sudo systemctl stop nextepc-sgwd
sudo systemctl stop nextepc-pgwd
sudo systemctl stop nextepc-hssd
sudo systemctl stop nextepc-pcrfd
acetcom@nextepc:~/nextepc$ ./test/testepc
```
It is a convenient tool called `nextepc-epcd` for developers. This daemon includes both *MME*, *SGW*, *PGW*, *HSS*, and *PCRF*. So, instead of running all 5 daemons, you can just run `nextepc-epcd` in your development environment.
```bash
acetcom@nextepc:~/nextepc$ ./nextepc-epcd
NextEPC daemon v0.3.3 - Feb 11 2018 07:19:59
PID[3720] : '/home/acetcom/nextepc/install/var/run/nextepc-epcd/pid'
File Logging : '/home/acetcom/nextepc/install/var/log/nextepc/nextepc.log'
MongoDB URI : 'mongodb://localhost/nextepc'
Configuration : '/home/acetcom/nextepc/install/etc/nextepc/nextepc.conf'
[02/11 07:26:42.001] PCRF try to initialize
...
```
When you run `nextepc-epcd`, all logs for MME, SGW, PGW, PCRF, and HSS are written to `nextepc.log`, and all settings are managed in one place for `nextepc.conf`. You can find the log/conf path at the beginning of running screen.
Sometimes, you may want to use newly updated source code.
```bash
(Control-C kill nextepc-epcd)
acetcom@nextepc:~/nextepc$ make maintainer-clean
acetcom@nextepc:~/nextepc$ rm -rf ./install
acetcom@nextepc:~/nextepc$ git pull
acetcom@nextepc:~/nextepc$ autoreconf -iv
acetcom@nextepc:~/nextepc$ ./configure --prefix=`pwd`/install
acetcom@nextepc:~/nextepc$ make -j `nproc`
acetcom@nextepc:~/nextepc$ make install
acetcom@nextepc:~/nextepc$ ./nextepc-epcd
```
## Web User Interface
To get the latest [Node.js](https://nodejs.org/) and [NPM](https://www.npmjs.com/), please visit the official Node.js website:
[https://nodesjs.org/en/download/](https://nodesjs.org/en/download/).
Or, you can install [Node.js](https://nodejs.org/) and [NPM](https://www.npmjs.com/) with a package manager.
```bash
sudo apt-get -y install curl
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get -y install nodejs
```
Install the dependencies to run WebUI
```bash
acetcom@nextepc:~/nextepc$ cd webui
acetcom@nextepc:~/nextepc/webui$ npm install
```
Running WebUI
```bash
acetcom@nextepc:~/nextepc/webui$ npm run dev
```
Now the web server is running on _http://localhost:3000_.
Configuraiton
=============
In LTE, there are tons of configurable parameters. This page will guide you to set essential parameters up. The configuration consists of two parts: IP network connectivity and LTE network settings.
In LTE, there are tons of configurable parameters. This page will guide you to set essential parameters up. The configuration consists of three parts: IP network connectivity, LTE network settings and Subscribers registering.
## 1. IP Connectivity between Network Entities
The minimum requirement of having IP connectvity is to add a route for UE to have Internet connectivity.
The minimum requirement of having IP connectvity is to modify the configuration files of MME and SGW. Once NextEPC has been installed, you can find [YAML](http://yaml.org/)-format configuration files in `/etc/nextepc/*.conf`.
By default, a LTE UE will receive a IP address with the network address of 45.45.0.0/16 or cafe::0/64. If you have a [NAT](https://en.wikipedia.org/wiki/Network_address_translation) router (e.g., wireless router, cable modem, etc), the LTE UE can reach Internet in uplink, but it cannot in downlink. It's because the NAT router has no idea on these IP addresses, so adding a route is required. Please refer to the user manual to know how to add a static route in your router.
Note that [/etc/nextepc/nextepc.conf](https://github.com/acetcom/nextepc/blob/master/support/config/nextepc.conf.in) is just a manual. If you use `nextepc-epcd` in a build environment, this configuration file could be used, but if you installed it with the package manager, modifying this configuration file has no effect.
Anyway, before setting up, please decide a network interface to run NextEPC, and then the IP address of the interface needs to be recorded in the configuration files.
### Modification of MME config
Open `/etc/nextepc/mme.conf` file, and find an item in mme &rarr; s1ap. Please set your IP address with putting `addr:` keyword.
```yaml
mme:
freeDiameter: mme.conf
s1ap:
addr: <ip address>
...
```
Save and exit.
### Modification of SGW config
Open `/etc/nextepc/sgw.conf` file, and find an item in sgw &rarr; gtpu. Please set your IP address with putting `addr:` keyword.
```yaml
sgw:
gtpc:
addr: 127.0.0.2
gtpu:
addr: <ip address>
...
```
Save and exit.
### Adding a route for UE to have Internet connectivity
By default, a LTE UE will receive a IP address with the network address of 45.45.0.0/16. If you have a [NAT](https://en.wikipedia.org/wiki/Network_address_translation) router (e.g., wireless router, cable modem, etc), the LTE UE can reach Internet in uplink, but it cannot in downlink. It's because the NAT router has no idea on 45.45.0.0/16, so adding a route is required. Please refer to the user manual to know how to add a static route in your router.
Add a route of both 45.45.0.0/16 and cafe::0/64 to go the PGW IP address. For example, a command for Linux will be:
@@ -86,8 +316,18 @@ sudo ip route add 45.45.0.0/16 via <PGW IP address>
sudo ip route add cafe::0/64 via <PGW IP address>
```
If you have no NAT router, there is another option for you. `iptables` can solve the problem. You execute the following command in NextEPC installed host. The `eth0` shown below is just an example. Do not miss out on modifying your interface name(e.g `enp0s25`, `wls3`).
```bash
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -I INPUT -i pgwtun -j ACCEPT
```
## 2. LTE Network Settings
### PLMN and TAC
By default, LTE PLMN and TAC are set as shown in the following:
```yaml
@@ -108,76 +348,98 @@ mme:
The LTE EnodeBs need to be set to use the same values of PLMN and TAC in NextEPC. If you want to change them, please modifiy in `/etc/nextepc/mme.conf`.
### Restarting MME and SGW.
After changing conf files, please restart NextEPC daemons.
```bash
systemctl restart nextepc-mmed
sudo systemctl restart nextepc-mmed
sudo systemctl restart nextepc-sgwd
```
## 3. Register a subscriber
Web UI
==================
Open _http://localhost:3000_. Login with **admin**. Later, you can change the password in _Account_ Menu.
NextEPC has a number of configuration files corresponding to LTE network entities, which are in [YAML](http://yaml.org/) format. The LTE user subcription information of NextEPC is stored and maintained by [Mongo DB](https://www.mongodb.com/). Configuration files, located in `etc/nextepc/*.conf` can be easily modified using a general text editor such as [vi](http://www.vim.org/) or [emacs](https://www.gnu.org/s/emacs/), while managing the subscriber information requires a [Mongo DB client](https://docs.mongodb.com/ecosystem/tools/).
NextEPC provides an alternative management interface for customers to manage their subscriber information in an easy way, that is **Web User Interface**. The following shows how to install the Web UI of NextEPC.
## 1. Install Node.js and NPM
To get the latest [Node.js](https://nodejs.org/) and [NPM](https://www.npmjs.com/), please visit the official Node.js website:
[https://nodesjs.org/en/download/](https://nodesjs.org/en/download/).
Or, you can install [Node.js](https://nodejs.org/) and [NPM](https://www.npmjs.com/) if you're using [Ubuntu](https://www.ubuntu.com):
```bash
sudo apt-get -y install curl gnupg
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get -y install nodejs
```markdown
- Username : admin
- Password : 1423
```
## 2. Obtain the source code
```bash
git clone https://github.com/acetcom/nextepc
```
## 3. Install the dependencies to build the code
```bash
cd nextepc/webui
npm install
```
## 4. Build
```bash
npm run build
```
## 5. Running
```bash
npm run start
```
Now the web server is running on _http://localhost:3000_.
## 6. Login with the default account
Open _http://localhost:3000_. Login with **admin**.
* Username : admin
* Password : 1423
Please change the password in _Account_ Menu.
## 7. Register a subscriber
Using Web UI, you can add a subscriber without a Mongo DB client.
* Go to Subscriber Menu.
* Click `+` Button to add a new subscriber.
* Fill the IMSI, security context(K, OPc, AMF), and APN of the subscriber.
* Click `SAVE` Button
```markdown
- Go to Subscriber Menu.
- Click `+` Button to add a new subscriber.
- Fill the IMSI, security context(K, OPc, AMF), and APN of the subscriber.
- Click `SAVE` Button
```
This addition affects immediately NextEPC without restaring any daemon.
## Appendix
When you install NextEPC for the first time, the default configuration looks like this:
### Network
```
* MME
S1AP: listen on all address avaiable in system
GTP-C: listen on the first IP address in system
DIAMETER: 127.0.0.2 (No TLS)
* SGW
GTP-C: 127.0.0.2
GTP-U: listen on the first IP address in system
* PGW
GTP-C: Both 127.0.0.3 and [::1]
GTP-U: Both 127.0.0.3 and [::1]
DIAMETER: 127.0.0.3 (No TLS)
* HSS
DIAMETER: 127.0.0.4 (No TLS)
* PCRF
DIAMETER: 127.0.0.5 (No TLS)
```
### GUMMEI, PLMN and TAC
```
* GUMMEI
PLMN ID - MNC: 001, MCC: 01
MME Group : 2
MME Code : 1
* TAI
PLMN ID - MNC: 001, MCC: 01
TAC : 12345
```
### Security
```
* Integrity : EIA1 - Snow 3G
* Ciphering : EEA0 - Nothing
```
### UE Network
```
* IPv4 : 45.45.0.1/16
* IPv6 : cafe::1/64
```
### DNS
```
* IPv4
Primary : 8.8.8.8
Secondary : 8.8.4.4
* IPv6
Primary : 2001:4860:4860::8888
Secondary : 2001:4860:4860::8844
```

View File

@@ -8,7 +8,7 @@ dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
AC_INIT([NEXTEPC], [0.3.2], [acetcom@gmail.com])
AC_INIT([NextEPC], [0.3.5], [acetcom@gmail.com])
AC_SUBST(LIBVERSION)
LIBVERSION=1:0:0
@@ -17,6 +17,7 @@ CORE_CONFIG_NICE(config.nice)
dnl Must come before AM_INIT_AUTOMAKE.
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_TESTDIR(test)
AM_INIT_AUTOMAKE([1.10 -Wall -Werror foreign subdir-objects])
# Where to generate output; srcdir location.
@@ -73,6 +74,7 @@ dnl Checks CC and freinds
AC_PROG_MAKE_SET
AC_PROG_MKDIR_P
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_INSTALL
AM_PROG_AR
LT_INIT([pic-only disable-static])
@@ -377,24 +379,15 @@ AC_FUNC_VPRINTF
AC_CHECK_FUNCS(\
atexit \
gettimeofday \
inet_ntop \
inet_pton \
inet_aton \
memmove \
sigaction \
sigwait \
sigsuspend \
stpcpy \
strcasecmp \
strtoul \
stricmp \
strerror \
inet_ntop inet_pton inet_aton \
sigaction sigwait sigsuspend \
stpcpy strcasecmp strtoul stricmp \
writev \
utime \
utimes \
sem_timedwait \
pthread_yield \
sched_yield \
utime utimes sem_timedwait \
pthread_yield sched_yield \
getenv putenv setenv unsetenv \
)
AC_SEARCH_LIBS(gethostbyname, nsl)
@@ -466,7 +459,8 @@ AC_CONFIG_FILES([support/logrotate/Makefile])
AC_CONFIG_FILES([support/newsyslog/nextepc.conf])
AC_CONFIG_FILES([support/newsyslog/Makefile])
AC_CONFIG_FILES([support/Makefile])
AC_CONFIG_FILES([test/volte/Makefile])
AC_CONFIG_FILES([test/sample.conf])
AC_CONFIG_FILES([test/sample-volte.conf])
AC_CONFIG_FILES([test/Makefile])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

84
debian/changelog vendored
View File

@@ -1,3 +1,87 @@
nextepc (0.3.5~xenial) xenial; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Tue, 06 Mar 2018 12:41:53 +0000
nextepc (0.3.5~artful) artful; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Tue, 06 Mar 2018 12:40:07 +0000
nextepc (0.3.4-1~xenial) xenial; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Thu, 22 Feb 2018 02:16:08 +0000
nextepc (0.3.4-1~artful) artful; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Thu, 22 Feb 2018 02:14:43 +0000
nextepc (0.3.4~xenial) xenial; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Thu, 22 Feb 2018 02:09:23 +0000
nextepc (0.3.4~artful) artful; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Thu, 22 Feb 2018 01:33:04 +0000
nextepc (0.3.3-3~artful) artful; urgency=medium
* Support Docker
-- Sukchan Lee <acetcom@gmail.com> Tue, 13 Feb 2018 04:47:43 +0000
nextepc (0.3.3-3~xenial) xenial; urgency=medium
* Support Docker
-- Sukchan Lee <acetcom@gmail.com> Tue, 13 Feb 2018 04:44:47 +0000
nextepc (0.3.3-2~xenial) xenial; urgency=medium
* Minor bug fixes
-- Sukchan Lee <acetcom@gmail.com> Sun, 11 Feb 2018 16:08:14 +0000
nextepc (0.3.3-2~artful) artful; urgency=medium
* Minor bug fixes
-- Sukchan Lee <acetcom@gmail.com> Sun, 11 Feb 2018 16:05:44 +0000
nextepc (0.3.3-1~xenial) xenial; urgency=medium
* Minor bug fixes
-- Sukchan Lee <acetcom@gmail.com> Sun, 11 Feb 2018 15:39:37 +0000
nextepc (0.3.3-1~artful) artful; urgency=medium
* Minor bug fixes
-- Sukchan Lee <acetcom@gmail.com> Sun, 11 Feb 2018 15:33:57 +0000
nextepc (0.3.3~artful) artful; urgency=medium
* Minor bug fixes
-- Sukchan Lee <acetcom@gmail.com> Sun, 11 Feb 2018 15:05:08 +0000
nextepc (0.3.3~xenial) xenial; urgency=medium
* Minor bug fixes
-- Sukchan Lee <acetcom@gmail.com> Sun, 11 Feb 2018 15:00:24 +0000
nextepc (0.3.2~zesty) zesty; urgency=medium
* VoLTE Support

4
debian/control vendored
View File

@@ -68,8 +68,8 @@ Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends},
${misc:Depends},
nextepc-core (= ${binary:Version}),
ifupdown
udev,
nextepc-core (= ${binary:Version})
Description: Open Source based 3GPP EPC PGW (Packet Data Network Gateway)
NextEPC is a C-language Open Source implementation of the 3GPP Evolved
Packet Core, i.e. the core network of an LTE network.

View File

@@ -3,5 +3,5 @@ etc/nextepc/freeDiameter/pgw.conf
etc/nextepc/freeDiameter/pgw.cert.pem
etc/nextepc/freeDiameter/pgw.key.pem
etc/nextepc/pgw.conf
support/network/nextepc etc/network/interfaces.d
support/network/99-nextepc.* etc/systemd/network
support/systemd/nextepc-pgwd.service lib/systemd/system

View File

@@ -20,12 +20,18 @@ set -e
case "$1" in
configure)
if ! grep "source-directory" /etc/network/interfaces | grep "/etc/network/interfaces.d" > /dev/null; then
echo "source-directory /etc/network/interfaces.d" >> /etc/network/interfaces
fi
if ! grep "pgwtun" /proc/net/dev > /dev/null; then
ifup pgwtun
fi
if test "x`sysctl -n net.ipv6.conf.all.disable_ipv6`" = x1; then
echo "net.ipv6.conf.all.disable_ipv6=0" > /etc/sysctl.d/30-nextepc.conf
sysctl -p /etc/sysctl.d/30-nextepc.conf
fi
if test "x`systemctl is-enabled systemd-networkd`" = xdisabled; then
systemctl enable systemd-networkd
fi
deb-systemd-invoke restart systemd-networkd
if test -f /etc/sysctl.d/30-nextepc.conf && grep "pgwtun" /proc/net/dev > /dev/null; then
echo "net.ipv6.conf.pgwtun.disable_ipv6=0" > /etc/sysctl.d/30-nextepc.conf
sysctl -p /etc/sysctl.d/30-nextepc.conf
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)

View File

@@ -24,6 +24,7 @@ case "$1" in
if grep "pgwtun" /proc/net/dev > /dev/null; then
ip tuntap del name pgwtun mode tun
fi
rm -f /etc/sysctl.d/30-nextepc.conf
;;
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)

View File

@@ -114,6 +114,26 @@ CORE_DECLARE(void *) core_buffer_to_bcd(c_uint8_t *in, int in_len, void *out);
*/
CORE_DECLARE(char *)core_cpystrn(char *dst, const char *src, size_t dst_size);
/**
* Get the value of an environment variable
* @param value the returned value, allocated from @a pool
* @param envvar the name of the environment variable
*/
CORE_DECLARE(char *) core_env_get(const char *envvar);
/**
* Set the value of an environment variable
* @param envvar the name of the environment variable
* @param value the value to set
*/
CORE_DECLARE(status_t) core_env_set(const char *envvar, const char *value);
/**
* Delete a variable from the environment
* @param envvar the name of the environment variable
*/
CORE_DECLARE(status_t) core_env_delete(const char *envvar);
/** @} */
#ifdef __cplusplus

View File

@@ -13,6 +13,8 @@ extern "C" {
#define TLV_MAX_MORE 8
#define TLV_1_OR_MORE(__v) __v[TLV_MAX_MORE]
#define TLV_MAX_CHILD_DESC 128
typedef enum {
TLV_UINT8,
TLV_UINT16,
@@ -37,7 +39,7 @@ typedef struct _tlv_desc_t {
c_uint16_t length;
c_uint8_t instance;
c_uint16_t vsize;
void *child_descs[];
void *child_descs[TLV_MAX_CHILD_DESC];
} tlv_desc_t;
extern tlv_desc_t tlv_desc_more1;

View File

@@ -43,10 +43,16 @@ void fsm_dispatch(void *s, void *_e)
fsm_t *fsm = s;
event_t *e = _e;
fsm_handler_t tmp = fsm->state;
#if OLD_FSM_DISPATCH
fsm->state = (fsm_handler_t)0;
#endif
(*tmp)(s, e);
#if OLD_FSM_DISPATCH
if (fsm->state != NULL)
#else
if (fsm->state != tmp)
#endif
{
if (e)
{
@@ -64,13 +70,19 @@ void fsm_dispatch(void *s, void *_e)
}
else
{
#if OLD_FSM_DISPATCH
(*tmp)(s, &entry_event);
#else
(*fsm->state)(s, &entry_event);
#endif
}
}
#if OLD_FSM_DISPATCH
else
{
fsm->state = tmp;
}
#endif
}
void fsm_final(void *s, void *_e)

View File

@@ -143,3 +143,56 @@ char *core_cpystrn(char *dst, const char *src, size_t dst_size)
return (d);
}
char *core_env_get(const char *envvar)
{
#ifdef HAVE_GETENV
return getenv(envvar);
#else
return NULL;
#endif
}
status_t core_env_set(const char *envvar, const char *value)
{
#if defined(HAVE_SETENV)
if (0 > setenv(envvar, value, 1))
return CORE_ENOMEM;
return CORE_OK;
#elif defined(HAVE_PUTENV)
char buf[HUGE_STRING_LEN];
if (snprintf(buf, HUGE_STRING_LEN, "%s=%s", envvar, value) < 0)
return CORE_ENOMEM;
if (0 > putenv(buf))
return CORE_ENOMEM;
return CORE_OK;
#else
return CORE_ENOTIMPL;
#endif
}
status_t core_env_delete(const char *envvar)
{
#ifdef HAVE_UNSETENV
unsetenv(envvar);
return CORE_OK;
#else
/* hint: some platforms allow envvars to be unset via
* putenv("varname")... that isn't Single Unix spec,
* but if your platform doesn't have unsetenv() it is
* worth investigating and potentially adding a
* configure check to decide when to use that form of
* putenv() here
*/
return CORE_ENOTIMPL;
#endif
}

View File

@@ -44,6 +44,13 @@ status_t tm_init(void)
status_t tm_final(void)
{
if (pool_size(&timer_pool) != pool_avail(&timer_pool))
d_error("%d not freed in timer_pool[%d]",
pool_size(&timer_pool) - pool_avail(&timer_pool),
pool_size(&timer_pool));
d_trace(9, "%d not freed in timer_pool[%d]\n",
pool_size(&timer_pool) - pool_avail(&timer_pool),
pool_size(&timer_pool));
pool_final(&timer_pool);
return CORE_OK;
}

View File

@@ -29,7 +29,7 @@ const struct testlist {
{testaes},
{testsha2},
{testsock},
#if USE_USRSCTP != 1
#ifndef DARWIN
{testsctp},
#endif
{testtime},

View File

@@ -137,6 +137,54 @@ static void misc_test7(abts_case *tc, void *data)
ABTS_TRUE(tc, strcmp("001010123456819", out) == 0);
}
#define TEST_ENVVAR_NAME "core_test_envvar"
#define TEST_ENVVAR2_NAME "core_test_envvar2"
#define TEST_ENVVAR_VALUE "Just a value that we'll check"
static void misc_test8(abts_case *tc, void *data)
{
char *value;
status_t rv;
rv = core_env_set(TEST_ENVVAR_NAME, TEST_ENVVAR_VALUE);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
value = core_env_get(TEST_ENVVAR_NAME);
ABTS_PTR_NOTNULL(tc, value);
ABTS_STR_EQUAL(tc, TEST_ENVVAR_VALUE, value);
rv = core_env_delete(TEST_ENVVAR_NAME);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
value = core_env_get(TEST_ENVVAR_NAME);
ABTS_PTR_NULL(tc, value);
rv = core_env_set(TEST_ENVVAR_NAME, "");
ABTS_INT_EQUAL(tc, CORE_OK, rv);
value = core_env_get(TEST_ENVVAR_NAME);
ABTS_PTR_NOTNULL(tc, value);
ABTS_STR_EQUAL(tc, "", value);
rv = core_env_delete(TEST_ENVVAR_NAME);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
value = core_env_get(TEST_ENVVAR_NAME);
ABTS_PTR_NULL(tc, value);
rv = core_env_set(TEST_ENVVAR2_NAME, TEST_ENVVAR_VALUE);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
value = core_env_get(TEST_ENVVAR2_NAME);
ABTS_PTR_NOTNULL(tc, value);
ABTS_STR_EQUAL(tc, TEST_ENVVAR_VALUE, value);
value = core_env_get(TEST_ENVVAR_NAME);
ABTS_PTR_NULL(tc, value);
value = core_env_get(TEST_ENVVAR2_NAME);
ABTS_PTR_NOTNULL(tc, value);
ABTS_STR_EQUAL(tc, TEST_ENVVAR_VALUE, value);
rv = core_env_delete(TEST_ENVVAR2_NAME);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
value = core_env_get(TEST_ENVVAR2_NAME);
ABTS_PTR_NULL(tc, value);
}
abts_suite *testmisc(abts_suite *suite)
{
suite = ADD_SUITE(suite)
@@ -148,6 +196,7 @@ abts_suite *testmisc(abts_suite *suite)
abts_run_test(suite, misc_test5, NULL);
abts_run_test(suite, misc_test6, NULL);
abts_run_test(suite, misc_test7, NULL);
abts_run_test(suite, misc_test8, NULL);
return suite;
}

View File

@@ -28,6 +28,8 @@ extern "C" {
memcpy((__dST)->buffer, (__sRC)->buffer, (__dST)->length); \
} while(0)
#define NAS_KSI_NO_KEY_IS_AVAILABLE 0x7
/* 9.9.2.0 Additional information
* O TLV 3-n */
#define NAX_MAX_ADDITIONAL_INFORMATION_LEN 255

View File

@@ -172,6 +172,14 @@ static int s1ap_decode_initiating(s1ap_message_t *message,
s1ap_xer_print_s1ap_errorindication,
s1ap_xer__print2sp, message);
break;
case S1ap_ProcedureCode_id_Reset:
ret = s1ap_decode_s1ap_reseties(
&message->s1ap_ResetIEs,
&initiating_p->value);
s1ap_decode_xer_print_message(
s1ap_xer_print_s1ap_reset,
s1ap_xer__print2sp, message);
break;
default:
d_error("Unknown procedure ID (%d) for initiating message",
(int)initiating_p->procedureCode);
@@ -254,6 +262,15 @@ static int s1ap_decode_successfull_outcome(s1ap_message_t *message,
s1ap_xer__print2sp, message);
break;
case S1ap_ProcedureCode_id_Reset:
ret = s1ap_decode_s1ap_resetacknowledgeies(
&message->s1ap_ResetAcknowledgeIEs,
&successfullOutcome_p->value);
s1ap_decode_xer_print_message(
s1ap_xer_print_s1ap_resetacknowledge,
s1ap_xer__print2sp, message);
break;
default:
d_error("Unknown procedure ID (%ld) for successfull "
"outcome message", successfullOutcome_p->procedureCode);

View File

@@ -56,6 +56,13 @@ static inline int s1ap_encode_handover_preparation_failure(
static inline int s1ap_encode_mme_status_transfer(
s1ap_message_t *message_p, pkbuf_t *pkbuf);
static inline int s1ap_encode_error_indication(
s1ap_message_t *message_p, pkbuf_t *pkbuf);
static inline int s1ap_encode_reset(
s1ap_message_t *message_p, pkbuf_t *pkbuf);
static inline int s1ap_encode_reset_ack(
s1ap_message_t *message_p, pkbuf_t *pkbuf);
static void s1ap_encode_xer_print_message(
asn_enc_rval_t (*func)(asn_app_consume_bytes_f *cb,
void *app_key, s1ap_message_t *message_p),
@@ -182,6 +189,18 @@ static inline int s1ap_encode_initiating_message(
ret = s1ap_encode_mme_status_transfer(message_p, pkbuf);
break;
case S1ap_ProcedureCode_id_ErrorIndication:
s1ap_encode_xer_print_message(s1ap_xer_print_s1ap_errorindication,
s1ap_xer__print2sp, message_p);
ret = s1ap_encode_error_indication(message_p, pkbuf);
break;
case S1ap_ProcedureCode_id_Reset:
s1ap_encode_xer_print_message(s1ap_xer_print_s1ap_reset,
s1ap_xer__print2sp, message_p);
ret = s1ap_encode_reset(message_p, pkbuf);
break;
default:
d_warn("Unknown procedure ID (%d) for initiating message_p\n",
(int)message_p->procedureCode);
@@ -246,6 +265,12 @@ static inline int s1ap_encode_successfull_outcome(
ret = s1ap_encode_handover_cancel_ack(message_p, pkbuf);
break;
case S1ap_ProcedureCode_id_Reset:
s1ap_encode_xer_print_message(s1ap_xer_print_s1ap_resetacknowledge,
s1ap_xer__print2sp, message_p);
ret = s1ap_encode_reset_ack(message_p, pkbuf);
break;
default:
d_warn("Unknown procedure ID (%d) for successfull "
"outcome message\n", (int)message_p->procedureCode);
@@ -1079,6 +1104,116 @@ static inline int s1ap_encode_mme_status_transfer(
return enc_ret.encoded;
}
static inline int s1ap_encode_error_indication(
s1ap_message_t *message_p, pkbuf_t *pkbuf)
{
asn_enc_rval_t enc_ret = {0};
S1AP_PDU_t pdu;
S1ap_ErrorIndication_t error;
asn_TYPE_descriptor_t *td = &asn_DEF_S1ap_ErrorIndication;
memset(&error, 0, sizeof(S1ap_ErrorIndication_t));
if (s1ap_encode_s1ap_errorindicationies(
&error, &message_p->s1ap_ErrorIndicationIEs) < 0)
{
d_error("Encoding of %s failed", td->name);
return -1;
}
memset(&pdu, 0, sizeof (S1AP_PDU_t));
pdu.present = S1AP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = message_p->procedureCode;
pdu.choice.initiatingMessage.criticality = S1ap_Criticality_ignore;
ANY_fromType_aper(&pdu.choice.initiatingMessage.value, td, &error);
enc_ret = aper_encode_to_buffer(&asn_DEF_S1AP_PDU,
&pdu, pkbuf->payload, MAX_SDU_LEN);
ASN_STRUCT_FREE_CONTENTS_ONLY(*td, &error);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_S1AP_PDU, &pdu);
if (enc_ret.encoded < 0)
{
d_error("Encoding of %s failed", td->name);
}
return enc_ret.encoded;
}
static inline int s1ap_encode_reset(s1ap_message_t *message_p, pkbuf_t *pkbuf)
{
asn_enc_rval_t enc_ret = {0};
S1AP_PDU_t pdu;
S1ap_Reset_t reset;
asn_TYPE_descriptor_t *td = &asn_DEF_S1ap_Reset;
memset(&reset, 0, sizeof(S1ap_Reset_t));
if (s1ap_encode_s1ap_reseties(
&reset, &message_p->s1ap_ResetIEs) < 0)
{
d_error("Encoding of %s failed", td->name);
return -1;
}
memset(&pdu, 0, sizeof (S1AP_PDU_t));
pdu.present = S1AP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = message_p->procedureCode;
pdu.choice.initiatingMessage.criticality = S1ap_Criticality_reject;
ANY_fromType_aper(&pdu.choice.initiatingMessage.value, td, &reset);
enc_ret = aper_encode_to_buffer(&asn_DEF_S1AP_PDU,
&pdu, pkbuf->payload, MAX_SDU_LEN);
ASN_STRUCT_FREE_CONTENTS_ONLY(*td, &reset);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_S1AP_PDU, &pdu);
if (enc_ret.encoded < 0)
{
d_error("Encoding of %s failed", td->name);
}
return enc_ret.encoded;
}
static inline int s1ap_encode_reset_ack(
s1ap_message_t *message_p, pkbuf_t *pkbuf)
{
asn_enc_rval_t enc_ret = {0};
S1AP_PDU_t pdu;
S1ap_ResetAcknowledge_t ack;
asn_TYPE_descriptor_t *td = &asn_DEF_S1ap_ResetAcknowledge;
memset(&ack, 0, sizeof(S1ap_ResetAcknowledge_t));
if (s1ap_encode_s1ap_resetacknowledgeies(
&ack, &message_p->s1ap_ResetAcknowledgeIEs) < 0)
{
d_error("Encoding of %s failed", td->name);
return -1;
}
memset(&pdu, 0, sizeof (S1AP_PDU_t));
pdu.present = S1AP_PDU_PR_successfulOutcome;
pdu.choice.successfulOutcome.procedureCode = message_p->procedureCode;
pdu.choice.successfulOutcome.criticality = S1ap_Criticality_reject;
ANY_fromType_aper(&pdu.choice.successfulOutcome.value, td, &ack);
enc_ret = aper_encode_to_buffer(&asn_DEF_S1AP_PDU,
&pdu, pkbuf->payload, MAX_SDU_LEN);
ASN_STRUCT_FREE_CONTENTS_ONLY(*td, &ack);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_S1AP_PDU, &pdu);
if (enc_ret.encoded < 0)
{
d_error("Encoding of %s failed", td->name);
}
return enc_ret.encoded;
}
static void s1ap_encode_xer_print_message(
asn_enc_rval_t (*func)(asn_app_consume_bytes_f *cb,
void *app_key, s1ap_message_t *message_p),

View File

@@ -140,6 +140,11 @@ static inline int s1ap_free_initiating_message(s1ap_message_t *message)
&message->s1ap_ErrorIndicationIEs);
break;
case S1ap_ProcedureCode_id_Reset:
s1ap_free_s1ap_reseties(
&message->s1ap_ResetIEs);
break;
default:
d_warn("Unknown procedure ID (%d) for initiating message\n",
(int)message->procedureCode);
@@ -203,6 +208,11 @@ static inline int s1ap_free_successfull_outcome(s1ap_message_t *message)
&message->s1ap_HandoverCommandIEs);
break;
case S1ap_ProcedureCode_id_Reset:
s1ap_free_s1ap_resetacknowledgeies(
&message->s1ap_ResetAcknowledgeIEs);
break;
default:
d_warn("Unknown procedure ID (%d) for successfull "
"outcome message\n", (int)message->procedureCode);

View File

@@ -58,7 +58,8 @@ status_t context_read_file()
d_assert(config->path, return CORE_ERROR,);
file = fopen(config->path, "rb");
d_assert(file, return CORE_ERROR,);
d_assert(file, return CORE_ERROR,
"Failed to read configuration file `%s`", config->path);
d_assert(yaml_parser_initialize(&parser), return CORE_ERROR,);
yaml_parser_set_input_file(&parser, file);
@@ -79,6 +80,26 @@ status_t context_read_file()
return CORE_OK;
}
status_t context_setup_trace_module()
{
int app = context_self()->logger.trace.app;
if (app)
{
extern int _mutex;
d_trace_level(&_mutex, app);
extern int _pkbuf;
d_trace_level(&_pkbuf, app);
extern int _timer;
d_trace_level(&_timer, app);
extern int _context;
d_trace_level(&_context, app);
}
return CORE_OK;
}
static status_t context_prepare()
{
self.logger.console = -1;

View File

@@ -69,6 +69,7 @@ CORE_DECLARE(context_t*) context_self(void);
CORE_DECLARE(status_t) context_read_file(void);
CORE_DECLARE(status_t) context_parse_config(void);
CORE_DECLARE(status_t) context_setup_trace_module(void);
CORE_DECLARE(status_t) context_db_init(const char *db_uri);
CORE_DECLARE(status_t) context_db_final(void);

View File

@@ -3,6 +3,7 @@
#include "core_debug.h"
#include "core_thread.h"
#include "core_file.h"
#include "core_lib.h"
#include "context.h"
@@ -33,6 +34,9 @@ status_t app_will_initialize(const char *config_path, const char *log_path)
rv = context_parse_config();
if (rv != CORE_OK) return rv;
rv = context_setup_trace_module();
if (rv != CORE_OK) return rv;
app = context_self()->logger.trace.app;
if (app)
{
@@ -45,6 +49,10 @@ status_t app_will_initialize(const char *config_path, const char *log_path)
if (context_self()->db_uri)
{
/* Override configuration if DB_URI environment variable is existed */
if (core_env_get("DB_URI"))
context_self()->db_uri = core_env_get("DB_URI");
rv = context_db_init(context_self()->db_uri);
if (rv != CORE_OK) return rv;
d_print(" MongoDB URI : '%s'\n", context_self()->db_uri);

View File

@@ -25,7 +25,11 @@ status_t app_initialize(const char *config_path, const char *log_path)
d_trace(1, "HSS try to initialize\n");
rv = hss_initialize();
d_assert(rv == CORE_OK, return rv, "Failed to intialize HSS");
if (rv != CORE_OK)
{
d_error("Failed to intialize HSS");
return rv;
}
d_trace(1, "HSS initialize...done\n");
rv = app_did_initialize();

View File

@@ -311,13 +311,6 @@ status_t hss_context_setup_trace_module()
if (app)
{
extern int _mutex;
d_trace_level(&_mutex, app);
extern int _pkbuf;
d_trace_level(&_pkbuf, app);
extern int _context;
d_trace_level(&_context, app);
extern int _hss_context;
d_trace_level(&_hss_context, app);
}

View File

@@ -25,7 +25,11 @@ status_t app_initialize(const char *config_path, const char *log_path)
d_trace(1, "MME try to initialize\n");
rv = mme_initialize();
d_assert(rv == CORE_OK, return rv, "Failed to intialize MME");
if (rv != CORE_OK)
{
d_error("Failed to intialize MME");
return rv;
}
d_trace(1, "MME initialize...done\n");
rv = app_did_initialize();

View File

@@ -11,7 +11,7 @@ libmme_la_SOURCES = \
emm_handler.h emm_build.h \
esm_handler.h esm_build.h \
mme_gtp_path.h mme_s11_build.h mme_s11_handler.h \
mme_sm.h \
mme_sm.h mme_path.h \
mme_kdf.c kasumi.c snow_3g.c zuc.c \
mme_init.c mme_event.c mme_context.c \
s1ap_sm.c s1ap_build.c s1ap_handler.c s1ap_conv.c s1ap_path.c \
@@ -20,7 +20,7 @@ libmme_la_SOURCES = \
emm_sm.c emm_handler.c emm_build.c \
esm_sm.c esm_handler.c esm_build.c \
mme_gtp_path.c mme_s11_build.c mme_s11_handler.c \
mme_sm.c \
mme_sm.c mme_path.c \
$(NULL)
if USRSCTP

View File

@@ -19,13 +19,10 @@ status_t emm_build_attach_accept(
nas_gprs_timer_t *t3412_value = &attach_accept->t3412_value;
int served_tai_index = 0;
nas_eps_mobile_identity_t *guti = &attach_accept->guti;
nas_gprs_timer_t *t3402_value = &attach_accept->t3402_value;
nas_gprs_timer_t *t3423_value = &attach_accept->t3423_value;
nas_eps_network_feature_support_t *eps_network_feature_support =
&attach_accept->eps_network_feature_support;
d_assert(mme_ue, return CORE_ERROR, "Null param");
d_assert(mme_ue->enb_ue, return CORE_ERROR, "Null param");
d_assert(esmbuf, return CORE_ERROR, "Null param");
d_trace(3, "[EMM] Attach accept\n");
@@ -38,11 +35,17 @@ status_t emm_build_attach_accept(
message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = NAS_ATTACH_ACCEPT;
/* Set T3412 */
eps_attach_result->result = mme_ue->nas_eps.attach.attach_type;
t3412_value->unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_DECI_HH;
t3412_value->value = 9;
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
served_tai_index = mme_find_served_tai(&mme_ue->tai);
d_trace(5, " SERVED_TAI_INDEX[%d]\n", served_tai_index);
d_assert(served_tai_index >= 0 &&
served_tai_index < MAX_NUM_OF_SERVED_TAI, return CORE_ERROR,
"Cannot find Served TAI. Check 'mme.tai' configuration");
@@ -53,24 +56,34 @@ status_t emm_build_attach_accept(
attach_accept->esm_message_container.buffer = esmbuf->payload;
attach_accept->esm_message_container.length = esmbuf->len;
attach_accept->presencemask |= NAS_ATTACH_ACCEPT_GUTI_PRESENT;
guti->length = sizeof(nas_eps_mobile_identity_guti_t);
guti->guti.odd_even = NAS_EPS_MOBILE_IDENTITY_EVEN;
guti->guti.type = NAS_EPS_MOBILE_IDENTITY_GUTI;
memcpy(&guti->guti.plmn_id, &mme_ue->guti.plmn_id, PLMN_ID_LEN);
guti->guti.mme_gid = mme_ue->guti.mme_gid;
guti->guti.mme_code = mme_ue->guti.mme_code;
guti->guti.m_tmsi = mme_ue->guti.m_tmsi;
d_trace(5, " GUTI[G:%d,C:%d,M_TMSI:0x%x] IMSI:[%s]\n",
guti->guti.mme_gid, guti->guti.mme_code, guti->guti.m_tmsi,
mme_ue->imsi_bcd);
d_trace(5, " %s GUTI[G:%d,C:%d,M_TMSI:0x%x] IMSI:[%s]\n",
mme_ue->guti_present ? "[V]" : "[N]",
mme_ue->guti.mme_gid, mme_ue->guti.mme_code,
mme_ue->guti.m_tmsi, mme_ue->imsi_bcd);
if (mme_ue->guti_present)
{
attach_accept->presencemask |= NAS_ATTACH_ACCEPT_GUTI_PRESENT;
guti->length = sizeof(nas_eps_mobile_identity_guti_t);
guti->guti.odd_even = NAS_EPS_MOBILE_IDENTITY_EVEN;
guti->guti.type = NAS_EPS_MOBILE_IDENTITY_GUTI;
memcpy(&guti->guti.plmn_id, &mme_ue->guti.plmn_id, PLMN_ID_LEN);
guti->guti.mme_gid = mme_ue->guti.mme_gid;
guti->guti.mme_code = mme_ue->guti.mme_code;
guti->guti.m_tmsi = mme_ue->guti.m_tmsi;
}
mme_ue->guti_present = 0;
#if 0 /* Need not to include T3402 */
/* Set T3402 */
attach_accept->presencemask |= NAS_ATTACH_ACCEPT_T3402_VALUE_PRESENT;
t3402_value->unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_1_MM;
t3402_value->value = 12;
attach_accept->t3402_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_1_MM;
attach_accept->t3402_value.value = 12;
#endif
/* Set T3423 */
attach_accept->presencemask |= NAS_ATTACH_ACCEPT_T3423_VALUE_PRESENT;
t3423_value->unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_DECI_HH;
t3423_value->value = 9;
attach_accept->t3423_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_DECI_HH;
attach_accept->t3423_value.value = 9;
attach_accept->presencemask |=
NAS_ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT;
eps_network_feature_support->length = 1;
@@ -239,20 +252,40 @@ status_t emm_build_security_mode_command(
nas_key_set_identifier->tsc = 0;
nas_key_set_identifier->nas_key_set_identifier = 0;
replayed_ue_security_capabilities->length =
sizeof(replayed_ue_security_capabilities->eea) +
sizeof(replayed_ue_security_capabilities->eia) +
sizeof(replayed_ue_security_capabilities->uea) +
sizeof(replayed_ue_security_capabilities->uia) +
sizeof(replayed_ue_security_capabilities->gea);
replayed_ue_security_capabilities->eea = mme_ue->ue_network_capability.eea;
replayed_ue_security_capabilities->eia = mme_ue->ue_network_capability.eia;
replayed_ue_security_capabilities->uea = mme_ue->ue_network_capability.uea;
replayed_ue_security_capabilities->uia = mme_ue->ue_network_capability.uia;
replayed_ue_security_capabilities->uia =
mme_ue->ue_network_capability.uia & 0x7f;
replayed_ue_security_capabilities->gea =
(mme_ue->ms_network_capability.gea1 << 6) |
mme_ue->ms_network_capability.extended_gea;
replayed_ue_security_capabilities->length =
sizeof(replayed_ue_security_capabilities->eea) +
sizeof(replayed_ue_security_capabilities->eia);
if (replayed_ue_security_capabilities->uea ||
replayed_ue_security_capabilities->uia)
replayed_ue_security_capabilities->length =
sizeof(replayed_ue_security_capabilities->eea) +
sizeof(replayed_ue_security_capabilities->eia) +
sizeof(replayed_ue_security_capabilities->uea) +
sizeof(replayed_ue_security_capabilities->uia);
if (replayed_ue_security_capabilities->gea)
replayed_ue_security_capabilities->length =
sizeof(replayed_ue_security_capabilities->eea) +
sizeof(replayed_ue_security_capabilities->eia) +
sizeof(replayed_ue_security_capabilities->uea) +
sizeof(replayed_ue_security_capabilities->uia) +
sizeof(replayed_ue_security_capabilities->gea);
d_trace(5, " SEC[LEN:%d EEA:0x%x EIA:0x%x UEA:0x%x UIA:0x%x GEA:0x%x]\n",
replayed_ue_security_capabilities->length,
replayed_ue_security_capabilities->eea,
replayed_ue_security_capabilities->eia,
replayed_ue_security_capabilities->uea,
replayed_ue_security_capabilities->uia,
replayed_ue_security_capabilities->gea);
mme_kdf_nas(MME_KDF_NAS_INT_ALG, mme_ue->selected_int_algorithm,
mme_ue->kasme, mme_ue->knas_int);
mme_kdf_nas(MME_KDF_NAS_ENC_ALG, mme_ue->selected_enc_algorithm,
@@ -295,10 +328,9 @@ status_t emm_build_tau_accept(pkbuf_t **emmbuf, mme_ue_t *mme_ue)
&message.emm.tracking_area_update_accept;
int served_tai_index = 0;
d_assert(mme_ue, return CORE_ERROR,);
mme_sess_t *sess = NULL;
d_trace(3, "[EMM] Tracking area update accept\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
d_assert(mme_ue, return CORE_ERROR,);
memset(&message, 0, sizeof(message));
message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
@@ -309,8 +341,6 @@ status_t emm_build_tau_accept(pkbuf_t **emmbuf, mme_ue_t *mme_ue)
/* Set T3412 */
tau_accept->presencemask |=
NAS_TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_PRESENT ;
/* FIXME: Use the value from configuration */
tau_accept->t3412_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_DECI_HH;
tau_accept->t3412_value.value = 9;
@@ -318,7 +348,12 @@ status_t emm_build_tau_accept(pkbuf_t **emmbuf, mme_ue_t *mme_ue)
tau_accept->presencemask |=
NAS_TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_PRESENT;
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
served_tai_index = mme_find_served_tai(&mme_ue->tai);
d_trace(5, " SERVED_TAI_INDEX[%d]\n", served_tai_index);
d_assert(served_tai_index >= 0 &&
served_tai_index < MAX_NUM_OF_SERVED_TAI, return CORE_ERROR,
"Cannot find Served TAI. Check 'mme.tai' configuration");
@@ -329,39 +364,52 @@ status_t emm_build_tau_accept(pkbuf_t **emmbuf, mme_ue_t *mme_ue)
/* Set EPS bearer context status */
tau_accept->presencemask |=
NAS_TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_PRESENT;
tau_accept->eps_bearer_context_status.length = 2;
tau_accept->eps_bearer_context_status.ebi5 =
(mme_bearer_find_by_ue_ebi(mme_ue, 5) ? 1 : 0);
tau_accept->eps_bearer_context_status.ebi6 =
(mme_bearer_find_by_ue_ebi(mme_ue, 6) ? 1 : 0);
tau_accept->eps_bearer_context_status.ebi7 =
(mme_bearer_find_by_ue_ebi(mme_ue, 7) ? 1 : 0);
/* FIXME : Need to set other ebi */
sess = mme_sess_first(mme_ue);
while(sess)
{
mme_bearer_t *bearer = mme_bearer_first(sess);
while(bearer)
{
switch(bearer->ebi)
{
case 5: tau_accept->eps_bearer_context_status.ebi5 = 1; break;
case 6: tau_accept->eps_bearer_context_status.ebi6 = 1; break;
case 7: tau_accept->eps_bearer_context_status.ebi7 = 1; break;
case 8: tau_accept->eps_bearer_context_status.ebi8 = 1; break;
case 9: tau_accept->eps_bearer_context_status.ebi9 = 1; break;
case 10: tau_accept->eps_bearer_context_status.ebi10 = 1; break;
case 11: tau_accept->eps_bearer_context_status.ebi11 = 1; break;
case 12: tau_accept->eps_bearer_context_status.ebi12 = 1; break;
case 13: tau_accept->eps_bearer_context_status.ebi13 = 1; break;
case 14: tau_accept->eps_bearer_context_status.ebi14 = 1; break;
case 15: tau_accept->eps_bearer_context_status.ebi15 = 1; break;
default: break;
}
bearer = mme_bearer_next(bearer);
}
sess = mme_sess_next(sess);
}
#if 0 /* Need not to include T3402 */
/* Set T3402 */
tau_accept->presencemask |=
NAS_TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_PRESENT;
/* FIXME: Use the value from configuration */
tau_accept->t3402_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_1_MM;
tau_accept->t3402_value.value = 12;
#endif
/* Set T3423 */
tau_accept->presencemask |=
NAS_TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_PRESENT;
/* FIXME: Use the value from configuration */
tau_accept->t3423_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_DECI_HH;
tau_accept->t3423_value.value = 9;
/* Set EPS network feature support */
tau_accept->presencemask |=
NAS_TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT;
tau_accept->eps_network_feature_support.length = 1;
tau_accept->eps_network_feature_support.esr_ps = 1;
tau_accept->eps_network_feature_support.epc_lcs = 1;
tau_accept->eps_network_feature_support.ims_vops = 1;
d_assert(nas_security_encode(emmbuf, mme_ue, &message) == CORE_OK &&

View File

@@ -38,6 +38,13 @@ status_t emm_handle_attach_request(
d_assert(esm_message_container, return CORE_ERROR, "Null param");
d_assert(esm_message_container->length, return CORE_ERROR, "Null param");
/* Set EPS Attach Type */
memcpy(&mme_ue->nas_eps.attach, eps_attach_type,
sizeof(nas_eps_attach_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_ATTACH_REQUEST;
mme_ue->nas_eps.ksi = eps_attach_type->nas_key_set_identifier;
d_trace(5, " NAS_EPS TYPE[%d] KSI[%d] ATTACH[0x%x]\n",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi, mme_ue->nas_eps.data);
/*
* ATTACH_REQUEST
* Clear EBI generator
@@ -60,11 +67,14 @@ status_t emm_handle_attach_request(
mme_ue->nhcc = 1;
}
/* Set EPS Attach Type */
memcpy(&mme_ue->nas_eps.attach, eps_attach_type,
sizeof(nas_eps_attach_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_ATTACH_REQUEST;
d_trace(9, " ATTACH_TYPE[%d]\n", eps_attach_type->attach_type);
d_trace(5, " OLD TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " OLD E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
enb_ue->nas.tai.plmn_id, enb_ue->nas.tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
enb_ue->nas.e_cgi.plmn_id, enb_ue->nas.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->nas.tai, sizeof(tai_t));
@@ -75,11 +85,14 @@ status_t emm_handle_attach_request(
if (served_tai_index < 0)
{
/* Send Attach Reject */
d_warn("Cannot find Served TAI[PLMN_ID:0x%x,TAC:%d]",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
nas_send_attach_reject(mme_ue,
EMM_CAUSE_TRACKING_AREA_NOT_ALLOWED,
ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
return CORE_ERROR;
}
d_trace(5, " SERVED_TAI_INDEX[%d]\n", served_tai_index);
/* Store UE specific information */
if (attach_request->presencemask &
@@ -99,9 +112,14 @@ status_t emm_handle_attach_request(
memcpy(&mme_ue->ue_network_capability,
&attach_request->ue_network_capability,
sizeof(attach_request->ue_network_capability));
memcpy(&mme_ue->ms_network_capability,
&attach_request->ms_network_capability,
sizeof(attach_request->ms_network_capability));
if (attach_request->presencemask &
NAS_ATTACH_REQUEST_MS_NETWORK_CAPABILITY_PRESENT)
{
memcpy(&mme_ue->ms_network_capability,
&attach_request->ms_network_capability,
sizeof(attach_request->ms_network_capability));
}
switch(eps_mobile_identity->imsi.type)
{
@@ -182,7 +200,8 @@ status_t emm_handle_attach_complete(
NAS_EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_PRESENT;
universal_time_and_local_time_zone->year =
NAS_TIME_TO_BCD(time_exp.tm_year % 100);
universal_time_and_local_time_zone->mon = NAS_TIME_TO_BCD(time_exp.tm_mon);
universal_time_and_local_time_zone->mon =
NAS_TIME_TO_BCD(time_exp.tm_mon+1);
universal_time_and_local_time_zone->mday =
NAS_TIME_TO_BCD(time_exp.tm_mday);
universal_time_and_local_time_zone->hour =
@@ -201,6 +220,22 @@ status_t emm_handle_attach_complete(
NAS_EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_PRESENT;
network_daylight_saving_time->length = 1;
if(mme_self()->full_name.length)
{
emm_information->presencemask |=
NAS_EMM_INFORMATION_FULL_NAME_FOR_NETWORK_PRESENT;
memcpy(&emm_information->full_name_for_network,
&mme_self()->full_name, sizeof(nas_network_name_t));
}
if(mme_self()->short_name.length)
{
emm_information->presencemask |=
NAS_EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_PRESENT;
memcpy(&emm_information->short_name_for_network,
&mme_self()->short_name, sizeof(nas_network_name_t));
}
rv = nas_security_encode(&emmbuf, mme_ue, &message);
d_assert(rv == CORE_OK && emmbuf, return CORE_ERROR, "emm build error");
d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,);
@@ -247,13 +282,19 @@ status_t emm_handle_identity_response(
status_t emm_handle_detach_request(
mme_ue_t *mme_ue, nas_detach_request_from_ue_t *detach_request)
{
status_t rv;
enb_ue_t *enb_ue = NULL;
nas_detach_type_t *detach_type = NULL;
d_assert(detach_request, return CORE_ERROR, "Null param");
d_assert(mme_ue, return CORE_ERROR, "Null param");
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return CORE_ERROR, "Null param");
detach_type = &detach_request->detach_type;
/* Set EPS Attach Type */
memcpy(&mme_ue->nas_eps.detach, detach_type, sizeof(nas_detach_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_DETACH_REQUEST_FROM_UE;
mme_ue->nas_eps.ksi = detach_type->nas_key_set_identifier;
d_trace(5, " NAS_EPS TYPE[%d] KSI[%d] DETACH[0x%x]\n",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi, mme_ue->nas_eps.data);
switch (detach_request->detach_type.detach_type)
{
@@ -276,22 +317,8 @@ status_t emm_handle_detach_request(
default: /* all other values */
break;
}
/* Save detach type */
mme_ue->detach_type = detach_request->detach_type;
if (MME_HAVE_SGW_S11_PATH(mme_ue))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK, return CORE_ERROR,
"mme_gtp_send_delete_all_sessions failed");
}
else
{
rv = nas_send_detach_accept(mme_ue);
d_assert(rv == CORE_OK, return CORE_ERROR,
"nas_send_detach_accept failed");
}
if (detach_request->detach_type.switch_off)
d_trace(5, " Switch-Off\n");
return CORE_OK;
}
@@ -299,8 +326,17 @@ status_t emm_handle_detach_request(
status_t emm_handle_service_request(
mme_ue_t *mme_ue, nas_service_request_t *service_request)
{
nas_ksi_and_sequence_number_t *ksi_and_sequence_number =
&service_request->ksi_and_sequence_number;
d_assert(mme_ue, return CORE_ERROR, "Null param");
/* Set EPS Update Type */
mme_ue->nas_eps.type = MME_EPS_TYPE_SERVICE_REQUEST;
mme_ue->nas_eps.ksi = ksi_and_sequence_number->ksi;
d_trace(5, " NAS_EPS TYPE[%d] KSI[%d]\n",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi);
/*
* ATTACH_REQUEST
* Clear EBI generator
@@ -322,8 +358,11 @@ status_t emm_handle_service_request(
mme_ue->nhcc = 1;
}
/* Set EPS Update Type */
mme_ue->nas_eps.type = MME_EPS_TYPE_SERVICE_REQUEST;
d_trace(5, " GUTI[G:%d,C:%d,M_TMSI:0x%x] IMSI[%s]\n",
mme_ue->guti.mme_gid,
mme_ue->guti.mme_code,
mme_ue->guti.m_tmsi,
MME_UE_HAVE_IMSI(mme_ue) ? mme_ue->imsi_bcd : "Unknown");
return CORE_OK;
}
@@ -343,6 +382,15 @@ status_t emm_handle_tau_request(
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return CORE_ERROR, "Null param");
/* Set EPS Update Type */
memcpy(&mme_ue->nas_eps.update, eps_update_type,
sizeof(nas_eps_update_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_TAU_REQUEST;
mme_ue->nas_eps.ksi = eps_update_type->nas_key_set_identifier;
d_trace(5, " NAS_EPS TYPE[%d] KSI[%d] UPDATE[0x%x]\n",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi,
mme_ue->nas_eps.data);
/*
* ATTACH_REQUEST
* Clear EBI generator
@@ -358,10 +406,24 @@ status_t emm_handle_tau_request(
*/
CLEAR_PAGING_INFO(mme_ue);
/* Set EPS Update Type */
memcpy(&mme_ue->nas_eps.update, eps_update_type,
sizeof(nas_eps_update_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_TAU_REQUEST;
if (BEARER_CONTEXT_IS_ACTIVE(mme_ue))
d_trace(5, " Bearer-Active\n");
else
d_trace(5, " Bearer-Inactive\n");
if (mme_ue->nas_eps.update.active_flag)
d_trace(5, " Active flag\n");
else
d_trace(5, " No Active flag\n");
d_trace(5, " OLD TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " OLD E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
enb_ue->nas.tai.plmn_id, enb_ue->nas.tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
enb_ue->nas.e_cgi.plmn_id, enb_ue->nas.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->nas.tai, sizeof(tai_t));
@@ -372,9 +434,12 @@ status_t emm_handle_tau_request(
if (served_tai_index < 0)
{
/* Send TAU reject */
d_warn("Cannot find Served TAI[PLMN_ID:0x%x,TAC:%d]",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
nas_send_tau_reject(mme_ue, EMM_CAUSE_TRACKING_AREA_NOT_ALLOWED);
return CORE_ERROR;
}
d_trace(5, " SERVED_TAI_INDEX[%d]\n", served_tai_index);
/* Store UE specific information */
if (tau_request->presencemask &

View File

@@ -16,6 +16,7 @@
#include "nas_path.h"
#include "s1ap_path.h"
#include "mme_gtp_path.h"
#include "mme_path.h"
#include "mme_sm.h"
void emm_state_initial(fsm_t *s, event_t *e)
@@ -60,8 +61,8 @@ static void common_register_state(fsm_t *s, event_t *e)
{
status_t rv;
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
mme_ue = mme_ue_find(event_get_param1(e));
d_assert(mme_ue, return, "Null param");
@@ -78,9 +79,12 @@ static void common_register_state(fsm_t *s, event_t *e)
}
case MME_EVT_EMM_MESSAGE:
{
nas_message_t *message = (nas_message_t *)event_get_param4(e);
nas_message_t *message = (nas_message_t *)event_get_param5(e);
d_assert(message, return, "Null param");
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return, "Null param");
if (message->emm.h.security_header_type
== NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE)
{
@@ -99,7 +103,7 @@ static void common_register_state(fsm_t *s, event_t *e)
d_warn("Unknown UE");
rv = nas_send_service_reject(mme_ue,
EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
d_assert(rv == CORE_OK, return,
d_assert(rv == CORE_OK,,
"nas_send_service_reject() failed");
FSM_TRAN(s, &emm_state_exception);
return;
@@ -110,15 +114,12 @@ static void common_register_state(fsm_t *s, event_t *e)
d_warn("No Security Context : IMSI[%s]", mme_ue->imsi_bcd);
rv = nas_send_service_reject(mme_ue,
EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
d_assert(rv == CORE_OK, return,
d_assert(rv == CORE_OK,,
"nas_send_service_reject() failed");
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return, "No ENB UE context");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);
d_assert(rv == CORE_OK,,
"s1ap_send_ue_context_release_command() failed");
return;
@@ -185,14 +186,6 @@ static void common_register_state(fsm_t *s, event_t *e)
{
d_trace(3, "[EMM] Tracking area update complete\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return, "Null param");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
return;
}
case NAS_EMM_STATUS:
@@ -207,8 +200,19 @@ static void common_register_state(fsm_t *s, event_t *e)
{
d_trace(3, "[EMM] Detach request\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
emm_handle_detach_request(
rv = emm_handle_detach_request(
mme_ue, &message->emm.detach_request_from_ue);
if (rv != CORE_OK)
{
d_error("emm_handle_attach_request() failed");
FSM_TRAN(s, emm_state_exception);
return;
}
rv = mme_send_delete_session_or_detach(mme_ue);
d_assert(rv == CORE_OK,,
"mme_send_delete_session_or_detach() failed");
FSM_TRAN(s, &emm_state_de_registered);
return;
}
@@ -256,6 +260,9 @@ static void common_register_state(fsm_t *s, event_t *e)
return;
}
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return, "Null param");
switch(mme_ue->nas_eps.type)
{
case MME_EPS_TYPE_ATTACH_REQUEST:
@@ -269,7 +276,7 @@ static void common_register_state(fsm_t *s, event_t *e)
}
else
{
if (MME_HAVE_SGW_S11_PATH(mme_ue))
if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK,,
@@ -285,28 +292,56 @@ static void common_register_state(fsm_t *s, event_t *e)
}
case MME_EPS_TYPE_TAU_REQUEST:
{
if (SECURITY_CONTEXT_IS_VALID(mme_ue))
S1ap_ProcedureCode_t procedureCode =
(S1ap_ProcedureCode_t)event_get_param2(e);
if (!SESSION_CONTEXT_IS_AVAILABLE(mme_ue))
{
rv = nas_send_tau_accept(mme_ue);
d_assert(rv == CORE_OK,, "nas_send_tau_accept() failed");
FSM_TRAN(&mme_ue->sm, &emm_state_registered);
d_warn("No PDN Connection : UE[%s]", mme_ue->imsi_bcd);
rv = nas_send_tau_reject(mme_ue,
EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
d_assert(rv == CORE_OK,, "nas_send_tau_reject() failed");
FSM_TRAN(s, emm_state_exception);
break;
}
else
if (!SECURITY_CONTEXT_IS_VALID(mme_ue))
{
if (MME_HAVE_SGW_S11_PATH(mme_ue))
mme_s6a_send_air(mme_ue, NULL);
FSM_TRAN(&mme_ue->sm, &emm_state_authentication);
break;
}
if (procedureCode == S1ap_ProcedureCode_id_initialUEMessage)
{
d_trace(5, " Iniital UE Message\n");
if (mme_ue->nas_eps.update.active_flag)
{
mme_s6a_send_air(mme_ue, NULL);
FSM_TRAN(&mme_ue->sm, &emm_state_authentication);
rv = nas_send_tau_accept(mme_ue,
S1ap_ProcedureCode_id_InitialContextSetup);
d_assert(rv == CORE_OK,, "nas_send_tau_accept() failed");
}
else
{
d_warn("No PDN Connection : UE[%s]", mme_ue->imsi_bcd);
rv = nas_send_tau_reject(mme_ue,
EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
d_assert(rv == CORE_OK,, "nas_send_tau_reject() failed");
FSM_TRAN(s, emm_state_exception);
rv = nas_send_tau_accept(mme_ue,
S1ap_ProcedureCode_id_downlinkNASTransport);
d_assert(rv == CORE_OK,, "nas_send_tau_accept() failed");
rv = mme_send_release_access_bearer_or_ue_context_release(
mme_ue, enb_ue);
d_assert(rv == CORE_OK,, "mme_send_release_access_bearer"
"_or_ue_context_release() failed");
}
}
else if (procedureCode == S1ap_ProcedureCode_id_uplinkNASTransport)
{
d_trace(5, " Uplink NAS Transport\n");
rv = nas_send_tau_accept(mme_ue,
S1ap_ProcedureCode_id_downlinkNASTransport);
d_assert(rv == CORE_OK,, "nas_send_tau_accept() failed");
}
else
d_assert(0,, "Invalid Procedure Code[%d]", procedureCode);
break;
}
default:
@@ -317,6 +352,7 @@ static void common_register_state(fsm_t *s, event_t *e)
void emm_state_authentication(fsm_t *s, event_t *e)
{
status_t rv;
mme_ue_t *mme_ue = NULL;
d_assert(s, return, "Null param");
@@ -339,7 +375,7 @@ void emm_state_authentication(fsm_t *s, event_t *e)
}
case MME_EVT_EMM_MESSAGE:
{
nas_message_t *message = (nas_message_t *)event_get_param4(e);
nas_message_t *message = (nas_message_t *)event_get_param5(e);
d_assert(message, break, "Null param");
switch(message->emm.h.message_type)
@@ -361,8 +397,6 @@ void emm_state_authentication(fsm_t *s, event_t *e)
memcmp(authentication_response_parameter->res,
mme_ue->xres, mme_ue->xres_len) != 0)
{
status_t rv;
rv = nas_send_authentication_reject(mme_ue);
d_assert(rv == CORE_OK,, "nas send error");
FSM_TRAN(&mme_ue->sm, &emm_state_exception);
@@ -383,9 +417,33 @@ void emm_state_authentication(fsm_t *s, event_t *e)
authentication_failure_parameter;
d_trace(3, "[EMM] Authentication failure\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
d_trace(5, " IMSI[%s] EMM_CAUSE[%d]\n", mme_ue->imsi_bcd,
authentication_failure->emm_cause);
mme_s6a_send_air(mme_ue, authentication_failure_parameter);
switch(authentication_failure->emm_cause)
{
case EMM_CAUSE_MAC_FAILURE:
d_error("Authentication failure(MAC failure)");
break;
case EMM_CAUSE_NON_EPS_AUTHENTICATION_UNACCEPTABLE:
d_error("Authentication failure"
"(Non-EPS authentication unacceptable)");
break;
case EMM_CAUSE_SYNCH_FAILURE:
d_warn("Authentication failure(Synch failure)");
mme_s6a_send_air(mme_ue,
authentication_failure_parameter);
return;
default:
d_error("Unknown EMM_CAUSE{%d] in Authentication"
" failure",
authentication_failure->emm_cause);
break;
}
rv = nas_send_authentication_reject(mme_ue);
d_assert(rv == CORE_OK,, "nas send error");
FSM_TRAN(&mme_ue->sm, &emm_state_exception);
break;
}
case NAS_EMM_STATUS:
@@ -396,6 +454,26 @@ void emm_state_authentication(fsm_t *s, event_t *e)
FSM_TRAN(s, &emm_state_exception);
break;
}
case NAS_DETACH_REQUEST:
{
d_trace(3, "[EMM] Detach request\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
rv = emm_handle_detach_request(
mme_ue, &message->emm.detach_request_from_ue);
if (rv != CORE_OK)
{
d_error("emm_handle_attach_request() failed");
FSM_TRAN(s, emm_state_exception);
return;
}
rv = mme_send_delete_session_or_detach(mme_ue);
d_assert(rv == CORE_OK,,
"mme_send_delete_session_or_detach() failed");
FSM_TRAN(s, &emm_state_de_registered);
break;
}
default:
{
d_warn("Unknown message[%d]", message->emm.h.message_type);
@@ -414,6 +492,7 @@ void emm_state_authentication(fsm_t *s, event_t *e)
void emm_state_security_mode(fsm_t *s, event_t *e)
{
status_t rv;
mme_ue_t *mme_ue = NULL;
d_assert(s, return, "Null param");
@@ -428,7 +507,6 @@ void emm_state_security_mode(fsm_t *s, event_t *e)
{
case FSM_ENTRY_SIG:
{
status_t rv;
pkbuf_t *emmbuf = NULL;
rv = emm_build_security_mode_command(&emmbuf, mme_ue);
@@ -445,7 +523,7 @@ void emm_state_security_mode(fsm_t *s, event_t *e)
}
case MME_EVT_EMM_MESSAGE:
{
nas_message_t *message = (nas_message_t *)event_get_param4(e);
nas_message_t *message = (nas_message_t *)event_get_param5(e);
d_assert(message, break, "Null param");
switch(message->emm.h.message_type)
@@ -496,6 +574,26 @@ void emm_state_security_mode(fsm_t *s, event_t *e)
FSM_TRAN(s, &emm_state_exception);
break;
}
case NAS_DETACH_REQUEST:
{
d_trace(3, "[EMM] Detach request\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
rv = emm_handle_detach_request(
mme_ue, &message->emm.detach_request_from_ue);
if (rv != CORE_OK)
{
d_error("emm_handle_attach_request() failed");
FSM_TRAN(s, emm_state_exception);
return;
}
rv = mme_send_delete_session_or_detach(mme_ue);
d_assert(rv == CORE_OK,,
"mme_send_delete_session_or_detach() failed");
FSM_TRAN(s, &emm_state_de_registered);
break;
}
default:
{
d_warn("Unknown message[%d]", message->emm.h.message_type);
@@ -537,7 +635,7 @@ void emm_state_initial_context_setup(fsm_t *s, event_t *e)
}
case MME_EVT_EMM_MESSAGE:
{
nas_message_t *message = (nas_message_t *)event_get_param4(e);
nas_message_t *message = (nas_message_t *)event_get_param5(e);
d_assert(message, break, "Null param");
switch(message->emm.h.message_type)
@@ -566,6 +664,26 @@ void emm_state_initial_context_setup(fsm_t *s, event_t *e)
FSM_TRAN(s, &emm_state_exception);
break;
}
case NAS_DETACH_REQUEST:
{
d_trace(3, "[EMM] Detach request\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
rv = emm_handle_detach_request(
mme_ue, &message->emm.detach_request_from_ue);
if (rv != CORE_OK)
{
d_error("emm_handle_attach_request() failed");
FSM_TRAN(s, emm_state_exception);
return;
}
rv = mme_send_delete_session_or_detach(mme_ue);
d_assert(rv == CORE_OK,,
"mme_send_delete_session_or_detach() failed");
FSM_TRAN(s, &emm_state_de_registered);
break;
}
default:
{
d_warn("Unknown message[%d]",

View File

@@ -131,7 +131,7 @@ status_t esm_handle_information_response(mme_sess_t *sess,
if (sess->pdn)
{
d_trace(5, " APN[%s]\n", sess->pdn->apn);
if (MME_HAVE_SGW_S11_PATH(mme_ue))
if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue))
{
rv = nas_send_attach_accept(mme_ue);
d_assert(rv == CORE_OK, return CORE_ERROR, "nas send failed");
@@ -153,21 +153,3 @@ status_t esm_handle_information_response(mme_sess_t *sess,
return CORE_OK;
}
void esm_handle_activate_default_bearer_accept(mme_bearer_t *bearer)
{
status_t rv;
d_assert(bearer, return, "Null param");
mme_bearer_t *dedicated_bearer = mme_bearer_next(bearer);
while(dedicated_bearer)
{
rv = nas_send_activate_dedicated_bearer_context_request(
dedicated_bearer);
d_assert(rv == CORE_OK, return,
"nas_send_activate_dedicated_bearer_context failed");
dedicated_bearer = mme_bearer_next(dedicated_bearer);
}
}

View File

@@ -13,10 +13,6 @@ CORE_DECLARE(status_t) esm_handle_pdn_connectivity_request(mme_bearer_t *bearer,
nas_pdn_connectivity_request_t *pdn_connectivity_request);
CORE_DECLARE(status_t) esm_handle_information_response(mme_sess_t *sess,
nas_esm_information_response_t *bearer_information_response);
CORE_DECLARE(void) esm_handle_activate_default_bearer_accept(
mme_bearer_t *bearer);
CORE_DECLARE(void) esm_handle_activate_dedicated_bearer_accept(
mme_bearer_t *bearer);
#ifdef __cplusplus
}

View File

@@ -100,13 +100,17 @@ void esm_state_inactive(fsm_t *s, event_t *e)
"context accept\n");
d_trace(5, " IMSI[%s] PTI[%d] EBI[%d]\n",
mme_ue->imsi_bcd, sess->pti, bearer->ebi);
/* Check if Initial Context Setup Response or
* E-RAB Setup Response is received */
if (MME_HAVE_ENB_S1U_PATH(bearer))
{
rv = mme_gtp_send_modify_bearer_request(bearer, 0);
d_assert(rv == CORE_OK, return, "gtp send failed");
d_assert(rv == CORE_OK,, "gtp send failed");
}
esm_handle_activate_default_bearer_accept(bearer);
rv = nas_send_activate_all_dedicated_bearers(bearer);
d_assert(rv == CORE_OK,, "nas send failed");
FSM_TRAN(s, esm_state_active);
break;
}
@@ -116,11 +120,12 @@ void esm_state_inactive(fsm_t *s, event_t *e)
"context accept\n");
d_trace(5, " IMSI[%s] PTI[%d] EBI[%d]\n",
mme_ue->imsi_bcd, sess->pti, bearer->ebi);
/* Check if Initial Context Setup Response or
* E-RAB Setup Response is received */
if (MME_HAVE_ENB_S1U_PATH(bearer))
{
rv = mme_gtp_send_create_bearer_response(bearer);
d_assert(rv == CORE_OK, return, "gtp send failed");
d_assert(rv == CORE_OK,, "gtp send failed");
}
FSM_TRAN(s, esm_state_active);
@@ -198,9 +203,9 @@ void esm_state_active(fsm_t *s, event_t *e)
}
case NAS_PDN_DISCONNECT_REQUEST:
{
d_trace(3, "[NAS] PDN disconnect request : "
"UE[%s] --> ESM[EBI:%d]\n",
mme_ue->imsi_bcd, bearer->ebi);
d_trace(3, "[ESM] PDN disconnect request\n");
d_trace(5, " IMSI[%s] PTI[%d] EBI[%d]\n",
mme_ue->imsi_bcd, sess->pti, bearer->ebi);
if (MME_HAVE_SGW_S1U_PATH(sess))
{
rv = mme_gtp_send_delete_session_request(sess);
@@ -218,9 +223,9 @@ void esm_state_active(fsm_t *s, event_t *e)
}
case NAS_MODIFY_EPS_BEARER_CONTEXT_ACCEPT:
{
d_trace(3, "[NAS] Modify EPS bearer context accept : "
"UE[%s] --> ESM[EBI:%d] in ACTIVE state\n",
mme_ue->imsi_bcd, bearer->ebi);
d_trace(3, "[ESM] Modify EPS bearer context accept\n");
d_trace(5, " IMSI[%s] PTI[%d] EBI[%d]\n",
mme_ue->imsi_bcd, sess->pti, bearer->ebi);
rv = mme_gtp_send_update_bearer_response(bearer);
d_assert(rv == CORE_OK, return,
@@ -229,9 +234,10 @@ void esm_state_active(fsm_t *s, event_t *e)
}
case NAS_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT:
{
d_trace(3, "[NAS] Deactivate EPS bearer context accept : "
"UE[%s] --> ESM[EBI:%d] in ACTIVE state\n",
mme_ue->imsi_bcd, bearer->ebi);
d_trace(3, "[ESM] [A] Deactivate EPS bearer "
"context accept\n");
d_trace(5, " IMSI[%s] PTI[%d] EBI[%d]\n",
mme_ue->imsi_bcd, sess->pti, bearer->ebi);
rv = mme_gtp_send_delete_bearer_response(bearer);
d_assert(rv == CORE_OK, return,
"mme_gtp_send_delete_session_request error");
@@ -293,9 +299,10 @@ void esm_state_pdn_will_disconnect(fsm_t *s, event_t *e)
{
case NAS_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT:
{
d_trace(3, "[NAS] Deactivate EPS bearer context accept : "
"UE[%s] --> ESM[EBI:%d] in PDN WILL DISCONNECT state\n",
mme_ue->imsi_bcd, bearer->ebi);
d_trace(3, "[ESM] [D] Deactivate EPS bearer "
"context accept\n");
d_trace(5, " IMSI[%s] PTI[%d] EBI[%d]\n",
mme_ue->imsi_bcd, sess->pti, bearer->ebi);
FSM_TRAN(s, esm_state_pdn_did_disconnect);
break;
}

View File

@@ -75,7 +75,8 @@ status_t mme_context_init()
self.guti_ue_hash = hash_make();
/* Timer value */
self.t3413_value = 2; /* Paging retry Timer: 2 secs */
self.t3413_value = 2; /* Paging retry timer: 2 secs */
self.s1_holding_timer_value = 30; /* S1 holding timer: 30 secs */
context_initialized = 1;
@@ -1210,6 +1211,57 @@ status_t mme_context_parse_config()
}
}
}
else if(!strcmp(mme_key, "network_name"))
{
yaml_iter_t network_name_iter;
yaml_iter_recurse(&mme_iter, &network_name_iter);
while(yaml_iter_next(&network_name_iter))
{
const char *network_name_key =
yaml_iter_key(&network_name_iter);
d_assert(network_name_key,
return CORE_ERROR,);
if (!strcmp(network_name_key, "full"))
{
nas_network_name_t *network_full_name =
&self.full_name;
const char *c_network_name =
yaml_iter_value(&network_name_iter);
c_uint8_t size = strlen(c_network_name);
c_uint8_t i;
for(i = 0;i<size;i++)
{
/* Workaround to convert the ASCII to USC-2 */
network_full_name->name[i*2] = 0;
network_full_name->name[(i*2)+1] =
c_network_name[i];
}
network_full_name->length = size*2+1;
network_full_name->coding_scheme = 1;
}
else if (!strcmp(network_name_key, "short"))
{
nas_network_name_t *network_short_name =
&self.short_name;
const char *c_network_name =
yaml_iter_value(&network_name_iter);
c_uint8_t size = strlen(c_network_name);
c_uint8_t i;
for(i = 0;i<size;i++)
{
/* Workaround to convert the ASCII to USC-2 */
network_short_name->name[i*2] = 0;
network_short_name->name[(i*2)+1] =
c_network_name[i];
}
network_short_name->length = size*2+1;
network_short_name->coding_scheme = 1;
}
}
}
else
d_warn("unknown key `%s`", mme_key);
}
@@ -1460,13 +1512,6 @@ status_t mme_context_setup_trace_module()
if (app)
{
extern int _mutex;
d_trace_level(&_mutex, app);
extern int _pkbuf;
d_trace_level(&_pkbuf, app);
extern int _context;
d_trace_level(&_context, app);
extern int _mme_context;
d_trace_level(&_mme_context, app);
extern int _mme_sm;
@@ -1479,6 +1524,8 @@ status_t mme_context_setup_trace_module()
d_trace_level(&_s1ap_sm, s1ap);
extern int _s1ap_build;
d_trace_level(&_s1ap_build, s1ap);
extern int _s1ap_conv;
d_trace_level(&_s1ap_conv, s1ap);
extern int _s1ap_handler;
d_trace_level(&_s1ap_handler, s1ap);
extern int _s1ap_sctp;
@@ -1725,6 +1772,12 @@ enb_ue_t* enb_ue_add(mme_enb_t *enb)
sizeof(enb_ue->mme_ue_s1ap_id), enb_ue);
list_append(&enb->enb_ue_list, enb_ue);
/* Create S1 holding timer */
enb_ue->holding_timer = timer_create(&self.tm_service,
MME_EVT_S1AP_S1_HOLDING_TIMER, self.s1_holding_timer_value * 1000);
d_assert(enb_ue->holding_timer, return NULL, "Null param");
timer_set_param1(enb_ue->holding_timer, enb_ue->index);
return enb_ue;
}
@@ -1738,17 +1791,22 @@ unsigned int enb_ue_count()
status_t enb_ue_remove(enb_ue_t *enb_ue)
{
status_t rv;
d_assert(self.mme_ue_s1ap_id_hash, return CORE_ERROR, "Null param");
d_assert(enb_ue, return CORE_ERROR, "Null param");
d_assert(enb_ue->enb, return CORE_ERROR, "Null param");
/* De-associate S1 with NAS/EMM */
rv = enb_ue_deassociate(enb_ue);
d_assert(rv == CORE_OK,,);
/* Delete All Timers */
tm_delete(enb_ue->holding_timer);
list_remove(&enb_ue->enb->enb_ue_list, enb_ue);
hash_set(self.mme_ue_s1ap_id_hash, &enb_ue->mme_ue_s1ap_id,
sizeof(enb_ue->mme_ue_s1ap_id), NULL);
rv = source_ue_deassociate_target_ue(enb_ue);
d_assert(rv == CORE_OK, return CORE_ERROR, "Null param");
index_free(&enb_ue_pool, enb_ue);
return CORE_OK;
@@ -1829,6 +1887,46 @@ enb_ue_t* enb_ue_next_in_enb(enb_ue_t *enb_ue)
return list_next(enb_ue);
}
static status_t mme_ue_new_guti(mme_ue_t *mme_ue)
{
served_gummei_t *served_gummei = NULL;
d_assert(mme_ue, return CORE_ERROR, "Invalid param");
d_assert(mme_self()->max_num_of_served_gummei > 0,
return CORE_ERROR, "Invalid param");
served_gummei = &mme_self()->served_gummei[0];
d_assert(served_gummei->num_of_plmn_id > 0,
return CORE_ERROR, "Invalid param");
d_assert(served_gummei->num_of_mme_gid > 0,
return CORE_ERROR, "Invalid param");
d_assert(served_gummei->num_of_mme_code > 0,
return CORE_ERROR, "Invalid param");
if (mme_ue->m_tmsi)
{
/* MME has a VALID GUIT
* As such, we need to remove previous GUTI in hash table */
hash_set(self.guti_ue_hash, &mme_ue->guti, sizeof(guti_t), NULL);
d_assert(mme_m_tmsi_free(mme_ue->m_tmsi) == CORE_OK,,);
}
memset(&mme_ue->guti, 0, sizeof(guti_t));
/* Use the first configured plmn_id and mme group id */
memcpy(&mme_ue->guti.plmn_id, &served_gummei->plmn_id[0], PLMN_ID_LEN);
mme_ue->guti.mme_gid = served_gummei->mme_gid[0];
mme_ue->guti.mme_code = served_gummei->mme_code[0];
mme_ue->m_tmsi = mme_m_tmsi_alloc();
d_assert(mme_ue->m_tmsi, return CORE_ERROR,);
mme_ue->guti.m_tmsi = *(mme_ue->m_tmsi);
hash_set(self.guti_ue_hash, &mme_ue->guti, sizeof(guti_t), mme_ue);
return CORE_OK;
}
mme_ue_t* mme_ue_add(enb_ue_t *enb_ue)
{
mme_ue_t *mme_ue = NULL;
@@ -1843,6 +1941,9 @@ mme_ue_t* mme_ue_add(enb_ue_t *enb_ue)
mme_ue->mme_s11_teid = mme_ue->index;
/* Create New GUTI */
mme_ue_new_guti(mme_ue);
/* Setup SGW with round-robin manner */
if (mme_self()->sgw == NULL)
mme_self()->sgw = list_first(&mme_self()->sgw_list);
@@ -1851,7 +1952,7 @@ mme_ue_t* mme_ue_add(enb_ue_t *enb_ue)
mme_self()->sgw = list_next(mme_self()->sgw);
/* Create t3413 timer */
/* Create paging retry timer */
mme_ue->t3413 = timer_create(&self.tm_service, MME_EVT_EMM_T3413,
self.t3413_value * 1000);
d_assert(mme_ue->t3413, return NULL, "Null param");
@@ -1866,6 +1967,7 @@ mme_ue_t* mme_ue_add(enb_ue_t *enb_ue)
status_t mme_ue_remove(mme_ue_t *mme_ue)
{
status_t rv;
event_t e;
d_assert(mme_ue, return CORE_ERROR, "Null param");
@@ -1886,7 +1988,7 @@ status_t mme_ue_remove(mme_ue_t *mme_ue)
/* Clear the saved PDN Connectivity Request */
NAS_CLEAR_DATA(&mme_ue->pdn_connectivity_request);
/* Clear Paging info : t3413, last_paing_msg */
/* Clear Paging info : stop t3413, last_paing_msg */
CLEAR_PAGING_INFO(mme_ue);
/* Free UeRadioCapability */
@@ -1903,11 +2005,15 @@ status_t mme_ue_remove(mme_ue_t *mme_ue)
/* Clear Transparent Container */
S1AP_CLEAR_DATA(&mme_ue->container);
/* Delete All Timers */
tm_delete(mme_ue->t3413);
rv = mme_ue_deassociate(mme_ue);
d_assert(rv == CORE_OK,,);
mme_sess_remove_all(mme_ue);
mme_pdn_remove_all(mme_ue);
mme_ue_deassociate_enb_ue(mme_ue->enb_ue);
index_free(&mme_ue_pool, mme_ue);
return CORE_OK;
@@ -2115,46 +2221,6 @@ mme_ue_t* mme_ue_find_by_message(nas_message_t *message)
return mme_ue;
}
/* At this point, I'm not sure whether this function is exported or not */
static status_t mme_ue_new_guti(mme_ue_t *mme_ue)
{
served_gummei_t *served_gummei = NULL;
d_assert(mme_ue, return CORE_ERROR, "Invalid param");
d_assert(mme_self()->max_num_of_served_gummei > 0,
return CORE_ERROR, "Invalid param");
served_gummei = &mme_self()->served_gummei[0];
d_assert(served_gummei->num_of_plmn_id > 0,
return CORE_ERROR, "Invalid param");
d_assert(served_gummei->num_of_mme_gid > 0,
return CORE_ERROR, "Invalid param");
d_assert(served_gummei->num_of_mme_code > 0,
return CORE_ERROR, "Invalid param");
if (mme_ue->m_tmsi)
{
/* MME has a VALID GUIT
* As such, we need to remove previous GUTI in hash table */
hash_set(self.guti_ue_hash, &mme_ue->guti, sizeof(guti_t), NULL);
d_assert(mme_m_tmsi_free(mme_ue->m_tmsi) == CORE_OK,,);
}
memset(&mme_ue->guti, 0, sizeof(guti_t));
memcpy(&mme_ue->guti.plmn_id, &served_gummei->plmn_id[0], PLMN_ID_LEN);
mme_ue->guti.mme_gid = served_gummei->mme_gid[0];
mme_ue->guti.mme_code = served_gummei->mme_code[0];
mme_ue->m_tmsi = mme_m_tmsi_alloc();
d_assert(mme_ue->m_tmsi, return CORE_ERROR,);
mme_ue->guti.m_tmsi = *(mme_ue->m_tmsi);
hash_set(self.guti_ue_hash, &mme_ue->guti, sizeof(guti_t), mme_ue);
return CORE_OK;
}
status_t mme_ue_set_imsi(mme_ue_t *mme_ue, c_int8_t *imsi_bcd)
{
d_assert(mme_ue && imsi_bcd, return CORE_ERROR, "Invalid param");
@@ -2164,17 +2230,11 @@ status_t mme_ue_set_imsi(mme_ue_t *mme_ue, c_int8_t *imsi_bcd)
hash_set(self.imsi_ue_hash, mme_ue->imsi, mme_ue->imsi_len, mme_ue);
mme_ue_new_guti(mme_ue);
mme_ue->guti_present = 1;
return CORE_OK;
}
/*
* S1AP Initial UE-Message : S-TMSI
* NAS ATTACH_REQUEST : IMSI, GUTI
* NAS TAU_REQUEST : GUTI
* S1AP Handover Notification
*/
status_t mme_ue_associate_enb_ue(mme_ue_t *mme_ue, enb_ue_t *enb_ue)
{
d_assert(mme_ue, return CORE_ERROR, "Null param");
@@ -2186,32 +2246,22 @@ status_t mme_ue_associate_enb_ue(mme_ue_t *mme_ue, enb_ue_t *enb_ue)
return CORE_OK;
}
/*
* mme_ue_remove()
*
* Note : should not call in enb_ue_remove()
*
* When mme_ue is removed, enb_ue->mme_ue must be NULL.
* However, when enb_ue is removed, mme_ue->enb_ue need not be NULL.
* mme_ue->enb_ue will be updated again when enb_ue is added.
*/
status_t mme_ue_deassociate_enb_ue(enb_ue_t *enb_ue)
status_t enb_ue_deassociate(enb_ue_t *enb_ue)
{
mme_ue_t *mme_ue = NULL;
d_assert(enb_ue, return CORE_ERROR, "Null param");
mme_ue = enb_ue->mme_ue;
d_assert(mme_ue, return CORE_ERROR, "Null param");
mme_ue->enb_ue = NULL;
enb_ue->mme_ue = NULL;
return CORE_OK;
}
/*
* S1AP Handover Required
*/
status_t mme_ue_deassociate(mme_ue_t *mme_ue)
{
d_assert(mme_ue, return CORE_ERROR, "Null param");
mme_ue->enb_ue = NULL;
return CORE_OK;
}
status_t source_ue_associate_target_ue(
enb_ue_t *source_ue, enb_ue_t *target_ue)
{
@@ -2229,13 +2279,6 @@ status_t source_ue_associate_target_ue(
return CORE_OK;
}
/*
* enb_ue_remove()
*
* enb_ue->mme_ue->enb_ue should not be set to NULL.
* This is because enb_ue is not known as source_ue or target_ue.
* Therefore, when enb_ue is removed, leave enb_ue->mme_ue->enb_ue as is.
*/
status_t source_ue_deassociate_target_ue(enb_ue_t *enb_ue)
{
enb_ue_t *source_ue = NULL;
@@ -2385,6 +2428,21 @@ mme_sess_t* mme_sess_next(mme_sess_t *sess)
return list_next(sess);
}
unsigned int mme_sess_count(mme_ue_t *mme_ue)
{
unsigned int count = 0;
mme_sess_t *sess = NULL;
sess = mme_sess_first(mme_ue);
while(sess)
{
sess = mme_sess_next(sess);
count++;
}
return count;
}
mme_bearer_t* mme_bearer_add(mme_sess_t *sess)
{
event_t e;
@@ -2598,6 +2656,51 @@ mme_bearer_t* mme_bearer_next(mme_bearer_t *bearer)
return list_next(bearer);
}
int mme_bearer_is_inactive(mme_ue_t *mme_ue)
{
mme_sess_t *sess = NULL;
d_assert(mme_ue, return 1,);
sess = mme_sess_first(mme_ue);
while(sess)
{
mme_bearer_t *bearer = mme_bearer_first(sess);
while(bearer)
{
if (MME_HAVE_ENB_S1U_PATH(bearer))
{
return 0;
}
bearer = mme_bearer_next(bearer);
}
sess = mme_sess_next(sess);
}
return 1;
}
status_t mme_bearer_set_inactive(mme_ue_t *mme_ue)
{
mme_sess_t *sess = NULL;
d_assert(mme_ue, return CORE_ERROR,);
sess = mme_sess_first(mme_ue);
while(sess)
{
mme_bearer_t *bearer = mme_bearer_first(sess);
while(bearer)
{
CLEAR_ENB_S1U_PATH(bearer);
bearer = mme_bearer_next(bearer);
}
sess = mme_sess_next(sess);
}
return CORE_OK;
}
status_t mme_pdn_remove_all(mme_ue_t *mme_ue)
{
s6a_subscription_data_t *subscription_data = NULL;
@@ -2710,7 +2813,7 @@ status_t mme_m_tmsi_pool_generate()
int i, j;
int index = 0;
d_trace(5, "M-TMSI Pool try to generate...\n");
d_trace(9, "M-TMSI Pool try to generate...\n");
for (i = 0; index < MAX_POOL_OF_UE; i++)
{
mme_m_tmsi_t *m_tmsi = NULL;
@@ -2719,21 +2822,27 @@ status_t mme_m_tmsi_pool_generate()
m_tmsi = &self.m_tmsi.pool[index];
rv = core_generate_random_bytes((c_uint8_t *)m_tmsi, sizeof(*m_tmsi));
d_assert(rv == CORE_OK, return CORE_ERROR, "Cannot generate random");
/* for mapped-GUTI */
*m_tmsi |= 0xc0000000;
*m_tmsi &= 0xff00ffff;
for (j = 0; j < index; j++)
{
if (*m_tmsi == self.m_tmsi.pool[j])
{
conflict = 1;
d_warn("[M-TMSI CONFLICT] %d:0x%x == %d:0x%x",
d_trace(11, "[M-TMSI CONFLICT] %d:0x%x == %d:0x%x\n",
index, *m_tmsi, j, self.m_tmsi.pool[j]);
break;
}
}
if (conflict == 1) continue;
index++;
}
self.m_tmsi.size = index;
d_trace(5, "M-TMSI Pool generate...done\n");
d_trace(9, "M-TMSI Pool generate...done\n");
return CORE_OK;
}

View File

@@ -108,7 +108,8 @@ typedef struct _mme_context_t {
c_uint8_t relative_capacity;
/* Timer value */
c_uint32_t t3413_value; /* Paging retry timer */
c_uint32_t t3413_value; /* Paging retry timer value */
c_uint32_t s1_holding_timer_value; /* S1 holding timer value */
/* Generator for unique identification */
c_uint32_t mme_ue_s1ap_id; /* mme_ue_s1ap_id generator */
@@ -131,10 +132,14 @@ typedef struct _mme_context_t {
/* System */
msgq_id queue_id; /* Queue for processing MME control plane */
tm_service_t tm_service; /* Timer Service */
/* Network Name */
nas_network_name_t short_name; /* Network short name */
nas_network_name_t full_name; /* Network Full Name */
} mme_context_t;
typedef struct _mme_enb_t {
lnode_t node; /* FIXME : remove it */
index_t index; /* An index of this node */
fsm_t sm; /* A state machine */
@@ -176,17 +181,35 @@ struct _enb_ue_t {
* Retrieve by UE Context Release Complete */
#define S1AP_UE_CTX_REL_INVALID_ACTION 0
#define S1AP_UE_CTX_REL_NO_ACTION 1
#define S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT 2
#define S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL 3
#define S1AP_UE_CTX_REL_S1_NORMAL_RELEASE 2
#define S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE 3
#define S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL 4
c_uint8_t ue_ctx_rel_action;
/*
* S1 holding timer
*
* When eNodeB sends Attach Request, TAU Request, Service Request repeatly,
* S1(enb_ue_t) context is repeatly created.
*
* NAS(mme_ue_t) context is associated with last created S1(enb_ue_t)
* context, and older S1(enb_ue_t) context might not be freed.
*
* If NAS(mme_ue_t) has already been associated with
* older S1(enb_ue_t) context, the holding timer(30secs) is started.
* Newly associated S1(enb_ue_t) context holding timer is stopped.
*
* If the holding timer expires,
* S1(enb_ue_t) context will be implicitly deleted.
*/
tm_block_id holding_timer;
/* Related Context */
mme_enb_t *enb;
mme_ue_t *mme_ue;
};
struct _mme_ue_t {
lnode_t node; /* FIXME : remove it */
index_t index; /* An index of this node */
fsm_t sm; /* A state machine */
@@ -194,10 +217,15 @@ struct _mme_ue_t {
#define MME_EPS_TYPE_ATTACH_REQUEST 1
#define MME_EPS_TYPE_TAU_REQUEST 2
#define MME_EPS_TYPE_SERVICE_REQUEST 3
#define MME_EPS_TYPE_DETACH_REQUEST_FROM_UE 4
#define MME_EPS_TYPE_DETACH_REQUEST_TO_UE 5
c_uint8_t type;
c_uint8_t ksi;
union {
nas_eps_attach_type_t attach;
nas_eps_update_type_t update;
nas_detach_type_t detach;
c_uint8_t data;
};
} nas_eps;
@@ -207,8 +235,10 @@ struct _mme_ue_t {
c_uint8_t imsi[MAX_IMSI_LEN];
int imsi_len;
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
mme_m_tmsi_t *m_tmsi;
guti_t guti;
int guti_present;
c_uint32_t mme_s11_teid; /* MME-S11-TEID is derived from INDEX */
c_uint32_t sgw_s11_teid; /* SGW-S11-TEID is received from SGW */
@@ -220,12 +250,15 @@ struct _mme_ue_t {
#define SECURITY_CONTEXT_IS_VALID(__mME) \
((__mME) && \
((__mME)->security_context_available == 1) && ((__mME)->mac_failed == 0))
((__mME)->security_context_available == 1) && \
((__mME)->mac_failed == 0) && \
((__mME)->nas_eps.ksi != NAS_KSI_NO_KEY_IS_AVAILABLE))
#define CLEAR_SECURITY_CONTEXT(__mME) \
do { \
d_assert((__mME), break, "Null param"); \
(__mME)->security_context_available = 0; \
(__mME)->mac_failed = 0; \
(__mME)->nas_eps.ksi = 0; \
} while(0)
int security_context_available;
int mac_failed;
@@ -284,7 +317,11 @@ struct _mme_ue_t {
c_uint8_t ebi; /* EPS Bearer ID generator */
list_t sess_list;
/* eNB UE context */
#define ECM_CONNECTED(__mME) \
((__mME) && ((__mME)->enb_ue != NULL) && \
enb_ue_find((__mME)->enb_ue->index))
#define ECM_IDLE(__mME) (!ECM_CONNECTED(__mME))
/* S1 UE context */
enb_ue_t *enb_ue;
/* Save PDN Connectivity Request */
@@ -311,9 +348,6 @@ struct _mme_ue_t {
/* UE Radio Capability */
void *radio_capa;
/* Detach Request */
nas_detach_type_t detach_type;
/* S1AP Transparent Container */
OCTET_STRING_t container;
@@ -340,7 +374,9 @@ struct _mme_ue_t {
#define MAX_NUM_OF_GTP_COUNTER 16
#if 0 /* Deprecated */
#define GTP_COUNTER_DELETE_SESSION 0
#endif
#define GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH 1
#define GTP_COUNTER_MODIFY_BEARER_BY_HANDOVER_NOTIFY 2
struct {
@@ -354,11 +390,18 @@ struct _mme_ue_t {
#define MME_HAVE_SGW_S1U_PATH(__sESS) \
((__sESS) && (mme_bearer_first(__sESS)) && \
((mme_default_bearer_in_sess(__sESS)->sgw_s1u_teid)))
#define CLEAR_SGW_S1U_PATH(__sESS) \
do { \
mme_bearer_t *__bEARER = NULL; \
d_assert((__sESS), break, "Null param"); \
__bEARER = mme_default_bearer_in_sess(__sESS); \
__bEARER->sgw_s1u_teid = 0; \
} while(0)
#define MME_HAVE_SGW_S11_PATH(__mME) \
#define SESSION_CONTEXT_IS_AVAILABLE(__mME) \
((__mME) && ((__mME)->sgw_s11_teid))
#define CLEAR_SGW_S11_PATH(__mME) \
#define CLEAR_SESSION_CONTEXT(__mME) \
do { \
d_assert((__mME), break, "Null param"); \
(__mME)->sgw_s11_teid = 0; \
@@ -393,8 +436,18 @@ typedef struct _mme_sess_t {
tlv_octet_t pgw_pco;
} mme_sess_t;
#define BEARER_CONTEXT_IS_ACTIVE(__mME) \
(mme_bearer_is_inactive(__mME) == 0)
#define CLEAR_BEARER_CONTEXT(__mME) \
mme_bearer_set_inactive(__mME)
#define MME_HAVE_ENB_S1U_PATH(__bEARER) \
((__bEARER) && ((__bEARER)->enb_s1u_teid))
#define CLEAR_ENB_S1U_PATH(__bEARER) \
do { \
d_assert((__bEARER), break, "Null param"); \
(__bEARER)->enb_s1u_teid = 0; \
} while(0)
#define MME_HAVE_ENB_DL_INDIRECT_TUNNEL(__bEARER) \
((__bEARER) && ((__bEARER)->enb_dl_teid))
@@ -494,9 +547,59 @@ CORE_DECLARE(mme_ue_t*) mme_ue_find_by_teid(c_uint32_t teid);
CORE_DECLARE(mme_ue_t*) mme_ue_find_by_message(nas_message_t *message);
CORE_DECLARE(status_t) mme_ue_set_imsi(
mme_ue_t *mme_ue, c_int8_t *imsi_bcd);
/*
* o RECV Initial UE-Message : S-TMSI
* o RECV Attach Request : IMSI, GUTI
* o RECV TAU Request : GUTI
* ### MME_UE_ASSOCIATE_ENB_UE() ###
* ### MME_UE_ECM_CONNECTED() ###
*
* o RECV Initial Context Setup Failure in EMM Registered State
* ### MME_UE_DEASSOCIATE_ENB_UE() ###
* ### ENB_UE_REMOVE() ###
* ### MME_UE_DEASSOCIATE() ###
*
* o SEND UE Context Release Command with NO_ACTION
* - RECV UE Context Release Complete
* ### ENB_UE_REMOVE() ###
* ### MME_UE_DEASSOCIATE() ###
*
* o SEND UE Context Release Command with REMOVE_MME_UE_CONTEXT
* - RECV UE Context Release Complete
* ### ENB_UE_REMOVE() ###
* ### MME_UE_REMOVE() ###
*
*
* o RECV Handover Required
* ### SOURCE_UE_ASSOCIATE_TARGET_UE() ####
* - SEND Handover Request
*
* o RECV Handover Notify
* ### MME_UE_ASSOCIATE_ENB_UE(TARGET) ###
* ### MME_UE_ECM_CONNECTED(TARGET) ###
* - Modify Bearer Request/Response
* - UE Context Release Command/Complete
* ### SOURCE_UE_DEASSOCIATE_TARGET_UE() ####
* ### ENB_UE_REMOVE() ####
* - Delete Indirect Data Forwarding Tunnel Request/Response
*
* o RECV Handover Cancel
* - UE Context Release Command/Complete
* ### SOURCE_UE_DEASSOCIATE_TARGET_UE() ####
* ### ENB_UE_REMOVE() ####
* - Delete Indirect Data Forwarding Tunnel Request/Response
*
* o RECV Handover Failure
* - UE Context Release Command/Complete
* ### SOURCE_UE_DEASSOCIATE_TARGET_UE() ####
* ### ENB_UE_REMOVE() ####
* - Delete Indirect Data Forwarding Tunnel Request/Response
*/
CORE_DECLARE(status_t) mme_ue_associate_enb_ue(
mme_ue_t *mme_ue, enb_ue_t *enb_ue);
CORE_DECLARE(status_t) mme_ue_deassociate_enb_ue(enb_ue_t *enb_ue);
CORE_DECLARE(status_t) enb_ue_deassociate(enb_ue_t *enb_ue);
CORE_DECLARE(status_t) mme_ue_deassociate(mme_ue_t *mme_ue);
CORE_DECLARE(status_t) source_ue_associate_target_ue(
enb_ue_t *source_ue, enb_ue_t *target_ue);
CORE_DECLARE(status_t) source_ue_deassociate_target_ue(enb_ue_t *enb_ue);
@@ -517,6 +620,7 @@ CORE_DECLARE(mme_sess_t*) mme_sess_find_by_apn(
mme_ue_t *mme_ue, c_int8_t *apn);
CORE_DECLARE(mme_sess_t*) mme_sess_first(mme_ue_t *mme_ue);
CORE_DECLARE(mme_sess_t*) mme_sess_next(mme_sess_t *sess);
CORE_DECLARE(unsigned int) mme_sess_count(mme_ue_t *mme_ue);
CORE_DECLARE(mme_bearer_t*) mme_bearer_add(mme_sess_t *sess);
CORE_DECLARE(status_t) mme_bearer_remove(mme_bearer_t *bearer);
@@ -533,6 +637,9 @@ CORE_DECLARE(mme_bearer_t*) mme_linked_bearer(mme_bearer_t *bearer);
CORE_DECLARE(mme_bearer_t*) mme_bearer_first(mme_sess_t *sess);
CORE_DECLARE(mme_bearer_t*) mme_bearer_next(mme_bearer_t *bearer);
CORE_DECLARE(int) mme_bearer_is_inactive(mme_ue_t *mme_ue);
CORE_DECLARE(status_t) mme_bearer_set_inactive(mme_ue_t *mme_ue);
CORE_DECLARE(pdn_t*) mme_pdn_add(mme_ue_t *mme_ue, c_int8_t *apn);
CORE_DECLARE(status_t) mme_pdn_remove_all(mme_ue_t *mme_ue);
CORE_DECLARE(pdn_t*) mme_pdn_find_by_apn(

View File

@@ -23,7 +23,9 @@ char* mme_event_get_name(event_t *e)
case MME_EVT_S1AP_LO_ACCEPT:
return "MME_EVT_S1AP_LO_ACCEPT";
case MME_EVT_S1AP_LO_CONNREFUSED:
return"MME_EVT_S1AP_LO_CONNREFUSED";
return "MME_EVT_S1AP_LO_CONNREFUSED";
case MME_EVT_S1AP_S1_HOLDING_TIMER:
return "MME_EVT_S1AP_S1_HOLDING_TIMER";
case MME_EVT_EMM_MESSAGE:
return "MME_EVT_EMM_MESSAGE";

View File

@@ -17,6 +17,7 @@ typedef enum {
MME_EVT_S1AP_DELAYED_SEND,
MME_EVT_S1AP_LO_ACCEPT,
MME_EVT_S1AP_LO_CONNREFUSED,
MME_EVT_S1AP_S1_HOLDING_TIMER,
MME_EVT_EMM_MESSAGE,
MME_EVT_EMM_T3413,

View File

@@ -270,7 +270,7 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, " From '%.*s' ",
d_trace(5, " From '%.*s'\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else
@@ -286,7 +286,7 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, "('%.*s') ",
d_trace(5, " ('%.*s')\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else
@@ -668,7 +668,7 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, " From '%.*s' ",
d_trace(5, " From '%.*s'\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else
@@ -684,7 +684,7 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, "('%.*s') ",
d_trace(5, " ('%.*s')\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else

View File

@@ -9,6 +9,7 @@
#include "mme_event.h"
#include "mme_gtp_path.h"
#include "mme_s11_build.h"
#include "mme_sm.h"
static int _gtpv2_c_recv_cb(sock_id sock, void *data)
{
@@ -194,8 +195,6 @@ status_t mme_gtp_send_delete_session_request(mme_sess_t *sess)
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return CORE_ERROR, "xact_commit error");
GTP_COUNTER_INCREMENT(mme_ue, GTP_COUNTER_DELETE_SESSION);
return CORE_OK;
}
@@ -212,9 +211,19 @@ status_t mme_gtp_send_delete_all_sessions(mme_ue_t *mme_ue)
if (MME_HAVE_SGW_S1U_PATH(sess))
{
rv = mme_gtp_send_delete_session_request(sess);
d_assert(rv == CORE_OK, return CORE_ERROR,
"mme_gtp_send_delete_session_request error");
mme_bearer_t *bearer = mme_default_bearer_in_sess(sess);
d_assert(bearer,, "Null param");
if (bearer && FSM_CHECK(&bearer->sm, esm_state_pdn_will_disconnect))
{
d_warn("PDN will disconnect[EBI:%d]", bearer->ebi);
}
else
{
rv = mme_gtp_send_delete_session_request(sess);
d_assert(rv == CORE_OK, return CORE_ERROR,
"mme_gtp_send_delete_session_request error");
}
}
else
{

75
src/mme/mme_path.c Normal file
View File

@@ -0,0 +1,75 @@
#define TRACE_MODULE _mme_path
#include "s1ap_path.h"
#include "nas_path.h"
#include "mme_gtp_path.h"
#include "mme_path.h"
status_t mme_send_delete_session_or_detach(mme_ue_t *mme_ue)
{
status_t rv;
d_assert(mme_ue, return CORE_ERROR,);
if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK,,
"mme_gtp_send_delete_all_sessions failed");
}
else
{
rv = nas_send_detach_accept(mme_ue);
d_assert(rv == CORE_OK,,
"nas_send_detach_accept failed");
}
return rv;
}
status_t mme_send_delete_session_or_ue_context_release(
mme_ue_t *mme_ue, enb_ue_t *enb_ue)
{
status_t rv;
d_assert(enb_ue, return CORE_ERROR,);
if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK,,
"mme_gtp_send_delete_all_sessions failed");
}
else
{
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
}
return rv;
}
status_t mme_send_release_access_bearer_or_ue_context_release(
mme_ue_t *mme_ue, enb_ue_t *enb_ue)
{
status_t rv;
d_assert(enb_ue, return CORE_ERROR,);
if (BEARER_CONTEXT_IS_ACTIVE(mme_ue))
{
rv = mme_gtp_send_release_access_bearers_request(mme_ue);
d_assert(rv == CORE_OK,, "gtp send failed");
}
else
{
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
}
return rv;
}

22
src/mme/mme_path.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef __MME_PATH_H__
#define __MME_PATH_H__
#include "core_errno.h"
#include "mme_context.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
CORE_DECLARE(status_t) mme_send_delete_session_or_detach(mme_ue_t *mme_ue);
CORE_DECLARE(status_t) mme_send_delete_session_or_ue_context_release(
mme_ue_t *mme_ue, enb_ue_t *enb_ue);
CORE_DECLARE(status_t) mme_send_release_access_bearer_or_ue_context_release(
mme_ue_t *mme_ue, enb_ue_t *enb_ue);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __MME_PATH_H__ */

View File

@@ -249,6 +249,8 @@ status_t mme_s11_build_modify_bearer_request(pkbuf_t **pkbuf,
d_trace(3, "[MME] Modifty Bearer Request\n");
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
d_trace(5, " ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]\n",
bearer->enb_s1u_teid, bearer->sgw_s1u_teid);
memset(&gtp_message, 0, sizeof(gtp_message_t));

View File

@@ -75,9 +75,6 @@ void mme_s11_handle_create_session_response(
sgw_s11_teid = rsp->sender_f_teid_for_control_plane.data;
mme_ue->sgw_s11_teid = ntohl(sgw_s11_teid->teid);
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
memcpy(&pdn->paa, rsp->pdn_address_allocation.data,
rsp->pdn_address_allocation.len);
@@ -90,6 +87,12 @@ void mme_s11_handle_create_session_response(
/* Data Plane(UL) : SGW-S1U */
sgw_s1u_teid = rsp->bearer_contexts_created.s1_u_enodeb_f_teid.data;
bearer->sgw_s1u_teid = ntohl(sgw_s1u_teid->teid);
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
d_trace(5, " ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]\n",
bearer->enb_s1u_teid, bearer->sgw_s1u_teid);
rv = gtp_f_teid_to_ip(sgw_s1u_teid, &bearer->sgw_s1u_ip);
d_assert(rv == CORE_OK, return,);
@@ -116,20 +119,20 @@ void mme_s11_handle_modify_bearer_response(
status_t rv;
enb_ue_t *source_ue = NULL, *target_ue = NULL;
d_assert(xact, return, "Null param");
d_assert(mme_ue, return, "Null param");
d_assert(rsp, return, "Null param");
d_assert(xact, goto cleanup, "Null param");
d_assert(rsp, goto cleanup, "Null param");
d_trace(3, "[MME] Modify Bearer Response\n");
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
d_assert(rv == CORE_OK, goto cleanup, "xact_commit error");
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH,
rv = s1ap_send_path_switch_ack(mme_ue);
d_assert(rv == CORE_OK, return, "s1ap send error");
d_assert(rv == CORE_OK,, "s1ap send error");
);
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_HANDOVER_NOTIFY,
@@ -139,10 +142,17 @@ void mme_s11_handle_modify_bearer_response(
d_assert(source_ue, return, "Null param");
rv = s1ap_send_ue_context_release_command(source_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1ap_Cause_PR_radioNetwork,
S1ap_CauseRadioNetwork_successful_handover,
S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, 300);
d_assert(rv == CORE_OK, return, "s1ap send error");
d_assert(rv == CORE_OK,, "s1ap send error");
);
return;
cleanup:
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH,);
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_HANDOVER_NOTIFY,);
}
void mme_s11_handle_delete_session_response(
@@ -151,91 +161,85 @@ void mme_s11_handle_delete_session_response(
status_t rv;
mme_sess_t *sess = NULL;
d_assert(rsp, return, "Null param");
d_assert(mme_ue, return, "Null param");
d_assert(xact, return, "Null param");
sess = GTP_XACT_RETRIEVE_SESSION(xact);
d_assert(sess, return, "Null param");
d_assert(rsp, goto cleanup, "Null param");
d_trace(3, "[MME] Delete Session Response\n");
if (rsp->cause.presence == 0)
{
d_error("No Cause");
return;
goto cleanup;
}
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
d_assert(rv == CORE_OK, goto cleanup, "xact_commit error");
if (FSM_CHECK(&mme_ue->sm, emm_state_authentication))
{
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION,
CLEAR_SGW_S11_PATH(mme_ue);
if (mme_sess_count(mme_ue) == 1) /* Last Session */
{
mme_s6a_send_air(mme_ue, NULL);
);
mme_sess_remove(sess);
}
}
else if (FSM_CHECK(&mme_ue->sm, emm_state_de_registered))
{
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION,
CLEAR_SGW_S11_PATH(mme_ue);
if (mme_sess_count(mme_ue) == 1) /* Last Session */
{
rv = nas_send_detach_accept(mme_ue);
d_assert(rv == CORE_OK, return, "nas_send_detach_accept failed");
);
mme_sess_remove(sess);
d_assert(rv == CORE_OK,, "nas_send_detach_accept failed");
}
}
else if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
mme_bearer_t *bearer = mme_default_bearer_in_sess(sess);
d_assert(bearer, return, "Null param");
d_assert(bearer, goto cleanup, "Null param");
if (FSM_CHECK(&bearer->sm, esm_state_pdn_will_disconnect))
{
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION,);
rv = nas_send_deactivate_bearer_context_request(bearer);
d_assert(rv == CORE_OK, return,
d_assert(rv == CORE_OK,,
"nas_send_deactivate_bearer_context_request failed");
}
else if (FSM_CHECK(&bearer->sm, esm_state_active))
{
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION,
enb_ue_t *enb_ue = NULL;
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return, );
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
);
/*
* mme_sess_remove() should not be called here.
*
* Session will be removed if Deactivate bearer context
* accept is received */
CLEAR_SGW_S1U_PATH(sess);
return;
}
else
{
d_assert(0,, "Invalid ESM state");
}
}
else if (FSM_CHECK(&mme_ue->sm, emm_state_initial_context_setup) ||
FSM_CHECK(&mme_ue->sm, emm_state_exception))
{
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION,
if (mme_sess_count(mme_ue) == 1) /* Last Session */
{
enb_ue_t *enb_ue = NULL;
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return, );
d_assert(enb_ue, goto cleanup, );
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
);
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
}
}
else
d_assert(0,, "Invalid EMM state");
cleanup:
if (mme_sess_count(mme_ue) == 1) /* Last Session */
CLEAR_SESSION_CONTEXT(mme_ue);
mme_sess_remove(sess);
}
void mme_s11_handle_create_bearer_request(
@@ -512,20 +516,24 @@ void mme_s11_handle_release_access_bearers_response(
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return, "Null param");
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK,, "xact_commit error");
if (rsp->cause.presence == 0)
{
d_error("No Cause");
return;
}
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
rv = CLEAR_BEARER_CONTEXT(mme_ue);
d_assert(rv == CORE_OK,, "MME_BEARER_SET_INACTIVE failed");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
}

View File

@@ -30,7 +30,6 @@ void mme_s6a_handle_aia(mme_ue_t *mme_ue, s6a_aia_message_t *aia_message)
void mme_s6a_handle_ula(mme_ue_t *mme_ue, s6a_ula_message_t *ula_message)
{
status_t rv;
s6a_subscription_data_t *subscription_data = NULL;
d_assert(mme_ue, return, "Null param");
@@ -40,28 +39,4 @@ void mme_s6a_handle_ula(mme_ue_t *mme_ue, s6a_ula_message_t *ula_message)
memcpy(&mme_ue->subscription_data,
subscription_data, sizeof(s6a_subscription_data_t));
if (FSM_CHECK(&mme_ue->sm, emm_state_initial_context_setup))
{
if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST)
{
rv = nas_send_emm_to_esm(mme_ue, &mme_ue->pdn_connectivity_request);
d_assert(rv == CORE_OK,, "nas_send_emm_to_esm() failed");
}
else
d_assert(0,, "Invalid Type(%d)", mme_ue->nas_eps.type);
}
else if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST)
{
rv = nas_send_tau_accept(mme_ue);
d_assert(rv == CORE_OK,, "nas_send_tau_accept() failed");
}
else
d_assert(0,, "Invalid EPS-Type[%d]", mme_ue->nas_eps.type);
}
else
d_assert(0,, "Invaild EMM state for EPS-Type[%d]",
mme_ue->nas_eps.type);
}

View File

@@ -19,6 +19,7 @@
#include "mme_s11_handler.h"
#include "mme_fd_path.h"
#include "mme_s6a_handler.h"
#include "mme_path.h"
void mme_state_initial(fsm_t *s, event_t *e)
{
@@ -212,6 +213,20 @@ void mme_state_operational(fsm_t *s, event_t *e)
tm_delete(timer);
break;
}
case MME_EVT_S1AP_S1_HOLDING_TIMER:
{
enb_ue_t *enb_ue = NULL;
enb_ue = enb_ue_find(event_get_param1(e));
d_assert(enb_ue, break, "No ENB UE context");
d_warn("Implicit S1 release");
d_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,,);
break;
}
case MME_EVT_EMM_MESSAGE:
{
nas_message_t message;
@@ -221,7 +236,7 @@ void mme_state_operational(fsm_t *s, event_t *e)
enb_ue = enb_ue_find(event_get_param1(e));
d_assert(enb_ue, break, "No ENB UE context");
pkbuf = (pkbuf_t *)event_get_param3(e);
pkbuf = (pkbuf_t *)event_get_param4(e);
d_assert(pkbuf, break, "Null param");
d_assert(nas_emm_decode(&message, pkbuf) == CORE_OK,
pkbuf_free(pkbuf); break, "Can't decode NAS_EMM");
@@ -244,7 +259,7 @@ void mme_state_operational(fsm_t *s, event_t *e)
*
* Now, We will check the MAC in the NAS message*/
nas_security_header_type_t h;
h.type = (c_uint8_t)event_get_param2(e);
h.type = (c_uint8_t)event_get_param3(e);
if (h.integrity_protected)
{
/* Decryption was performed in S1AP handler.
@@ -257,6 +272,38 @@ void mme_state_operational(fsm_t *s, event_t *e)
"nas_security_decode failed");
}
}
/* If NAS(mme_ue_t) has already been associated with
* older S1(enb_ue_t) context */
if (ECM_CONNECTED(mme_ue))
{
#if IMPLICIT_S1_RELEASE
/* Implcit S1 release */
d_warn("Implicit S1 release");
d_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
rv = enb_ue_remove(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
#else /* S1_HOLDING_TIMER */
/* Previous S1(enb_ue_t) context the holding timer(30secs)
* is started.
* Newly associated S1(enb_ue_t) context holding timer
* is stopped. */
d_trace(5, "Start S1 Holding Timer\n");
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
tm_start(mme_ue->enb_ue->holding_timer);
/* De-associate S1 with NAS/EMM */
rv = enb_ue_deassociate(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
#endif
}
tm_stop(enb_ue->holding_timer);
mme_ue_associate_enb_ue(mme_ue, enb_ue);
}
@@ -264,27 +311,16 @@ void mme_state_operational(fsm_t *s, event_t *e)
d_assert(FSM_STATE(&mme_ue->sm), pkbuf_free(pkbuf); break,
"No EMM State Machine");
/* Set event */
event_set_param1(e, (c_uintptr_t)mme_ue->index);/* mme_ue index */
event_set_param4(e, (c_uintptr_t)&message);
event_set_param1(e, (c_uintptr_t)mme_ue->index);
event_set_param5(e, (c_uintptr_t)&message);
fsm_dispatch(&mme_ue->sm, (fsm_event_t*)e);
if (FSM_CHECK(&mme_ue->sm, emm_state_exception))
{
if (MME_HAVE_SGW_S11_PATH(mme_ue))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK, pkbuf_free(pkbuf); break,
"gtp send failed");
}
else
{
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, pkbuf_free(pkbuf); break,
"s1ap send failed");
}
rv = mme_send_delete_session_or_ue_context_release(
mme_ue, enb_ue);
d_assert(rv == CORE_OK,,
"mme_send_delete_session_or_ue_context_release() failed");
}
pkbuf_free(pkbuf);
@@ -373,7 +409,7 @@ void mme_state_operational(fsm_t *s, event_t *e)
enb_ue_t *enb_ue = NULL;
rv = nas_send_attach_reject(mme_ue,
EMM_CAUSE_EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED,
EMM_CAUSE_IMSI_UNKNOWN_IN_HSS,
ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
d_assert(rv == CORE_OK,,
"nas_send_attach_reject failed");
@@ -382,8 +418,8 @@ void mme_state_operational(fsm_t *s, event_t *e)
d_assert(enb_ue, break, "No ENB UE context");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_authentication_failure,
S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT, 0);
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
pkbuf_free(s6abuf);
@@ -400,11 +436,50 @@ void mme_state_operational(fsm_t *s, event_t *e)
case S6A_CMD_CODE_UPDATE_LOCATION:
{
mme_s6a_handle_ula(mme_ue, &s6a_message->ula_message);
if (FSM_CHECK(&mme_ue->sm, emm_state_initial_context_setup))
{
if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST)
{
rv = nas_send_emm_to_esm(mme_ue,
&mme_ue->pdn_connectivity_request);
d_assert(rv == CORE_OK,,
"nas_send_emm_to_esm() failed");
}
else
d_assert(0,, "Invalid Type[%d]",
mme_ue->nas_eps.type);
}
else if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST)
{
rv = nas_send_tau_accept(mme_ue,
S1ap_ProcedureCode_id_InitialContextSetup);
d_assert(rv == CORE_OK,,
"nas_send_tau_accept() failed");
}
else if (mme_ue->nas_eps.type ==
MME_EPS_TYPE_SERVICE_REQUEST)
{
rv = s1ap_send_initial_context_setup_request(
mme_ue);
d_assert(rv == CORE_OK,,
"s1ap_send_initial_context_setup_request()"
"failed");
}
else
d_assert(0,, "Invalid EPS-Type[%d]",
mme_ue->nas_eps.type);
}
else
d_assert(0,, "Invaild EMM state for EPS-Type[%d]",
mme_ue->nas_eps.type);
break;
}
default:
{
d_error("Invalid type(%d)", event_get_param2(e));
d_error("Invalid Type[%d]", event_get_param2(e));
break;
}
}
@@ -468,7 +543,21 @@ void mme_state_operational(fsm_t *s, event_t *e)
mme_s11_handle_downlink_data_notification(
xact, mme_ue, &message.downlink_data_notification);
if (mme_ue->enb_ue == NULL)
/*
* 5.3.4.2 in Spec 23.401
* Under certain conditions, the current UE triggered Service Request
* procedure can cause unnecessary Downlink Packet Notification messages
* which increase the load of the MME.
*
* This can occur when uplink data sent in step 6 causes a response
* on the downlink which arrives at the Serving GW before the Modify Bearer
* Request message, step 8. This data cannot be forwarded from the Serving GW
* to the eNodeB and hence it triggers a Downlink Data Notification message.
*
* If the MME receives a Downlink Data Notification after step 2 and
* before step 9, the MME shall not send S1 interface paging messages
*/
if (ECM_IDLE(mme_ue))
{
s1ap_handle_paging(mme_ue);
/* Start T3413 */

View File

@@ -22,7 +22,6 @@ void s1ap_state_exception(fsm_t *s, event_t *e);
void emm_state_initial(fsm_t *s, event_t *e);
void emm_state_final(fsm_t *s, event_t *e);
void emm_state_de_registered(fsm_t *s, event_t *e);
void emm_state_identity(fsm_t *s, event_t *e);
void emm_state_authentication(fsm_t *s, event_t *e);
void emm_state_security_mode(fsm_t *s, event_t *e);
void emm_state_initial_context_setup(fsm_t *s, event_t *e);

View File

@@ -194,14 +194,13 @@ status_t nas_send_detach_accept(mme_ue_t *mme_ue)
status_t rv;
enb_ue_t *enb_ue = NULL;
pkbuf_t *emmbuf = NULL;
c_uint8_t ue_ctx_rel_action = S1AP_UE_CTX_REL_NO_ACTION;
d_assert(mme_ue, return CORE_ERROR, "Null param");
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return CORE_ERROR, "Null param");
/* reply with detach accept */
if (mme_ue->detach_type.switch_off == 0)
if (mme_ue->nas_eps.detach.switch_off == 0)
{
rv = emm_build_detach_accept(&emmbuf, mme_ue);
d_assert(rv == CORE_OK && emmbuf, return CORE_ERROR,
@@ -210,13 +209,10 @@ status_t nas_send_detach_accept(mme_ue_t *mme_ue)
rv = nas_send_to_downlink_nas_transport(mme_ue, emmbuf);
d_assert(rv == CORE_OK, return CORE_ERROR, "nas send failed");
}
else
{
ue_ctx_rel_action = S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT;
}
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_detach, ue_ctx_rel_action, 0);
S1ap_Cause_PR_nas, S1ap_CauseNas_detach,
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);
d_assert(rv == CORE_OK, return CORE_ERROR, "s1ap send error");
return CORE_OK;
@@ -314,6 +310,26 @@ status_t nas_send_activate_dedicated_bearer_context_request(
return CORE_OK;
}
status_t nas_send_activate_all_dedicated_bearers(mme_bearer_t *default_bearer)
{
status_t rv;
d_assert(default_bearer, return CORE_ERROR, "Null param");
mme_bearer_t *dedicated_bearer = mme_bearer_next(default_bearer);
while(dedicated_bearer)
{
rv = nas_send_activate_dedicated_bearer_context_request(
dedicated_bearer);
d_assert(rv == CORE_OK, return CORE_ERROR,
"nas_send_activate_dedicated_bearer_context failed");
dedicated_bearer = mme_bearer_next(dedicated_bearer);
}
return CORE_OK;
}
status_t nas_send_modify_bearer_context_request(
mme_bearer_t *bearer, int qos_presence, int tft_presence)
{
@@ -372,47 +388,40 @@ status_t nas_send_deactivate_bearer_context_request(mme_bearer_t *bearer)
return CORE_OK;
}
status_t nas_send_tau_accept(mme_ue_t *mme_ue)
status_t nas_send_tau_accept(
mme_ue_t *mme_ue, S1ap_ProcedureCode_t procedureCode)
{
status_t rv;
enb_ue_t *enb_ue = NULL;
pkbuf_t *s1apbuf = NULL, *emmbuf = NULL;
pkbuf_t *emmbuf = NULL;
d_assert(mme_ue, return CORE_ERROR, "Null param");
if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
d_trace(3, "[EMM] Tracking area update accept\n");
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
rv = emm_build_tau_accept(&emmbuf, mme_ue);
d_assert(rv == CORE_OK, return CORE_ERROR, "emm build error");
if (procedureCode == S1ap_ProcedureCode_id_InitialContextSetup)
{
enb_ue = mme_ue->enb_ue;
d_assert(enb_ue, return CORE_ERROR, "Null param");
/* Build TAU accept */
rv = emm_build_tau_accept(&emmbuf, mme_ue);
d_assert(rv == CORE_OK, return CORE_ERROR, "emm build error");
/* Send Dl NAS to UE */
rv = nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK;
d_assert(rv == CORE_OK,, "nas_send_to_downlink_nas_transport");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK, return CORE_ERROR, "s1ap send error");
}
else
{
rv = emm_build_tau_accept(&emmbuf, mme_ue);
d_assert(rv == CORE_OK, return CORE_ERROR, "emm build error");
pkbuf_t *s1apbuf = NULL;
rv = s1ap_build_initial_context_setup_request(&s1apbuf, mme_ue, emmbuf);
d_assert(rv == CORE_OK && s1apbuf,
pkbuf_free(emmbuf); return CORE_ERROR, "s1ap build error");
pkbuf_free(emmbuf); return CORE_ERROR, "s1ap build error");
rv = nas_send_to_enb(mme_ue, s1apbuf);
d_assert(rv == CORE_OK, return CORE_ERROR, "nas send error");
d_assert(rv == CORE_OK,, "nas send error");
}
else if (procedureCode == S1ap_ProcedureCode_id_downlinkNASTransport)
{
rv = nas_send_to_downlink_nas_transport(mme_ue, emmbuf);
d_assert(rv == CORE_OK,, "nas_send_to_downlink_nas_transport");
}
else
d_assert(0, pkbuf_free(emmbuf); return CORE_ERROR,
"Invalid Procedure Code[%d]", procedureCode);
return CORE_OK;
return rv;
}
status_t nas_send_tau_reject(mme_ue_t *mme_ue, nas_emm_cause_t emm_cause)

View File

@@ -34,12 +34,15 @@ CORE_DECLARE(status_t) nas_send_activate_default_bearer_context_request(
mme_bearer_t *bearer);
CORE_DECLARE(status_t) nas_send_activate_dedicated_bearer_context_request(
mme_bearer_t *bearer);
CORE_DECLARE(status_t) nas_send_activate_all_dedicated_bearers(
mme_bearer_t *default_bearer);
CORE_DECLARE(status_t) nas_send_modify_bearer_context_request(
mme_bearer_t *bearer, int qos_presence, int tft_presence);
CORE_DECLARE(status_t) nas_send_deactivate_bearer_context_request(
mme_bearer_t *bearer);
CORE_DECLARE(status_t) nas_send_tau_accept(mme_ue_t *mme_ue);
CORE_DECLARE(status_t) nas_send_tau_accept(
mme_ue_t *mme_ue, S1ap_ProcedureCode_t procedureCode);
CORE_DECLARE(status_t) nas_send_tau_reject(
mme_ue_t *mme_ue, nas_esm_cause_t emm_cause);

View File

@@ -85,7 +85,7 @@ status_t s1ap_build_setup_rsp(pkbuf_t **pkbuf)
status_t s1ap_build_setup_failure(
pkbuf_t **pkbuf, S1ap_Cause_PR group, long cause)
pkbuf_t **pkbuf, S1ap_Cause_PR group, long cause, long time_to_wait)
{
int erval;
@@ -97,6 +97,14 @@ status_t s1ap_build_setup_failure(
ies = &message.s1ap_S1SetupFailureIEs;
ies->cause.present = group;
ies->cause.choice.radioNetwork = cause;
d_trace(5, " Gruop[%d] Cause[%d] TimeToWait[%ld]\n",
group, cause, time_to_wait);
if (time_to_wait > -1)
{
ies->presenceMask |= S1AP_S1SETUPFAILUREIES_TIMETOWAIT_PRESENT;
ies->timeToWait = time_to_wait;
}
message.procedureCode = S1ap_ProcedureCode_id_S1Setup;
message.direction = S1AP_PDU_PR_unsuccessfulOutcome;
@@ -200,7 +208,8 @@ status_t s1ap_build_initial_context_setup_request(
e_rab->e_RAB_ID = bearer->ebi;
e_rab->e_RABlevelQoSParameters.qCI = bearer->qos.qci;
d_trace(5, " EBI[%d] QCI[%d]\n", bearer->ebi, bearer->qos.qci);
d_trace(5, " EBI[%d] QCI[%d] SGW-S1U-TEID[%d]\n",
bearer->ebi, bearer->qos.qci, bearer->sgw_s1u_teid);
e_rab->e_RABlevelQoSParameters.allocationRetentionPriority.
priorityLevel = bearer->qos.arp.priority_level;
@@ -385,6 +394,7 @@ status_t s1ap_build_e_rab_setup_request(
&bearer->sgw_s1u_ip, &e_rab->transportLayerAddress);
d_assert(rv == CORE_OK, return CORE_ERROR,);
s1ap_uint32_to_OCTET_STRING(bearer->sgw_s1u_teid, &e_rab->gTP_TEID);
d_trace(5, " SGW-S1U-TEID[%d]\n", bearer->sgw_s1u_teid);
nasPdu = &e_rab->nAS_PDU;
nasPdu->size = esmbuf->len;
@@ -517,7 +527,7 @@ status_t s1ap_build_e_rab_release_command(pkbuf_t **s1apbuf,
subscription_data = &mme_ue->subscription_data;
d_assert(subscription_data, return CORE_ERROR, "Null param");
d_trace(3, "[MME] E-RAB release request\n");
d_trace(3, "[MME] E-RAB release command\n");
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
@@ -581,7 +591,9 @@ status_t s1ap_build_ue_context_release_command(
return CORE_ERROR;
}
#if 0 /* ENB_UE_S1AP_ID could be allocated with 0 from eNodeB */
if (enb_ue->enb_ue_s1ap_id)
#endif
{
ies->uE_S1AP_IDs.present = S1ap_UE_S1AP_IDs_PR_uE_S1AP_ID_pair;
ies->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID =
@@ -590,11 +602,13 @@ status_t s1ap_build_ue_context_release_command(
enb_ue->enb_ue_s1ap_id;
ies->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.iE_Extensions = NULL;
}
#if 0
else
{
ies->uE_S1AP_IDs.present = S1ap_UE_S1AP_IDs_PR_mME_UE_S1AP_ID;
ies->uE_S1AP_IDs.choice.mME_UE_S1AP_ID = enb_ue->mme_ue_s1ap_id;
}
#endif
ies->cause.present = group;
ies->cause.choice.radioNetwork = cause;
@@ -803,6 +817,7 @@ status_t s1ap_build_handover_command(pkbuf_t **s1apbuf, enb_ue_t *source_ue)
core_calloc(1, sizeof(S1ap_GTP_TEID_t));
s1ap_uint32_to_OCTET_STRING(
bearer->sgw_dl_teid, e_rab->dL_gTP_TEID);
d_trace(5, " SGW-DL-TEID[%d]\n", bearer->sgw_dl_teid);
}
if (MME_HAVE_SGW_UL_INDIRECT_TUNNEL(bearer))
@@ -818,6 +833,7 @@ status_t s1ap_build_handover_command(pkbuf_t **s1apbuf, enb_ue_t *source_ue)
core_calloc(1, sizeof(S1ap_GTP_TEID_t));
s1ap_uint32_to_OCTET_STRING(
bearer->sgw_ul_teid, e_rab->uL_S1ap_GTP_TEID);
d_trace(5, " SGW-UL-TEID[%d]\n", bearer->sgw_dl_teid);
}
if (MME_HAVE_SGW_DL_INDIRECT_TUNNEL(bearer) ||
@@ -974,6 +990,7 @@ status_t s1ap_build_handover_request(
&bearer->sgw_s1u_ip, &e_rab->transportLayerAddress);
d_assert(rv == CORE_OK, return CORE_ERROR,);
s1ap_uint32_to_OCTET_STRING(bearer->sgw_s1u_teid, &e_rab->gTP_TEID);
d_trace(5, " SGW-S1U-TEID[%d]\n", bearer->sgw_s1u_teid);
ASN_SEQUENCE_ADD(&ies->e_RABToBeSetupListHOReq, e_rab);
@@ -1103,3 +1120,41 @@ status_t s1ap_build_mme_status_transfer(pkbuf_t **s1apbuf,
return CORE_OK;
}
status_t s1ap_build_error_indication(
pkbuf_t **s1apbuf, c_uint16_t presenceMask,
c_uint32_t enb_ue_s1ap_id, c_uint32_t mme_ue_s1ap_id,
S1ap_Cause_PR group, long cause)
{
int encoded;
s1ap_message_t message;
S1ap_ErrorIndicationIEs_t *ies = &message.s1ap_ErrorIndicationIEs;
d_assert(presenceMask, return CORE_ERROR,
"Invalid PresenceMask[0x%x]", presenceMask);
d_trace(3, "[MME] Error Indication\n");
memset(&message, 0, sizeof(s1ap_message_t));
ies->presenceMask = presenceMask;
ies->mme_ue_s1ap_id = mme_ue_s1ap_id;
ies->eNB_UE_S1AP_ID = enb_ue_s1ap_id;
ies->cause.present = group;
ies->cause.choice.radioNetwork = cause;
d_trace(5, " PresenceMask[0x%x]\n", presenceMask);
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue_s1ap_id, mme_ue_s1ap_id);
d_trace(5, " Group[%d] Cause[%d]\n", group, cause);
message.procedureCode = S1ap_ProcedureCode_id_ErrorIndication;
message.direction = S1AP_PDU_PR_initiatingMessage;
encoded = s1ap_encode_pdu(s1apbuf, &message);
s1ap_free_pdu(&message);
d_assert(s1apbuf && encoded >= 0,return CORE_ERROR,);
return CORE_OK;
}

View File

@@ -10,7 +10,7 @@ extern "C" {
CORE_DECLARE(status_t) s1ap_build_setup_rsp(pkbuf_t **pkbuf);
CORE_DECLARE(status_t) s1ap_build_setup_failure(
pkbuf_t **pkbuf, S1ap_Cause_PR group, long cause);
pkbuf_t **pkbuf, S1ap_Cause_PR group, long cause, long time_to_wait);
CORE_DECLARE(status_t) s1ap_build_downlink_nas_transport(
pkbuf_t **s1apbuf, enb_ue_t *enb_ue, pkbuf_t *emmbuf);
CORE_DECLARE(status_t) s1ap_build_initial_context_setup_request(
@@ -46,6 +46,11 @@ CORE_DECLARE(status_t) s1ap_build_handover_cancel_ack(
CORE_DECLARE(status_t) s1ap_build_mme_status_transfer(pkbuf_t **s1apbuf,
enb_ue_t *target_ue, S1ap_ENBStatusTransferIEs_t *enb_ies);
CORE_DECLARE(status_t) s1ap_build_error_indication(
pkbuf_t **s1apbuf, c_uint16_t presenceMask,
c_uint32_t enb_ue_s1ap_id, c_uint32_t mme_ue_s1ap_id,
S1ap_Cause_PR group, long cause);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@@ -1,6 +1,7 @@
#define TRACE_MODULE _s1ap_conv
#include "core_debug.h"
#include "core_network.h"
#include "3gpp_types.h"
#include "s1ap_conv.h"
@@ -111,6 +112,8 @@ void s1ap_ENB_ID_to_uint32(S1ap_ENB_ID_t *eNB_ID, c_uint32_t *uint32)
status_t s1ap_BIT_STRING_to_ip(BIT_STRING_t *bit_string, ip_t *ip)
{
char buf[CORE_ADDRSTRLEN], buf2[CORE_ADDRSTRLEN];
d_assert(bit_string, return CORE_ERROR,);
d_assert(ip, return CORE_ERROR,);
@@ -120,16 +123,20 @@ status_t s1ap_BIT_STRING_to_ip(BIT_STRING_t *bit_string, ip_t *ip)
ip->ipv6 = 1;
memcpy(&ip->both.addr, bit_string->buf, IPV4_LEN);
memcpy(&ip->both.addr6, bit_string->buf+IPV4_LEN, IPV6_LEN);
d_trace(5, " IPv4[%s] IPv6[%s]\n",
INET_NTOP(&ip->both.addr, buf), INET6_NTOP(&ip->both.addr6, buf2));
}
else if (bit_string->size == IPV4_LEN)
{
ip->ipv4 = 1;
memcpy(&ip->addr, bit_string->buf, IPV4_LEN);
d_trace(5, " IPv4[%s]\n", INET_NTOP(&ip->addr, buf));
}
else if (bit_string->size == IPV6_LEN)
{
ip->ipv6 = 1;
memcpy(&ip->addr6, bit_string->buf, IPV6_LEN);
d_trace(5, " IPv6[%s]\n", INET_NTOP(&ip->addr6, buf));
}
else
d_assert(0, return CORE_ERROR, "Invalid Length(%d)", bit_string->size);
@@ -140,6 +147,8 @@ status_t s1ap_BIT_STRING_to_ip(BIT_STRING_t *bit_string, ip_t *ip)
}
status_t s1ap_ip_to_BIT_STRING(ip_t *ip, BIT_STRING_t *bit_string)
{
char buf[CORE_ADDRSTRLEN], buf2[CORE_ADDRSTRLEN];
d_assert(ip, return CORE_ERROR,);
d_assert(bit_string, return CORE_ERROR,);
@@ -149,18 +158,22 @@ status_t s1ap_ip_to_BIT_STRING(ip_t *ip, BIT_STRING_t *bit_string)
bit_string->buf = core_calloc(bit_string->size, sizeof(c_uint8_t));
memcpy(bit_string->buf, &ip->both.addr, IPV4_LEN);
memcpy(bit_string->buf+IPV4_LEN, &ip->both.addr6, IPV6_LEN);
d_trace(5, " IPv4[%s] IPv6[%s]\n",
INET_NTOP(&ip->both.addr, buf), INET6_NTOP(&ip->both.addr6, buf2));
}
else if (ip->ipv4)
{
bit_string->size = IPV4_LEN;
bit_string->buf = core_calloc(bit_string->size, sizeof(c_uint8_t));
memcpy(bit_string->buf, &ip->addr, IPV4_LEN);
d_trace(5, " IPv4[%s]\n", INET_NTOP(&ip->addr, buf));
}
else if (ip->ipv6)
{
bit_string->size = IPV6_LEN;
bit_string->buf = core_calloc(bit_string->size, sizeof(c_uint8_t));
memcpy(bit_string->buf, &ip->addr6, IPV6_LEN);
d_trace(5, " IPv6[%s]\n", INET_NTOP(&ip->addr6, buf));
}
else
d_assert(0, return CORE_ERROR,);

View File

@@ -14,6 +14,7 @@
#include "s1ap_build.h"
#include "s1ap_handler.h"
#include "mme_path.h"
#include "mme_sm.h"
void s1ap_handle_s1_setup_request(mme_enb_t *enb, s1ap_message_t *message)
@@ -24,6 +25,8 @@ void s1ap_handle_s1_setup_request(mme_enb_t *enb, s1ap_message_t *message)
pkbuf_t *s1apbuf = NULL;
c_uint32_t enb_id;
int i, j;
S1ap_Cause_PR group = S1ap_Cause_PR_NOTHING;
long cause = 0;
d_assert(enb, return, "Null param");
d_assert(enb->sock, return, "Null param");
@@ -37,6 +40,8 @@ void s1ap_handle_s1_setup_request(mme_enb_t *enb, s1ap_message_t *message)
s1ap_ENB_ID_to_uint32(&ies->global_ENB_ID.eNB_ID, &enb_id);
d_trace(5, " IP[%s] ENB_ID[%d]\n", CORE_ADDR(enb->addr, buf), enb_id);
mme_enb_set_enb_id(enb, enb_id);
/* Parse Supported TA */
enb->num_of_supported_ta_list = 0;
for (i = 0; i < ies->supportedTAs.list.count; i++)
@@ -58,42 +63,71 @@ void s1ap_handle_s1_setup_request(mme_enb_t *enb, s1ap_message_t *message)
enb->supported_ta_list[enb->num_of_supported_ta_list].tac =
ntohs(enb->supported_ta_list
[enb->num_of_supported_ta_list].tac);
d_trace(5, " TAC[%d]\n",
enb->supported_ta_list[enb->num_of_supported_ta_list].tac);
memcpy(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id,
pLMNidentity->buf, sizeof(plmn_id_t));
d_trace(5, " PLMN_ID[MCC:%d MNC:%d]\n",
d_trace(5, " PLMN_ID[MCC:%d MNC:%d] TAC[%d]\n",
plmn_id_mcc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id),
plmn_id_mnc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id));
[enb->num_of_supported_ta_list].plmn_id),
enb->supported_ta_list[enb->num_of_supported_ta_list].tac);
enb->num_of_supported_ta_list++;
}
}
if (enb->num_of_supported_ta_list == 0)
{
d_error("No supported TA exist in s1stup_req messages");
d_warn("S1-Setup failure:");
d_warn(" No supported TA exist in S1-Setup request");
group = S1ap_Cause_PR_misc;
cause = S1ap_CauseMisc_unspecified;
}
else
{
int served_tai_index = -1;
for (i = 0; i < enb->num_of_supported_ta_list; i++)
{
served_tai_index =
mme_find_served_tai(&enb->supported_ta_list[i]);
if (served_tai_index >= 0 &&
served_tai_index < MAX_NUM_OF_SERVED_TAI)
{
d_trace(5, " SERVED_TAI_INDEX[%d]\n", served_tai_index);
break;
}
}
if (served_tai_index < 0)
{
d_warn("S1-Setup failure:");
d_warn(" Cannot find Served TAI. Check 'mme.tai' configuration");
group = S1ap_Cause_PR_misc;
cause = S1ap_CauseMisc_unknown_PLMN;
}
}
d_assert(enb->sock, return,);
if (group == S1ap_Cause_PR_NOTHING)
{
d_trace(3, "[MME] S1-Setup response\n");
d_assert(s1ap_build_setup_rsp(&s1apbuf) == CORE_OK,
return, "s1ap_build_setup_rsp() failed");
}
else
{
d_trace(3, "[MME] S1-Setup failure\n");
d_assert(s1ap_build_setup_failure(
&s1apbuf, group, cause, S1ap_TimeToWait_v10s) == CORE_OK,
return, "s1ap_build_setup_failure() failed");
}
d_trace(3, "[MME] S1-Setup response\n");
d_assert(mme_enb_set_enb_id(enb, enb_id) == CORE_OK,
return, "hash add error");
d_assert(s1ap_build_setup_rsp(&s1apbuf) == CORE_OK,
return, "build error");
d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK, , "send error");
d_assert(enb->sock, return,);
d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,,
"s1ap_send_to_enb() failed");
}
void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *enb_ue = NULL;
@@ -105,6 +139,7 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
S1ap_CellIdentity_t *cell_ID = NULL;
d_assert(enb, return, "Null param");
d_assert(enb->sock, return, "Null param");
ies = &message->s1ap_InitialUEMessage_IEs;
d_assert(ies, return, "Null param");
@@ -131,7 +166,7 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
memset(&guti, 0, sizeof(guti_t));
/* FIXME : Use the first configured plmn_id and mme group id */
/* Use the first configured plmn_id and mme group id */
memcpy(&guti.plmn_id, &served_gummei->plmn_id[0], PLMN_ID_LEN);
guti.mme_gid = served_gummei->mme_gid[0];
@@ -149,8 +184,45 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
}
else
{
d_trace(5, " S_TMSI[G:%d,C:%d,M_TMSI:0x%x]\n",
guti.mme_gid, guti.mme_code, guti.m_tmsi);
d_trace(5, " S_TMSI[G:%d,C:%d,M_TMSI:0x%x] IMSI:[%s]\n",
mme_ue->guti.mme_gid,
mme_ue->guti.mme_code,
mme_ue->guti.m_tmsi,
MME_UE_HAVE_IMSI(mme_ue)
? mme_ue->imsi_bcd : "Unknown");
/* If NAS(mme_ue_t) has already been associated with
* older S1(enb_ue_t) context */
if (ECM_CONNECTED(mme_ue))
{
#if IMPLICIT_S1_RELEASE
/* Implcit S1 release */
d_warn("Implicit S1 release");
d_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
rv = enb_ue_remove(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
#else /* S1_HOLDING_TIMER */
/* Previous S1(enb_ue_t) context the holding timer(30secs)
* is started.
* Newly associated S1(enb_ue_t) context holding timer
* is stopped. */
d_trace(5, "Start S1 Holding Timer\n");
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
/* De-associate S1 with NAS/EMM */
rv = enb_ue_deassociate(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
tm_start(mme_ue->enb_ue->holding_timer);
#endif
}
tm_stop(enb_ue->holding_timer);
mme_ue_associate_enb_ue(mme_ue, enb_ue);
}
}
@@ -180,12 +252,12 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
sizeof(enb_ue->nas.e_cgi.cell_id));
enb_ue->nas.e_cgi.cell_id = (ntohl(enb_ue->nas.e_cgi.cell_id) >> 4);
d_assert(enb->sock, enb_ue_remove(enb_ue); return,);
d_trace(5, " ENB_UE_S1AP_ID[%d] TAC[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->nas.tai.tac);
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d] TAC[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id, enb_ue->nas.tai.tac);
d_assert(s1ap_send_to_nas(enb_ue, &ies->nas_pdu) == CORE_OK,,
"s1ap_send_to_nas failed");
d_assert(s1ap_send_to_nas(enb_ue,
S1ap_ProcedureCode_id_initialUEMessage, &ies->nas_pdu) == CORE_OK,,
"s1ap_send_to_nas failed");
}
void s1ap_handle_uplink_nas_transport(
@@ -204,13 +276,15 @@ void s1ap_handle_uplink_nas_transport(
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[%d]", ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[ENB_UE_S1AP_ID:%d]",
ies->eNB_UE_S1AP_ID);
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
d_assert(s1ap_send_to_nas(enb_ue, &ies->nas_pdu) == CORE_OK,,
"s1ap_send_to_nas failed");
d_assert(s1ap_send_to_nas(enb_ue,
S1ap_ProcedureCode_id_uplinkNASTransport, &ies->nas_pdu) == CORE_OK,,
"s1ap_send_to_nas failed");
}
void s1ap_handle_ue_capability_info_indication(
@@ -313,13 +387,16 @@ void s1ap_handle_initial_context_setup_response(
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
d_assert(rv == CORE_OK, return,);
d_trace(5, " EBI[%d]\n", bearer->ebi);
d_trace(5, " EBI[%d] ENB-S1U-TEID[%d]\n",
bearer->ebi, bearer->enb_s1u_teid);
if (FSM_CHECK(&bearer->sm, esm_state_active))
{
d_trace(5, " NAS_EPS Type[%d]\n", mme_ue->nas_eps.type);
int uli_presence = 0;
if (mme_ue->nas_eps.type != MME_EPS_TYPE_ATTACH_REQUEST)
{
d_trace(5, " ### ULI PRESENT ###\n");
uli_presence = 1;
}
rv = mme_gtp_send_modify_bearer_request(bearer, uli_presence);
@@ -344,25 +421,73 @@ void s1ap_handle_initial_context_setup_failure(
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[%d]", ies->eNB_UE_S1AP_ID);
mme_ue = enb_ue->mme_ue;
d_assert(mme_ue, return,);
d_error("[MME] Initial context setup failure : "
"ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d] ENB[%s:%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id,
d_trace(3, "[MME] Initial context setup failure\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
d_trace(5, " Cause[Group:%d Cause:%d]\n",
ies->cause.present, ies->cause.choice.radioNetwork);
if (MME_HAVE_SGW_S11_PATH(mme_ue))
d_assert(mme_ue,,);
if (mme_ue && FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK, return,
"mme_gtp_send_delete_all_sessions failed");
d_trace(5, " EMM-Registered\n");
/*
* 19.2.2.3 in Spec 36.300
*
* In case of failure, eNB and MME behaviours are not mandated.
*
* Both implicit release (local release at each node) and
* explicit release (MME-initiated UE Context Release procedure)
* may in principle be adopted. The eNB should ensure
* that no hanging resources remain at the eNB.
*/
#if 0 /* NOTHING TO DO */
#if 0 /* FIXME : Does it needed? */
rv = nas_send_service_reject(mme_ue,
EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
d_assert(rv == CORE_OK,,
"nas_send_service_reject() failed");
#endif
#if 1 /* Explicit Release */
d_trace(5, " Explicit Release\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas,
#if 1 /* NAS Cause: Normal Relase */
S1ap_CauseNas_normal_release,
#else /* NAS Cause : Detach */
S1ap_CauseNas_detach,
#endif
S1AP_UE_CTX_REL_UNLINK_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
#else /* Implicit Release */
d_trace(5, " Implicit Release\n");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
rv = mme_ue_deassociate(mme_ue);
d_assert(rv == CORE_OK,, "mme_ue_deassociate() failed");
#endif
#endif
}
else
{
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
d_trace(5, " NOT EMM-Registered\n");
d_assert(mme_ue,,);
rv = mme_send_delete_session_or_ue_context_release(mme_ue, enb_ue);
d_assert(rv == CORE_OK,,
"mme_send_delete_session_or_ue_context_release() failed");
}
}
@@ -446,17 +571,35 @@ void s1ap_handle_ue_context_release_request(
char buf[CORE_ADDRSTRLEN];
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_UEContextReleaseRequest_IEs_t *ies = NULL;
d_assert(enb, return,);
d_assert(message, return,);
ies = &message->s1ap_UEContextReleaseRequest_IEs;
d_assert(ies, return, "Null param");
d_assert(ies, return,);
d_trace(3, "[MME] UE Context release request\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id);
d_assert(enb_ue, return, "No UE Context[%d]", ies->mme_ue_s1ap_id);
if (!enb_ue)
{
d_warn("No ENB UE Context : MME_UE_S1AP_ID[%d]", ies->mme_ue_s1ap_id);
rv = s1ap_send_error_indication(enb,
S1AP_ERRORINDICATIONIES_MME_UE_S1AP_ID_PRESENT |
S1AP_ERRORINDICATIONIES_ENB_UE_S1AP_ID_PRESENT |
S1AP_ERRORINDICATIONIES_CAUSE_PRESENT,
ies->eNB_UE_S1AP_ID,
ies->mme_ue_s1ap_id,
S1ap_Cause_PR_radioNetwork,
S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id);
d_assert(rv == CORE_OK, return, "s1ap send error");
return;
}
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
@@ -466,91 +609,44 @@ void s1ap_handle_ue_context_release_request(
switch(ies->cause.present)
{
case S1ap_Cause_PR_radioNetwork:
{
mme_ue_t *mme_ue = enb_ue->mme_ue;
if (ies->cause.choice.radioNetwork
== S1ap_CauseRadioNetwork_user_inactivity)
{
d_assert(mme_ue, return,);
if (MME_HAVE_SGW_S11_PATH(mme_ue))
{
rv = mme_gtp_send_release_access_bearers_request(mme_ue);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
else
{
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
}
}
else
{
d_error("[MME] UE Context release request : "
"RadioNetwork Cause[%d] "
"ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d] ENB[%s:%d]\n",
ies->cause.choice.radioNetwork,
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id,
CORE_ADDR(enb->addr, buf), enb->enb_id);
if (MME_HAVE_SGW_S11_PATH(mme_ue))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK, return,
"mme_gtp_send_delete_all_sessions failed");
}
else
{
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
}
}
break;
}
case S1ap_Cause_PR_transport:
{
mme_ue_t *mme_ue = enb_ue->mme_ue;
d_error("[MME] UE Context release request : "
"Transport Cause[%d] "
"ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d] ENB[%s:%d]\n",
ies->cause.choice.radioNetwork,
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id,
CORE_ADDR(enb->addr, buf), enb->enb_id);
if (MME_HAVE_SGW_S11_PATH(mme_ue))
{
rv = mme_gtp_send_delete_all_sessions(mme_ue);
d_assert(rv == CORE_OK, return,
"mme_gtp_send_delete_all_sessions failed");
}
else
{
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
}
break;
}
case S1ap_Cause_PR_nas:
d_warn("Not implmented (nas cause : %d)", ies->cause.choice.nas);
break;
case S1ap_Cause_PR_protocol:
d_warn("Not implmented (protocol cause : %d)",
ies->cause.choice.protocol);
break;
case S1ap_Cause_PR_misc:
d_warn("Not implmented (misc cause : %d)", ies->cause.choice.misc);
break;
case S1ap_Cause_PR_nas:
d_warn("NAS-Cause[%d]", ies->cause.choice.nas);
default:
d_warn("Invalid cause type : %d", ies->cause.present);
d_warn("Invalid cause group[%d]", ies->cause.present);
break;
}
mme_ue = enb_ue->mme_ue;
if (mme_ue)
{
if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
d_trace(5, " EMM-Registered\n");
rv = mme_send_release_access_bearer_or_ue_context_release(
mme_ue, enb_ue);
d_assert(rv == CORE_OK,, "mme_send_release_access_bearer_or_"
"ue_context_release() failed");
}
else
{
d_trace(5, " NOT EMM-Registered\n");
rv = mme_send_delete_session_or_ue_context_release(mme_ue, enb_ue);
d_assert(rv == CORE_OK,,
"mme_send_delete_session_or_ue_context_release() failed");
}
}
else
{
d_trace(5, " S1 Context Not Associated\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
}
}
void s1ap_handle_ue_context_release_complete(
@@ -559,7 +655,6 @@ void s1ap_handle_ue_context_release_complete(
status_t rv;
char buf[CORE_ADDRSTRLEN];
c_uint8_t ue_ctx_rel_action = 0;
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_UEContextReleaseComplete_IEs_t *ies = NULL;
@@ -573,44 +668,85 @@ void s1ap_handle_ue_context_release_complete(
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id);
d_assert(enb_ue, return, "No UE Context[%d]", ies->mme_ue_s1ap_id);
mme_ue = enb_ue->mme_ue;
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ue_ctx_rel_action = enb_ue->ue_ctx_rel_action;
enb_ue->ue_ctx_rel_action = S1AP_UE_CTX_REL_INVALID_ACTION;
mme_ue = enb_ue->mme_ue;
enb_ue_remove(enb_ue);
if (mme_ue)
switch (enb_ue->ue_ctx_rel_action)
{
switch (ue_ctx_rel_action)
case S1AP_UE_CTX_REL_NO_ACTION:
{
case S1AP_UE_CTX_REL_NO_ACTION:
d_trace(5, " No Action\n");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
break;
}
case S1AP_UE_CTX_REL_S1_NORMAL_RELEASE:
{
d_trace(5, " Action: S1 normal release\n");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
d_assert(mme_ue,,);
rv = mme_ue_deassociate(mme_ue);
d_assert(rv == CORE_OK,, "mme_ue_deassociate() failed");
break;
}
case S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE:
{
d_trace(5, " Action: UE context remove()\n");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_removeI() failed");
d_assert(mme_ue,,);
rv = mme_ue_remove(mme_ue);
d_assert(rv == CORE_OK,, "mme_ue_remove() failed");
break;
}
case S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL:
{
d_trace(5, " Action: Delete indirect tunnel\n");
rv = source_ue_deassociate_target_ue(enb_ue);
d_assert(rv == CORE_OK,,
"source_ue_deassociate_target_ue() failed");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_removeI() failed");
d_assert(mme_ue,,);
if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue))
{
d_trace(5, " No Action\n");
break;
rv = mme_gtp_send_delete_indirect_data_forwarding_tunnel_request(mme_ue);
d_assert(rv == CORE_OK,, "mme_gtp_send_delete_indirect_data_"
"forwarding_tunnel_request() failed");
}
case S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT:
else
{
d_trace(5, " Action: UE(mme) context\n");
mme_ue_remove(mme_ue);
break;
}
case S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL:
{
d_trace(5, " Action: Delete indirect tunnel\n");
rv = mme_gtp_send_delete_indirect_data_forwarding_tunnel_request(
mme_ue);
d_assert(rv == CORE_OK, return, "gtp send error");
break;
}
default:
{
d_assert(0, return, "Invalid action[%d]", ue_ctx_rel_action);
break;
mme_sess_t *sess = NULL;
mme_bearer_t *bearer = NULL;
d_warn("GTP-C(S11) has already been deleted");
sess = mme_sess_first(mme_ue);
while(sess)
{
bearer = mme_bearer_first(sess);
while(bearer)
{
CLEAR_INDIRECT_TUNNEL(bearer);
bearer = mme_bearer_next(bearer);
}
sess = mme_sess_next(sess);
}
}
break;
}
default:
{
d_assert(0,, "Invalid Action[%d]", enb_ue->ue_ctx_rel_action);
break;
}
}
}
@@ -738,14 +874,29 @@ void s1ap_handle_path_switch_request(
enb_ue->enb_ue_s1ap_id = ies->eNB_UE_S1AP_ID;
memcpy(&mme_ue->tai.plmn_id, pLMNidentity->buf,
sizeof(mme_ue->tai.plmn_id));
memcpy(&mme_ue->tai.tac, tAC->buf, sizeof(mme_ue->tai.tac));
mme_ue->tai.tac = ntohs(mme_ue->tai.tac);
memcpy(&mme_ue->e_cgi.plmn_id, pLMNidentity->buf,
sizeof(mme_ue->e_cgi.plmn_id));
memcpy(&mme_ue->e_cgi.cell_id, cell_ID->buf, sizeof(mme_ue->e_cgi.cell_id));
mme_ue->e_cgi.cell_id = (ntohl(mme_ue->e_cgi.cell_id) >> 4);
memcpy(&enb_ue->nas.tai.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->nas.tai.plmn_id));
memcpy(&enb_ue->nas.tai.tac, tAC->buf, sizeof(enb_ue->nas.tai.tac));
enb_ue->nas.tai.tac = ntohs(enb_ue->nas.tai.tac);
memcpy(&enb_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->nas.e_cgi.plmn_id));
memcpy(&enb_ue->nas.e_cgi.cell_id, cell_ID->buf,
sizeof(enb_ue->nas.e_cgi.cell_id));
enb_ue->nas.e_cgi.cell_id = (ntohl(enb_ue->nas.e_cgi.cell_id) >> 4);
d_trace(5, " OLD TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " OLD E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
enb_ue->nas.tai.plmn_id, enb_ue->nas.tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
enb_ue->nas.e_cgi.plmn_id, enb_ue->nas.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->nas.tai, sizeof(tai_t));
memcpy(&mme_ue->e_cgi, &enb_ue->nas.e_cgi, sizeof(e_cgi_t));
memcpy(&eea, encryptionAlgorithms->buf, sizeof(eea));
eea = ntohs(eea);
@@ -1136,14 +1287,29 @@ void s1ap_handle_handover_notification(mme_enb_t *enb, s1ap_message_t *message)
mme_ue_associate_enb_ue(mme_ue, target_ue);
memcpy(&mme_ue->tai.plmn_id, pLMNidentity->buf,
sizeof(mme_ue->tai.plmn_id));
memcpy(&mme_ue->tai.tac, tAC->buf, sizeof(mme_ue->tai.tac));
mme_ue->tai.tac = ntohs(mme_ue->tai.tac);
memcpy(&mme_ue->e_cgi.plmn_id, pLMNidentity->buf,
sizeof(mme_ue->e_cgi.plmn_id));
memcpy(&mme_ue->e_cgi.cell_id, cell_ID->buf, sizeof(mme_ue->e_cgi.cell_id));
mme_ue->e_cgi.cell_id = (ntohl(mme_ue->e_cgi.cell_id) >> 4);
memcpy(&target_ue->nas.tai.plmn_id, pLMNidentity->buf,
sizeof(target_ue->nas.tai.plmn_id));
memcpy(&target_ue->nas.tai.tac, tAC->buf, sizeof(target_ue->nas.tai.tac));
target_ue->nas.tai.tac = ntohs(target_ue->nas.tai.tac);
memcpy(&target_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(target_ue->nas.e_cgi.plmn_id));
memcpy(&target_ue->nas.e_cgi.cell_id, cell_ID->buf,
sizeof(target_ue->nas.e_cgi.cell_id));
target_ue->nas.e_cgi.cell_id = (ntohl(target_ue->nas.e_cgi.cell_id) >> 4);
d_trace(5, " OLD TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " OLD E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
target_ue->nas.tai.plmn_id, target_ue->nas.tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
target_ue->nas.e_cgi.plmn_id, target_ue->nas.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &target_ue->nas.tai, sizeof(tai_t));
memcpy(&mme_ue->e_cgi, &target_ue->nas.e_cgi, sizeof(e_cgi_t));
sess = mme_sess_first(mme_ue);
while(sess)

View File

@@ -134,7 +134,8 @@ status_t s1ap_send_to_esm(mme_ue_t *mme_ue, pkbuf_t *esmbuf)
return CORE_OK;
}
status_t s1ap_send_to_nas(enb_ue_t *enb_ue, S1ap_NAS_PDU_t *nasPdu)
status_t s1ap_send_to_nas(enb_ue_t *enb_ue,
S1ap_ProcedureCode_t procedureCode, S1ap_NAS_PDU_t *nasPdu)
{
nas_security_header_t *sh = NULL;
nas_security_header_type_t security_header_type;
@@ -206,8 +207,9 @@ status_t s1ap_send_to_nas(enb_ue_t *enb_ue, S1ap_NAS_PDU_t *nasPdu)
{
event_set(&e, MME_EVT_EMM_MESSAGE);
event_set_param1(&e, (c_uintptr_t)enb_ue->index);
event_set_param2(&e, (c_uintptr_t)security_header_type.type);
event_set_param3(&e, (c_uintptr_t)nasbuf);
event_set_param2(&e, (c_uintptr_t)procedureCode);
event_set_param3(&e, (c_uintptr_t)security_header_type.type);
event_set_param4(&e, (c_uintptr_t)nasbuf);
mme_event_send(&e);
}
else if (h->protocol_discriminator == NAS_PROTOCOL_DISCRIMINATOR_ESM)
@@ -417,18 +419,17 @@ status_t s1ap_send_handover_request(
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
d_trace(5, " Target : ENB_UE_S1AP_ID[Unknown] MME_UE_S1AP_ID[%d]\n",
target_ue->mme_ue_s1ap_id);
rv = source_ue_associate_target_ue(source_ue, target_ue);
d_assert(rv == CORE_OK, return CORE_ERROR,);
rv = s1ap_build_handover_request(&s1apbuf, mme_ue, target_ue, ies);
d_assert(rv == CORE_OK && s1apbuf,
enb_ue_remove(target_ue); return CORE_ERROR, "s1ap build error");
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
rv = s1ap_send_to_enb(target_enb, s1apbuf);
d_assert(rv == CORE_OK, enb_ue_remove(target_ue), "s1ap send error");
d_assert(rv == CORE_OK,, "s1ap send error");
return rv;
}
@@ -453,3 +454,23 @@ status_t s1ap_send_mme_status_transfer(
return rv;
}
status_t s1ap_send_error_indication(
mme_enb_t *enb, c_uint16_t presenceMask,
c_uint32_t enb_ue_s1ap_id, c_uint32_t mme_ue_s1ap_id,
S1ap_Cause_PR group, long cause)
{
status_t rv;
pkbuf_t *s1apbuf = NULL;
d_assert(enb, return CORE_ERROR,);
rv = s1ap_build_error_indication(&s1apbuf,
presenceMask, enb_ue_s1ap_id, mme_ue_s1ap_id, group, cause);
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
rv = s1ap_send_to_enb(enb, s1apbuf);
d_assert(rv == CORE_OK,, "s1ap send error");
return rv;
}

View File

@@ -29,7 +29,8 @@ CORE_DECLARE(status_t) s1ap_send_to_enb(mme_enb_t *enb, pkbuf_t *pkb);
CORE_DECLARE(status_t) s1ap_delayed_send_to_enb(mme_enb_t *enb,
pkbuf_t *pkbuf, c_uint32_t duration);
CORE_DECLARE(status_t) s1ap_send_to_nas(
enb_ue_t *enb_ue, S1ap_NAS_PDU_t *nasPdu);
enb_ue_t *enb_ue,
S1ap_ProcedureCode_t procedureCode, S1ap_NAS_PDU_t *nasPdu);
CORE_DECLARE(status_t) s1ap_send_to_esm(mme_ue_t *mme_ue, pkbuf_t *esmbuf);
CORE_DECLARE(status_t) s1ap_send_initial_context_setup_request(
@@ -54,6 +55,10 @@ CORE_DECLARE(status_t) s1ap_send_handover_cancel_ack(enb_ue_t *source_ue);
CORE_DECLARE(status_t) s1ap_send_mme_status_transfer(
enb_ue_t *target_ue, S1ap_ENBStatusTransferIEs_t *ies);
CORE_DECLARE(status_t) s1ap_send_error_indication(
mme_enb_t *enb, c_uint16_t presenceMask,
c_uint32_t enb_ue_s1ap_id, c_uint32_t mme_ue_s1ap_id,
S1ap_Cause_PR group, long cause);
#ifdef __cplusplus
}

View File

@@ -396,8 +396,9 @@ static int s1ap_usrsctp_recv_handler(struct socket *sock,
case SCTP_PEER_ADDR_CHANGE:
break;
case SCTP_SEND_FAILED :
d_error("SCTP_SEND_FAILED"
d_error("flags:0x%x - SCTP_SEND_FAILED"
"(type:0x%x, flags:0x%x, error:0x%x)\n",
flags,
not->sn_send_failed_event.ssfe_type,
not->sn_send_failed_event.ssfe_flags,
not->sn_send_failed_event.ssfe_error);
@@ -416,6 +417,16 @@ static int s1ap_usrsctp_recv_handler(struct socket *sock,
}
break;
}
case SCTP_REMOTE_ERROR:
{
d_warn("flags:0x%x - SCTP_REMOTE_ERROR"
"(type:0x%x, flags:0x%x, error:0x%x)\n",
flags,
not->sn_remote_error.sre_type,
not->sn_remote_error.sre_flags,
not->sn_remote_error.sre_error);
break;
}
default :
d_error("Discarding event with unknown "
"flags = 0x%x, type 0x%x",

View File

@@ -25,7 +25,11 @@ status_t app_initialize(const char *config_path, const char *log_path)
d_trace(1, "PCRF try to initialize\n");
rv = pcrf_initialize();
d_assert(rv == CORE_OK, return rv, "Failed to intialize PCRF");
if (rv != CORE_OK)
{
d_error("Failed to intialize PCRF");
return rv;
}
d_trace(1, "PCRF initialize...done\n");
rv = app_did_initialize();

View File

@@ -319,13 +319,6 @@ status_t pcrf_context_setup_trace_module()
if (app)
{
extern int _mutex;
d_trace_level(&_mutex, app);
extern int _pkbuf;
d_trace_level(&_pkbuf, app);
extern int _context;
d_trace_level(&_context, app);
extern int _pcrf_context;
d_trace_level(&_pcrf_context, app);
}

View File

@@ -1097,7 +1097,7 @@ static void pcrf_gx_raa_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, " From '%.*s' ",
d_trace(5, " From '%.*s'\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else
@@ -1113,7 +1113,7 @@ static void pcrf_gx_raa_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, "('%.*s') ",
d_trace(5, " ('%.*s')\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else

View File

@@ -606,7 +606,7 @@ static void pcrf_rx_asa_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, " From '%.*s' ",
d_trace(5, " From '%.*s'\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else
@@ -621,7 +621,7 @@ static void pcrf_rx_asa_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, "('%.*s') ",
d_trace(5, " ('%.*s')\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else

View File

@@ -25,7 +25,11 @@ status_t app_initialize(const char *config_path, const char *log_path)
d_trace(1, "PGW try to initialize\n");
rv = pgw_initialize();
d_assert(rv == CORE_OK, return rv, "Failed to intialize PGW");
if (rv != CORE_OK)
{
d_error("Failed to intialize PGW");
return rv;
}
d_trace(1, "PGW initialize...done\n");
rv = app_did_initialize();

View File

@@ -863,13 +863,6 @@ status_t pgw_context_setup_trace_module()
if (app)
{
extern int _mutex;
d_trace_level(&_mutex, app);
extern int _pkbuf;
d_trace_level(&_pkbuf, app);
extern int _context;
d_trace_level(&_context, app);
extern int _pgw_context;
d_trace_level(&_pgw_context, app);
}
@@ -938,6 +931,8 @@ pgw_sess_t *pgw_sess_add(
index_alloc(&pgw_sess_pool, &sess);
d_assert(sess, return NULL, "Null param");
sess->gnode = NULL;
sess->pgw_s5c_teid = sess->index; /* derived from an index */
/* Set IMSI */
@@ -1178,6 +1173,8 @@ pgw_bearer_t* pgw_bearer_add(pgw_sess_t *sess)
bearer->pgw_s5u_teid = bearer->index;
bearer->sess = sess;
bearer->gnode = NULL;
list_append(&sess->bearer_list, bearer);
return bearer;

View File

@@ -108,8 +108,7 @@ typedef struct _pgw_subnet_t {
} pgw_subnet_t;
typedef struct _pgw_sess_t {
lnode_t node; /* FIXME : remove it */
index_t index; /**< An index of this node */
index_t index; /**< An index of this node */
c_uint32_t pgw_s5c_teid; /* PGW-S5C-TEID is derived from INDEX */
c_uint32_t sgw_s5c_teid; /* SGW-S5C-TEID is received from SGW */

View File

@@ -531,7 +531,7 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, " From '%.*s' ",
d_trace(5, " From '%.*s'\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else
@@ -547,7 +547,7 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg)
{
ret = fd_msg_avp_hdr(avp, &hdr);
d_assert(ret == 0, return,);
d_trace(5, "('%.*s') ",
d_trace(5, " ('%.*s')\n",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
}
else

View File

@@ -149,8 +149,8 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
if (!subnet)
{
d_print_hex(pkbuf->payload, pkbuf->len);
d_warn("[DROP] Cannot find subnet V:%d, IPv4:%p, IPv6:%p",
d_trace_hex(9, pkbuf->payload, pkbuf->len);
d_trace(9, "[DROP] Cannot find subnet V:%d, IPv4:%p, IPv6:%p\n",
ip_h->ip_v, sess->ipv4, sess->ipv6);
goto cleanup;
}

View File

@@ -59,6 +59,10 @@ void pgw_gx_handle_cca_termination_request(
/* backup sgw_s5c_teid in session context */
sgw_s5c_teid = sess->sgw_s5c_teid;
d_trace(3, "[PGW] Delete Session Response\n");
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
/* Remove a pgw session */
pgw_sess_remove(sess);
@@ -67,7 +71,7 @@ void pgw_gx_handle_cca_termination_request(
h.teid = sgw_s5c_teid;
rv = pgw_s5c_build_delete_session_response(
&pkbuf, h.type, sess, gx_message, req);
&pkbuf, h.type, gx_message, req);
d_assert(rv == CORE_OK, return, "S11 build error");
rv = gtp_xact_update_tx(xact, &h, pkbuf);

View File

@@ -30,16 +30,18 @@ status_t pgw_s5c_build_create_session_response(
c_uint8_t pco_buf[MAX_PCO_LEN];
c_int16_t pco_len;
d_trace(3, "[PGW] Create Session Response\n");
d_assert(sess, return CORE_ERROR, "Null param");
d_assert(req, return CORE_ERROR, "Null param");
d_trace(3, "[PGW] Create Session Response\n");
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
bearer = pgw_default_bearer_in_sess(sess);
d_assert(bearer, return CORE_ERROR, "Null param");
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
d_trace(5, " SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]\n",
bearer->sgw_s5u_teid, bearer->pgw_s5u_teid);
rsp = &gtp_message.create_session_response;
memset(&gtp_message, 0, sizeof(gtp_message_t));
@@ -120,7 +122,7 @@ status_t pgw_s5c_build_create_session_response(
}
status_t pgw_s5c_build_delete_session_response(
pkbuf_t **pkbuf, c_uint8_t type, pgw_sess_t *sess,
pkbuf_t **pkbuf, c_uint8_t type,
gx_message_t *gx_message, gtp_delete_session_request_t *req)
{
status_t rv;
@@ -132,14 +134,9 @@ status_t pgw_s5c_build_delete_session_response(
c_uint8_t pco_buf[MAX_PCO_LEN];
c_int16_t pco_len;
d_assert(sess, return CORE_ERROR, "Null param");
d_assert(gx_message, return CORE_ERROR, "Null param");
d_assert(req, return CORE_ERROR, "Null param");
d_trace(3, "[PGW] Delete Session Response\n");
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
/* prepare cause */
memset(&cause, 0, sizeof(cause));
cause.value = GTP_CAUSE_REQUEST_ACCEPTED;

View File

@@ -11,7 +11,7 @@ CORE_DECLARE(status_t) pgw_s5c_build_create_session_response(
pkbuf_t **pkbuf, c_uint8_t type, pgw_sess_t *sess,
gx_message_t *gx_message, gtp_create_session_request_t *req);
CORE_DECLARE(status_t) pgw_s5c_build_delete_session_response(
pkbuf_t **pkbuf, c_uint8_t type, pgw_sess_t *sess,
pkbuf_t **pkbuf, c_uint8_t type,
gx_message_t *gx_message, gtp_delete_session_request_t *req);
CORE_DECLARE(status_t) pgw_s5c_build_create_bearer_request(

View File

@@ -73,13 +73,16 @@ void pgw_s5c_handle_create_session_request(
d_assert(sgw_s5c_teid, return, "Null param");
sess->sgw_s5c_teid = ntohl(sgw_s5c_teid->teid);
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
/* Control Plane(DL) : SGW-S5U */
sgw_s5u_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data;
d_assert(sgw_s5u_teid, return, "Null param");
bearer->sgw_s5u_teid = ntohl(sgw_s5u_teid->teid);
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
d_trace(5, " SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]\n",
bearer->sgw_s5u_teid, bearer->pgw_s5u_teid);
sgw = gtp_find_node(&pgw_self()->sgw_s5u_list, sgw_s5u_teid);
if (!sgw)
{

View File

@@ -95,8 +95,7 @@ void pgw_state_operational(fsm_t *s, event_t *e)
{
sess = pgw_sess_find_by_teid(message->h.teid);
}
d_assert(sess,
pkbuf_free(recvbuf); pkbuf_free(copybuf); break,
d_assert(sess, pkbuf_free(recvbuf); pkbuf_free(copybuf); break,
"No Session Context");
rv = gtp_xact_receive(sess->gnode, &message->h, &xact);

View File

@@ -25,7 +25,11 @@ status_t app_initialize(const char *config_path, const char *log_path)
d_trace(1, "SGW try to initialize\n");
rv = sgw_initialize();
d_assert(rv == CORE_OK, return rv, "Failed to intialize SGW");
if (rv != CORE_OK)
{
d_error("Failed to intialize SGW");
return rv;
}
d_trace(1, "SGW initialize...done\n");
rv = app_did_initialize();

View File

@@ -461,13 +461,6 @@ status_t sgw_context_setup_trace_module()
if (app)
{
extern int _mutex;
d_trace_level(&_mutex, app);
extern int _pkbuf;
d_trace_level(&_pkbuf, app);
extern int _context;
d_trace_level(&_context, app);
extern int _sgw_context;
d_trace_level(&_sgw_context, app);
}
@@ -478,8 +471,8 @@ status_t sgw_context_setup_trace_module()
d_trace_level(&_sgw_sm, gtpv2);
extern int _sgw_s11_handler;
d_trace_level(&_sgw_s11_handler, gtpv2);
extern int _sgw_s11_handler;
d_trace_level(&_sgw_s11_handler, gtpv2);
extern int _sgw_s5c_handler;
d_trace_level(&_sgw_s5c_handler, gtpv2);
extern int _gtp_node;
d_trace_level(&_gtp_node, gtpv2);
@@ -677,6 +670,7 @@ sgw_sess_t *sgw_sess_add(
core_cpystrn(sess->pdn.apn, apn, MAX_APN_LEN+1);
sess->sgw_ue = sgw_ue;
sess->gnode = NULL;
list_init(&sess->bearer_list);
@@ -915,6 +909,7 @@ sgw_tunnel_t* sgw_tunnel_add(sgw_bearer_t *bearer, c_uint8_t interface_type)
tunnel->local_teid = tunnel->index;
tunnel->bearer = bearer;
tunnel->gnode = NULL;
list_append(&bearer->tunnel_list, tunnel);

View File

@@ -49,7 +49,6 @@ typedef struct _sgw_context_t {
} sgw_context_t;
typedef struct _sgw_ue_t {
lnode_t node; /* FIXME : remove it */
index_t index; /* An index of this node */
c_uint32_t sgw_s11_teid; /* SGW-S11-TEID is derived from INDEX */

View File

@@ -121,7 +121,12 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
tunnel = sgw_tunnel_find_by_teid(teid);
if (!tunnel)
{
d_error("No TEID(0x%x)", teid);
if (gtp_h->type == GTPU_MSGTYPE_GPDU)
d_warn("[SGW] RECV GPU-U from [%s] : No TEID[0x%x]",
CORE_ADDR(&from, buf), teid);
else if (gtp_h->type == GTPU_MSGTYPE_END_MARKER)
d_warn("[SGW] RECV End Marker from [%s] : No TEID[0x%x]",
CORE_ADDR(&from, buf), teid);
pkbuf_free(pkbuf);
return 0;
}
@@ -169,14 +174,15 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
d_assert(s1u_tunnel, pkbuf_free(pkbuf); return 0, "Null param");
d_assert(s1u_tunnel->gnode, pkbuf_free(pkbuf); return 0,);
d_assert(s1u_tunnel->gnode->sock, pkbuf_free(pkbuf); return 0,);
d_trace(3, "[SGW] SEND GPU-U to ENB[%s]: TEID[0x%x]\n",
CORE_ADDR(sock_remote_addr(s1u_tunnel->gnode->sock), buf),
s1u_tunnel->remote_teid);
if (s1u_tunnel->remote_teid)
{
d_assert(s1u_tunnel->gnode, pkbuf_free(pkbuf); return 0,);
d_assert(s1u_tunnel->gnode->sock, pkbuf_free(pkbuf); return 0,);
d_trace(3, "[SGW] SEND GPU-U to ENB[%s]: TEID[0x%x]\n",
CORE_ADDR(sock_remote_addr(s1u_tunnel->gnode->sock), buf),
s1u_tunnel->remote_teid);
/* If there is buffered packet, send it first */
for (i = 0; i < bearer->num_buffered_pkt; i++)
{
@@ -208,15 +214,17 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
sgw_ue = bearer->sess->sgw_ue;
d_trace(3, "[SGW] S1U PATH deactivated : STATE[0x%x]\n",
SGW_GET_UE_STATE(sgw_ue));
if ((SGW_GET_UE_STATE(sgw_ue) & SGW_S1U_INACTIVE))
{
d_trace(9, " SGW-S1U Inactive\n");
if ( !(SGW_GET_UE_STATE(sgw_ue) & SGW_DL_NOTI_SENT))
d_trace(5, " SGW-S1U Inactive\n");
if (!(SGW_GET_UE_STATE(sgw_ue) & SGW_DL_NOTI_SENT))
{
event_t e;
status_t rv;
d_trace(9, " EVENT DL Data Notification\n");
d_trace(5, " EVENT DL Data Notification\n");
event_set(&e, SGW_EVT_LO_DLDATA_NOTI);
event_set_param1(&e, (c_uintptr_t)bearer->index);
rv = sgw_event_send(&e);
@@ -241,8 +249,8 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
else
{
/* UE is S1U_ACTIVE state but there is no s1u teid */
d_warn("UE is ACITVE but there is no matched "
"s1u_teid(tedid = 0x%x)",teid);
d_trace(5, "[SGW] UE is ACITVE but there is no matched "
"ENB_S1U_TEID[%d]", teid);
/* Just drop it */
}
@@ -298,19 +306,17 @@ status_t sgw_gtp_close()
return CORE_OK;
}
status_t sgw_gtp_send_end_marker(sgw_bearer_t *bearer)
status_t sgw_gtp_send_end_marker(sgw_tunnel_t *s1u_tunnel)
{
char buf[CORE_ADDRSTRLEN];
status_t rv;
pkbuf_t *pkbuf = NULL;
gtp_header_t *h = NULL;
sgw_tunnel_t *s1u_tunnel = NULL;
d_assert(bearer, return CORE_ERROR,);
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
d_assert(s1u_tunnel, return CORE_ERROR,);
d_assert(s1u_tunnel->gnode, return CORE_ERROR,);
d_assert(s1u_tunnel->gnode->sock, return CORE_ERROR,);
d_trace(3, "[SGW] SEND End Marker to ENB[%s]: TEID[0x%x]\n",
CORE_ADDR(sock_remote_addr(s1u_tunnel->gnode->sock), buf),
s1u_tunnel->remote_teid);
@@ -331,7 +337,7 @@ status_t sgw_gtp_send_end_marker(sgw_bearer_t *bearer)
h->teid = htonl(s1u_tunnel->remote_teid);
rv = gtp_send(s1u_tunnel->gnode, pkbuf);
d_assert(rv == CORE_OK, , "gtp send failed");
d_assert(rv == CORE_OK,, "gtp send failed");
pkbuf_free(pkbuf);
return rv;

View File

@@ -10,7 +10,7 @@ extern "C" {
CORE_DECLARE(status_t) sgw_gtp_open();
CORE_DECLARE(status_t) sgw_gtp_close();
CORE_DECLARE(status_t) sgw_gtp_send_end_marker(sgw_bearer_t *bearer);
CORE_DECLARE(status_t) sgw_gtp_send_end_marker(sgw_tunnel_t *s1u_tunnel);
#ifdef __cplusplus
}

View File

@@ -111,6 +111,8 @@ void sgw_s11_handle_create_session_request(
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
d_trace(5, " SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]\n",
s5u_tunnel->local_teid, s5u_tunnel->remote_teid);
pgw_s5c_teid = req->pgw_s5_s8_address_for_control_plane_or_pmip.data;
d_assert(pgw_s5c_teid, return, "Null param");
@@ -172,6 +174,8 @@ CORE_DECLARE(void) sgw_s11_handle_modify_bearer_request(gtp_xact_t *s11_xact,
sgw_ue_t *sgw_ue, gtp_modify_bearer_request_t *req)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
c_uint16_t decoded;
gtp_node_t *enb = NULL;
sgw_bearer_t *bearer = NULL;
@@ -189,8 +193,6 @@ CORE_DECLARE(void) sgw_s11_handle_modify_bearer_request(gtp_xact_t *s11_xact,
d_assert(req, return, "Null param");
d_trace(3, "[SGW] Modify Bearer Reqeust\n");
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
if (req->bearer_contexts_to_be_modified.presence == 0)
{
d_error("No Bearer");
@@ -213,27 +215,15 @@ CORE_DECLARE(void) sgw_s11_handle_modify_bearer_request(gtp_xact_t *s11_xact,
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
d_assert(s1u_tunnel, return, "No S1U Tunnel Context");
/* Set User Location Information */
if (req->user_location_information.presence == 1)
{
decoded = gtp_parse_uli(&uli, &req->user_location_information);
d_assert(req->user_location_information.len == decoded, return,);
memcpy(&bearer->tai.plmn_id, &uli.tai.plmn_id, sizeof(uli.tai.plmn_id));
bearer->tai.tac = uli.tai.tac;
memcpy(&bearer->e_cgi.plmn_id, &uli.e_cgi.plmn_id, sizeof(uli.e_cgi.plmn_id));
if (bearer->e_cgi.cell_id != uli.e_cgi.cell_id)
{
rv = sgw_gtp_send_end_marker(bearer);
if (rv != CORE_OK)
d_error("gtp send end marker failed");
bearer->e_cgi.cell_id = uli.e_cgi.cell_id;
}
}
/* Data Plane(DL) : eNB-S1U */
enb_s1u_teid = req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.data;
s1u_tunnel->remote_teid = ntohl(enb_s1u_teid->teid);
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
d_trace(5, " ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]\n",
s1u_tunnel->remote_teid, s1u_tunnel->local_teid);
enb = gtp_find_node(&sgw_self()->enb_s1u_list, enb_s1u_teid);
if (!enb)
{
@@ -244,13 +234,70 @@ CORE_DECLARE(void) sgw_s11_handle_modify_bearer_request(gtp_xact_t *s11_xact,
context_self()->parameter.prefer_ipv4);
d_assert(enb, return,);
#if 1
rv = gtp_client(enb);
#else /* Exmaple code for GTP code */
#if UNBOUNDED_UDP_SOCKET
rv = gtp_connect(sgw_self()->gtpu_sock, sgw_self()->gtpu_sock6, enb);
#else
rv = gtp_client(enb);
#endif
d_assert(rv == CORE_OK, return,);
}
#if ULI_END_MARKER
/* if ULI's Cell ID changes, End Marker is sent out or not */
if (req->user_location_information.presence == 1)
{
/* Set User Location Information */
decoded = gtp_parse_uli(&uli, &req->user_location_information);
d_assert(req->user_location_information.len == decoded, return,);
memcpy(&bearer->tai.plmn_id, &uli.tai.plmn_id, sizeof(uli.tai.plmn_id));
bearer->tai.tac = uli.tai.tac;
memcpy(&bearer->e_cgi.plmn_id, &uli.e_cgi.plmn_id,
sizeof(uli.e_cgi.plmn_id));
d_trace(5, " ULI Presence: CellID[OLD:0x%x, NEW:0x%x]\n",
bearer->e_cgi.cell_id, uli.e_cgi.cell_id);
if (bearer->e_cgi.cell_id != uli.e_cgi.cell_id)
{
d_trace(3, "[SGW] SEND End Marker to ENB[%s]: TEID[0x%x]\n",
CORE_ADDR(sock_remote_addr(s1u_tunnel->gnode->sock), buf),
s1u_tunnel->remote_teid);
rv = sgw_gtp_send_end_marker(s1u_tunnel);
if (rv != CORE_OK)
d_error("gtp send end marker failed");
bearer->e_cgi.cell_id = uli.e_cgi.cell_id;
}
}
#else /* GNODE_END_MARKER */
/* if GTP Node changes, End Marker is sent out or not */
if (req->user_location_information.presence == 1)
{
/* Set User Location Information */
decoded = gtp_parse_uli(&uli, &req->user_location_information);
d_assert(req->user_location_information.len == decoded, return,);
memcpy(&bearer->tai.plmn_id, &uli.tai.plmn_id, sizeof(uli.tai.plmn_id));
bearer->tai.tac = uli.tai.tac;
memcpy(&bearer->e_cgi.plmn_id, &uli.e_cgi.plmn_id,
sizeof(uli.e_cgi.plmn_id));
bearer->e_cgi.cell_id = uli.e_cgi.cell_id;
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
bearer->tai.plmn_id, bearer->tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
bearer->e_cgi.plmn_id, bearer->e_cgi.cell_id);
}
if (s1u_tunnel->gnode && s1u_tunnel->gnode != enb)
{
d_assert(s1u_tunnel->gnode->sock, return,);
d_trace(3, "[SGW] SEND End Marker to ENB[%s]: TEID[0x%x]",
CORE_ADDR(sock_remote_addr(s1u_tunnel->gnode->sock), buf),
s1u_tunnel->remote_teid);
rv = sgw_gtp_send_end_marker(s1u_tunnel);
if (rv != CORE_OK)
d_error("gtp send end marker failed");
}
#endif
/* Setup GTP Node */
SETUP_GTP_NODE(s1u_tunnel, enb);
@@ -394,17 +441,22 @@ void sgw_s11_handle_create_bearer_response(gtp_xact_t *s11_xact,
sess = bearer->sess;
d_assert(sess, return, "Null param");
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
/* Set EBI */
bearer->ebi = req->bearer_contexts.eps_bearer_id.u8;
/* Data Plane(DL) : eNB-S1U */
enb_s1u_teid = req->bearer_contexts.s1_u_enodeb_f_teid.data;
s1u_tunnel->remote_teid = ntohl(enb_s1u_teid->teid);
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
d_trace(5, " ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]\n",
s1u_tunnel->remote_teid, s1u_tunnel->local_teid);
d_trace(5, " SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]\n",
s5u_tunnel->local_teid, s5u_tunnel->remote_teid);
enb = gtp_find_node(&sgw_self()->enb_s1u_list, enb_s1u_teid);
if (!enb)
{
@@ -694,13 +746,20 @@ void sgw_s11_handle_lo_dldata_notification(sgw_bearer_t *bearer)
d_assert(rv == CORE_OK, return, "xact_commit error");
}
void sgw_s11_handle_downlink_data_notification_ack(sgw_ue_t *sgw_ue,
void sgw_s11_handle_downlink_data_notification_ack(
gtp_xact_t *s11_xact, sgw_ue_t *sgw_ue,
gtp_downlink_data_notification_acknowledge_t *ack)
{
status_t rv;
d_assert(sgw_ue, return, "Null param");
d_assert(s11_xact, return, "Null param");
d_trace(3, "[SGW] Downlink Data Notification Acknowledge\n");
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
rv = gtp_xact_commit(s11_xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
}
void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
@@ -771,7 +830,8 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
enb = gtp_find_node(&sgw_self()->enb_s1u_list, req_teid);
if (!enb)
{
enb = gtp_add_node_with_teid(&sgw_self()->enb_s1u_list, req_teid,
enb = gtp_add_node_with_teid(
&sgw_self()->enb_s1u_list, req_teid,
sgw_self()->gtpu_port,
context_self()->parameter.no_ipv4,
context_self()->parameter.no_ipv6,
@@ -793,6 +853,9 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
rsp_bearers[i]->s4_u_sgsn_f_teid.presence = 1;
rsp_bearers[i]->s4_u_sgsn_f_teid.data = &rsp_dl_teid[i];
rsp_bearers[i]->s4_u_sgsn_f_teid.len = len;
d_trace(5, " SGW_DL_TEID[%d] ENB_DL_TEID[%d]\n",
tunnel->local_teid, tunnel->remote_teid);
}
if (req_bearers[i]->s12_rnc_f_teid.presence)
@@ -831,6 +894,8 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
rsp_bearers[i]->s2b_u_epdg_f_teid_5.presence = 1;
rsp_bearers[i]->s2b_u_epdg_f_teid_5.data = &rsp_ul_teid[i];
rsp_bearers[i]->s2b_u_epdg_f_teid_5.len = len;
d_trace(5, " SGW_UL_TEID[%d] ENB_UL_TEID[%d]\n",
tunnel->local_teid, tunnel->remote_teid);
}
if (req_bearers[i]->s1_u_enodeb_f_teid.presence ||

View File

@@ -27,7 +27,8 @@ CORE_DECLARE(void) sgw_s11_handle_release_access_bearers_request(
gtp_release_access_bearers_request_t *req);
CORE_DECLARE(void) sgw_s11_handle_lo_dldata_notification(sgw_bearer_t *bearer);
CORE_DECLARE(void) sgw_s11_handle_downlink_data_notification_ack(
sgw_ue_t *sgw_ue, gtp_downlink_data_notification_acknowledge_t *ack);
gtp_xact_t *s11_xact, sgw_ue_t *sgw_ue,
gtp_downlink_data_notification_acknowledge_t *ack);
CORE_DECLARE(void) sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
gtp_xact_t *s11_xact, sgw_ue_t *sgw_ue,

View File

@@ -81,15 +81,20 @@ void sgw_s5c_handle_create_session_response(gtp_xact_t *s5c_xact,
rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.
presence = 0;
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
/* Receive Data Plane(UL) : PGW-S5U */
pgw_s5u_teid = rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data;
d_assert(pgw_s5u_teid, return, "Null param");
s5u_tunnel->remote_teid = ntohl(pgw_s5u_teid->teid);
d_trace(5, " MME_S11_TEID[%d] SGW_S11_TEID[%d]\n",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
d_trace(5, " SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]\n",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
d_trace(5, " ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]\n",
s1u_tunnel->remote_teid, s1u_tunnel->local_teid);
d_trace(5, " SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]\n",
s5u_tunnel->local_teid, s5u_tunnel->remote_teid);
pgw = gtp_find_node(&sgw_self()->pgw_s5u_list, pgw_s5u_teid);
if (!pgw)
{
@@ -418,7 +423,5 @@ void sgw_s5c_handle_delete_bearer_request(gtp_xact_t *s5c_xact,
rv = gtp_xact_commit(s11_xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
d_trace(3, "[SGW] Delete Bearer Request : SGW <-- PGW\n");
}

View File

@@ -119,7 +119,7 @@ void sgw_state_operational(fsm_t *s, event_t *e)
&message.release_access_bearers_request);
break;
case GTP_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE_TYPE:
sgw_s11_handle_downlink_data_notification_ack(sgw_ue,
sgw_s11_handle_downlink_data_notification_ack(xact, sgw_ue,
&message.downlink_data_notification_acknowledge);
break;
case GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST_TYPE:

View File

@@ -1,7 +1,5 @@
### For reference, see `nextepc.conf`
db_uri: mongodb://localhost/nextepc
logger:
file: @LOCALSTATE_DIR@/log/nextepc/mme.log
trace:
@@ -31,6 +29,8 @@ mme:
security:
integrity_order : [ EIA1, EIA2, EIA0 ]
ciphering_order : [ EEA0, EEA1, EEA2 ]
network_name:
full: NextEPC
sgw:
gtpc:
@@ -39,5 +39,5 @@ sgw:
pgw:
gtpc:
addr:
- 127.0.0.1
- 127.0.0.3
- ::1

View File

@@ -45,10 +45,15 @@ mme:
# s1ap:
# addr: 0.0.0.0
#
# o S1AP Server(127.0.0.3:36412, [fe80::3%@LO_DEV@]:36412)
# o S1AP Server(127.0.0.1:36412, [::1]:36412)
# s1ap:
# - addr: 127.0.0.3
# - addr: fe80::3%@LO_DEV@
# - addr: 127.0.0.1
# - addr: ::1
# o S1AP Server(different port)
# s1ap:
# - addr: 127.0.0.1
# port: 36413
#
# o S1AP Server(address avaiable in `eth0` interface)
# s1ap:
@@ -138,6 +143,16 @@ mme:
integrity_order : [ EIA1, EIA2, EIA0 ]
ciphering_order : [ EEA0, EEA1, EEA2 ]
#
# <Network Name>
# network_name:
# full: NextEPC
# short: Next
#
network_name:
full: NextEPC
hss:
freeDiameter: hss.conf
@@ -165,7 +180,7 @@ sgw:
# - fe80::2%@LO_DEV@
# - addr
# - 127.0.0.12
# - fec0::12%@LO_DEV@
# - fe80::12%@LO_DEV@
# - name: sgw3.nextepc.org
#
# ------------------------ SGW --------------------------
@@ -201,49 +216,49 @@ pgw:
# o Only first node is attempted. Others are ignored.
# o if HSS provide PGW addresss(per-UE), DB overwrites YAML-configuration.
#
# o Two PGW are defined. 127.0.0.1:2123 is attempted. [::1]:2123 is ignored.
# o Two PGW are defined. 127.0.0.3:2123 is attempted. [fe80::3%@LO_DEV@]:2123 is ignored.
# gtpc:
# - addr: 127.0.0.1
# - addr: ::1
# - addr: 127.0.0.3
# - addr: fe80::3%@LO_DEV@
#
# o One PGW is defined. if prefer_ipv4 is not true, [::1] is selected.
# o One PGW is defined. if prefer_ipv4 is not true, [fe80::3%@LO_DEV@] is selected.
# gtpc:
# - addr:
# - 127.0.0.1
# - ::1
# - 127.0.0.3
# - fe80::3%@LO_DEV@
#
# ------------------------ PGW --------------------------
#
# o GTP-C Server(127.0.0.1:2123, [::1]:2123)
# o GTP-C Server(127.0.0.3:2123, [fe80::3%@LO_DEV@]:2123)
# gtpc:
# addr:
# - 127.0.0.1
# - ::1
# - 127.0.0.3
# - fe80::3%@LO_DEV@
#
# o On PGW, Same configuration(127.0.0.1:2123, [::1]:2123) as below.
# o On PGW, Same configuration(127.0.0.3:2123, [fe80::3%@LO_DEV@]:2123) as below.
# gtpc:
# - addr: 127.0.0.1
# - addr: ::1
# - addr: 127.0.0.3
# - addr: fe80::3%@LO_DEV@
#
gtpc:
addr:
- 127.0.0.1
- 127.0.0.3
- ::1
#
# <GTP-U Server>>
#
# o GTP-U Server(127.0.0.1:2152, [::1]:2152)
# o GTP-U Server(127.0.0.3:2152, [::1]:2152)
# gtpu:
# - addr: 127.0.0.1
# - addr: 127.0.0.3
# - addr: ::1
#
# o Same configuration(127.0.0.1:2152, [::1]:2152) as below.
# o Same configuration(127.0.0.3:2152, [::1]:2152) as below.
# gtpu:
# name: localhost
#
gtpu:
- addr: 127.0.0.1
- addr: 127.0.0.3
- addr: ::1
#

View File

@@ -1,7 +1,5 @@
### For reference, see `nextepc.conf`
db_uri: mongodb://localhost/nextepc
logger:
file: @LOCALSTATE_DIR@/log/nextepc/pgw.log
trace:
@@ -16,10 +14,10 @@ pgw:
freeDiameter: pgw.conf
gtpc:
addr:
- 127.0.0.1
- 127.0.0.3
- ::1
gtpu:
- addr: 127.0.0.1
- addr: 127.0.0.3
- addr: ::1
ue_pool:
- addr: 45.45.0.1/16

View File

@@ -1,16 +0,0 @@
FROM ubuntu:16.04
# Base dependencies
# freeDiameter core dependencies
# freeDiameter extension dependencies
# Debian package dependencies
RUN apt update && apt -y install \
bison flex wget gcc g++ cmake git \
libsctp-dev libgnutls-dev libidn11-dev \
libxml2-dev libpostgresql-ocaml-dev libmysql-ocaml-dev libgcrypt-dev swig python-dev \
fakeroot debhelper
WORKDIR /root
ADD ./build-freediameter.sh /root/
#ENTRYPOINT ["ls"]
ENTRYPOINT ["/root/build-freediameter.sh"]

View File

@@ -1,44 +1,64 @@
Debian Pakcage
Docker running example
===========================================
* Build Image
$ docker-compose build
* Development
$ docker-compose run dev
* Runtime
$ docker-compose \
-f docker-compose.yml -f docker-compose.run.yml run run
* Test
$ docker-compose \
-f docker-compose.yml -f docker-compose.test.yml run test
* Test(ubuntu:artful)
$ TAG=artful docker-compose build
$ TAG=artful docker-compose \
-f docker-compose.yml -f docker-compose.test.yml run test
* Development(fedora:latest)
$ DIST=fedora docker-compose build
$ DIST=fedora docker-compose run dev
* Runtime(debian:jessie)
$ DIST=debian TAG=jessie docker-compose build
$ DIST=debian TAG=jessie docker-compose
-f docker-compose.yml -f docker-compose.run.yml run run
* All Test with All Environment
$ ./check.sh
* Run WebUI
$ docker-compose up -d
For Debian Package Release
===========================================
* Ubuntu Docker Setup
$ docker run -p 4000:3000 --hostname build -ti --name build --privileged --cap-add=SYS_ADMIN -e "container=docker" -v /sys/fs/cgroup:/sys/fs/cgroup -v $PWD:/mnt ubuntu /sbin/init
$ docker exec -it ubuntu /bin/login
* Access Source Repository
$ sudo apt-get install sudo vim dpkg-dev git
$ git clone https://github.com/acetcom/nextepc
$ git checkout new_branch
* Check Pakcage
$ dpkg-buildpackage
$ sudo apt-get install ....
$ dpkg-buildpackage
* Run Docker
$ docker-compose run dev
* Setup Debian Environment
export DEBFULLNAME='Sukchan Lee'
export DEBEMAIL='acetcom@gmail.com'
* Transfer GPG key
$ gpg --export-secret-keys --armor --output private.asc'
$ gpg --export-secret-keys --armor --output private.asc
$ gpg --import private.asc
$ gpg --export > public.asc'
$ gpg --export > public.asc
$ gpg --import public.asc
* Update debian/changelog
$ sudo apt-get install devscripts
$ dch -i
* Test OBS
$ debuild -S
- Upload *.dsc and *.tar.gz to https://build.opensuse.org/package/show/home:acetcom/nextepc
* Upload LaunchPad
$ dch -i
$ debuild -S
$ dput ppa:acetcom/nextepc *.source.changes
* Build pckage
$ dpkg-buildpackage
Docker Tun IPv6
For Mac OS X (SCTP-patch)
===========================================
* sysctl -w net.ipv6.conf.all.disable_ipv6=0
* /Applications/Docker.app/Contents/Resources/moby
Update linuxkit-kernel, vmlinuz64

View File

@@ -1,6 +0,0 @@
#!/bin/sh
mkdir -p /root/build-freediameter/freeDiameter
wget -q -O - http://www.freediameter.net/hg/freeDiameter/archive/2cb8d71a405d.tar.bz2 | tar xj -C build-freediameter/freeDiameter --strip-components=1
cd /root/build-freediameter/freeDiameter
ln -s contrib/debian .
fakeroot dh binary

View File

@@ -0,0 +1,24 @@
ARG dist=ubuntu
ARG tag=latest
ARG username=acetcom
FROM ${username}/${dist}-${tag}-base
MAINTAINER Sukchan Lee <acetcom@gmail.com>
WORKDIR /root
COPY setup.sh /root
ARG USER=acetcom
ARG REPO=nextepc
ARG BRANCH=master
RUN git clone https://github.com/$USER/$REPO
ADD https://api.github.com/repos/$USER/$REPO/git/refs/heads/$BRANCH /root/nextepc-ver.json
RUN cd nextepc && \
git fetch && git checkout -f -B master origin/master && \
autoreconf -f -i && \
./configure \
--prefix=/usr \
--sysconfdir=/etc \
--localstatedir=/var && \
make -j `nproc` install

10
support/docker/build/setup.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
if ! grep "pgwtun" /proc/net/dev > /dev/null; then
ip tuntap add name pgwtun mode tun
fi
ip addr del 45.45.0.1/16 dev pgwtun 2> /dev/null
ip addr add 45.45.0.1/16 dev pgwtun
ip addr del cafe::1/64 dev pgwtun 2> /dev/null
ip addr add cafe::1/64 dev pgwtun
ip link set pgwtun up

View File

@@ -0,0 +1,24 @@
ARG dist=centos
ARG tag=latest
FROM ${dist}:${tag}
MAINTAINER Sukchan Lee <acetcom@gmail.com>
RUN yum -y install \
autoconf \
libtool \
gcc \
flex \
bison \
git \
lksctp-tools-devel \
libidn-devel \
gnutls-devel \
libgcrypt-devel \
openssl-devel \
cyrus-sasl-devel \
libyaml-devel \
iproute
RUN yum -y install epel-release && \
yum -y install mongo-c-driver-devel

View File

@@ -0,0 +1,22 @@
ARG dist=centos
ARG tag=latest
ARG username=acetcom
FROM ${username}/${dist}-${tag}-base
MAINTAINER Sukchan Lee <acetcom@gmail.com>
RUN yum -y install \
cscope \
vim \
sudo \
iputils \
net-tools
COPY setup.sh /root
ARG username=acetcom
RUN useradd -m --uid=1000 ${username} && \
echo "${username} ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/${username} && \
chmod 0440 /etc/sudoers.d/${username}
WORKDIR /home/${username}

View File

@@ -0,0 +1,10 @@
#!/bin/sh
if ! grep "pgwtun" /proc/net/dev > /dev/null; then
ip tuntap add name pgwtun mode tun
fi
ip addr del 45.45.0.1/16 dev pgwtun 2> /dev/null
ip addr add 45.45.0.1/16 dev pgwtun
ip addr del cafe::1/64 dev pgwtun 2> /dev/null
ip addr add cafe::1/64 dev pgwtun
ip link set pgwtun up

View File

@@ -0,0 +1 @@
7

18
support/docker/check.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
docker-compose build
docker-compose -f docker-compose.yml -f docker-compose.test.yml run --rm test
TAG=artful docker-compose build
TAG=artful docker-compose -f docker-compose.yml -f docker-compose.test.yml run --rm test
DIST=fedora docker-compose build
DIST=fedora docker-compose -f docker-compose.yml -f docker-compose.test.yml run --rm test
DIST=centos docker-compose build
DIST=centos docker-compose -f docker-compose.yml -f docker-compose.test.yml run --rm test
DIST=debian TAG=jessie docker-compose build
DIST=debian TAG=jessie docker-compose -f docker-compose.yml -f docker-compose.test.yml run --rm test
docker rm $(docker ps -qa --no-trunc --filter "status=exited")

1
support/docker/debian Symbolic link
View File

@@ -0,0 +1 @@
ubuntu/

View File

@@ -0,0 +1,22 @@
version: '3'
services:
run:
network_mode: "host"
image: ${USER}/${DIST-ubuntu}-${TAG-latest}-build
depends_on:
- mongodb
- build
cap_add:
- NET_ADMIN
devices:
- "/dev/net/tun:/dev/net/tun"
sysctls:
- net.ipv6.conf.all.disable_ipv6=0
volumes:
- config:/etc/nextepc
hostname: nextepc-run
command: /bin/bash -c "/root/setup.sh; /usr/bin/nextepc-epcd"
volumes:
config: {}

View File

@@ -0,0 +1,18 @@
version: '3'
services:
test:
image: ${USER}/${DIST-ubuntu}-${TAG-latest}-build
depends_on:
- mongodb
- build
environment:
DB_URI: mongodb://mongodb/nextepc
cap_add:
- NET_ADMIN
devices:
- "/dev/net/tun:/dev/net/tun"
sysctls:
- net.ipv6.conf.all.disable_ipv6=0
hostname: nextepc-test
command: /bin/bash -c "/root/setup.sh; /usr/bin/testepc"

View File

@@ -0,0 +1,73 @@
version: '3'
services:
mongodb:
image: mongo
container_name: nextepc-mongodb
ports:
- "27017:27017"
volumes:
- mongodb:/data/db
webui:
build: webui
image: ${USER}/nextepc-webui
container_name: nextepc-webui
depends_on:
- mongodb
ports:
- "3000:3000"
depends_on:
- mongodb
environment:
DB_URI: mongodb://mongodb/nextepc
base:
build:
context: ./${DIST-ubuntu}/${TAG-latest}/base
args:
dist: ${DIST-ubuntu}
tag: ${TAG-latest}
image: ${USER}/${DIST-ubuntu}-${TAG-latest}-base
command: /bin/bash -c "echo 'base' services"
build:
build:
context: ./build
args:
dist: ${DIST-ubuntu}
tag: ${TAG-latest}
username: ${USER}
image: ${USER}/${DIST-ubuntu}-${TAG-latest}-build
depends_on:
- base
command: /bin/bash -c "echo 'build' services"
dev:
build:
context: ./${DIST-ubuntu}/${TAG-latest}/dev
args:
dist: ${DIST-ubuntu}
tag: ${TAG-latest}
username: ${USER}
image: ${USER}/${DIST-ubuntu}-${TAG-latest}-dev
depends_on:
- mongodb
- base
environment:
DB_URI: mongodb://mongodb/nextepc
cap_add:
- NET_ADMIN
devices:
- "/dev/net/tun:/dev/net/tun"
sysctls:
- net.ipv6.conf.all.disable_ipv6=0
volumes:
- home:/home/${USER}
- ${HOME}:/mnt
hostname: nextepc-dev
command: /bin/bash -c "chmod 666 /dev/net/tun; /root/setup.sh; su acetcom"
volumes:
mongodb: {}
home: {}

View File

@@ -1,7 +0,0 @@
#!/bin/sh
DOCKER_IMAGE="ubuntu:16.04-build-freediameter"
HOST_OUT_PATH="${PWD}/ubuntu-16.04-build-freediameter.out"
docker build -f "Dockerfile.${DOCKER_IMAGE}" -t ${DOCKER_IMAGE} .
docker run -i -t --rm -v ${HOST_OUT_PATH}:/root/build-freediameter ${DOCKER_IMAGE}

View File

@@ -0,0 +1,23 @@
ARG dist=fedora
ARG tag=latest
FROM ${dist}:${tag}
MAINTAINER Sukchan Lee <acetcom@gmail.com>
RUN dnf -y install \
autoconf \
libtool \
gcc \
flex \
bison \
git \
lksctp-tools-devel \
libidn-devel \
gnutls-devel \
libgcrypt-devel \
mongo-c-driver-devel \
openssl-devel \
cyrus-sasl-devel \
snappy-devel \
libyaml-devel \
iproute

View File

@@ -0,0 +1,22 @@
ARG dist=fedora
ARG tag=latest
ARG username=acetcom
FROM ${username}/${dist}-${tag}-base
MAINTAINER Sukchan Lee <acetcom@gmail.com>
RUN dnf -y install \
cscope \
vim \
sudo \
iputils \
net-tools
COPY setup.sh /root
ARG username=acetcom
RUN useradd -m --uid=1000 ${username} && \
echo "${username} ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/${username} && \
chmod 0440 /etc/sudoers.d/${username}
WORKDIR /home/${username}

View File

@@ -0,0 +1,10 @@
#!/bin/sh
if ! grep "pgwtun" /proc/net/dev > /dev/null; then
ip tuntap add name pgwtun mode tun
fi
ip addr del 45.45.0.1/16 dev pgwtun 2> /dev/null
ip addr add 45.45.0.1/16 dev pgwtun
ip addr del cafe::1/64 dev pgwtun 2> /dev/null
ip addr add cafe::1/64 dev pgwtun
ip link set pgwtun up

View File

@@ -0,0 +1 @@
27

View File

@@ -0,0 +1,10 @@
ARG tag=latest
FROM ubuntu:${tag}
RUN apt-get update && \
apt-get -y install software-properties-common && \
add-apt-repository ppa:acetcom/nextepc && \
apt-get update && \
apt-get install -y nextepc
WORKDIR /root

Some files were not shown because too many files have changed in this diff Show More