Mod skinny

From FreeSWITCH Wiki
Jump to: navigation, search

Synopsis

SCCP (or Skinny), is a ToIP protocol used in Cisco products like Cisco IP Phones 79xx.

For moreinfo, see Skinny Call Control Protocol on Wikipedia.

Table of Contents

Contents


Features

  • Features:
    • Incoming and outgoing calls (early media supported)
    • Shared lines and multiple calls per lines
    • CallInfo set as early as possible
    • New call made from: OffHook, Softkeys (Redial, NewCall), Stimulus (LastNumberRedial, VoiceMail, SpeedDial)
    • Answering calls via: OffHook, Softkeys (Answer)
    • Holding/Unholding calls via Softkeys (Hold, Resume) or Stimulus (Hold), with MOH (music on hold)
    • Transfer via Softkeys (Transfer) or Stimulus (Transfer). Blind transfer (with OnHook)
    • Ending call via: OnHook, Softkeys (EndCall)
    • Misc: SoftKeys (Backspace)
    • Handle firmware version request (VersionReqMessage) per device type or per device
    • Patterns for dialed numbers to process (patterns-dialplan and patterns-context)
    • Custom applications can be made using the API and events: See #Custom applications
  • Custom Events: See #Custom Events
  • API Commands: See #API Commands
  • Message Waiting indicator (MWI) on first line of each device
  • Working on x86 and x86_64


Missing features: mod_skinny/Development#TODO

Interop List

This list is incomplete, please add any tested SCCP phone.

Model DeviceTypeId Status
Cisco IP Phone 7910 6 OK(1)
Cisco IP Phone 7940 8 OK(2)
Cisco IP Phone 7960 7 OK(2)
Cisco IP Phone 7961 30018 OK
Cisco IP Phone 7975 437 OK
Nokia Call Connect 2.0  ? Not tested(3)

Footnotes:

  1. The six buttons (msgs, conf, forward, speed 1, speed 2 and redial) have button positions 5 to 10 respectively.
  2. Also tested with Cisco Unified IP Phone Expansion Module 7914: adds 14 definable buttons with working lights. Button number starts with 3 for the 7940 and 7 for the 7960.
  3. Mobile Business Solutions From Cisco and Nokia Downloads

"DeviceTypeId" can be found when issuing on CLI :

 skinny status profile internal device <your_device>

Building

There is no additional dependency needed to build mod_skinny. You just need to edit modules.conf (uncomment endpoints/mod_skinny) and run:

make mod_skinny

Don't forget to uncomment <load module="mod_skinny"/> in ~/freeswitch/conf/auto_configs/modules.conf.xml

Configuration

  • 192.168.0.2 is the IP of the TFTP server
  • 192.168.0.3 is the IP of the FreeSWITCH server (with mod_skinny)
  • SEP001120AABBCC is the phone id (based on the MAC address)
  • Voicemail/Messages is hardwired in code to dial extension "vmain".

DHCP and TFTP Configuration

