Javascript NIB

The Network in a Box (NIB) 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 Box page.

See Yate's Javascript implementation for more information and examples.

NIB Setup
The NIB application is composed of two Javascript scripts located in the nib directory from YateBTS sources:
 * nib.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

javascript.conf
To set it up, edit javascript.conf.

[general] routing=welcome.js

ybts.conf
You can enable NIB by setting themode=nib in the [ybts] section. This is the default behaviour. If the 'mode' is not set, then the NIB mode is loaded by default:

[ybts] mode=nib

extmodule.conf
When using 2G or 3G authentication set in extmodule.conf:

[scripts] gsm_auth.sh=

subscribers.conf
Use the YateBTS NIB 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 NIB (Network in a box) mode ; File generated by the YateBTS NIB 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

NIB Commands
You can interact with the nib.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 NIB 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
nib list registered Example output: IMSI           MSISDN --- --- 00101000000000  +3014567 00101001100110   +9233298 00101000000003   +3453456 00101000000002   +9999272

Reload subscribers.conf configurations
nib reload

This will reload settings from subscribers.conf without losing existing registrations. (This was added in YateBTS 3)

List rejected IMSIs
nib list rejected

Output example:

IMSI           No attempts register --- --- 10101000000000   1

List pending SMSs
nib 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.

nib.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","nib_cache"); Message.install(onSMS,"msg.execute",80,"callto","nib_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 nib.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 nib_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=nib_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 nib.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: 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);
 * 1 - startEchoTest will be called,
 * 2 - sendToConference,
 * 3 - make outbound call to David.

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"}); }