The Network in a PC (NiPC) application is a demo application written in Javascript that comes by default with YateBTS.
It was provided to ease the use of YateBTS as a small network and as an example on how to build applications based on YateBTS.
For a recap of the features implemented see Network in a PC page.
See Yate’s Javascript implementation for more information and examples.

NiPC Setup
The NiPC application is composed of two Javascript scripts located in the nipc directory from YateBTS sources:
- nipc.js - a global script that contains basic HLR/AuC,VLR/MSC,SMSC for its users
- welcome.js - a small IVR that welcomes the user into the network when calling (david - 32843) and routes him to an echo test or to a conference room based on the user's input
Note: Keep in mind that welcome.js can also be used in Roaming mode
javascript.conf
To set it up, edit javascript.conf.
[general]
routing=welcome.js
ybts.conf
You can enable NiPC by setting the mode=nipc in the [ybts] section. This is the default behaviour. If the ‘mode’ is not set, then the NiPC mode is loaded by default:
[ybts]
mode=nipc
extmodule.conf
When using 2G or 3G authentication set in extmodule.conf:
[scripts]
gsm_auth.sh=
subscribers.conf
Use the YateBTS LMI Web GUI to set subscribers or configure regexp.
From YateBTS machine access http://127.0.0.1/nib or http://ip_yatebts/nib from another server.
You can also edit subscribers.conf located together with Yate’s configuration files in /etc/yate or /usr/local/etc/yate but this is not recommended.
Required configurations in subscribers.conf:
- country_code
- configuring regexp OR adding subscribers
You can’t use regexp and subscribers as the same time. If you configured a subscriber (even if it’s not active), regexp setting will be ignored.
This is an example of subscribers.conf with subscribers set individually:
; !!! NOTE !!!
; This file is used when YateBTS is in NiPC (Network in a PC) mode
; File generated by the YateBTS NiPC interface
[general]
; Your Country code (where YateBTS is installed)
; Ex: 1 for US, 44 for UK
country_code=40
; Subscribers are accepted by either matching the IMSI against this configured
; regular expression or by setting subscribers individually
; Note! If a regular expression is used, 2G/3G authentication cannot be used.
; Ex: regexp=^001
;regexp=^001
; you have to put subscriber IMSI as a category and the subscriber parameters
; as keys
[001990010001014]
; Oficial phone number. Should include configured country code
; Ex: msisdn=10744341111
msisdn=10744341111
; Whether this subscriber is allowed to use the service
; Allowed values: on, off
; Ex: active=off
active=on
; Card secrety. Set or generated when SIMs are written
; Ex:ki=00112233445566778899aabbccddeeff
ki=00112233445566778899aabbccddeeff
; Operator secret.
; Allowed values: empty for 2G IMSIs, 00000000000000000000000000000000 for 3G IMSIs.
; Ex: op=00000000000000000000000000000000
; SIM type
; Allowed values: 2G, 3G
; Ex: imsi_type=3G
imsi_type=2G
; Short number subscribers can use to dial each other. Can be empty or not set
; Ex:short_number=111
short_number=111
NiPC Commands
You can interact with the nipc.js script by using Yate’s Telnet interface. 5038 is Yate’s default rmanager port (port on which it accepts Telnet connections). Staring with version 2 you will see this information in the LMI Web GUI as well, but until then you can only retrieve them directly from Yate.
From the console:
telnet 127.0.0.1 5038
You can:
List registered users
nipc list registered
Example output:
IMSI MSISDN
————— —————
00101000000000 +3014567
00101001100110 +9233298
00101000000003 +3453456
00101000000002 +9999272
Reload subscribers.conf configurations
nipc reload
This will reload settings from subscribers.conf without losing existing registrations. (This was added in YateBTS 3)
List rejected IMSIs
nipc list rejected
Output example:
IMSI No attempts register
————— —————
10101000000000 1
List pending SMSs
nipc list sms
Output example:
FROM_IMSI FROM_MSISDN TO_IMSI TO_MSISDN
————— ————— ————— —————
00101000000000 +3014567 00101000000002 +9999272
Implementation
NOTE! This information is for developers.
You might also find this useful if you wish to modify the provided scripts. It’s not necessary to read it when you are just starting with YateBTS.
nipc.js
This scripts implements a basic HLR, MSC/VLR and SMSC for local users. It’s a global script.
Handled messages
To register and unregister users you need to handle user.register and user.unregister messages:
Message.install(onUnregister,”user.unregister”,80);
Message.install(onRegister,”user.register”,80);
To route calls between the local users and outside YateBTS you must handle the call.route message:
Message.install(onRoute,”call.route”,80);
To implement a small local SMSC:
Message.install(onIdleAction,”idle.execute”,110,”module”,”nipc_cache”);
Message.install(onSMS,”msg.execute”,80,”callto”,”nipc_smsc”);
Engine.setInterval(onInterval,1000);
To provide telnet commands:
Message.install(onCommand,”engine.command”,120);
When one of the messages handled by the script is received, the function associated with the handler will be called. For example, when the message call.route is received, the onRoute function is called.
The main points in detail
Although nipc.js is too large to be listed on the wiki, when inspecting the code you will notice various facts:
- for registration
- the IMSI is set in username parameter for user.register/user.unregister messages
- you must return false to deny the registration (the message should not be handled even if you set the error)
- for routing
- call.route is used for routing calls, SMSs, USSDs. To distinguish between them, see route_type parameter. If the parameter is empty or missing, then it’s assumed you are routing a call
- again, the IMSI is set in username parameter
- depending on the lower level, the caller parameter can look like: ‘IMSI…..’. In this case, you should rewrite it to the real number associated to the IMSI before you finish routing
- to finish routing a call (with or without an error) you must return true from the routing function. To leave the message to be handled in another module, use return false
- the returned value should look like: ybts/IMSI00101000000000 or ybts/+998838838 (msisdn preceded by +) or ybts/IMEI….
- for SMSs
- to route SMS you must handle the call.route with route_type=msg. We simply return the nipc_smsc– string representing our SMSC (implemented in this scrip as well)
- as you saw above, the script catches the msg.execute with priority 80 when callto=nipc_smsc.
- SMSs are stored locally and, afterwards, we periodically try to deliver them until the maximum number of attempts is exceeded
- the mobile originated SMSs come decoded from the lower layer. Assuming A sends a SMS to B:
- the sms.called holds the real called number (B)
- the caller parameter will look like IMSI….. (Ex: IMSI00101000000000) or +….. (subscriber msisdn). If it’s in the IMSI format it must be rewritten to msisdn before sending the Mobile terminated (MT) SMS
- the called parameter holds the number of the SMSC (if set in the phone)
- the text parameter holds the text of the SMS
- when delivering an SMS, you must send the msg.execute message with following parameters:
- caller – SMSC number
- called – destination number (B in above example)
- sms.caller – source number (A in above example)
- text – the text of the message
- callto – IMSI resource looking like ybts/IMSI……. (Ex: ybts/IMSI00101000000000)
welcome.js
welcome.js is a routing script, this is different from the global nipc.js presented above. Click on the link to read more about Javascript routing scripts.
When calling the number 32843(david), a welcomeIVR function is called. This will play a prompt and in case user presses:
- 1 - startEchoTest will be called,
- 2 - sendToConference,
- 3 - make outbound call to David.
function welcomeIVR(msg)
{
Engine.debug(Engine.DebugInfo,”Got call to welcome IVR.”);
Message.install(onChanDtmf, “chan.dtmf”, 90, “id”, msg.id);
Channel.callTo(“wave/play/”+getPathPrompt(“welcome.au”));
if (state == “”)
// No digit was pressed
// Wait aprox 10 seconds to see if digit is pressed
Channel.callTo(“wave/record/-“,{“maxlen”:180000});
Engine.debug(Engine.DebugInfo,”Returned to main function in state ‘”+state+”‘”);
if (state == “echoTest”)
Channel.callJust(“external/playrec/echo.sh”);
}
state = “”;
prompts_dir = “”;
Engine.debugName(“welcome”);
if (message.called==”32843″)
welcomeIVR(message);
This is the function that handles the received DTMFs.
function onChanDtmf(msg)
{
if(msg.text == 1) {
state = “echoTest”;
Channel.callTo(“wave/play/”+getPathPrompt(“echo.au”));
}
else if (msg.text == 2)
Channel.callJust(“conf/333”,{“lonely”:true});
else if (msg.text == 3)
Channel.callJust(“iax/iax:32843@83.166.206.79/32843”,{“caller”:”yatebts”});
//Channel.callJust(“iax/iax:090@192.168.1.1/090”,{“caller”:”yatebts”});
}