mirror of
https://github.com/open5gs/open5gs.git
synced 2025-11-06 06:53:22 +00:00
Compare commits
137 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fad2f0e5c | ||
|
|
e69cea9b5b | ||
|
|
6f9e45a332 | ||
|
|
9357381839 | ||
|
|
84e7f50b3f | ||
|
|
2bc92c5ac8 | ||
|
|
2429a4e363 | ||
|
|
dab0f3ef3a | ||
|
|
144548f4c0 | ||
|
|
1f44efbc3d | ||
|
|
02712a38e6 | ||
|
|
888cbfbdb8 | ||
|
|
cdf7fb94bf | ||
|
|
e4989c7aa3 | ||
|
|
5365893c34 | ||
|
|
3c65414135 | ||
|
|
80bcfcf646 | ||
|
|
7e460fbcb4 | ||
|
|
62fe796d41 | ||
|
|
0104543f7d | ||
|
|
39c30cb908 | ||
|
|
c09b272e53 | ||
|
|
92d8bde84a | ||
|
|
e2bb5706fa | ||
|
|
d74afc5bc7 | ||
|
|
c8a65b6b18 | ||
|
|
f5582c97b5 | ||
|
|
b8cc130bf5 | ||
|
|
12d65e92d1 | ||
|
|
2904284405 | ||
|
|
f1b0cd5748 | ||
|
|
91c9586561 | ||
|
|
05cfcf4cc3 | ||
|
|
c827701824 | ||
|
|
5fcc7e2ee6 | ||
|
|
bd1dff2dc5 | ||
|
|
f1ad0b11ae | ||
|
|
9a86d4cb7c | ||
|
|
38cccb8a85 | ||
|
|
2d72eaa24d | ||
|
|
f915820f3a | ||
|
|
1009ac5e47 | ||
|
|
536138457e | ||
|
|
730053cef4 | ||
|
|
4a01623d6e | ||
|
|
0cf0e73bf9 | ||
|
|
87e7992450 | ||
|
|
75aaf632b8 | ||
|
|
5c3c99acda | ||
|
|
081170a86e | ||
|
|
c9b4a20223 | ||
|
|
926e73e87d | ||
|
|
61f796d341 | ||
|
|
03715c84be | ||
|
|
72d28286ea | ||
|
|
c2d68cf4b6 | ||
|
|
e99f6c7789 | ||
|
|
340b3cb69c | ||
|
|
5d8231e6c2 | ||
|
|
1e5313c230 | ||
|
|
d488bc3ed7 | ||
|
|
0de9185545 | ||
|
|
9563e49f48 | ||
|
|
881196cde2 | ||
|
|
c096cce571 | ||
|
|
3c33206dee | ||
|
|
382c52a481 | ||
|
|
f904b63053 | ||
|
|
7769ded65a | ||
|
|
0170166b6b | ||
|
|
935e81f9c9 | ||
|
|
9fbcb45171 | ||
|
|
c9596d82f7 | ||
|
|
598b711c01 | ||
|
|
f9096d55f5 | ||
|
|
0e87056e2e | ||
|
|
ad10c84ffe | ||
|
|
7b99cc7d7c | ||
|
|
75cc9bbb47 | ||
|
|
3a57990cbc | ||
|
|
14ef938fb9 | ||
|
|
5c1a3d54e3 | ||
|
|
2defa5c868 | ||
|
|
4371084af4 | ||
|
|
c0d4f25717 | ||
|
|
aacaa83eea | ||
|
|
de04e1de45 | ||
|
|
95551de5f9 | ||
|
|
bb4339de2a | ||
|
|
831b3e8985 | ||
|
|
f37b3cbfd3 | ||
|
|
23998862f2 | ||
|
|
e72d79a328 | ||
|
|
66d16ae1bb | ||
|
|
00178ff65e | ||
|
|
582c771605 | ||
|
|
52a1e05f41 | ||
|
|
c293bef05a | ||
|
|
ebddb2ad9f | ||
|
|
7c2dd5e462 | ||
|
|
f61233e627 | ||
|
|
b97597ae7c | ||
|
|
57f3baa273 | ||
|
|
d944bca038 | ||
|
|
857a250e4f | ||
|
|
34986be707 | ||
|
|
cb7132a2fa | ||
|
|
5397cfd2d8 | ||
|
|
0cd0221b29 | ||
|
|
8bd186adad | ||
|
|
4e5d156a6a | ||
|
|
c9e44579d8 | ||
|
|
4648dc05d5 | ||
|
|
ca79c05fe6 | ||
|
|
b040214364 | ||
|
|
c3afd65ff3 | ||
|
|
f4baa62209 | ||
|
|
03cf945f95 | ||
|
|
01d7f157ff | ||
|
|
e49e1d2331 | ||
|
|
67393d0160 | ||
|
|
7ca9ead4b9 | ||
|
|
3f7c3d3041 | ||
|
|
cf6df20ad7 | ||
|
|
b77c9b8ff6 | ||
|
|
795ecc8cf8 | ||
|
|
b704e94efa | ||
|
|
ae6e747e52 | ||
|
|
60cfbed747 | ||
|
|
597fcfbad9 | ||
|
|
762431cb6f | ||
|
|
21a130bc16 | ||
|
|
5774aeb62d | ||
|
|
7b2355a40f | ||
|
|
28237ea6af | ||
|
|
09969e859d | ||
|
|
9451928786 |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -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
408
README.md
@@ -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 → 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 → 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
|
||||
```
|
||||
|
||||
28
configure.ac
28
configure.ac
@@ -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
84
debian/changelog
vendored
@@ -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
4
debian/control
vendored
@@ -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.
|
||||
|
||||
2
debian/nextepc-pgw.install
vendored
2
debian/nextepc-pgw.install
vendored
@@ -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
|
||||
|
||||
18
debian/nextepc-pgw.postinst
vendored
18
debian/nextepc-pgw.postinst
vendored
@@ -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)
|
||||
|
||||
1
debian/nextepc-pgw.postrm
vendored
1
debian/nextepc-pgw.postrm
vendored
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ const struct testlist {
|
||||
{testaes},
|
||||
{testsha2},
|
||||
{testsock},
|
||||
#if USE_USRSCTP != 1
|
||||
#ifndef DARWIN
|
||||
{testsctp},
|
||||
#endif
|
||||
{testtime},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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 &
|
||||
|
||||
196
src/mme/emm_sm.c
196
src/mme/emm_sm.c
@@ -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]",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
75
src/mme/mme_path.c
Normal 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
22
src/mme/mme_path.h
Normal 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__ */
|
||||
@@ -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(>p_message, 0, sizeof(gtp_message_t));
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
137
src/mme/mme_sm.c
137
src/mme/mme_sm.c
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = >p_message.create_session_response;
|
||||
memset(>p_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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
#
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
24
support/docker/build/Dockerfile
Normal file
24
support/docker/build/Dockerfile
Normal 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
10
support/docker/build/setup.sh
Executable 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
|
||||
24
support/docker/centos/7/base/Dockerfile
Normal file
24
support/docker/centos/7/base/Dockerfile
Normal 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
|
||||
22
support/docker/centos/7/dev/Dockerfile
Normal file
22
support/docker/centos/7/dev/Dockerfile
Normal 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}
|
||||
10
support/docker/centos/7/dev/setup.sh
Executable file
10
support/docker/centos/7/dev/setup.sh
Executable 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
|
||||
1
support/docker/centos/latest
Symbolic link
1
support/docker/centos/latest
Symbolic link
@@ -0,0 +1 @@
|
||||
7
|
||||
18
support/docker/check.sh
Executable file
18
support/docker/check.sh
Executable 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
1
support/docker/debian
Symbolic link
@@ -0,0 +1 @@
|
||||
ubuntu/
|
||||
22
support/docker/docker-compose.run.yml
Normal file
22
support/docker/docker-compose.run.yml
Normal 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: {}
|
||||
18
support/docker/docker-compose.test.yml
Normal file
18
support/docker/docker-compose.test.yml
Normal 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"
|
||||
73
support/docker/docker-compose.yml
Normal file
73
support/docker/docker-compose.yml
Normal 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: {}
|
||||
@@ -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}
|
||||
23
support/docker/fedora/27/base/Dockerfile
Normal file
23
support/docker/fedora/27/base/Dockerfile
Normal 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
|
||||
22
support/docker/fedora/27/dev/Dockerfile
Normal file
22
support/docker/fedora/27/dev/Dockerfile
Normal 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}
|
||||
10
support/docker/fedora/27/dev/setup.sh
Executable file
10
support/docker/fedora/27/dev/setup.sh
Executable 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
|
||||
1
support/docker/fedora/latest
Symbolic link
1
support/docker/fedora/latest
Symbolic link
@@ -0,0 +1 @@
|
||||
27
|
||||
10
support/docker/package/Dockerfile
Normal file
10
support/docker/package/Dockerfile
Normal 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
Reference in New Issue
Block a user