Supplementary Services
๐ Back to Main Documentation
Configuration and implementation of call forwarding, CLI blocking, and emergency calling services.
Related Documentationโ
Core Documentationโ
- ๐ Main README - Overview and quick start
- ๐ง Configuration Guide - Service configuration parameters (emergency codes, CLI blocking, default call forward)
- ๐ง Operations Guide - Testing supplementary services
Call Processing & Data Sourcesโ
- ๐ Dialplan Configuration - Implementing services in dialplan logic
- ๐ฅ Sh Interface - MMTel-Config for call forwarding settings
- ๐ก SS7 MAP - HLR-based call forwarding (alternative to Sh)
- ๐ข Number Translation - CLI blocking prefix handling
Service Interactionsโ
- ๐ณ Online Charging - Emergency calls bypass OCS
- ๐ Voicemail - Call forward on busy/no-answer routes to voicemail
Monitoringโ
- ๐ Metrics Reference - Call forwarding and service metrics
- ๐ Dialplan Metrics - Service usage metrics
Supplementary Services (Call Forward / Blocked CLI / Emergency Codes)โ
Config for blocked CLI prefixes, emergency call codes, and default Call Forward data (Call Forward / No Reply data is only used when no MMTel-Config data is returned from the Repository on Sh).
config :tas,
...
blocked_cli_prefix: ["*67"],
call_forward_not_reachable_destination: "2222",
default_no_reply_timer: 30,
emergency_call_codes: ["911", "912", "913", "sos"],
...
Configuration Parameters:
-
blocked_cli_prefix(list of strings): Prefixes that trigger CLI (Calling Line ID) withholding- Example:
["*67"]- dialing *67 before a number hides caller ID - Used in dialplan to set
cli_withheldvariable
- Example:
-
call_forward_not_reachable_destination(string): Default destination for Call Forward Not Reachable (CFNRc)- Only used when no MMTel-Config is returned from Sh interface
- Example:
"2222"- forwards to voicemail
-
default_no_reply_timer(integer): Default timeout in seconds before CFNRc activates- Only used when no MMTel-Config is returned from Sh interface
- Example:
30- rings for 30 seconds before forwarding
-
emergency_call_codes(list of strings): Emergency service numbers for your jurisdiction- Checked during call authorization to detect emergency calls
- SIP emergency URNs (e.g.,
<urn:service:sos>) are always checked in addition to these codes - Common examples:
["911", "112", "000", "999", "sos"] - See Emergency Calling section for detailed usage
How Caller ID Blocking Worksโ
The TAS supports two methods for blocking caller ID (CLI withholding), both of which set the cli_withheld dialplan variable to "true":
Method 1: Prefix-Based Blocking
When a subscriber dials a destination number prefixed with a code from blocked_cli_prefix:
- The number translation module detects the prefix (e.g., caller dials
*67555123456) - The prefix is stripped from the destination number (becomes
555123456) - The
cli_withheldvariable is set to"true" - The dialplan can then use this variable to hide the caller's identity
Example configuration:
blocked_cli_prefix: ["*67"] # US-style blocking
blocked_cli_prefix: ["#31#"] # European GSM-style blocking
blocked_cli_prefix: ["*67", "#31#"] # Support both
Method 2: SIP From Header Detection
When the UE/handset requests privacy via SIP headers:
- The TAS checks if the SIP From header display name contains "anonymous" (case-insensitive)
- If found, the
cli_withheldvariable is set to"true" - This honors the subscriber's privacy request set at the device level
Implementing CLI Blocking in Dialplan
The TAS sets the cli_withheld variable, but your dialplan XML must implement the actual blocking behavior:
<extension name="CLI-Privacy" continue="true">
<condition field="${cli_withheld}" expression="true">
<!-- Hide caller identity -->
<action application="set" data="effective_caller_id_name=anonymous"/>
<action application="set" data="effective_caller_id_number=anonymous"/>
<action application="set" data="origination_privacy=hide_number"/>
<!-- Optionally set P-Asserted-Identity privacy -->
<action application="set" data="sip_h_Privacy=id"/>
</condition>
</extension>
Variables Set by TAS for CLI Blocking:
The TAS sets these variables before dialplan execution:
| Variable | Type | Values | Description |
|---|---|---|---|
cli_withheld | string | "true" or "false" | Indicates if CLI blocking was requested via prefix OR From header |
tas_destination_number | string | normalized number | Destination with blocking prefix removed (e.g., 555123456) |
destination_number | string | normalized number | Same as tas_destination_number (both are set) |
Variables Your Dialplan Should Set (when cli_withheld="true"):
These variables control how caller identity is presented:
| Variable | Recommended Value | Purpose |
|---|---|---|
effective_caller_id_number | "anonymous" | Hides the caller's phone number |
effective_caller_id_name | "anonymous" | Hides the caller's display name |
origination_privacy | "hide_number" | SIP privacy flag for outbound leg |
sip_h_Privacy | "id" | SIP Privacy header (RFC 3323) |
sip_h_P-Asserted-Identity | (unset or remove) | Optional: Remove P-Asserted-Identity header |
Complete Dialplan Example:
<extension name="CLI-Privacy-Handler" continue="true">
<condition field="${cli_withheld}" expression="true">
<!-- Log for troubleshooting -->
<action application="log" data="INFO CLI blocking requested for call to ${tas_destination_number}"/>
<!-- Hide caller identity on outbound call -->
<action application="set" data="effective_caller_id_name=anonymous"/>
<action application="set" data="effective_caller_id_number=anonymous"/>
<action application="set" data="origination_privacy=hide_number"/>
<!-- Set SIP Privacy headers -->
<action application="set" data="sip_h_Privacy=id"/>
<!-- Optional: Remove P-Asserted-Identity if present -->
<action application="unset" data="sip_h_P-Asserted-Identity"/>
<!-- Anti-action runs if cli_withheld is false -->
<anti-action application="log" data="DEBUG Using normal caller ID: ${msisdn}"/>
<anti-action application="set" data="effective_caller_id_number=${msisdn}"/>
</condition>
</extension>
<!-- This extension continues to the actual call routing -->
<extension name="Route-Outbound-Call">
<condition field="${tas_destination_number}" expression="^(.+)$">
<action application="bridge" data="sofia/gateway/trunk/${tas_destination_number}"/>
</condition>
</extension>
Important Notes:
- Both methods can work simultaneously (prefix OR SIP header triggers blocking)
- The prefix is always stripped from the destination number, even if dialplan doesn't implement privacy
- The
cli_withheldvariable is a string ("true"or"false"), not a boolean - Call Forwarding / Blocked CLI behavior is implemented in your dialplan XML
- The example config includes these features, but if you do not define them in your dialplan, they will not function
- Variables are set during the MO (Mobile Originating) call flow only
How Call Forwarding Worksโ
Call forwarding (also known as Communication Diversion or CDIV) allows subscribers to redirect incoming calls to another destination. The TAS supports multiple types of call forwarding with configurable behavior.
Types of Call Forwardingโ
1. Call Forward All (CFA) - Unconditional Forwarding
- Variable:
call_forward_all_destination - When Active: All incoming calls are immediately forwarded
- Priority: Checked first (after HLR forwarding)
- Common Use: Subscriber wants all calls sent to another number
- Example: Business calls forwarded to personal phone
2. Call Forward Busy (CFB)
- When Active: Call forwarded when subscriber is already on a call
- SIP Response: 486 Busy triggers forwarding
- Common Use: Forward to voicemail when on another call
3. Call Forward No Reply (CFNRy)
- Variable:
no_reply_timer - When Active: Call forwarded after ringing for specified seconds with no answer
- Timeout: Typically 15-30 seconds
- Common Use: Forward to voicemail if not answered
4. Call Forward Not Reachable (CFNRc)
- Variable:
call_forward_not_reachable_destination - When Active: Subscriber is offline, unregistered, or unreachable
- SIP Response: 480 Temporarily Unavailable
- Common Use: Forward to voicemail when phone is off
- Default: Configuration parameter used if no MMTel-Config
Data Source Priorityโ
Call forwarding data is retrieved from multiple sources with this priority:
1. HLR Data (SS7 MAP) [Highest Priority - overrides all]
โ (if no HLR forwarding active)
2. MMTel-Config (Sh Interface) [Subscriber-specific settings from HSS]
โ (if no MMTel-Config returned)
3. Configuration Defaults [Lowest Priority - fallback values]
Why This Priority?
- HLR Data: Real-time forwarding status for roaming/network scenarios
- MMTel-Config: Subscriber-configured preferences in IMS
- Config Defaults: Network-wide fallback (typically voicemail)
Dialplan Variables for Call Forwardingโ
| Variable | Type | Source | Example Value | Description |
|---|---|---|---|---|
call_forward_all_destination | string | Sh/MMTel or "none" | "61403555123" | CFA destination if active |
call_forward_not_reachable_destination | string | Sh/MMTel or config | "2222" | CFNRc destination (voicemail) |
no_reply_timer | integer | Sh/MMTel or config | 30 | Seconds to ring before CFNRy |
msrn | string | HLR (MT only) | "61400123456" | MSRN or forwarded number from HLR |
tas_destination_number | string | Calculated | "2222" | Actual routing destination (may be forwarding number) |
Implementing Call Forwarding in Dialplanโ
Example MT Dialplan with Call Forwarding:
<!-- Check for Call Forward All (highest priority after HLR) -->
<extension name="Check-CFA" continue="true">
<condition field="${call_forward_all_destination}" expression="^(?!none$).+$">
<action application="log" data="INFO Call Forward All active to ${call_forward_all_destination}"/>
<action application="set" data="tas_destination_number=${call_forward_all_destination}"/>
</condition>
</extension>
<!-- Attempt to bridge to subscriber -->
<extension name="Bridge-To-Subscriber">
<condition field="${msrn}" expression="^none$">
<!-- No MSRN, route to local subscriber -->
<action application="set" data="call_timeout=${no_reply_timer}"/>
<action application="bridge" data="sofia/internal/${tas_destination_number}@${scscf_address}"/>
<!-- If bridge fails, check forwarding -->
<action application="log" data="INFO Bridge failed, checking call forwarding"/>
<!-- Call Forward Not Reachable -->
<action application="set" data="forward_destination=${call_forward_not_reachable_destination}"/>
<action application="log" data="INFO Forwarding to ${forward_destination}"/>
<action application="answer"/>
<action application="voicemail" data="default default ${msisdn}"/>
</condition>
</extension>
Configuring Default Call Forwardingโ
Set network-wide defaults in config/runtime.exs:
config :tas,
# Default CFNRc destination (used when no MMTel-Config)
call_forward_not_reachable_destination: "2222", # Voicemail access number
# Default timeout before CFNRy activates (used when no MMTel-Config)
default_no_reply_timer: 30 # Ring for 30 seconds
When Defaults Are Used:
- Subscriber exists in HSS but has no MMTel-Config provisioned
- Sh lookup succeeds but returns no call forwarding settings
- New subscribers before call forwarding is configured
Troubleshooting Call Forwardingโ
Problem: Calls not forwarding as expected
-
Check Sh Data:
- Use Web UI
/sh_testto query subscriber - Verify MMTel-Config contains CDIV rules
- Check
call_forward_all_destinationvalue
- Use Web UI
-
Check Dialplan Variables:
- Review call logs for variable values
- Confirm
call_forward_all_destination!="none" - Verify
tas_destination_numberis set to forwarding destination
-
Check HLR Data (if SS7 MAP enabled):
- Use Web UI
/hlrto query subscriber - HLR forwarding overrides Sh data
- Verify
msrnvariable doesn't contain unexpected forwarding number
- Use Web UI
-
Check Configuration Defaults:
- Verify
call_forward_not_reachable_destinationin config - Confirm
default_no_reply_timeris appropriate - These only apply when no MMTel-Config exists
- Verify
Problem: Forwarding loops
Symptoms: Call forwards to a number that forwards back, creating a loop
Prevention in Dialplan:
<!-- Track forwarding hop count -->
<extension name="Prevent-Forward-Loop" continue="true">
<condition field="${sip_h_X-Forward-Hop-Count}" expression="^$">
<action application="set" data="sip_h_X-Forward-Hop-Count=1"/>
<anti-action application="set" data="sip_h_X-Forward-Hop-Count=${expr(${sip_h_X-Forward-Hop-Count}+1)}"/>
</condition>
</extension>
<extension name="Check-Forward-Hop-Limit">
<condition field="${sip_h_X-Forward-Hop-Count}" expression="^([3-9]|[1-9][0-9]+)$">
<action application="log" data="ERROR Forwarding loop detected, hop count: ${sip_h_X-Forward-Hop-Count}"/>
<action application="hangup" data="LOOP_DETECTED"/>
</condition>
</extension>
Monitoring Call Forwardingโ
Key Indicators:
- High rate of calls to voicemail numbers
- Pattern of calls timing out at
no_reply_timervalue - Calls consistently routed to same forwarding destinations
Useful Logs:
INFO Call Forward All active to 61403555123
INFO Forwarding to 2222
INFO Bridge failed, checking call forwarding
Business Intelligence:
- Track forwarding activation rates by subscriber
- Monitor voicemail usage patterns
- Identify subscribers with unconditional forwarding