This is widely discussed at voip-info.org (http://www.voip-info.org/wiki/view/Asterisk+phone+cisco+79xx), here is a quick overview.

DHCP

First, the phone get its IP and other network configs through DHCP.

The important setting is the tftp:

  • in udhcp (the most lightweight) , this is set in /etc/udhcpd.conf:
opt tftp 192.168.0.2
  • in ISC DHCP (widely used), this is set in /etc/dhcp3/dhcpd.conf:
option tftp-server-name 192.168.0.2;

TFTP

There are plenty of TFTP server implementations. In the root of the tftp directory (usually /srv/tftp), put the following files:

  • XMLDefault.cnf.xml
<Default>
    <callManagerGroup>
    <members>
        <member priority="0">
        <callManager>
            <ports>
            <ethernetPhonePort>2000</ethernetPhonePort>
            </ports>
            <processNodeName>192.168.0.3</processNodeName>
        </callManager>
        </member>
    </members>
    </callManagerGroup>
    <loadInformation30002 model="Cisco 7960">P00307010100</loadInformation30002>
</Default> 
  • SEP001120AABBCC.cnf.xml (minimal)
<device>
    <devicePool>
        <callManagerGroup>
        <members>
            <member  priority="0">
            <callManager>
                <ports>
                    <ethernetPhonePort>2000</ethernetPhonePort>
                </ports>
                <processNodeName>192.168.0.3</processNodeName>
            </callManager>
            </member>
        </members>
        </callManagerGroup>
    </devicePool>
</device>
  • SEP001120AABBCC.cnf.xml (extended)
<device>
    <devicePool>
        <callManagerGroup>
        <members>
            <member  priority="0">
            <callManager>
                <ports>
                    <ethernetPhonePort>2000</ethernetPhonePort>
                </ports>
                <processNodeName>192.168.0.3</processNodeName>
            </callManager>
            </member>
        </members>
        </callManagerGroup>
        <dateTimeSetting>
            <dateTemplate>M/D/YA</dateTemplate>
            <timeZone>Central Europe Standard/Daylight Time</timeZone>
        </dateTimeSetting>
    </devicePool>
    <versionStamp>{Jan 20 01 00:00:00}</versionStamp>
    <userLocale>
        <name>French_France</name>
        <uid>2</uid>
        <langCode>fr</langCode>
        <version>4.0(1)SR1FRA</version>
        <winCharSet>iso-8859-1</winCharSet>
    </userLocale>
    <networkLocale>France</networkLocale>
    <networkLocaleInfo>
        <name>France</name>
        <uid>14</uid>
        <version>4.0(1)SR1</version>
    </networkLocaleInfo>
    <idleTimeout>0</idleTimeout>
    <authenticationURL></authenticationURL>
    <directoryURL></directoryURL>
    <idleURL></idleURL>
    <informationURL></informationURL>
    <messagesURL></messagesURL>
    <proxyServerURL></proxyServerURL>
    <servicesURL></servicesURL>
</device>

Notes :

FreeSWITCH Configuration

The configuration is loaded from autolad_configs (nothing exciting here). Nothing to change here.

  • conf/autoload_configs/skinny.conf.xml:
<configuration name="skinny.conf" description="Skinny Profiles">
  <profiles>
    <X-PRE-PROCESS cmd="include" data="../skinny_profiles/*.xml"/>
  </profiles>
</configuration>

Profile Configurations

Each profile is put in conf/skinny_profiles. The default configuration should work without modifications.

  • conf/skinny_profiles/internal.xml
<profile name="internal">
  <settings>
    <param name="domain" value="$${domain}"/>
    <param name="ip" value="$${local_ip_v4}"/>
    <param name="port" value="2000"/>
    <param name="patterns-dialplan" value="XML"/>
    <param name="patterns-context" value="skinny-patterns"/>
    <param name="dialplan" value="XML"/>
    <param name="context" value="default"/>
    <param name="keep-alive" value="60"/>
    <param name="date-format" value="D/M/Y"/>
    <param name="odbc-dsn" value=""/>
    <param name="debug" value="4"/>
    <param name="auto-restart" value="true"/>
    <param name="ext-voicemail" value="vmain"/>
    <param name="ext-redial" value="redial"/>
  </settings>
  <soft-key-set-sets>
    <soft-key-set-set name="default">
      <soft-key-set name="KeySetOnHook" value="SoftkeyNewcall,SoftkeyRedial"/>
      <soft-key-set name="KeySetConnected" value="SoftkeyEndcall,SoftkeyHold,SoftkeyNewcall,SoftkeyTransfer"/>
      <soft-key-set name="KeySetOnHold" value="SoftkeyNewcall,SoftkeyResume,SoftkeyEndcall"/>
      <soft-key-set name="KeySetRingIn" value="SoftkeyAnswer,SoftkeyEndcall,SoftkeyNewcall"/>
      <soft-key-set name="KeySetOffHook" value=",SoftkeyRedial,SoftkeyEndcall"/>
      <soft-key-set name="KeySetConnectedWithTransfer" value="SoftkeyEndcall,SoftkeyHold,SoftkeyNewcall,SoftkeyTransfer"/>
      <soft-key-set name="KeySetDigitsAfterDialingFirstDigit" value="SoftkeyBackspace,,SoftkeyEndcall"/>
      <!-- <soft-key-set name="KeySetConnectedWithConference" value=""/> -->
      <soft-key-set name="KeySetRingOut" value=",,SoftkeyEndcall,SoftkeyTransfer"/>
      <soft-key-set name="KeySetOffHookWithFeatures" value=",SoftkeyRedial,SoftkeyEndcall"/>
      <soft-key-set name="KeySetInUseHint" value="SoftkeyNewcall,SoftkeyRedial"/>
    </soft-key-set-set>
  </soft-key-set-sets>
  <device-types>
    <device-type id="Cisco ATA 186">
        <param name="firmware-version" value="ATA030101SCCP04"/>
    </device-type>
  </device-types>
</profile>

NB :

  • if ip="", mod_skinny will listen on all IP addresses. Il you want to force IPv6, use ip="::"
  • mod_skinny logs a lot under [DEBUG]: Every skinny message received or sent. keepAlive and keepAliveAck messages are only logged if profile's debug is >=10.
  • when issuing a reloadxml, those values are not reloaded. Use skinny profile <profile_name> set <name> <value> instead.
  • You mostly don't have to bother about firmware-versions unless your phone ask it through skinny (most Cisco phones use XML files from tftp). If you have missed one, mod_skinny will complain in the log:
[DEBUG] skinny_server.c:1501 Device SEP001120AABBCC:0 is requesting for firmware version, but none is set.
  • The auto-restart param is used when network interface ip changes. If set to true, the socket will be closed (including all connected listeners) and reopened on the new IP.

Device Configuration

Devices are set up as users in directory. The critical parameter here is id, which corresponds to the MAC address.

  • conf/directory/default/skinny-example.xml
<include>
 <user id="SEP001120AABBCC">
   <params>
    <!-- for devices requesting firmware via SCCP, like ATA186
    <param name="skinny-firmware-version" value="ATA030101SCCP04"
    <param name="skinny-soft-key-set-set" value="default"
    -->
    <param name="foo" value="bar"/>
   </params>
   <skinny>
    <buttons>
      <!--
      position: 1..
      type: one of line, speed-dial
      label: button label
      -->
      <!--
      value is the directory number (or user)
      caller-name is shown to the calling party during call
      -->
      <button position="1" type="Line" label="Line 1" value="1101" caller-name="Calling as 1101"/>
      <button position="3" type="Line" label="Shared Line 10" value="1110" caller-name="Calling as 1110"/>
      <!--
      value is the directory number to call
      -->
      <button position="5" type="SpeedDial" label="Call 1001" value="1001"/>
      <!--
      value is the URL
      -->
      <button position="6" type="ServiceUrl" label="Some URL" value="http://phone-xml.berbee.com/menu.xml"/>
    </buttons>
   </skinny>
  </user>
</include>

More information on ServiceUrls at http://www.voip-info.org/wiki/view/Asterisk+Cisco+79XX+XML+Services

Patterns Dialplan configuration

This dialplan is used when calling from a skinny phone. Default configuration will allow you to call SIP phones and some tests like the tetris one (9998).

As all the call process is made on the server, we need a way to know how many digits are necessary to route the call. Executing the dialplan each time a digit is pressed is not correct. An other dialplan context is used to simply say what mod_skinny should do:

  • conf/dialplan/skinny-patterns.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
    NOTICE:

    This context is used for skinny to match dialed number

    The special applications:
    - skinny-process tells skinny to process the call (route, set call forwarding, ...)
    - skinny-drop tells skinny to drop the call
    - skinny-wait tells skinny to wait for more digits
-->
<!-- http://wiki.freeswitch.org/wiki/Mod_skinny -->
<include>
  <context name="skinny-patterns">
    <!--
    Wait for another digit by default
    -->
    <extension name="Default">
      <condition>
        <action application="skinny-wait" />
      </condition>
    </extension>

    <!--
	You can place files in the skinny-patterns directory to get included.
    -->
    <X-PRE-PROCESS cmd="include" data="skinny-patterns/*.xml"/>
    
  </context>
</include>

You can select the diaplan context by setting patterns-dialplan and patterns-context in the skinny profile configuration.

Dialplan configuration

This dialplan snippet is necessary when you need to call a skinny phone. Without this, you will not be able to call your skinny phones!

Add something like this to conf/dialplan/default.xml (Example with 11xx):

    <extension name="Local_Extension_Skinny">
      <condition field="destination_number" expression="^(11[01][0-9])$">
        <action application="bridge" data="skinny/internal/${destination_number}"/>
      </condition>
    </extension>

Outgoing Channel Syntax

Basic form:

skinny/<profile>/<number>

API Commands

Note: most of the command arguments can be auto completed on CLI by using tab (for example <ring_type>).

USAGE:
--------------------------------------------------------------------------------
skinny help
skinny status profile <profile_name>
skinny status profile <profile_name> device <device_name>
skinny profile <profile_name> device <device_name> send ResetMessage [DeviceReset|DeviceRestart]
skinny profile <profile_name> device <device_name> send SetRingerMessage <ring_type> <ring_mode>
skinny profile <profile_name> device <device_name> send SetLampMessage <stimulus> <instance> <lamp_mode>
skinny profile <profile_name> device <device_name> send SetSpeakerModeMessage <speaker_mode>
skinny profile <profile_name> device <device_name> send CallStateMessage <call_state> <line_instance> <call_id>
skinny profile <profile_name> device <device_name> send <UserToDeviceDataMessage|UserToDeviceDataVersion1Message> [ <param>=<value>;... ] <data>
skinny profile <profile_name> set <name> <value>
--------------------------------------------------------------------------------

(More TODO)

Custom Events

skinny::register

Event-Subclass: skinny%3A%3Aregister
Event-Name: CUSTOM
Core-UUID: 1f9d861e-e5cc-4b5c-b32d-9a7a1dd0b540
FreeSWITCH-Hostname: netthieu
FreeSWITCH-IPv4: 192.168.0.3
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-09-24%2002%3A19%3A16
Event-Date-GMT: Fri,%2024%20Sep%202010%2000%3A19%3A16%20GMT
Event-Date-Timestamp: 1285287556518629
Event-Calling-File: skinny_protocol.c
Event-Calling-Function: skinny_device_event
Event-Calling-Line-Number: 224
Skinny-Profile-Name: internal
Skinny-Device-Name: SEP001120AABBCC
Skinny-Station-User-Id: 0
Skinny-Station-Instance: 0
Skinny-IP-Address: 192.168.0.4
Skinny-Device-Type: 30018
Skinny-Max-Streams: 5
Skinny-Port: (null)
Skinny-Codecs: _undef_

skinny::unregister

Event-Subclass: skinny%3A%3Aunregister
Event-Name: CUSTOM
Core-UUID: 1f9d861e-e5cc-4b5c-b32d-9a7a1dd0b540
FreeSWITCH-Hostname: netthieu
FreeSWITCH-IPv4: 192.168.0.3
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-09-24%2002%3A18%3A39
Event-Date-GMT: Fri,%2024%20Sep%202010%2000%3A18%3A39%20GMT
Event-Date-Timestamp: 1285287519036825
Event-Calling-File: skinny_protocol.c
Event-Calling-Function: skinny_device_event
Event-Calling-Line-Number: 224
Skinny-Profile-Name: internal
Skinny-Device-Name: SEP001120AABBCC
Skinny-Station-User-Id: 0
Skinny-Station-Instance: 0
Skinny-IP-Address: 192.168.0.4
Skinny-Device-Type: 30018
Skinny-Max-Streams: 5
Skinny-Port: 3500
Skinny-Codecs: WIDEBAND,ULAW,ALAW,G729,G729,G729,G729,RFC2833_DYNPAYLOAD

skinny::expire

skinny::alarm

Event-Subclass: skinny%3A%3Aalarm
Event-Name: CUSTOM
Core-UUID: 1f9d861e-e5cc-4b5c-b32d-9a7a1dd0b540
FreeSWITCH-Hostname: netthieu
FreeSWITCH-IPv4: 192.168.0.3
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-09-24%2002%3A19%3A16
Event-Date-GMT: Fri,%2024%20Sep%202010%2000%3A19%3A16%20GMT
Event-Date-Timestamp: 1285287556312672
Event-Calling-File: skinny_protocol.c
Event-Calling-Function: skinny_device_event
Event-Calling-Line-Number: 224
Skinny-Alarm-Severity: 2
Skinny-Alarm-DisplayMessage: 22%3A%20Nom%SEP001120AABBCC%20Image%3D%20SCCP41.8-3-1S%20Dernier%3DR%E9init.-R%E9init.
Skinny-Alarm-Param1: 0
Skinny-Alarm-Param2: 0

skinny::call_state

this is for internal use and might change in the future.

skinny::user_to_device

Event-Subclass: skinny%3A%3Auser_to_device
Event-Name: CUSTOM
Core-UUID: 1f9d861e-e5cc-4b5c-b32d-9a7a1dd0b540
FreeSWITCH-Hostname: netthieu
FreeSWITCH-IPv4: 192.168.0.3
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-09-24%2002%3A10%3A01
Event-Date-GMT: Fri,%2024%20Sep%202010%2000%3A10%3A01%20GMT
Event-Date-Timestamp: 1285287001570252
Event-Calling-File: skinny_protocol.c
Event-Calling-Function: skinny_device_event
Event-Calling-Line-Number: 224
Skinny-Profile-Name: internal
Skinny-Device-Name: SEP001120AABBCC
Skinny-Station-User-Id: 0
Skinny-Station-Instance: 0
Skinny-IP-Address: 192.168.0.4
Skinny-Device-Type: 30018
Skinny-Max-Streams: 5
Skinny-Port: 3500
Skinny-Codecs: WIDEBAND,ULAW,ALAW,G729,G729,G729,G729,RFC2833_DYNPAYLOAD
Skinny-UserToDevice-Message-Id-String: UserToDeviceDataVersion1Message
Skinny-UserToDevice-sequence-flag: 2
Content-Length: 111

<CiscoIPPhoneText><Title>Hello</Title><Prompt>Amazing</Prompt><Text>This is some text</Text></CiscoIPPhoneText>

skinny::device_to_user

Event-Subclass: skinny%3A%3Adevice_to_user
Event-Name: CUSTOM
Core-UUID: 1f9d861e-e5cc-4b5c-b32d-9a7a1dd0b540
FreeSWITCH-Hostname: netthieu
FreeSWITCH-IPv4: 192.168.0.3
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-09-24%2002%3A10%3A01
Event-Date-GMT: Fri,%2024%20Sep%202010%2000%3A10%3A01%20GMT
Event-Date-Timestamp: 1285287001696990
Event-Calling-File: skinny_protocol.c
Event-Calling-Function: skinny_device_event
Event-Calling-Line-Number: 224
Skinny-Profile-Name: internal
Skinny-Device-Name: SEP001120AABBCC
Skinny-Station-User-Id: 0
Skinny-Station-Instance: 0
Skinny-IP-Address: 192.168.0.4
Skinny-Device-Type: 30018
Skinny-Max-Streams: 5
Skinny-Port: 3500
Skinny-Codecs: WIDEBAND,ULAW,ALAW,G729,G729,G729,G729,RFC2833_DYNPAYLOAD
Skinny-DeviceToUser-Message-Id: 66
Skinny-DeviceToUser-Message-Id-String: DeviceToUserDataResponseVersion1Message
Skinny-DeviceToUser-Application-Id: 0
Skinny-DeviceToUser-Line-Instance: 0
Skinny-DeviceToUser-Call-Id: 0
Skinny-DeviceToUser-Transaction-Id: 0
Skinny-DeviceToUser-Data-Length: 172
Skinny-DeviceToUser-Sequence-Flag: 2
Skinny-DeviceToUser-Display-Priority: 0
Skinny-DeviceToUser-Conference-Id: 0
Skinny-DeviceToUser-App-Instance-Id: 0
Skinny-DeviceToUser-Routing-Id: 0
Content-Length: 171

<?xml version="1.0" encoding="iso8859-1"?>
<CiscoIPPhoneResponse>
<ResponseItem URL="cip.xml.XmlTextObject@e771b" Data="SUCCESS" Status="0" />
</CiscoIPPhoneResponse>

skinny::xml_alarm

Event-Subclass: skinny%3A%3Axml_alarm
Event-Name: CUSTOM
Core-UUID: a4aaa78c-9cfe-4e15-abb8-52e222a361d8
FreeSWITCH-Hostname: servthieu
FreeSWITCH-IPv4: 192.168.0.3
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-12-19%2022%3A10%3A43
Event-Date-GMT: Sun,%2019%20Dec%202010%2021%3A10%3A43%20GMT
Event-Date-Timestamp: 1292793043629627
Event-Calling-File: skinny_protocol.c
Event-Calling-Function: skinny_device_event
Event-Calling-Line-Number: 224
Content-Length: 1232

<?xml version="1.0" encoding="UTF-8"?>
<x-cisco-alarm>
<Alarm Name="LastOutOfServiceInformation">
<ParameterList>
<String name="DeviceName">SEP001120AABBCC</String>
<String name="DeviceIPv4Address">192.168.0.4</String>
<String name="IPv4DefaultGateway">192.168.0.254</String>
<String name="DeviceIPv6Address"></String>
<String name="IPv6DefaultGateway"></String>
<String name="ModelNumber">CP-7961G</String>
<String name="NeighborIPv4Address">192.168.0.253</String>
<String name="NeighborIPv6Address"></String>
<String name="NeighborDeviceID">sw2.local</String>
<String name="NeighborPortID">3</String>
<Enum name="DHCPv4Status">1</Enum>
<Enum name="DHCPv6Status">0</Enum>
<Enum name="TFTPCfgStatus">0</Enum>
<Enum name="DNSStatusUnifiedCM1">0</Enum>
<Enum name="DNSStatusUnifiedCM2">0</Enum>
<Enum name="DNSStatusUnifiedCM3">0</Enum>
<String name="VoiceVLAN">4095</String>
<String name="UnifiedCMIPAddress"><not open></String>
<String name="LocalPort">-1</String>
<String name="TimeStamp">1289313813826</String>
<Enum name="ReasonForOutOfService"></Enum>
<String name="LastProtocolEventSent">1:Register</String>
<String name="LastProtocolEventReceived">129:RegisterAck</String>
</ParameterList>
</Alarm>
</x-cisco-alarm>

More

If you want one more, file a bug.

Custom applications

If you want to write a custom application, you can control the phone by using the API. For example:

skinny profile internal device SEP001120AABBCC send UserToDeviceDataVersion1Message sequence-flag=2 '<CiscoIPPhoneText><Title>Hello</Title><Prompt>Amazing</Prompt><Text>This is some text</Text></CiscoIPPhoneText>'

You can also register to event skinny::device_to_user (and others).

Related documentation:

Example implementations :

Development

See mod_skinny/Development.