diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..ae1ebf8
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,5 @@
+[submodule "thirdparty/srsRAN"]
+ path = thirdparty/srsLTE
+ url = https://github.com/FlUxIuS/srsRAN_4G.git
+ branch = modmobmap
+ update = merge
diff --git a/README.md b/README.md
index 58d6b41..ff920bf 100644
--- a/README.md
+++ b/README.md
@@ -1,247 +1,469 @@
-Modmobmap
-==========
+# 📡 Modmobmap
-Modmobmap is a tool aimed to retrieve information of cellular networks.
-As shown in the first [presentation made at BeeRump 2018](https://www.rump.beer/2018/slides/modmobmap.pdf), this tool is able to retrieve information of 2G, 3G, 4G and more cellular network types with minimum requierement: only a phone with ServiceMode.
+
-For the moment, the tool has only been tested and developped for the following devices:
-- Samsung Galaxy S3 via [xgoldmon (Modmobmap's edition)](https://github.com/FlUxIuS/xgoldmon);
-- Samsung Galaxy S4;
-- Samsung Galaxy S5;
-- Samsung Galaxy Note 2 with LTE;
+**Mobile Network Intelligence & Mapping Tool**
-Moreover, as it's compatible for XGold via Modmobmap's forked of *xgoldmon*, this tools should also be able to work with devices supported by *xgoldmon* as well:
-- Samsung Galaxy S4 GT-I9500 (this is the version without LTE!)
-- Samsung Galaxy Nexus GT-I9250 (has to be rooted!)
-- Samsung Galaxy S2 GT-I9100
-- Samsung Galaxy Note 2 GT-N7100
+*Retrieve comprehensive information on 2G/3G/4G/and soon 5G cellular networks with minimal equipment*
-Note that all devices should be rooted. In any other case, you will have to use the DFR technique by hand!
+[](https://www.python.org/)
+[](LICENSE)
+[](https://hub.docker.com/r/penthertz/modmobmap)
+[](https://www.linux.org/)
-Also: Patches, or engines, for other devices are very much welcomed! ;)
+[Features](#-key-features) • [Installation](#-installation) • [Quick Start](#-quick-start) • [Documentation](#-usage-examples) • [Docker](#-docker-deployment)
-Requirements
--------------
+
-Here are the following requirements:
-- Python 2 or 3;
-- Last Android SDK to run ADB: https://developer.android.com/studio/#downloads;
-- A compatible mobile phone;
-- A valid/unvalid SIM card (just in case to provide an IMSI number).
+---
-How to use
-----------
+## 🎯 Overview
-The tool is provided with a quick help that shows you the required argument as follows:
+Modmobmap is a comprehensive cellular network reconnaissance tool designed for security researchers, RF engineers, and penetration testers. Originally presented at [BeeRump 2018](https://www.rump.beer/2018/slides/modmobmap.pdf), it combines multiple techniques to map and analyze mobile networks using both commercial smartphones and Software-Defined Radio (SDR) devices.
+### 🔥 Key Features
+
+
+
+|
+
+**📱 Smartphone-Based Scanning**
+- Samsung Galaxy devices (S3-S20)
+- ServiceMode interface support
+- XGold modem compatibility
+- Real-time cell information
+
+ |
+
+
+**📻 SDR Integration**
+- GNU Radio GSM scanning
+- srsRAN LTE/NB-IoT support
+- Multi-band analysis
+- Passive reconnaissance
+
+ |
+
+
+|
+
+**🌐 Network Coverage**
+- 2G/GSM networks
+- 3G/UMTS systems
+- 4G/LTE cells
+- NB-IoT detection
+
+ |
+
+
+**💾 Data Management**
+- JSON export format
+- Real-time logging
+- Cell database
+- Operator caching
+
+ |
+
+
+
+---
+
+## 🛠️ Supported Hardware
+
+### 📱 Mobile Devices (Rooted Required)
+
+
+✅ Tested & Confirmed
+
+- **Samsung Galaxy S3** (via [xgoldmon](https://github.com/FlUxIuS/xgoldmon))
+- **Samsung Galaxy S4** (GT-I9500)
+- **Samsung Galaxy S5**
+- **Samsung Galaxy Note 2** (LTE version)
+- **Samsung Galaxy S20**
+- **Samsung Galaxy Nexus** (GT-I9250, rooted)
+- **Samsung Galaxy S2** (GT-I9100)
+
+> 💡 **Note:** All devices must be rooted. For non-rooted devices, manual DFR technique required.
+
+
+
+### 📻 SDR Devices (via gr-osmosdr & UHD)
+
+
+🎛️ Compatible SDR Hardware
+
+| Device | Driver | GSM | LTE | Notes |
+|--------|--------|-----|-----|-------|
+| **RTL-SDR** | rtlsdr/soapy | ✅ | ✅ | Budget option |
+| **HackRF One** | hackrf | ✅ | ✅ | Wide frequency range |
+| **BladeRF** | bladerf | ✅ | ✅ | High performance |
+| **USRP (all models)** | uhd | ✅ | ✅ | Professional grade |
+| **ANTSDR E200** | uhd | ✅ | ✅ | Requires proper UHD setup |
+| **AirSpy** | airspy | ✅ | ❌ | GSM only |
+| **SDRplay RSP** | sdrplay | ✅ | ❌ | GSM only |
+| **FunCube Dongle** | fcd | ✅ | ❌ | GSM only |
+
+
+
+---
+
+## 🚀 Installation
+
+### Prerequisites
+
+```bash
+# Core dependencies
+- Python 3.x
+- Android SDK (for ADB)
+- GNU Radio 3.10+ with gr-gsm
+- Valid/invalid SIM card (for IMSI)
+```
+
+### 🐧 Ubuntu 24.04 Quick Install
+
+```bash
+# Clone repository with submodules
+git clone --recursive https://github.com/FlUxIuS/modmobmap.git
+cd modmobmap
+
+# Run automated installation script
+sudo ./install_all-Ubuntu_24.04.sh
+
+# Update submodules (if needed)
+git submodule update --init --recursive --remote
```
-python modmobmap.py -h
-usage: modmobmap.py [-h] [-m MODULE] [-n NETWORKS] [-o] [-s ANDROIDSDK]
- [-a ATMODE] [-f FILE]
-Mobile network mapping tool with cheap equipments
+### 🔧 Manual Installation
-optional arguments:
- -h, --help show this help message and exit
- -m MODULE, --module MODULE
- Module to use (e.g: "servicemode" by default)
- -n NETWORKS, --networks NETWORKS
- Networks in MCCMNC format splitted with commas
- -o, --cached_operator
- Use operator in cache to speed up the passive scan
- -s ANDROIDSDK, --sdk ANDROIDSDK
- Android SDK path
- -a ATMODE, --at ATMODE
- AT access mode. If host put something like
- "/dev/ttyUSBxx. By default it uses ADB."
- -f FILE, --file FILE File to parse. For the moment it could be used in
- combination with AT mode host.
+
+Click to expand manual installation steps
+
+```bash
+# 1. Install Python dependencies
+pip3 install -r requirements.txt
+
+# 2. Install Android SDK
+# Download from: https://developer.android.com/studio/#downloads
+export ANDROID_SDK_ROOT=/path/to/android-sdk
+
+# 3. Install GNU Radio & gr-gsm
+sudo apt-get install gnuradio gr-gsm
+
+# 4. Build srsRAN (for LTE scanning)
+cd thirdparty/srsLTE
+mkdir build && cd build
+cmake ../
+make -j$(nproc)
+sudo make install
```
-Assuming the Android SDK is installed in */opt/Android*, the tool can be quickly started as follows:
+
+
+---
+
+## 🎯 Quick Start
+
+### 🔰 Basic Scanning (Smartphone)
+
+```bash
+# Auto-detect operators and scan all available networks
+sudo python3 modmobmap.py
+# Specify Android SDK location (if not in default path)
+sudo python3 modmobmap.py -s /opt/Android/sdk
+```
+
+**Expected Output:**
```
-$ sudo python modmobmap.py
=> Requesting a list of MCC/MNC. Please wait, it may take a while...
Found 2 operator(s)
-{u'20810': u'F SFR', u'20820': u'F-Bouygues Telecom'}
-[+] Unregistered from current PLMN
-[+] New cell detected [CellID/PCI-DL_freq (4XXX-81)]
+{'20810': 'F SFR', '20820': 'F-Bouygues Telecom'}
+
+[+] New cell detected [CellID/PCI-DL_freq (4XXX-81)]
Network type=2G
PLMN=208-10
ARFCN=81
-[+] New cell detected [CellID/PCI-DL_freq (6XXXXXX-2950)]
- Network type=3G
- PLMN=208-20
- Band=8
- Downlink UARFCN=2950
- Uplink UARFCN=2725
-[+] New cell detected [CellID/PCI-DL_freq (3XX-6300)]
+
+[+] New cell detected [CellID/PCI-DL_freq (3XX-6300)]
Network type=4G
PLMN=208-10
Band=20
Downlink EARFCN=6300
-[+] New cell detected [CellID/PCI-DL_freq (3XX-2825)]
- Network type=4G
- PLMN=208-10
- Band=7
- Downlink EARFCN=2825
-[+] New cell detected [CellID/PCI-DL_freq (3XX-1675)]
- Network type=4G
- PLMN=208-10
- Band=3
- Downlink EARFCN=1675
-[...]
```
-Note: If the Android SDK is installed anywhere else, you can use the *-s* parameter to specify its directory.
-
-Speed-up the passive scan
----------------------------
+### ⚡ Speed Up Scanning (Cached Operators)
-When looking for operators, an AT command is sent to the modem. If you want to speed-up the scanning, you can hardcoded the operators to the following file `cache/operators.json`:
-
-```
+Create `cache/operators.json`:
+```json
{
"20801": "Orange",
- "20810": "F SFR",
+ "20810": "F SFR",
"20815": "Free",
"20820": "F-Bouygues Telecom"
}
```
-Only the MCC/MNC codes are inmportant. Then you can re-launch the tool as follows:
+Run with cache:
+```bash
+sudo python3 modmobmap.py -o
+```
+
+### 🎯 Target Specific Operators
+
+```bash
+# Focus on Orange (MCC/MNC: 20801)
+sudo python3 modmobmap.py -n 20801
+# Multiple operators
+sudo python3 modmobmap.py -n 20801,20810,20815
```
-$ sudo python modmobmap.py -o
-=> Requesting a list of MCC/MNC. Please wait, it may take a while...
-Found 4 operators in cache, you choose to reuse them.
-Found 4 operator(s)
-{u'20810': u'F SFR', u'20820': u'F-Bouygues Telecom', u'20815': u'Free', u'20801': u'Orange'}
-[+] Unregistered from current PLMN
-[+] New cell detected [CellID/PCI-DL_freq (XXXX-10614)]
- Network type=3G
- PLMN=208-10
- Band=1
- Downlink UARFCN=10614
- Uplink UARFCN=9664
-[...]
-[+] New cell detected [CellID/PCI-DL_freq (XXX-3501)]
- Network type=4G
- PLMN=208-20
- Band=8
- Downlink EARFCN=3501
-[...]
-[+] Unregistered from current PLMN
-=> Changing MCC/MNC for: 20815
-[+] New cell detected [CellID/PCI-DL_freq (XXX-2825)]
- Network type=4G
- PLMN=208-15
- Band=7
- Downlink EARFCN=2825
-[...]
-=> Changing MCC/MNC for: 20801
-[+] New cell detected [CellID/PCI-DL_freq (XXXXX-3011)]
- Network type=3G
- PLMN=208-1
- Band=8
- Downlink UARFCN=3011
- Uplink UARFCN=2786
-[...]
+
+> 📚 **MCC/MNC Lookup:** [Wikipedia Mobile Country Codes](https://en.wikipedia.org/wiki/Mobile_country_code)
+
+---
+
+## 📖 Usage Examples
+
+### 🔵 Method 1: ServiceMode (Samsung Devices)
+
+The default and most straightforward method:
+
+```bash
+sudo python3 modmobmap.py -m servicemode
```
-Note we have been able to detect other cells the AT command *AT+COPS* did not returned.
+### 🟢 Method 2: XGoldmon (XGold Modems)
+
+For devices with XGold chipsets (S3, S4, Nexus):
-A complet list of MCC and MNC codes could be retrieved anywhere on internet and in Wikipedia: https://en.wikipedia.org/wiki/Mobile_country_code
+**Terminal 1 - Start xgoldmon:**
+```bash
+cd /path/to/xgoldmon
+sudo ./xgoldmon -t s3 -m /dev/ttyACM1
+# Creates celllog.fifo
+```
+
+**Terminal 2 - Run Modmobmap:**
+```bash
+sudo python3 modmobmap.py \
+ -f /path/to/xgoldmon/celllog.fifo \
+ -m xgoldmod \
+ -a /dev/ttyACM0 \
+ -o
+```
-Focusing some operators
-------------------------
+### 🟡 Method 3: GSM Scanning (SDR - gr-gsm)
-It is possible to tell *Modmobmap* to focus only on specific operators with the *-m* argument:
+Scan GSM bands with Software-Defined Radio:
+```bash
+# RTL-SDR scanning GSM-R and GSM900
+python3 modmobmap.py -m grgsm -b GSM-R,GSM900 -g rtlsdr
+
+# BladeRF scanning multiple bands
+python3 modmobmap.py -m grgsm -b GSM850,GSM900,DCS1800 -g bladerf
+
+# HackRF with custom gain
+python3 modmobmap.py -m grgsm -b GSM900 -g "driver=hackrf,gain=40"
```
-$ sudo python modmobmap.py -n 20801
-=> Manual MCC/MNC processing...
-Found 1 operator(s)
-{'20801': '20801'}
-[...]
-=> Changing MCC/MNC for: 20801
-[+] New cell detected [CellID/PCI-DL_freq (XXX-1675)]
- Network type=4G
- PLMN=208-01
- Band=3
- Downlink EARFCN=1675
-[+] New cell detected [CellID/PCI-DL_freq (XXXXX-3011)]
- Network type=3G
- PLMN=208-1
- Band=8
- Downlink UARFCN=3011
- Uplink UARFCN=2786
-=> Changing network type for 3G only
-[+] New cell detected [CellID/PCI-DL_freq (XXXXX-2950)]
- Network type=3G
- PLMN=208-1
- Band=8
- Downlink UARFCN=2950
- Uplink UARFCN=2725
+
+**Available GSM Bands:**
+- `GSM850` (824-849 MHz)
+- `GSM-R` (876-880 MHz, Railway)
+- `GSM900` (890-915 MHz)
+- `DCS1800` (1710-1785 MHz)
+- `PCS1900` (1850-1910 MHz)
+
+### 🔴 Method 4: LTE Scanning (SDR - srsRAN)
+
+Scan LTE cells using srsRAN:
+
+```bash
+# USRP scanning LTE Band 28
+python3 modmobmap.py -m srslte_pss -b 28 -g 'driver=usrp'
+
+# BladeRF scanning Band 7
+python3 modmobmap.py -m srslte_pss -b 7 -g 'driver=bladerf'
+
+# RTL-SDR via Soapy (specify device ID!)
+python3 modmobmap.py -m srslte_pss -b 20 -g 'soapy:id=1'
+
+# Multiple bands
+python3 modmobmap.py -m srslte_pss -b 3,7,20,28 -g 'driver=usrp'
```
-Using Modmobmap with xgoldmon
-------------------------------
+### 🟣 Method 5: NB-IoT Scanning
-With XGold modems, the use of xgoldmon will be required. But for now, only the fork for *Modmobmap* works to retrieve exact information of cells via the DIAG interface, and could be downloaded at: https://github.com/FlUxIuS/xgoldmon
+Detect Narrowband IoT cells:
-Then after compiling, the tool *xgoldmon* could be started using the *-m* parameter like this:
+```bash
+sudo python3 modmobmap.py -m srslte_npss -b 20 -g 'soapy:id=1'
+```
+---
+
+## 🔍 Finding Your SDR Device
+
+### List Soapy Devices
+```bash
+SoapySDRUtil --find
```
-sudo ./xgoldmon -t s3 -m /dev/ttyACM1
+
+**Example Output:**
+```
+Found device 0
+ driver = rtlsdr
+ label = Generic RTL2832U OEM :: 00000001
+ serial = 00000001
+
+Found device 1
+ driver = bladerf
+ label = BladeRF #0 [bd7fffbf..d5958b06]
+ serial = bd7fffbf8efb4de4ba08d94bd5958b06
+```
+
+### List UHD Devices
+```bash
+uhd_find_devices
```
-This will create a FIFO file that will be requested by Modmobmap later:
+---
+## 💾 Data Export
+
+Results are automatically saved when you stop the scan (`Ctrl+C`):
+
+```bash
+[+] Cells save as cells_1595446203.json
```
-$ ls
-celllog.fifo Makefile screenshot-mtsms-while-in-a-call.png xgoldmon
+
+### JSON Output Format
+
+```json
+{
+ "3XX-6300": {
+ "PLMN": "208-10",
+ "band": 20,
+ "bandwidth": "10MHz",
+ "eARFCN": 6300,
+ "PCI": "3XX",
+ "TAC": "XXXX",
+ "type": "4G"
+ }
+}
```
-Then we can start running *Modmobmap* as follows precising the AT serial interface (*/dev/ttyACM0*) and the fifo file created by *xgoldmon* (* 🔐 **Security Note:** `--privileged` flag required for USB/hardware access
+
+---
+
+## 📊 Command Reference
+
+```bash
+python3 modmobmap.py [OPTIONS]
+
+Required Options:
+ -m, --module MODULE Scanning module: servicemode|xgoldmod|grgsm|srslte_pss|srslte_npss
+
+Optional Parameters:
+ -n, --networks NETWORKS Target MCC/MNC codes (comma-separated)
+ -o, --cached_operator Use cached operators for faster scanning
+ -s, --sdk PATH Android SDK path (default: auto-detect)
+ -a, --at DEVICE AT serial device (e.g., /dev/ttyUSB0)
+ -f, --file FILE FIFO file for xgoldmon integration
+ -b, --bands BANDS Frequency bands to scan (SDR modes)
+ -g, --args ARGS SDR device arguments (driver, gain, etc.)
+
+Examples:
+ # Basic smartphone scan
+ sudo python3 modmobmap.py
+
+ # GSM scan with RTL-SDR
+ python3 modmobmap.py -m grgsm -b GSM900 -g rtlsdr
+
+ # LTE scan targeting Band 7
+ python3 modmobmap.py -m srslte_pss -b 7 -g 'driver=usrp'
+
+ # Cached operators, specific network
+ sudo python3 modmobmap.py -n 20810 -o
```
-$ sudo python3 modmobmap.py -f //celllog.fifo -m xgoldmod -a /dev/ttyACM0 -o
-=> Requesting a list of MCC/MNC. Please wait, it may take a while...
-Found 4 operators in cache, you choose to reuse them.
-Found 4 operator(s)
-{'20801': 'Orange', '20810': 'F SFR', '20815': 'Free', '20820': 'F-Bouygues Telecom'}
-[+] New cell detected [CellID/PCI-DL_freq (0x7XXXX-65535)]
- Network type=3G
- PLMN=208-1
- Downlink UARFCN=65535
- Uplink UARFCN=2850
-[+] Unregistered from current PLMN
-[+] New cell detected [CellID/PCI-DL_freq (0x7XXXX-3011)]
- Network type=3G
- PLMN=208-1
- Downlink UARFCN=3011
- Uplink UARFCN=2786
-[...]
-[+] Unregistered from current PLMN
-=> Changing MCC/MNC for: 20810
-[+] New cell detected [CellID/PCI-DL_freq (0x3XXXXX-3075)]
- Network type=3G
- PLMN=208-10
- Downlink UARFCN=3075
- Uplink UARFCN=2850
-[...]
- ```
-Note that retrieving results from AT+COPS command could take a lot of time and sometime would need to restart the tool. If the tool is blocked on the operator retrieving step, please use cached or targeted operators features instead.
+---
-Saving results
----------------
+## 🤝 Contributing
-The process could be stopped any time when killing the process with a keyboard interrupt signal. Then results will be automatically save in a JSON file as follows:
+We welcome contributions! Here's how you can help:
+
+- 🐛 **Bug Reports:** Open an issue with details
+- 🔧 **Device Support:** Add parsers for new phones
+- 📡 **SDR Engines:** Integrate new hardware/software
+- 📚 **Documentation:** Improve guides and examples
+
+---
+
+## 📞 Support & Community
+
+- 🐦 **Twitter:** [@Penthertz](https://twitter.com/penthertz)
+- 🌐 **Website:** [penthertz.com](https://www.penthertz.com)
+
+---
+
+## 📜 License
```
-[...]
-^C[+] Cells save as cells_1528738901.json
+----------------------------------------------------------------------------
+"THE BEER-WARE LICENSE" (Revision 42):
+ wrote this file. As long as you retain
+this notice you can do whatever you want with this stuff. If we meet some
+day, and you think this stuff is worth it, you can buy me a beer in return.
+ FlUxIuS ;)
+----------------------------------------------------------------------------
```
+
+---
+
+## 🙏 Acknowledgments
+
+- Original presentation: [BeeRump 2018](https://www.rump.beer/2018/slides/modmobmap.pdf)
+- [gr-gsm](https://github.com/ptrkrysik/gr-gsm) by Piotr Krysik
+- [srsRAN](https://github.com/srsran/srsRAN) by Software Radio Systems
+- [xgoldmon](https://github.com/2b-as/xgoldmon) by 2b-as
+
+---
+
+
+
+**Made with ☕ & 📡 by the Penthertz Team**
+
+⭐ Star us on GitHub if this project helped you!
+
+
diff --git a/__init__.py b/__init__.py
index e69de29..fe0868c 100644
--- a/__init__.py
+++ b/__init__.py
@@ -0,0 +1,6 @@
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# )penthertz.com> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
+# ----------------------------------------------------------------------------
diff --git a/cache/operators.json b/cache/operators.json
index 94f8921..9fb70c2 100644
--- a/cache/operators.json
+++ b/cache/operators.json
@@ -3,4 +3,4 @@
"20810": "F SFR",
"20815": "Free",
"20820": "F-Bouygues Telecom"
-}
\ No newline at end of file
+}
diff --git a/core/__init__.py b/core/__init__.py
index d13e961..1232884 100644
--- a/core/__init__.py
+++ b/core/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
-# ----------------------------------------------------------------------------
+# ----------------------------------------------------------------------------
\ No newline at end of file
diff --git a/core/mKB.py b/core/mKB.py
index 71ab956..f60f39c 100644
--- a/core/mKB.py
+++ b/core/mKB.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/core/mLog.py b/core/mLog.py
index 96406a8..1a3e728 100755
--- a/core/mLog.py
+++ b/core/mLog.py
@@ -3,7 +3,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
@@ -27,18 +27,19 @@ def wrapped(*args, **kwargs):
if id_ not in kb.data['SM_cells'] and id_ is not None:
kb.data['SM_cells'][id_] = v
if kb.config['verbose'] == True:
- string2print = "[+] New cell detected [CellID/PCI-DL_freq (%s)]" % id_
- string2print += "\n\r Network type=%s" % v['type']
- string2print += "\n\r PLMN=%s" % v['PLMN']
+ string2print = "[+] New cell detected [CellID/PCI-DL_freq ({})]".format(id_)
+ string2print += "\n\r Network type={}".format(v['type'])
+ string2print += "\n\r PLMN={}".format(v['PLMN'])
if 'band' in v:
- string2print += "\n\r Band=%i" % v['band']
+ string2print += "\n\r Band={}".format(v['band'])
if '4G' in v['type']:
- string2print += "\n\r Downlink EARFCN=%i" % v['eARFCN']
+ string2print += "\n\r Downlink EARFCN={}".format(v['eARFCN'])
elif '3G' in v['type']:
- string2print += "\n\r Downlink UARFCN=%i" % v['RX']
- string2print += "\n\r Uplink UARFCN=%i" % v['TX']
+ string2print += "\n\r Downlink UARFCN={}".format(v['RX'])
+ if 'TX' in v:
+ string2print += "\n\r Uplink UARFCN={}".format(v['TX'])
elif '2G' in v['type']:
- string2print += "\n\r ARFCN=%i" % v['arfcn']
+ string2print += "\n\r ARFCN={}".format(v['arfcn'])
print (bcolors.OKGREEN+string2print+bcolors.ENDC)
return result
return wrapped
diff --git a/engines/__init__.py b/engines/__init__.py
index d13e961..8df667a 100644
--- a/engines/__init__.py
+++ b/engines/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/engines/android/__init__.py b/engines/android/__init__.py
index d13e961..8df667a 100644
--- a/engines/android/__init__.py
+++ b/engines/android/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/engines/android/generic/ADBshell.py b/engines/android/generic/ADBshell.py
index e299ac1..53b9893 100644
--- a/engines/android/generic/ADBshell.py
+++ b/engines/android/generic/ADBshell.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
@@ -71,7 +71,7 @@ def _buildcommand(self, command):
adbpath = None
if self.androidsdkpath is not None:
if 'linux' in sys.platform.lower():
- adbpath = self.androidsdkpath + '/platform-tools/adb'
+ adbpath = self.androidsdkpath + '/adb'
if adbpath is None:
raise ADBError('platform')
commandstring = [adbpath, 'shell']
@@ -90,7 +90,7 @@ def getDevfile(self):
process = self.run_adbcmdshell('getprop rild.libargs')
devfile = process.stdout.readline().split(b'/dev/')
if len(devfile) >= 2:
- m = re.match(b'([\d\w]+)', devfile[1])
+ m = re.match(rb'([\d\w]+)', devfile[1])
if m is not None:
devfile = b'/dev/' + devfile[1].replace(b'\r\n', b'')
else:
diff --git a/engines/android/generic/RILd.py b/engines/android/generic/RILd.py
index 31200c7..96c7a25 100644
--- a/engines/android/generic/RILd.py
+++ b/engines/android/generic/RILd.py
@@ -3,7 +3,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/engines/android/generic/__init__.py b/engines/android/generic/__init__.py
index d13e961..8df667a 100644
--- a/engines/android/generic/__init__.py
+++ b/engines/android/generic/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/engines/android/samsung/ServiceMode.py b/engines/android/samsung/ServiceMode.py
index da141bc..ed255a4 100755
--- a/engines/android/samsung/ServiceMode.py
+++ b/engines/android/samsung/ServiceMode.py
@@ -3,7 +3,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
@@ -35,20 +35,20 @@ def parse4Gcell(self, string):
for s in string.split(b'\r\n'):
if b'LTE' in s:
if b'Band' in s:
- band = re.match(b'^.*Band?:?\s?(\d+)', s).group(1)
+ band = re.match(rb'^.*Band?:?\s?(\d+)', s).group(1)
elif b'BAND' in s and b'BW' in s:
- band, bandwidth = re.match(b'^.*BAND:?\s?(\d+)\sBW:?\s?([\d+\w]+)?\s?\_$', s).groups()
+ band, bandwidth = re.match(rb'^.*BAND:?\s?(\d+)\sBW:?\s?([\d+\w]+)?\s?\_$', s).groups()
if b'MCC-MNC' in s:
if b'TAC' in s:
- plmn, tac = re.match(b'^.*MCC-MNC?\s?:?\s?([\d\-]+)\,?\s?TAC:?\s?(\d+)?\s?\_$', s).groups()
+ plmn, tac = re.match(rb'^.*MCC-MNC?\s?:?\s?([\d\-]+)\,?\s?TAC:?\s?(\d+)?\s?\_$', s).groups()
elif b'MeG':
- plmn = re.match(b'^.*MCC-MNC?\s?:?\s?([\d\-\s]+)', s).group(1)
+ plmn = re.match(rb'^.*MCC-MNC?\s?:?\s?([\d\-\s]+)', s).group(1)
if b'Earfcn_dl:' in s:
- earfcn, pci = re.match(b'^.*Earfcn_dl:?\s?(\d+),?\s?PCI:?\s?(\d+)?\s?\_', s).groups()
+ earfcn, pci = re.match(rb'^.*Earfcn_dl:?\s?(\d+),?\s?PCI:?\s?(\d+)?\s?\_', s).groups()
if b'LTE DL BW' in s:
- bandwidth = re.match(b'^.*BW?\s?:?\s?([\d\w]+)', s).group(1)
+ bandwidth = re.match(rb'^.*BW?\s?:?\s?([\d\w]+)', s).group(1)
if tac is None and b'TAC' in s:
- tac = re.match(b'^.*TAC?\s?:?\s?([\d]+)', s).group(1)
+ tac = re.match(rb'^.*TAC?\s?:?\s?([\d]+)', s).group(1)
if None not in [plmn, tac, earfcn, band, bandwidth, pci]:
tac = tac.decode('utf-8')
plmn = plmn.decode('utf-8').replace(' ','')
@@ -65,6 +65,80 @@ def parse4Gcell(self, string):
}
return cell
+
+ @Cellslogger
+ def parse4Gcell_sgs20like(self, string):
+ '''
+ Parse 4G cells information for SGS 20 phone like
+ in(1): string returned by logcat
+ out: dict infos
+ '''
+ plmn = None
+ tac = None
+ earfcn = None
+ band = None
+ bandwidth = None
+ cid = None
+ pci = None
+ cell = {}
+ for s in string.split(b'\n'):
+ if b'Band' in s and b'BW' in s:
+ band, bandwidth = re.match(rb'^.*Band:?\s?(\d+)\sBW:?\s?([\d+\w]+)?\s?\_$', s).groups()
+ bandwidth = bandwidth.replace(b'MHz', b'')
+ if b'Registered' in s:
+ plmn = re.match(rb'^.*PLMN?\s?:?\s?([\d\-\s]+)', s).group(1).replace(b' ', b'')
+ if b'DL & UL Frequency' in s:
+ earfcn = re.match(rb'^.*Frequency:?\s?([\d+\w]+)', s).group(1)
+ if tac is None and b'TAC' in s:
+ tac = re.match(rb'^.*TAC?\s?:?\s?([\d]+)', s).group(1)
+ if b'CellID' in s and b'PCI' in s:
+ cid, pci = re.match(rb'^.*ServingCellID:?\s?([\w\d]+)PCI:?\s?([\w\d]+)?\s?\_$', s).groups()
+ if None not in [plmn, tac, earfcn, band, bandwidth]:
+ tac = tac.decode('utf-8')
+ plmn = plmn.decode('utf-8').replace(' ','')
+ bandwidth = bandwidth.decode('utf-8')
+ cid2 = "%s-%i" % (cid, int(pci))
+ cell[cid2] = { 'PLMN' : plmn,
+ 'band' : int(band),
+ 'bandwidth' : bandwidth,
+ 'eARFCN': int(earfcn),
+ 'TAC' : tac,
+ 'type' : '4G',
+ }
+ return cell
+
+
+ @Cellslogger
+ def parse3Gcell_sgs20like(self, string):
+ '''
+ Parse 3G cells information SGS20 like
+ in(1): string returned by logcat
+ out: dict infos
+ '''
+ plmn = None
+ cid = None
+ rx = None
+ cell = {}
+ for s in string.split(b'\n'):
+ if b'MCC' in s:
+ mcc, mnc = re.match(rb'^.*MCC?\s?:?\s?(\d+)?\s?MNC?\s?:?\s?(\d+)?\s?\_$', s).groups()
+ plmn = mcc+mnc
+ if b'CellId' in s:
+ cid = re.match(rb'^.*CellId?\s?:?\s?([\w\d]+)', s).group(1)
+ if b'uarfcn:' in s:
+ rx = re.match(rb'^.*uarfcn:?\s?(\d+)', s).group(1)
+ if None not in [rx, cid, plmn]:
+ cid = cid.decode('utf-8').replace('_','')
+ plmn = plmn.decode("utf-8")
+ cid2 = "%s-%i" % (cid, int(rx))
+ cell[cid2] = { 'PLMN' : plmn,
+ 'RX' : int(rx),
+ 'band': -1,
+ 'type' : '3G',
+ }
+ return cell
+
+
@Cellslogger
def parse3Gcell_sgs3like(self, string):
'''
@@ -80,15 +154,15 @@ def parse3Gcell_sgs3like(self, string):
cell = {}
for s in string.split(b'\r\n'):
if b'Band' in s:
- band = re.match(b'^.*Band?:?\s?(\d+)', s).group(1)
+ band = re.match(rb'^.*Band?:?\s?(\d+)', s).group(1)
if b'Reg PLMN' in s:
- plmn = re.match(b'^.*Reg PLMN?\s?([\d\-]+)', s).group(1)
+ plmn = re.match(rb'^.*Reg PLMN?\s?([\d\-]+)', s).group(1)
if b'CELL_ID' in s:
- cid = re.match(b'^.*CELL_ID:?\s?(\S+)', s).group(1)
+ cid = re.match(rb'^.*CELL_ID:?\s?(\S+)', s).group(1)
if b'CH DL:' in s:
- tx = re.match(b'^.*CH DL:?\s?(\d+)', s).group(1)
+ tx = re.match(rb'^.*CH DL:?\s?(\d+)', s).group(1)
if b', UL:' in s:
- rx = re.match(b'^.*\,\sUL:?\s?(\d+)', s).group(1)
+ rx = re.match(rb'^.*\,\sUL:?\s?(\d+)', s).group(1)
if None not in [tx, rx, cid, plmn, band]:
cid = cid.decode('utf-8').replace('_','')
plmn = plmn.decode("utf-8").replace(' ', '')
@@ -116,17 +190,20 @@ def parse3Gcell(self, string):
cell = {}
for s in string.split(b'\r\n'):
if b'Band' in s:
- band = re.match(b'^.*Band?:?\s?(\d+)', s).group(1)
+ band = re.match(rb'^.*Band?:?\s?(\d+)', s).group(1)
if b'PLMN:' in s:
- plmn = re.match(b'^.*PLMN:?\s?([\d\-]+)?\s?\_$', s).group(1)
+ plmn = re.match(rb'^.*PLMN:?\s?([\d\-]+)?\s?\_$', s).group(1)
elif b'MCC-MNC :' in s:
- plmn = re.match(b'^.*MCC-MNC\s:?\s?([\d\-\s]+)?\s?\_$', s).group(1)
+ try:
+ plmn = re.match(rb'^.*MCC-MNC\s:?\s?([\d\-\s]+)?\s?\_$', s).group(1)
+ except:
+ plmn = None
if b'CID:' in s:
- cid = re.match(b'^.*CID:?\s?(\S+)?\s?_$', s).group(1)
+ cid = re.match(rb'^.*CID:?\s?(\S+)?\s?_$', s).group(1)
if b' TX:' in s:
- tx = re.match(b'^.*TX:?\s?(\d+)', s).group(1)
+ tx = re.match(rb'^.*TX:?\s?(\d+)', s).group(1)
if b' RX:' in s:
- rx = re.match(b'^.*RX:?\s?(\d+)', s).group(1)
+ rx = re.match(rb'^.*RX:?\s?(\d+)', s).group(1)
if None not in [tx, rx, cid, plmn, band]:
cid = cid.decode('utf-8')
plmn = plmn.decode("utf-8").replace(' ', '')
@@ -139,6 +216,38 @@ def parse3Gcell(self, string):
}
return cell
+
+ @Cellslogger
+ def parse2Gcell_sgs20like(self, string):
+ '''
+ Parse 2G cells information SGS20 like structs
+ in(1): string returned by logcat
+ out: dict infos
+ '''
+ plmn = None
+ cid = None
+ arfcn = None
+ cell = {}
+ for s in string.split(b'\n'):
+ if b'MCC' in s:
+ mcc, mnc = re.match(rb'^.*MCC?\s?:?\s?(\d+)?\s?MNC?\s?:?\s?(\d+)?\s?\_$', s).groups()
+ plmn = mcc+mnc
+ if b'CellId' in s:
+ cid = re.match(rb'^.*CellId?\s?:?\s?([\w\d]+)', s).group(1)
+ if b'arfcn' in s:
+ arfcn = re.match(rb'^.*arfcn?\s?:?\s?(\d+)', s).group(1)
+ if None not in [arfcn, cid, plmn]:
+ cid = cid.decode('utf-8')
+ plmn = plmn.decode("utf-8").replace(' ', '')
+ cid2 = "%s-%i" % (cid, int(arfcn))
+ cell[cid2] = { 'PLMN' : plmn,
+ 'arfcn' : int(arfcn),
+ 'type' : '2G',
+ 'cid' : cid,
+ }
+ return cell
+
+
@Cellslogger
def parse2Gcell(self, string):
'''
@@ -152,13 +261,13 @@ def parse2Gcell(self, string):
cell = {}
for s in string.split(b'\r\n'):
if b'PLMN:' in s:
- plmn = re.match(b'^.*PLMN:?\s?([\d\-]+)?\s?\_$', s).group(1)
+ plmn = re.match(rb'^.*PLMN:?\s?([\d\-]+)?\s?\_$', s).group(1)
elif b'MCC-MNC :' in s:
- plmn = re.match(b'^.*MCC-MNC\s:?\s?([\d\-\s]+)?\s?\_$', s).group(1)
+ plmn = re.match(rb'^.*MCC-MNC\s:?\s?([\d\-\s]+)?\s?\_$', s).group(1)
if b'CID:' in s:
- cid = re.match(b'^.*CID:?\s?(\S+)?\s?_$', s).group(1)
+ cid = re.match(rb'^.*CID:?\s?(\S+)?\s?_$', s).group(1)
if b' Tra:' in s:
- arfcn = re.match(b'^.*Tra:?\s?(\d+)', s).group(1)
+ arfcn = re.match(rb'^.*Tra:?\s?(\d+)', s).group(1)
if None not in [arfcn, cid, plmn]:
cid = cid.decode('utf-8')
plmn = plmn.decode("utf-8").replace(' ', '')
@@ -190,17 +299,27 @@ def grablogcat(self):
if b'Update!' in line:
if b'LTE RRC:' in capture:
self.parse4Gcell(capture)
+ elif b'LTE-BASIC' in capture:
+ self.parse4Gcell_sgs20like(capture)
elif b'UMTS :' in capture:
self.parse3Gcell_sgs3like(capture)
- if b'GSM' in capture:
- self.parse2Gcell(capture)
+ elif b'Serving Cell Info' in capture:
+ self.parse3Gcell_sgs20like(capture)
+ elif b'GSM' in capture:
+ if b'2G-BASIC' in capture:
+ self.parse2Gcell_sgs20like(capture)
+ else:
+ self.parse2Gcell(capture)
else:
- self.parse3Gcell(capture)
+ if b'LTE' not in capture:
+ self.parse3Gcell(capture)
capture = b''
capture += line
except (KeyboardInterrupt, SystemExit):
stop = True
stdout_reader.stop()
+ #except Exception as e:
+ # print (e)
stdout_reader.stop()
process.stdout.close()
diff --git a/engines/android/samsung/__init__.py b/engines/android/samsung/__init__.py
index d13e961..1232884 100644
--- a/engines/android/samsung/__init__.py
+++ b/engines/android/samsung/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
-# ----------------------------------------------------------------------------
+# ----------------------------------------------------------------------------
\ No newline at end of file
diff --git a/engines/host/__init__.py b/engines/host/__init__.py
index d13e961..8df667a 100644
--- a/engines/host/__init__.py
+++ b/engines/host/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/engines/host/diag/__init__.py b/engines/host/diag/__init__.py
index d13e961..8df667a 100644
--- a/engines/host/diag/__init__.py
+++ b/engines/host/diag/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/engines/host/diag/xgoldmod.py b/engines/host/diag/xgoldmod.py
index 9457af7..030159a 100644
--- a/engines/host/diag/xgoldmod.py
+++ b/engines/host/diag/xgoldmod.py
@@ -3,7 +3,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/engines/host/serial/AT.py b/engines/host/serial/AT.py
index 7158ae2..0a4f211 100644
--- a/engines/host/serial/AT.py
+++ b/engines/host/serial/AT.py
@@ -1,4 +1,12 @@
# -*- coding: utf-8 -*-
+
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# )penthertz.com> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
+# ----------------------------------------------------------------------------
+
from __future__ import print_function
import serial
diff --git a/engines/host/serial/__init__.py b/engines/host/serial/__init__.py
index d13e961..1232884 100644
--- a/engines/host/serial/__init__.py
+++ b/engines/host/serial/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
-# ----------------------------------------------------------------------------
+# ----------------------------------------------------------------------------
\ No newline at end of file
diff --git a/engines/sdr/__init__.py b/engines/sdr/__init__.py
new file mode 100644
index 0000000..fe0868c
--- /dev/null
+++ b/engines/sdr/__init__.py
@@ -0,0 +1,6 @@
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# )penthertz.com> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
+# ----------------------------------------------------------------------------
diff --git a/engines/sdr/grgsm_scanner.py b/engines/sdr/grgsm_scanner.py
new file mode 100644
index 0000000..5fb2f7b
--- /dev/null
+++ b/engines/sdr/grgsm_scanner.py
@@ -0,0 +1,811 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# @file
+# @author (C) 2015 by Piotr Krysik
+# @author (C) 2015 by Roman Khassraf
+# @section LICENSE
+#
+# Gr-gsm is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# Gr-gsm is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with gr-gsm; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+#
+from core.mLog import *
+
+from gnuradio import blocks
+from gnuradio import network
+from gnuradio import gr
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from gnuradio.filter import firdes
+from gnuradio.filter import pfb
+from math import pi
+from optparse import OptionParser
+
+import math
+from gnuradio import gsm
+import numpy
+import os
+import osmosdr
+import pmt
+import time
+import sys
+import gnuradio.gsm.arfcn as arfcn
+import gc
+
+
+class multichannel_receiver(gr.hier_block2):
+ def __init__(self, arfcns=[], center_freq=935e6, osr=4, tseq=1, wide_samp_rate=2e6):
+ gr.hier_block2.__init__(
+ self, "Multi Arfcns GSM Receiver",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
+ gr.io_signaturev(len(arfcns), len(arfcns), list(map(lambda x: gr.sizeof_gr_complex * 1, arfcns))),
+ )
+ self.message_port_register_hier_out("out_c0")
+ self.message_port_register_hier_out("out_cx")
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.arfcns = arfcns
+ self.center_freq = center_freq
+ self.osr = osr
+ self.tseq = tseq
+ self.wide_samp_rate = wide_samp_rate
+ ##################################################
+ # Variables
+ ##################################################
+ self.samp_rate = samp_rate = 1e6
+ self.fcs = fcs = list(map(lambda x: arfcn.arfcn2downlink(x), arfcns))
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.gsm_receiver = gsm.receiver(osr, arfcns, [tseq], False)
+ self.gsm_clock_offset_control = gsm.clock_offset_control(fcs[0], samp_rate, osr)
+ self.pfb_arb_resamplers_xxx = []
+ self.gsm_inputs = []
+ self.blocks_rotators_cc = []
+
+ for i in range(len(self.fcs)):
+ resampler = pfb.arb_resampler_ccf(
+ samp_rate / wide_samp_rate,
+ taps=None,
+ flt_size=32)
+ resampler.declare_sample_delay(0)
+ self.pfb_arb_resamplers_xxx.append(resampler)
+
+ gsm_input = gsm.gsm_input(
+ ppm=0,
+ osr=osr,
+ fc=fcs[i],
+ samp_rate_in=samp_rate,
+ )
+ self.gsm_inputs.append(gsm_input)
+
+ blocks_rotator_cc = blocks.rotator_cc(-2 * pi * (fcs[i] - center_freq) / wide_samp_rate)
+ self.blocks_rotators_cc.append(blocks_rotator_cc)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.msg_connect((self.gsm_clock_offset_control, 'ctrl'), (gsm_input, 'ctrl_in'))
+ self.connect((blocks_rotator_cc, 0), (resampler, 0))
+ self.connect((gsm_input, 0), (self.gsm_receiver, i))
+ self.connect((gsm_input, 0), (self, i))
+ self.connect((self, 0), (blocks_rotator_cc, 0))
+ self.connect((resampler, 0), (gsm_input, 0))
+
+ self.msg_connect((self.gsm_receiver, 'measurements'), (self.gsm_clock_offset_control, 'measurements'))
+ self.msg_connect((self.gsm_receiver, 'C0'), (self, 'out_c0'))
+ self.msg_connect((self.gsm_receiver, 'CX'), (self, 'out_cx'))
+
+
+class sdcch8_decoder_hopping(gr.top_block):
+ def __init__(self, arfcns_list=[], ccch_index=2, hsn=5, maio=0, osr=4, ts=1, tseq=0, reclen=5, ppm=0, args=""):
+ gr.top_block.__init__(self, "Multy arfncs sdcch8 decoder")
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.arfcns_list = arfcns_list
+ self.ccch_index = ccch_index
+ self.hsn = hsn
+ self.maio = maio
+ self.osr = osr
+ self.ts = ts
+ self.tseq = tseq
+
+ ##################################################
+ # Variables
+ ##################################################
+ self.arfcns = arfcns = list(arfcns_list)
+ self.fcs = fcs = list(map(arfcn.arfcn2downlink, arfcns))
+ self.wide_samp_rate = wide_samp_rate = max(1e6, int(math.ceil((max(fcs) - min(fcs)) * 1.1 / 1e6)) * 1e6)
+ self.center_freq = center_freq = ((max(fcs) + min(fcs)) / 2)
+ snippets_main_after_init(self)
+ ##################################################
+ # Blocks
+ ##################################################
+ self.osmosdr_source_0 = osmosdr.source(args="numchan=" + str(1) + " " +
+ str(gsm.device.get_default_args(args)))
+
+ self.osmosdr_source_0.set_sample_rate(wide_samp_rate)
+ self.osmosdr_source_0.set_center_freq(center_freq, 0)
+ self.osmosdr_source_0.set_freq_corr(ppm, 0)
+
+ self.osmosdr_source_0.set_dc_offset_mode(2, 0)
+ self.osmosdr_source_0.set_iq_balance_mode(0, 0)
+ self.osmosdr_source_0.set_gain_mode(True, 0)
+ self.osmosdr_source_0.set_bandwidth(0, 0)
+ self.osmosdr_source_0.set_gain(14, 0)
+ self.osmosdr_source_0.set_if_gain(40, 0)
+ self.osmosdr_source_0.set_bb_gain(32, 0)
+ self.gsm_sdcch8_demapper_0 = gsm.gsm_sdcch8_demapper(
+ timeslot_nr=ts,
+ )
+ self.gsm_multiarfcns_receiver_0 = multichannel_receiver(
+ arfcns=[arfcns[ccch_index]] + arfcns[0:ccch_index] + arfcns[(ccch_index + 1):len(arfcns)],
+ center_freq=center_freq,
+ osr=osr,
+ tseq=tseq,
+ wide_samp_rate=wide_samp_rate,
+ )
+
+ self.gsm_extract_cmc_0 = gsm.extract_cmc()
+ self.gsm_cx_channel_hopper_0 = gsm.cx_channel_hopper(arfcns, maio, hsn)
+ self.gsm_control_channels_decoder_0 = gsm.control_channels_decoder()
+ self.blocks_head_0 = blocks.head(gr.sizeof_gr_complex * 1, int(wide_samp_rate * reclen))
+
+ self.blocks_socket_pdu_0 = network.socket_pdu('UDP_CLIENT', '127.0.0.1', '4729', 10000, False)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.msg_connect((self.gsm_control_channels_decoder_0, 'msgs'), (self.blocks_socket_pdu_0, 'pdus'))
+ self.msg_connect((self.gsm_control_channels_decoder_0, 'msgs'), (self.gsm_extract_cmc_0, 'msgs'))
+ self.msg_connect((self.gsm_cx_channel_hopper_0, 'bursts'), (self.gsm_sdcch8_demapper_0, 'bursts'))
+ self.msg_connect((self.gsm_multiarfcns_receiver_0, 'out_c0'), (self.gsm_cx_channel_hopper_0, 'CX'))
+ self.msg_connect((self.gsm_multiarfcns_receiver_0, 'out_cx'), (self.gsm_cx_channel_hopper_0, 'CX'))
+ self.msg_connect((self.gsm_sdcch8_demapper_0, 'bursts'), (self.gsm_control_channels_decoder_0, 'bursts'))
+ self.connect((self.blocks_head_0, 0), (self.gsm_multiarfcns_receiver_0, 0))
+ self.connect((self.osmosdr_source_0, 0), (self.blocks_head_0, 0))
+
+ def get_arfcns_list(self):
+ return self.arfcns_list
+
+ def set_arfcns_list(self, arfcns_list):
+ self.arfcns_list = arfcns_list
+
+ def get_ccch_index(self):
+ return self.ccch_index
+
+ def set_ccch_index(self, ccch_index):
+ self.ccch_index = ccch_index
+
+ def get_hsn(self):
+ return self.hsn
+
+ def set_hsn(self, hsn):
+ self.hsn = hsn
+
+ def get_maio(self):
+ return self.maio
+
+ def set_maio(self, maio):
+ self.maio = maio
+
+ def get_osr(self):
+ return self.osr
+
+ def set_osr(self, osr):
+ self.osr = osr
+ self.gsm_multiarfcns_receiver_0.set_osr(self.osr)
+
+ def get_ts(self):
+ return self.ts
+
+ def set_ts(self, ts):
+ self.ts = ts
+ self.gsm_sdcch8_demapper_0.set_timeslot_nr(self.ts)
+
+ def get_tseq(self):
+ return self.tseq
+
+ def set_tseq(self, tseq):
+ self.tseq = tseq
+ self.gsm_multiarfcns_receiver_0.set_tseq(self.tseq)
+
+ def get_arfcns(self):
+ return self.arfcns
+
+ def set_arfcns(self, arfcns):
+ self.arfcns = arfcns
+ self.set_fcs(list(map(arfcn.arfcn2downlink, self.arfcns)))
+
+ def get_fcs(self):
+ return self.fcs
+
+ def set_fcs(self, fcs):
+ self.fcs = fcs
+ self.set_center_freq(((max(self.fcs) + min(self.fcs)) / 2))
+ self.set_wide_samp_rate(max(1e6, int(math.ceil((max(self.fcs) - min(self.fcs)) * 1.1 / 1e6)) * 1e6))
+
+ def get_wide_samp_rate(self):
+ return self.wide_samp_rate
+
+ def set_wide_samp_rate(self, wide_samp_rate):
+ self.wide_samp_rate = wide_samp_rate
+ self.blocks_head_0.set_length(int(self.wide_samp_rate * 30))
+ self.gsm_multiarfcns_receiver_0.set_wide_samp_rate(self.wide_samp_rate)
+ self.osmosdr_source_0.set_sample_rate(self.wide_samp_rate)
+
+ def get_center_freq(self):
+ return self.center_freq
+
+ def set_center_freq(self, center_freq):
+ self.center_freq = center_freq
+ self.gsm_multiarfcns_receiver_0.set_center_freq(self.center_freq)
+ self.osmosdr_source_0.set_center_freq(self.center_freq, 0)
+
+
+def snipfcn_check_bandwidth(self):
+ if (self.wide_samp_rate > 20e6): # for hackrf
+ print("Very wide bandwidth for this arfcns: " + str(self.wide_samp_rate / 1e6) + " MHz")
+ self.stop()
+ else:
+ print("Wide bandwidth: " + str(self.wide_samp_rate / 1e6) + " MHz")
+
+
+def snippets_main_after_init(tb):
+ snipfcn_check_bandwidth(tb)
+
+
+# from wideband_receiver import *
+
+class receiver_with_decoder(gr.hier_block2):
+ def __init__(self, OSR=4, chan_num=0, fc=939.4e6, ppm=0, samp_rate=0.2e6):
+ gr.hier_block2.__init__(
+ self, "Receiver With Decoder",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
+ gr.io_signature(0, 0, 0),
+ )
+ self.message_port_register_hier_out("bursts")
+ self.message_port_register_hier_out("msgs")
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.OSR = OSR
+ self.chan_num = chan_num
+ self.fc = fc
+ self.ppm = ppm
+ self.samp_rate = samp_rate
+
+ ##################################################
+ # Variables
+ ##################################################
+ self.samp_rate_out = samp_rate_out = 1625000.0 / 6.0 * OSR
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.gsm_receiver_0 = gsm.receiver(OSR, ([chan_num]), ([]))
+ self.gsm_input_0 = gsm.gsm_input(
+ ppm=ppm,
+ osr=OSR,
+ fc=fc,
+ samp_rate_in=samp_rate,
+ )
+ self.gsm_control_channels_decoder_0 = gsm.control_channels_decoder()
+ self.gsm_clock_offset_control_0 = gsm.clock_offset_control(fc, samp_rate, osr=4)
+ self.gsm_bcch_ccch_demapper_0 = gsm.gsm_bcch_ccch_demapper(0)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.msg_connect(self.gsm_bcch_ccch_demapper_0, 'bursts', self, 'bursts')
+ self.msg_connect(self.gsm_bcch_ccch_demapper_0, 'bursts', self.gsm_control_channels_decoder_0, 'bursts')
+ self.msg_connect(self.gsm_clock_offset_control_0, 'ctrl', self.gsm_input_0, 'ctrl_in')
+ self.msg_connect(self.gsm_control_channels_decoder_0, 'msgs', self, 'msgs')
+ self.msg_connect(self.gsm_receiver_0, 'C0', self.gsm_bcch_ccch_demapper_0, 'bursts')
+ self.msg_connect(self.gsm_receiver_0, 'measurements', self.gsm_clock_offset_control_0, 'measurements')
+ self.connect((self.gsm_input_0, 0), (self.gsm_receiver_0, 0))
+ self.connect((self, 0), (self.gsm_input_0, 0))
+
+ def get_OSR(self):
+ return self.OSR
+
+ def set_OSR(self, OSR):
+ self.OSR = OSR
+ self.set_samp_rate_out(1625000.0 / 6.0 * self.OSR)
+ self.gsm_input_0.set_osr(self.OSR)
+
+ def get_chan_num(self):
+ return self.chan_num
+
+ def set_chan_num(self, chan_num):
+ self.chan_num = chan_num
+
+ def get_fc(self):
+ return self.fc
+
+ def set_fc(self, fc):
+ self.fc = fc
+ self.gsm_input_0.set_fc(self.fc)
+
+ def get_ppm(self):
+ return self.ppm
+
+ def set_ppm(self, ppm):
+ self.ppm = ppm
+ self.gsm_input_0.set_ppm(self.ppm)
+
+ def get_samp_rate(self):
+ return self.samp_rate
+
+ def set_samp_rate(self, samp_rate):
+ self.samp_rate = samp_rate
+ self.gsm_input_0.set_samp_rate_in(self.samp_rate)
+
+ def get_samp_rate_out(self):
+ return self.samp_rate_out
+
+ def set_samp_rate_out(self, samp_rate_out):
+ self.samp_rate_out = samp_rate_out
+
+
+class wideband_receiver(gr.hier_block2):
+ def __init__(self, OSR=4, fc=939.4e6, samp_rate=0.4e6):
+ gr.hier_block2.__init__(
+ self, "Wideband receiver",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
+ gr.io_signature(0, 0, 0),
+ )
+ self.message_port_register_hier_out("bursts")
+ self.message_port_register_hier_out("msgs")
+ self.__init(OSR, fc, samp_rate)
+
+ def __init(self, OSR=4, fc=939.4e6, samp_rate=0.4e6):
+ ##################################################
+ # Parameters
+ ##################################################
+ self.OSR = OSR
+ self.fc = fc
+ self.samp_rate = samp_rate
+ self.channels_num = int(samp_rate / 0.2e6)
+ self.OSR_PFB = 2
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.pfb_channelizer_ccf_0 = pfb.channelizer_ccf(
+ self.channels_num,
+ (),
+ self.OSR_PFB,
+ 100)
+ self.pfb_channelizer_ccf_0.set_channel_map(([]))
+ self.create_receivers()
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self, 0), (self.pfb_channelizer_ccf_0, 0))
+ for chan in range(0, self.channels_num):
+ self.connect((self.pfb_channelizer_ccf_0, chan), (self.receivers_with_decoders[chan], 0))
+ self.msg_connect(self.receivers_with_decoders[chan], 'bursts', self, 'bursts')
+ self.msg_connect(self.receivers_with_decoders[chan], 'msgs', self, 'msgs')
+
+ def create_receivers(self):
+ self.receivers_with_decoders = {}
+ for chan in range(0, self.channels_num):
+ self.receivers_with_decoders[chan] = receiver_with_decoder(fc=self.fc, OSR=self.OSR, chan_num=chan,
+ samp_rate=self.OSR_PFB * 0.2e6)
+
+ def get_OSR(self):
+ return self.OSR
+
+ def set_OSR(self, OSR):
+ self.OSR = OSR
+ self.create_receivers()
+
+ def get_fc(self):
+ return self.fc
+
+ def set_fc(self, fc):
+ self.fc = fc
+ self.create_receivers()
+
+ def get_samp_rate(self):
+ return self.samp_rate
+
+
+class wideband_scanner(gr.top_block):
+ def __init__(self, rec_len=3, sample_rate=2e6, carrier_frequency=939e6, gain=40, ppm=0, args=""):
+ gr.top_block.__init__(self, "Wideband Scanner")
+
+ self.rec_len = rec_len
+ self.sample_rate = sample_rate
+ self.carrier_frequency = carrier_frequency
+ self.ppm = ppm
+
+ # if no file name is given process data from rtl_sdr source
+ print("Args=", args)
+ self.rtlsdr_source = osmosdr.source(args="numchan=" + str(1) + " " +
+ str(gsm.device.get_default_args(args)))
+ # self.rtlsdr_source.set_min_output_buffer(int(sample_rate*rec_len)) #this line causes segfaults on HackRF
+ self.rtlsdr_source.set_sample_rate(sample_rate)
+
+ # capture half of GSM channel lower than channel center (-0.1MHz)
+ # this is needed when even number of channels is captured in order to process full captured bandwidth
+
+ self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
+
+ # correction of central frequency
+ # if the receiver has large frequency offset
+ # the value of this variable should be set close to that offset in ppm
+ self.rtlsdr_source.set_freq_corr(ppm, 0)
+
+ self.rtlsdr_source.set_dc_offset_mode(2, 0)
+ self.rtlsdr_source.set_iq_balance_mode(0, 0)
+ self.rtlsdr_source.set_gain_mode(True, 0)
+ self.rtlsdr_source.set_bandwidth(sample_rate, 0)
+ self.rtlsdr_source.set_gain(gain, 0)
+ self.rtlsdr_source.set_if_gain(40, 0)
+ self.rtlsdr_source.set_bb_gain(32, 0)
+ self.head = blocks.head(gr.sizeof_gr_complex * 1, int(rec_len * sample_rate))
+
+ # shift again by -0.1MHz in order to align channel center in 0Hz
+ self.blocks_rotator_cc = blocks.rotator_cc(-2 * pi * 0.1e6 / sample_rate)
+
+ self.wideband_receiver = wideband_receiver(OSR=4, fc=carrier_frequency, samp_rate=sample_rate)
+ self.extract_immediate_assignment = gsm.extract_immediate_assignment(False, True, True)
+ self.gsm_extract_system_info = gsm.extract_system_info()
+
+ self.connect((self.rtlsdr_source, 0), (self.head, 0))
+ self.connect((self.head, 0), (self.blocks_rotator_cc, 0))
+ self.connect((self.blocks_rotator_cc, 0), (self.wideband_receiver, 0))
+ self.msg_connect(self.wideband_receiver, 'msgs', self.gsm_extract_system_info, 'msgs')
+ self.msg_connect(self.wideband_receiver, 'msgs', self.extract_immediate_assignment, 'msgs')
+
+ def set_carrier_frequency(self, carrier_frequency):
+ self.carrier_frequency = carrier_frequency
+ self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
+
+
+class assignment_info(object):
+ def __init__(self, arfcn, channel, timeslot, tseq, maio, hsn, a5_vers=[]):
+ self.arfcn = arfcn
+ self.assignment_channel = channel
+ self.timeslot = timeslot
+ self.tseq = tseq
+ self.maio = maio
+ self.hsn = hsn
+ self.a5_vers = a5_vers
+
+ def __str__(self):
+ return str(self.assignment_channel) + ", Timeslot: " + str(self.timeslot) + ", Training Sequence: " + str(
+ self.tseq) + ", MAIO: " + str(self.maio) + ", HSN: " + str(self.hsn) + ", A5/1 Version: " + ", ".join(
+ map(str, list(set(self.a5_vers))))
+
+
+class channel_info(object):
+ def __init__(self, arfcn, freq, cid, lac, mcc, mnc, ccch_conf, power, neighbours, cell_arfcns, assignments):
+ self.arfcn = arfcn
+ self.freq = freq
+ self.cid = cid
+ self.lac = lac
+ self.mcc = mcc
+ self.mnc = mnc
+ self.ccch_conf = ccch_conf
+ self.power = power
+ self.neighbours = neighbours
+ self.cell_arfcns = cell_arfcns
+ self.assignments = assignments
+
+ def __lt__(self, other):
+ return self.arfcn < other.arfcn
+
+ def get_verbose_info(self):
+ v = " |---- Configuration: %s\n" % self.get_ccch_conf()
+ v += " |---- Cell ARFCNs: " + ", ".join(map(str, self.cell_arfcns)) + "\n"
+ if len(self.assignments) > 0:
+ v += " |---- DCCHs:\n"
+ for i in range(0, len(self.assignments)):
+ v += " |-------- " + "#" + str(i + 1) + " " + str(self.assignments[i]) + "\n"
+
+ v += " |---- Neighbour Cells: " + ", ".join(map(str, self.neighbours)) + "\n"
+
+ return v
+
+ def get_ccch_conf(self):
+ if self.ccch_conf == 0:
+ return "1 CCCH, not combined"
+ elif self.ccch_conf == 1:
+ return "1 CCCH, combined"
+ elif self.ccch_conf == 2:
+ return "2 CCCH, not combined"
+ elif self.ccch_conf == 4:
+ return "3 CCCH, not combined"
+ elif self.ccch_conf == 6:
+ return "4 CCCH, not combined"
+ else:
+ return "Unknown"
+
+ def getKey(self):
+ return self.arfcn
+
+
+ @Cellslogger
+ def attr2dic(self):
+ cell = {}
+ cid2 = str(self.cid) + '_' + str(self.arfcn)
+ cell[cid2] = {'PLMN' : str(self.mcc)+str(self.mnc),
+ 'arfcn' : int(self.arfcn),
+ 'type' : '2G',
+ 'cid' : str(self.cid)}
+ return cell
+
+
+ def __cmp__(self, other):
+ if hasattr(other, 'getKey'):
+ return self.getKey().__cmp__(other.getKey())
+
+ def __repr__(self):
+ return "%s(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (
+ self.__class__, self.arfcn, self.freq, self.cid, self.lac,
+ self.mcc, self.mnc, self.ccch_conf, self.power,
+ self.neighbours, self.cell_arfcns)
+
+ def __str__(self):
+ return "ARFCN: %4u, Freq: %6.1fM, CID: %5u, LAC: %5u, MCC: %3u, MNC: %3u, Pwr: %3i" % (
+ self.arfcn, self.freq / 1e6, self.cid, self.lac, self.mcc, self.mnc, self.power)
+
+
+def do_scan(samp_rate, band, speed, ppm, gain, args, prn=None, debug=False):
+ signallist = []
+ server = network.socket_pdu('UDP_SERVER', '127.0.0.1', '4729', 10000, False)
+ channels_num = int(samp_rate / 0.2e6)
+ for arfcn_range in gsm.arfcn.get_arfcn_ranges(band):
+ first_arfcn = arfcn_range[0]
+ last_arfcn = arfcn_range[1]
+ print("Try scan CCCH on " + str(first_arfcn) + "-" + str(last_arfcn) + " arfcn`s:")
+ last_center_arfcn = last_arfcn - int((channels_num / 2) - 1)
+
+ start_freq = gsm.arfcn.arfcn2downlink(first_arfcn + int(channels_num / 2) - 1)
+ current_freq = start_freq
+ last_freq = gsm.arfcn.arfcn2downlink(last_center_arfcn)
+ stop_freq = last_freq + 0.2e6 * channels_num
+
+ while current_freq < stop_freq:
+ print("Scanning: {percent:.2f}% done..".format(
+ percent=(current_freq - start_freq) / (stop_freq - start_freq) * 100))
+ if not debug:
+ # silence rtl_sdr output:
+ # open 2 fds
+ null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)]
+ # save the current file descriptors to a tuple
+ save = os.dup(1), os.dup(2)
+ # put /dev/null fds on 1 and 2
+ os.dup2(null_fds[0], 1)
+ os.dup2(null_fds[1], 2)
+ # instantiate scanner and processor
+ scanner = wideband_scanner(rec_len=30 - speed,
+ sample_rate=samp_rate,
+ carrier_frequency=current_freq,
+ ppm=ppm, gain=gain, args=args)
+ # start recording
+ scanner.start()
+ scanner.wait()
+ scanner.stop()
+ if not debug:
+ # restore file descriptors so we can print the results
+ os.dup2(save[0], 1)
+ os.dup2(save[1], 2)
+ # close the temporary fds
+ os.close(null_fds[0])
+ os.close(null_fds[1])
+
+ freq_offsets = numpy.fft.ifftshift(
+ numpy.array(range(int(-numpy.floor(channels_num / 2)), int(numpy.floor((channels_num + 1) / 2)))) * 2e5)
+ detected_c0_channels = scanner.gsm_extract_system_info.get_chans()
+
+ found_list = []
+
+ if detected_c0_channels:
+ chans = numpy.array(scanner.gsm_extract_system_info.get_chans())
+ found_freqs = current_freq + freq_offsets[(chans)]
+
+ cell_ids = numpy.array(scanner.gsm_extract_system_info.get_cell_id())
+ lacs = numpy.array(scanner.gsm_extract_system_info.get_lac())
+ mccs = numpy.array(scanner.gsm_extract_system_info.get_mcc())
+ mncs = numpy.array(scanner.gsm_extract_system_info.get_mnc())
+ ccch_confs = numpy.array(scanner.gsm_extract_system_info.get_ccch_conf())
+ powers = numpy.array(scanner.gsm_extract_system_info.get_pwrs())
+ assignment_arfcns = numpy.array(scanner.extract_immediate_assignment.get_arfcn_ids())
+ assignment_tseqs = numpy.array(scanner.extract_immediate_assignment.get_tseqs())
+ assignment_maios = numpy.array(scanner.extract_immediate_assignment.get_maios())
+ assignment_hsns = numpy.array(scanner.extract_immediate_assignment.get_hsns())
+ assignment_timeslots = numpy.array(scanner.extract_immediate_assignment.get_timeslots())
+ assignment_channels = numpy.array(scanner.extract_immediate_assignment.get_channel_types())
+ cell_arfcn_lists = []
+ neighbour_lists = []
+ for i in range(0, len(chans)):
+ cell_arfcn_lists.append(scanner.gsm_extract_system_info.get_cell_arfcns(chans[i]))
+ neighbour_lists.append(scanner.gsm_extract_system_info.get_neighbours(chans[i]))
+ scanner = None
+ gc.collect()
+ for i in range(0, len(chans)):
+ cell_arfcn_list = cell_arfcn_lists[i]
+ neighbour_list = neighbour_lists[i]
+ found_arfcn = gsm.arfcn.downlink2arfcn(found_freqs[i])
+ print("\nFound CCCH arfcn: " + str(found_arfcn))
+ found_arfcn_assignments = []
+
+ for a in range(0, len(assignment_arfcns)):
+
+ # print("Assigments: " + str(assignment_arfcns[a]) + "<->" + str(chans[i]))
+ if assignment_arfcns[a] == chans[i]:
+ dubl = False
+ for f in found_arfcn_assignments:
+ if f.assignment_channel == assignment_channels[a] and \
+ f.timeslot == assignment_timeslots[a] and \
+ f.tseq == assignment_tseqs[a] and \
+ f.maio == assignment_maios[a] and \
+ f.hsn == assignment_hsns[a]:
+ dubl = True
+ break
+ if not dubl:
+ a5_versions = []
+ if len(cell_arfcn_list) > 0:
+ fcs = list(map(arfcn.arfcn2downlink, cell_arfcn_list))
+ wide_samp_rate = max(1e6, int(math.ceil((max(fcs) - min(fcs)) * 1.1 / 1e6)) * 1e6)
+ if wide_samp_rate > 20e6:
+ # print("Very wide bandwidth for this hopping SDCCH/8 arfcns: " + str(wide_samp_rate/1e6) + " MHz, skip SDCCH/8 scan...")
+ a5_versions = [
+ "?, arfcn`s range too wide: " + str(wide_samp_rate / 1e6) + " MHz"]
+ else:
+ try:
+ # print("Wide bandwidth: " + str(wide_samp_rate/1e6) + " MHz")
+ # print(", ".join(map(str, cell_arfcn_list)))
+ # print(found_arfcn)
+ ccch_index = tuple(cell_arfcn_list).index(found_arfcn)
+ print("Start SDCCH/8 scanning on " + str(found_arfcn) + " arfcn...")
+ for t in range(0, 6):
+ print(str(t + 1) + "`th try..")
+ if not debug:
+ # silence rtl_sdr output:
+ # open 2 fds
+ null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)]
+ # save the current file descriptors to a tuple
+ save = os.dup(1), os.dup(2)
+ # put /dev/null fds on 1 and 2
+ os.dup2(null_fds[0], 1)
+ os.dup2(null_fds[1], 2)
+ sdcch8_scanner = sdcch8_decoder_hopping(cell_arfcn_list, ccch_index,
+ assignment_hsns[a],
+ assignment_maios[a], 4,
+ assignment_timeslots[a],
+ assignment_tseqs[a], 30, ppm,
+ args)
+ if not debug:
+ os.dup2(save[0], 1)
+ os.dup2(save[1], 2)
+ # close the temporary fds
+ os.close(null_fds[0])
+ os.close(null_fds[1])
+ sdcch8_scanner.start()
+ sdcch8_scanner.wait()
+ sdcch8_scanner.stop()
+ a5_versions = sdcch8_scanner.gsm_extract_cmc_0.get_a5_versions()
+ if len(a5_versions) == 0:
+ a5_versions = ["?, not found CMC"]
+ else:
+ break
+ # print(", ".join(map(str, a5_versions)))
+ sdcch8_scanner = None
+ gc.collect()
+ except ValueError:
+ # print("Found arfcn not present in arfcns hopping list, skip SDCCH/8 scan...")
+ a5_versions = [
+ "?, this CCCH is not present in hopping list | possible signal imposition"]
+ else:
+ print(
+ "!! Immidiate assigment got, but SDCCH/8 Channel Description not capture, skip SDCCH/8 scan...")
+ a5_versions = ["?, SDCCH/8 channel description not capture"]
+ found_arfcn_assignments.append(assignment_info(found_arfcn, assignment_channels[a],
+ assignment_timeslots[a],
+ assignment_tseqs[a],
+ assignment_maios[a], assignment_hsns[a],
+ a5_versions))
+ if len(found_arfcn_assignments) == 0:
+ print("Dont capture immediate assignments, skip extract SDCCH/8 info and scan...")
+ info = channel_info(found_arfcn, found_freqs[i],
+ cell_ids[i], lacs[i], mccs[i], mncs[i], ccch_confs[i], powers[i],
+ neighbour_list, cell_arfcn_list, found_arfcn_assignments)
+
+ print(info)
+ print(info.get_verbose_info())
+
+ found_list.append(info)
+
+ scanner = None
+
+ if prn:
+ prn(found_list)
+ signallist.extend(found_list)
+
+ current_freq += channels_num * 0.2e6
+ server = None
+ return signallist
+
+
+def argument_parser():
+ parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+ bands_list = ", ".join(gsm.arfcn.get_bands())
+ parser.add_option("-b", "--band", dest="band", default="GSM900",
+ help="Specify the GSM band for the frequency.\nAvailable bands are: " + bands_list)
+ parser.add_option("-s", "--samp-rate", dest="samp_rate", type="float", default=2e6,
+ help="Set sample rate [default=%default] - allowed values even_number*0.2e6")
+ parser.add_option("-p", "--ppm", dest="ppm", type="intx", default=0,
+ help="Set frequency correction in ppm [default=%default]")
+ parser.add_option("-g", "--gain", dest="gain", type="eng_float", default=24.0,
+ help="Set gain [default=%default]")
+ parser.add_option("", "--args", dest="args", type="string", default="",
+ help="Set device arguments [default=%default]."
+ " Use --list-devices the view the available devices")
+ parser.add_option("-l", "--list-devices", action="store_true",
+ help="List available SDR devices, use --args to specify hints")
+ parser.add_option("--speed", dest="speed", type="intx", default=15,
+ help="Scan speed [default=%default]. Value range 0-29.")
+ parser.add_option("-v", "--verbose", action="store_true",
+ help="If set, verbose information output is printed: ccch configuration, cell ARFCN's, neighbour ARFCN's")
+ parser.add_option("-d", "--debug", action="store_true",
+ help="Print additional debug messages")
+
+ """
+ Dont forget: sudo sysctl kernel.shmmni=32000
+ """
+ return parser
+
+
+def main(options=None):
+ if options is None:
+ (options, args) = argument_parser().parse_args()
+
+ if options.list_devices:
+ gsm.device.print_devices(options.args)
+ sys.exit(0)
+
+ if options.band not in gsm.arfcn.get_bands():
+ parser.error("Invalid GSM band\n")
+
+ if options.speed < 0 or options.speed > 29:
+ parser.error("Invalid scan speed.\n")
+
+ if (options.samp_rate / 0.2e6) % 2 != 0:
+ parser.error("Invalid sample rate. Sample rate must be an even numer * 0.2e6")
+
+ # def printfunc(found_list):
+ # for info in sorted(found_list):
+ # print(info)
+ # if options.verbose:
+ # print(info.get_verbose_info())
+ print("")
+ do_scan(options.samp_rate, options.band, options.speed,
+ options.ppm, options.gain, options.args, prn=None, debug=options.debug)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/engines/sdr/srslte_pss.py b/engines/sdr/srslte_pss.py
new file mode 100644
index 0000000..c298ade
--- /dev/null
+++ b/engines/sdr/srslte_pss.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# )penthertz.com> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
+#
+# We'd like to thank our contributors for maintening this code:
+# - @h0rac (Grzegorz Wypych) from PWNSec.pl
+# ----------------------------------------------------------------------------
+
+from __future__ import print_function
+from core.mLog import Cellslogger
+from core.mKB import *
+import os
+
+class srslte_pss(object):
+ @Cellslogger
+ def go2logs(self, cell):
+ return cell
+
+ def parseFifo(self):
+ kb = mKB()
+ FIFO = kb.config['file']
+ if os.path.isfile(FIFO) == False:
+ try:
+ os.mkfifo(FIFO)
+ except:
+ pass
+ if 'SM_cells' not in kb.data:
+ kb.data['SM_cells'] = {}
+ while True:
+ with open(FIFO) as fifo:
+ while True:
+ data = fifo.read()
+ if len(data) == 0:
+ break
+ infos = data.split(':')[1]
+ isplit = infos.split(';')
+ tmpcell = {}
+ tmpcell2 = {}
+ for cell in isplit:
+ pcell = cell.split('=')
+ tmpcell[pcell[0]] = pcell[1]
+ cid = tmpcell['CID'] + '-' + tmpcell['DL_EARFCN']
+ tmpcell2[cid] = { 'FREQ' : tmpcell['FREQ'],
+ 'PLMN' : "-1",
+ 'type' : "4G",
+ 'band' : tmpcell['BAND'],
+ 'eARFCN' : int(tmpcell['DL_EARFCN']),
+ 'POWER' : tmpcell['POWER'].split("\n")[0],
+ }
+ self.go2logs(tmpcell2)
+
+
diff --git a/install_all-Ubuntu_24.04.sh b/install_all-Ubuntu_24.04.sh
new file mode 100755
index 0000000..5ed4a67
--- /dev/null
+++ b/install_all-Ubuntu_24.04.sh
@@ -0,0 +1,104 @@
+#!/usr/bin/bash
+
+echo "[+] Retrieving submodules"
+git submodule update --init --recursive
+
+echo "[+] Installing Python3 requirements"
+sudo apt install -y python3-pip
+
+echo "[+] Installing GNU Radio dependencies"
+install_antsdr_uhd() {
+ sudo apt-get install autoconf automake build-essential ccache cmake cpufrequtils doxygen ethtool \
+ g++ git inetutils-tools libboost-all-dev libncurses5 libncurses5-dev libusb-1.0-0 libusb-1.0-0-dev \
+ libusb-dev python3-dev python3-mako python3-numpy python3-requests python3-scipy python3-setuptools \
+ python3-ruamel.yaml
+ git clone https://github.com/MicroPhase/antsdr_uhd.git
+ cd antsdr_uhd
+ cd host/
+ mkdir build
+ cd build
+ cmake ../
+ make -j$(nproc)
+ sudo make install
+ sudo ldconifg
+ cd ../../
+}
+
+sudo apt-get install gnuradio gnuradio-dev -y
+
+sudo apt install -y git cmake g++ libboost-all-dev libgmp-dev swig python3-numpy \
+python3-mako python3-sphinx python3-lxml doxygen libfftw3-dev \
+libsdl1.2-dev libgsl-dev libqwt-qt5-dev libqt5opengl5-dev python3-pyqt5 \
+liblog4cpp5-dev libzmq3-dev python3-yaml python3-click python3-click-plugins \
+python3-zmq python3-scipy python3-gi python3-gi-cairo gobject-introspection gir1.2-gtk-3.0 \
+libsndfile-dev libtalloc-dev libpcsclite-dev wget unzip python3-pip libbladerf-dev \
+libuhd-dev uhd-host librtlsdr-dev
+
+while true; do
+ read -p "Do you which to install the UHD version of ANTSDR (YES), or the original one [NO]? " yn
+ case $yn in
+ [Yy]* ) install_antsdr_uhd; break;;
+ [Nn]* ) sudo apt install libuhd-dev uhd-host librtlsdr-dev; break;;
+ * ) echo "Please answer [Y]yes or [N]no.";;
+ esac
+done
+
+sudo pip3 install pyserial --break-system-packages
+
+echo "[+] Installing osmocore"
+sudo apt -y install build-essential libosmocore libosmocore-dev libtool libtalloc-dev libsctp-dev shtool autoconf automake git-core pkg-config make gcc gnutls-dev libusb-1.0-0-dev libmnl-dev
+cd thirdparty
+REMPATH=`pwd`
+#sudo apt install gr-osmosdr
+git clone https://github.com/PentHertz/gr-osmosdr.git
+cd gr-osmosdr
+mkdir build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX=/usr/local ../
+make -j$(nproc)
+sudo make install
+cd $REMPATH
+echo "[+] Downloading gr-gsm for Python3 and GNU Radio 3.10"
+git clone https://github.com/FlUxIuS/gr-gsm.git
+echo "[+] Building and installing gr-gsm for GNU Radio 3.10"
+cd gr-gsm
+mkdir build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX=/usr/local ../
+make -j$(nproc)
+sudo make install
+cd ../../
+echo "[+] Installing SDK tools"
+sudo apt install -y openjdk-25-jdk
+wget https://dl.google.com/android/repository/platform-tools-latest-linux.zip
+unzip platform-tools-latest-linux.zip
+sudo mkdir -p /opt/Android
+sudo cp -R platform-tools
+echo "[+] Installing dependencies for srsLTE"
+sudo apt-get install cmake libfftw3-dev libmbedtls-dev libboost-program-options-dev libconfig++-dev libsctp-dev
+sudo apt install libsoapysdr-dev
+#osmo sdr support:
+sudo apt-get install osmo-sdr soapysdr-module-osmosdr
+#rtl sdr support:
+sudo apt-get install rtl-sdr soapysdr-module-rtlsdr
+#blade rf support:
+sudo apt-get install bladerf soapysdr-module-bladerf
+#hack rf support:
+sudo apt-get install hackrf soapysdr-module-hackrf
+#usrp support:
+sudo apt-get install uhd-soapysdr soapysdr-module-uhd
+#miri SDR support:
+sudo apt-get install miri-sdr soapysdr-module-mirisdr
+#rf space support:
+sudo apt-get install soapysdr-module-rfspace
+#airspy support:
+sudo apt-get install airspy soapysdr-module-airspy
+echo "[+] Installaing srsLTE for Modmobmap"
+cd $REMPATH
+ls
+cd srsLTE
+mkdir build
+cd build
+cmake ../
+make -j$(nproc)
+echo "====END===="
diff --git a/modmobmap.py b/modmobmap.py
index 5136de4..91dcb9f 100755
--- a/modmobmap.py
+++ b/modmobmap.py
@@ -3,7 +3,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
@@ -11,36 +11,22 @@
from __future__ import print_function
from utils.logprocess import *
+SRSLTE_PATH = "thirdparty/srsLTE/" # thirdparty project
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description='Mobile network mapping tool with cheap equipments')
- parser.add_argument('-m', '--module', dest='module', required=False, default='servicemode',
- help='Module to use (e.g: "servicemode" by default)')
- parser.add_argument('-n', '--networks', dest='networks', required=False, default=None,
- help='Networks in MCCMNC format splitted with commas')
- parser.add_argument('-o', '--cached_operator', dest='operators', required=False, default=False, action='store_true',
- help='Use operator in cache to speed up the passive scan')
- parser.add_argument('-s', '--sdk', dest='androidsdk', required=False, default='/opt/Android',
- help='Android SDK path')
- parser.add_argument('-a', '--at', dest='atmode', required=False, default=None,
- help='AT access mode. If host put something like "/dev/ttyUSBxx. By default it uses ADB."')
- parser.add_argument('-f', '--file', dest='file', required=False, default=None,
- help='File to parse. For the moment it could be used in combination with AT mode host.')
- args = parser.parse_args()
- sm = ADBshell()
- kb = mKB()
- kb.config['androidsdk'] = args.androidsdk
- sm.androidsdkpath = args.androidsdk
- if args.file is not None:
- kb.config['file'] = args.file
- if args.module == "xgoldmod":
- startXgoldmodCollect()
- else:
- startServiceModeCollect()
+
+FILES_TO_REMOVE = ["celllog.fifo"]
+
+def cleaning_file():
+ import os
+ for f in FILES_TO_REMOVE:
+ os.remove(f)
+
+
+def phone_actions(args):
cops = None
if args.networks is not None:
printInfo('=> Manual MCC/MNC processing...')
- cops = processManualMCCMN(args.networks)
+ cops = processManualMCCMN(args.networks)
else:
printInfo('=> Requesting a list of MCC/MNC. Please wait, it may take a while...')
operators = load_operators()
@@ -49,6 +35,8 @@
cops = operators
if cops is None:
if args.atmode is None:
+ sm = ADBshell()
+ sm.androidsdkpath = args.androidsdk
cops = sm.getCOPSfromRIL()
else:
at = AT(args.atmode)
@@ -65,3 +53,55 @@
else:
kb.config['tty_file'] = args.atmode
processOperatorAT(operators)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Mobile network mapping tool with cheap equipments')
+ parser.add_argument('-m', '--module', dest='module', required=False, default='servicemode',
+ help='Module to use (e.g: "servicemode" by default).')
+ parser.add_argument('-b', '--bands', dest='bands', required=False, default=None,
+ help='Bands to use for SDR engines (for GSM: GSM900, DCS1800, GSM850, PCS1900, GSM450, GSM480, GSM-R. For LTE provide band indexes such as 28 for B28 at 700 MHz, etc.). A list can be provided separated with commas.')
+ parser.add_argument('-n', '--networks', dest='networks', required=False, default=None,
+ help='Networks in MCCMNC format splitted with commas')
+ parser.add_argument('-o', '--cached_operator', dest='operators', required=False, default=False, action='store_true',
+ help='Use operator in cache to speed up the passive scan.')
+ parser.add_argument('-s', '--sdk', dest='androidsdk', required=False, default='thirdparty/platform-tools',
+ help='Android SDK path')
+ parser.add_argument('-a', '--at', dest='atmode', required=False, default=None,
+ help='AT access mode. If host put something like "/dev/ttyUSBxx. By default it uses ADB."')
+ parser.add_argument('-g', '--args', dest='dargs', required=False, default=None,
+ help='Device name arg for SDR engines (e.g: soapy:id=0))')
+ parser.add_argument('-f', '--file', dest='file', required=False, default=None,
+ help='File to parse. For the moment it could be used in combination with AT mode host.')
+ args = parser.parse_args()
+
+ phoneinteract = False
+
+ kb = mKB()
+ kb.config['androidsdk'] = args.androidsdk
+ kb.config['device_args'] = args.dargs
+ if args.file is not None:
+ kb.config['file'] = args.file
+ if args.module == "xgoldmod":
+ startXgoldmodCollect()
+ phoneinteract = True
+ elif args.module == "srslte_pss" or args.module == "srslte_npss":
+ kb.config['SRSLTETOOLS_PATH'] = SRSLTE_PATH + "build/lib/examples/"
+ kb.config['file'] = "celllog.fifo"
+ if args.file is not None:
+ kb.config['file'] = args.file
+
+ if args.bands is not None:
+ kb.config['bands'] = args.bands
+ else:
+ print ("Bands argument not set! Using band 7 by default instead.")
+ kb.config['bands'] = "7"
+ startSrsLTEPSS()
+ elif args.module == "grgsm":
+ processGRGSM(args.bands)
+ else:
+ startServiceModeCollect()
+ phoneinteract = True
+
+ if phoneinteract is True:
+ phone_actions(args)
diff --git a/requirements.txt b/requirements.txt
index b6be06a..f6c1a1f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1 @@
-serial
+pyserial
diff --git a/samples/cells_1537879258.json b/samples/cells_1537879258.json
new file mode 100644
index 0000000..cc3873c
--- /dev/null
+++ b/samples/cells_1537879258.json
@@ -0,0 +1,11 @@
+{
+ "346-1501": {
+ "PCI": "346",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ }
+}
\ No newline at end of file
diff --git a/samples/cells_1537879363.json b/samples/cells_1537879363.json
new file mode 100644
index 0000000..cc3873c
--- /dev/null
+++ b/samples/cells_1537879363.json
@@ -0,0 +1,11 @@
+{
+ "346-1501": {
+ "PCI": "346",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ }
+}
\ No newline at end of file
diff --git a/samples/cells_1537879796.json b/samples/cells_1537879796.json
new file mode 100644
index 0000000..cc3873c
--- /dev/null
+++ b/samples/cells_1537879796.json
@@ -0,0 +1,11 @@
+{
+ "346-1501": {
+ "PCI": "346",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ }
+}
\ No newline at end of file
diff --git a/samples/cells_1537880475.json b/samples/cells_1537880475.json
new file mode 100644
index 0000000..e85d316
--- /dev/null
+++ b/samples/cells_1537880475.json
@@ -0,0 +1,323 @@
+{
+ "11ee-9": {
+ "PLMN": "208-01",
+ "arfcn": 9,
+ "cid": "11ee",
+ "type": "2G"
+ },
+ "1882-10787": {
+ "PLMN": "208-01",
+ "RX": 10787,
+ "TX": 9837,
+ "band": 1,
+ "type": "3G"
+ },
+ "1882b-10787": {
+ "PLMN": "208-01",
+ "RX": 10787,
+ "TX": 9837,
+ "band": 1,
+ "type": "3G"
+ },
+ "1882b-10812": {
+ "PLMN": "208-01",
+ "RX": 10812,
+ "TX": 9862,
+ "band": 1,
+ "type": "3G"
+ },
+ "188ec3-3011": {
+ "PLMN": "208-01",
+ "RX": 3011,
+ "TX": 2786,
+ "band": 8,
+ "type": "3G"
+ },
+ "1ba-78": {
+ "PLMN": "208-10",
+ "arfcn": 78,
+ "cid": "1ba",
+ "type": "2G"
+ },
+ "1ba8-78": {
+ "PLMN": "208-10",
+ "arfcn": 78,
+ "cid": "1ba8",
+ "type": "2G"
+ },
+ "27-1019": {
+ "PLMN": "208-20",
+ "arfcn": 1019,
+ "cid": "27",
+ "type": "2G"
+ },
+ "2ca4-10737": {
+ "PLMN": "208-15",
+ "RX": 10737,
+ "TX": 9787,
+ "band": 1,
+ "type": "3G"
+ },
+ "346-1501": {
+ "PCI": "346",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ },
+ "346-6300": {
+ "PCI": "346",
+ "PLMN": "208-10",
+ "TAC": "0",
+ "band": 20,
+ "bandwidth": "20MHz_",
+ "eARFCN": 6300,
+ "type": "4G"
+ },
+ "351-1300": {
+ "PCI": "351",
+ "PLMN": "208-01",
+ "TAC": "0",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1300,
+ "type": "4G"
+ },
+ "351-1501": {
+ "PCI": "351",
+ "PLMN": "208-10",
+ "TAC": "0",
+ "band": 3,
+ "bandwidth": "10MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ },
+ "351-1850": {
+ "PCI": "351",
+ "PLMN": "208-20",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "15MHz_",
+ "eARFCN": 1850,
+ "type": "4G"
+ },
+ "351-3350": {
+ "PCI": "351",
+ "PLMN": "208-01",
+ "TAC": "0",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3350,
+ "type": "4G"
+ },
+ "353-1501": {
+ "PCI": "353",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 20,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ },
+ "353-1850": {
+ "PCI": "353",
+ "PLMN": "208-20",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1850,
+ "type": "4G"
+ },
+ "353-3000": {
+ "PCI": "353",
+ "PLMN": "208-01",
+ "TAC": "0",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3000,
+ "type": "4G"
+ },
+ "353-3350": {
+ "PCI": "353",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3350,
+ "type": "4G"
+ },
+ "353-6300": {
+ "PCI": "353",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 20,
+ "bandwidth": "10MHz_",
+ "eARFCN": 6300,
+ "type": "4G"
+ },
+ "391-6300": {
+ "PCI": "391",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 20,
+ "bandwidth": "10MHz_",
+ "eARFCN": 6300,
+ "type": "4G"
+ },
+ "435-1675": {
+ "PCI": "435",
+ "PLMN": "208-15",
+ "TAC": "6603",
+ "band": 3,
+ "bandwidth": "15MHz_",
+ "eARFCN": 1675,
+ "type": "4G"
+ },
+ "435-3350": {
+ "PCI": "435",
+ "PLMN": "208-15",
+ "TAC": "6603",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3350,
+ "type": "4G"
+ },
+ "56-1850": {
+ "PCI": "56",
+ "PLMN": "208-20",
+ "TAC": "0",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1850,
+ "type": "4G"
+ },
+ "5f28-8": {
+ "PLMN": "208-01",
+ "arfcn": 8,
+ "cid": "5f28",
+ "type": "2G"
+ },
+ "65-6200": {
+ "PCI": "65",
+ "PLMN": "208-20",
+ "TAC": "0",
+ "band": 20,
+ "bandwidth": "10MHz_",
+ "eARFCN": 6200,
+ "type": "4G"
+ },
+ "65-6300": {
+ "PCI": "65",
+ "PLMN": "208-20",
+ "TAC": "0",
+ "band": 20,
+ "bandwidth": "10MHz_",
+ "eARFCN": 6300,
+ "type": "4G"
+ },
+ "8fc3-10664": {
+ "PLMN": "208-20",
+ "RX": 10664,
+ "TX": 9714,
+ "band": 1,
+ "type": "3G"
+ },
+ "8fc30-10664": {
+ "PLMN": "208-20",
+ "RX": 10664,
+ "TX": 9714,
+ "band": 1,
+ "type": "3G"
+ },
+ "8fc6e-3075": {
+ "PLMN": "208-10",
+ "RX": 3075,
+ "TX": 2850,
+ "band": 8,
+ "type": "3G"
+ },
+ "8fc6e5-3075": {
+ "PLMN": "208-10",
+ "RX": 3075,
+ "TX": 2850,
+ "band": 8,
+ "type": "3G"
+ },
+ "8fc7-10564": {
+ "PLMN": "208-10",
+ "RX": 10564,
+ "TX": 9614,
+ "band": 1,
+ "type": "3G"
+ },
+ "8fc77-10564": {
+ "PLMN": "208-10",
+ "RX": 10564,
+ "TX": 9614,
+ "band": 1,
+ "type": "3G"
+ },
+ "8fcb-10589": {
+ "PLMN": "208-10",
+ "RX": 10589,
+ "TX": 9639,
+ "band": 1,
+ "type": "3G"
+ },
+ "8fcb2-10589": {
+ "PLMN": "208-10",
+ "RX": 10589,
+ "TX": 9639,
+ "band": 1,
+ "type": "3G"
+ },
+ "fbc8-9": {
+ "PLMN": "208-01",
+ "arfcn": 9,
+ "cid": "fbc8",
+ "type": "2G"
+ },
+ "fffff-10589": {
+ "PLMN": "208-10",
+ "RX": 10589,
+ "TX": 9639,
+ "band": 1,
+ "type": "3G"
+ },
+ "fffff-10664": {
+ "PLMN": "208-20",
+ "RX": 10664,
+ "TX": 9714,
+ "band": 1,
+ "type": "3G"
+ },
+ "fffff-10737": {
+ "PLMN": "208-15",
+ "RX": 10737,
+ "TX": 9787,
+ "band": 1,
+ "type": "3G"
+ },
+ "fffff-10812": {
+ "PLMN": "208-01",
+ "RX": 10812,
+ "TX": 9862,
+ "band": 1,
+ "type": "3G"
+ },
+ "ffffff-3075": {
+ "PLMN": "208-10",
+ "RX": 3075,
+ "TX": 2850,
+ "band": 8,
+ "type": "3G"
+ },
+ "ffffff-78": {
+ "PLMN": "208-10",
+ "arfcn": 78,
+ "cid": "ffffff",
+ "type": "2G"
+ }
+}
\ No newline at end of file
diff --git a/samples/cells_1537880525.json b/samples/cells_1537880525.json
new file mode 100644
index 0000000..a9daac8
--- /dev/null
+++ b/samples/cells_1537880525.json
@@ -0,0 +1,248 @@
+{
+ "11ee-9": {
+ "PLMN": "208-01",
+ "arfcn": 9,
+ "cid": "11ee",
+ "type": "2G"
+ },
+ "1882-10787": {
+ "PLMN": "208-01",
+ "RX": 10787,
+ "TX": 9837,
+ "band": 1,
+ "type": "3G"
+ },
+ "1882b-10787": {
+ "PLMN": "208-01",
+ "RX": 10787,
+ "TX": 9837,
+ "band": 1,
+ "type": "3G"
+ },
+ "1882b-10812": {
+ "PLMN": "208-01",
+ "RX": 10812,
+ "TX": 9862,
+ "band": 1,
+ "type": "3G"
+ },
+ "188ec3-3011": {
+ "PLMN": "208-01",
+ "RX": 3011,
+ "TX": 2786,
+ "band": 8,
+ "type": "3G"
+ },
+ "1ba8-78": {
+ "PLMN": "208-10",
+ "arfcn": 78,
+ "cid": "1ba8",
+ "type": "2G"
+ },
+ "27-1019": {
+ "PLMN": "208-20",
+ "arfcn": 1019,
+ "cid": "27",
+ "type": "2G"
+ },
+ "2ca4-10737": {
+ "PLMN": "208-15",
+ "RX": 10737,
+ "TX": 9787,
+ "band": 1,
+ "type": "3G"
+ },
+ "346-1501": {
+ "PCI": "346",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ },
+ "351-1300": {
+ "PCI": "351",
+ "PLMN": "208-01",
+ "TAC": "0",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1300,
+ "type": "4G"
+ },
+ "351-1501": {
+ "PCI": "351",
+ "PLMN": "208-10",
+ "TAC": "0",
+ "band": 3,
+ "bandwidth": "10MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ },
+ "351-1850": {
+ "PCI": "351",
+ "PLMN": "208-20",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "15MHz_",
+ "eARFCN": 1850,
+ "type": "4G"
+ },
+ "351-3350": {
+ "PCI": "351",
+ "PLMN": "208-01",
+ "TAC": "0",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3350,
+ "type": "4G"
+ },
+ "353-1501": {
+ "PCI": "353",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 20,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1501,
+ "type": "4G"
+ },
+ "353-1850": {
+ "PCI": "353",
+ "PLMN": "208-20",
+ "TAC": "58104",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1850,
+ "type": "4G"
+ },
+ "353-3000": {
+ "PCI": "353",
+ "PLMN": "208-01",
+ "TAC": "0",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3000,
+ "type": "4G"
+ },
+ "353-3350": {
+ "PCI": "353",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3350,
+ "type": "4G"
+ },
+ "353-6300": {
+ "PCI": "353",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 20,
+ "bandwidth": "10MHz_",
+ "eARFCN": 6300,
+ "type": "4G"
+ },
+ "391-6300": {
+ "PCI": "391",
+ "PLMN": "208-10",
+ "TAC": "58104",
+ "band": 20,
+ "bandwidth": "10MHz_",
+ "eARFCN": 6300,
+ "type": "4G"
+ },
+ "435-1675": {
+ "PCI": "435",
+ "PLMN": "208-15",
+ "TAC": "6603",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1675,
+ "type": "4G"
+ },
+ "435-3350": {
+ "PCI": "435",
+ "PLMN": "208-15",
+ "TAC": "6603",
+ "band": 7,
+ "bandwidth": "20MHz_",
+ "eARFCN": 3350,
+ "type": "4G"
+ },
+ "56-1850": {
+ "PCI": "56",
+ "PLMN": "208-20",
+ "TAC": "0",
+ "band": 3,
+ "bandwidth": "20MHz_",
+ "eARFCN": 1850,
+ "type": "4G"
+ },
+ "5f28-8": {
+ "PLMN": "208-01",
+ "arfcn": 8,
+ "cid": "5f28",
+ "type": "2G"
+ },
+ "8fc30-10664": {
+ "PLMN": "208-20",
+ "RX": 10664,
+ "TX": 9714,
+ "band": 1,
+ "type": "3G"
+ },
+ "8fc6e-3075": {
+ "PLMN": "208-10",
+ "RX": 3075,
+ "TX": 2850,
+ "band": 8,
+ "type": "3G"
+ },
+ "8fc6e5-3075": {
+ "PLMN": "208-10",
+ "RX": 3075,
+ "TX": 2850,
+ "band": 8,
+ "type": "3G"
+ },
+ "fbc8-9": {
+ "PLMN": "208-01",
+ "arfcn": 9,
+ "cid": "fbc8",
+ "type": "2G"
+ },
+ "fffff-10664": {
+ "PLMN": "208-20",
+ "RX": 10664,
+ "TX": 9714,
+ "band": 1,
+ "type": "3G"
+ },
+ "fffff-10737": {
+ "PLMN": "208-15",
+ "RX": 10737,
+ "TX": 9787,
+ "band": 1,
+ "type": "3G"
+ },
+ "fffff-10812": {
+ "PLMN": "208-01",
+ "RX": 10812,
+ "TX": 9862,
+ "band": 1,
+ "type": "3G"
+ },
+ "ffffff-3075": {
+ "PLMN": "208-10",
+ "RX": 3075,
+ "TX": 2850,
+ "band": 8,
+ "type": "3G"
+ },
+ "ffffff-78": {
+ "PLMN": "208-10",
+ "arfcn": 78,
+ "cid": "ffffff",
+ "type": "2G"
+ }
+}
\ No newline at end of file
diff --git a/thirdparty/srsLTE b/thirdparty/srsLTE
new file mode 160000
index 0000000..b5b7110
--- /dev/null
+++ b/thirdparty/srsLTE
@@ -0,0 +1 @@
+Subproject commit b5b7110d42d0be32398fe6ae9e627a69863887b4
diff --git a/utils/__init__.py b/utils/__init__.py
index d13e961..8df667a 100644
--- a/utils/__init__.py
+++ b/utils/__init__.py
@@ -2,7 +2,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
diff --git a/utils/eu_arfcn_calc.py b/utils/eu_arfcn_calc.py
index 157a721..4c79643 100755
--- a/utils/eu_arfcn_calc.py
+++ b/utils/eu_arfcn_calc.py
@@ -3,7 +3,7 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
@@ -23,7 +23,7 @@
'DL_range' : (0,599),
'FUL_Low' : 1920,
'NUL_Offset' : 18000,
- 'UP_range' : (1800,18599),
+ 'UP_range' : (18000,18599),
},
2 : { 'FDL_Low' : 1930,
'NDL_Offset' : 600,
@@ -214,6 +214,14 @@
'NUL_Offset' : 27760,
'UP_range' : (27760,27809),
},
+ 38 : { 'FDL_Low' : 2570,
+ 'NDL_Offset' : 37750,
+ 'DL_range' : (37750,38249),
+ },
+ 40 : { 'FDL_Low' : 2300,
+ 'NDL_Offset' : 38650,
+ 'DL_range' : (38650,39649),
+ },
65 : { 'FDL_Low' : 2110,
'NDL_Offset' : 65536,
'DL_range' : (65536,66435),
@@ -455,10 +463,15 @@ def earfcn2freq(band, dl_earfcn=None, ul_earfcn=None):
out: tuple (float downlink_freq, float uplink_freq)
'''
NDL_Offset = table_earfcn[band]['NDL_Offset']
- NUL_Offset = table_earfcn[band]['NUL_Offset']
- duplex_spacing = abs(table_earfcn[band]['FDL_Low']-table_earfcn[band]['FUL_Low'])
+ if table_earfcn[band].__contains__('NUL_Offset'):
+ NUL_Offset = table_earfcn[band]['NUL_Offset']
+ if table_earfcn[band].__contains__('FUL_Low'):
+ ful_low = table_earfcn[band]['FUL_Low']
+ else:
+ ful_low = 0
+ duplex_spacing = abs(table_earfcn[band]['FDL_Low']-ful_low)
FDL_Low = table_earfcn[band]['FDL_Low']
- FUL_Low = table_earfcn[band]['FUL_Low']
+ FUL_Low = ful_low
downlink_freq = uplink_freq = None
if dl_earfcn is not None:
downlink_freq = FDL_Low + 0.1 * (dl_earfcn-NDL_Offset)
@@ -468,6 +481,10 @@ def earfcn2freq(band, dl_earfcn=None, ul_earfcn=None):
uplink_freq = downlink_freq - duplex_spacing
elif downlink_freq is None and uplink_freq is not None:
downlink_freq = downlink_freq + duplex_spacing
+
+ if FUL_Low == 0:
+ uplink_freq = 0
+
return (downlink_freq, uplink_freq)
if __name__ == "__main__":
diff --git a/utils/logprocess.py b/utils/logprocess.py
index 3118165..20185d2 100644
--- a/utils/logprocess.py
+++ b/utils/logprocess.py
@@ -3,14 +3,16 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
-# )synacktiv.com> wrote this file. As long as you retain this notice you
+# )penthertz.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
+# ----------------------------------------------------------------------------
from __future__ import print_function
from engines.android.generic.ADBshell import *
from engines.android.samsung.ServiceMode import *
from engines.host.diag.xgoldmod import *
+from engines.sdr.srslte_pss import *
from engines.host.serial.AT import AT
from utils.colors import *
from core.mKB import *
@@ -18,9 +20,20 @@
from threading import Thread
import argparse
import json
+import signal
kb = mKB()
+def signal_handler(sig, frame):
+ global th, state
+ print('Keyboard interrupt received, stopping cellmapping and saving results...')
+ state = False
+ cells = kb.data['SM_cells']
+ saveCells(cells)
+ sys.exit(0)
+
+signal.signal(signal.SIGINT, signal_handler)
+
def statesmv(func, msg=None, wait=10, arg=None):
if msg is not None:
print (bcolors.OKBLUE+msg+bcolors.ENDC)
@@ -30,22 +43,106 @@ def statesmv(func, msg=None, wait=10, arg=None):
func()
time.sleep(wait)
+
def bringTestMode():
sm = ADBshell()
sm.androidsdkpath = mKB.config['androidsdk']
statesmv(sm.pushsecretcode, arg='4636', wait=2)
+
def bringServiceMode():
sm = ADBshell()
sm.androidsdkpath = mKB.config['androidsdk']
statesmv(sm.pushsecretcode, arg='0011', wait=2)
+
def startXgoldmodCollect():
xg = xgoldmod()
th = Thread(target=xg.parseFifo)
th.daemon = True
th.start()
+
+def startSrsLTExPSSProcess(cmdprog):
+ global state
+ import subprocess
+ state = True
+ bands = mKB.config['bands'].split(",")
+ while state:
+ try:
+ for band in bands:
+ commandstring = [mKB.config['SRSLTETOOLS_PATH']+cmdprog, "-b", band]
+ if mKB.config['device_args'] is not None:
+ if 'soapy' in mKB.config['device_args']:
+ splitted_arg = mKB.config['device_args'].split(':')
+ commandstring.append("-d")
+ commandstring.append(splitted_arg[0])
+ commandstring.append("-a")
+ commandstring.append(splitted_arg[1])
+ else: # TODO handle id of multiple devices connected on USB
+ commandstring.append("-a")
+ commandstring.append(mKB.config['device_args'])
+ p = subprocess.run(commandstring)
+ except (KeyboardInterrupt, SystemExit):
+ state = False
+ cells = kb.data['SM_cells']
+ saveCells(cells)
+
+
+def startSrsLTENPSSProcess():
+ startSrsLTExPSSProcess("cell_search_nbiot_modmobmap")
+
+
+def startSrsLTEPSSProcess():
+ startSrsLTExPSSProcess("cell_search_modmobmap")
+
+
+def startSrsLTEPSSCollect():
+ print("STARTED COLLECT")
+ srs = srslte_pss()
+ th = Thread(target=srs.parseFifo)
+ th.daemon = True
+ th.start()
+
+
+def startSrsLTENPSS():
+ th = Thread(target=startSrsLTENPSSProcess)
+ th.daemon = True
+ th.start()
+ startSrsLTENPSSCollect()
+ state = True
+ th.join()
+ while state:
+ try:
+ pass
+ except (KeyboardInterrupt, SystemExit):
+ state = False
+ cells = kb.data['SM_cells']
+ saveCells(cells)
+
+def startSrsLTEPSS():
+ #global th, state
+ th = Thread(target=startSrsLTEPSSProcess)
+ th.daemon = True
+ th.start()
+ startSrsLTEPSSCollect()
+ state=True
+ th.join()
+ while state:
+ try:
+ pass
+ except (KeyboardInterrupt, SystemExit):
+ state = False
+ cells = kb.data['SM_cells']
+ saveCells(cells)
+
+def startSrsLTEPSSCollect():
+ srs = srslte_pss()
+ th = Thread(target=srs.parseFifo)
+ th.daemon = True
+ th.start()
+
+
def startServiceModeCollect():
sm = ServiceMode()
sm.androidsdkpath = mKB.config['androidsdk']
@@ -55,9 +152,11 @@ def startServiceModeCollect():
th.daemon = True
th.start()
+
def printInfo(string):
print (bcolors.OKBLUE+string+bcolors.ENDC)
+
def saveCells(obj):
import time
jscells = json.dumps(obj, indent=4, sort_keys=True)
@@ -87,8 +186,10 @@ def processOperatorAT(operators):
"=> Switching back to auto-mode", arg=2)
except (KeyboardInterrupt, SystemExit):
state = False
- cells = kb.data['SM_cells']
- saveCells(cells)
+ break
+ cells = kb.data['SM_cells']
+ saveCells(cells)
+
def processOperatorADB(operators):
sm = ADBshell()
@@ -109,11 +210,51 @@ def processOperatorADB(operators):
"=> Switching back to auto-mode", arg=2)
except (KeyboardInterrupt, SystemExit):
state = False
- kb = mKB()
- cells = kb.data['SM_cells']
- saveCells(cells)
+ break
+ cells = kb.data['SM_cells']
+ saveCells(cells)
process = sm.grablogcat()
+
+def scanGRGSM(band):
+ from engines.sdr.grgsm_scanner import do_scan
+ def trigfunc(found_list):
+ for info in sorted(found_list):
+ info.attr2dic() # trigger log
+ device_args = ""
+ if mKB.config['device_args'] is not None:
+ device_args = mKB.config['device_args']
+ do_scan(2e6, band, 4, 0, 30.0, device_args, trigfunc, False)
+
+
+def processGRGSM(bands):
+ state = True
+ cbands_list = ["GSM900",
+ "DCS1800",
+ "GSM850",
+ "PCS1900",
+ "GSM450",
+ "GSM480",
+ "GSM-R"]
+
+ if bands is None:
+ bands_list = cbands_list
+ else:
+ bands_list = bands.split(',')
+
+ while state:
+ try:
+ for band in bands_list:
+ statesmv(scanGRGSM,
+ "=> Switching to %s band" % band, arg=band)
+ except (KeyboardInterrupt, SystemExit):
+ state = False
+ break
+ kb = mKB()
+ cells = kb.data['SM_cells']
+ saveCells(cells)
+
+
def processManualMCCMN(string):
dic_ = {}
splitted = string.replace(' ','').split(',')
@@ -121,6 +262,7 @@ def processManualMCCMN(string):
dic_[code] = code
return dic_
+
def load_operators():
try:
f = open('cache/operators.json', 'r')
@@ -129,12 +271,13 @@ def load_operators():
if len(operators) > 0 or operators is not None:
print (bcolors.WARNING+"Found %i operators in cache, do you want to reuse them?:\n\t%s"+bcolors.ENDC % (len(operators), str(operators)))
answ = input('(Y)es or (N)o?')
- if answ.lower() is 'y':
+ if answ.lower() == 'y':
return operators
f.close()
except:
return None
-
+
+
def saveMCCMNC(obj):
jscache = json.dumps(obj, indent=4, sort_keys=True)
f = open('cache/operators.json', 'w+')