diff --git a/dia/diameter_3gpp_ts29_229.dia b/dia/diameter_3gpp_ts29_229.dia index efaa147..557fed7 100644 --- a/dia/diameter_3gpp_ts29_229.dia +++ b/dia/diameter_3gpp_ts29_229.dia @@ -24,6 +24,8 @@ @vendor 10415 3GPP @inherits diameter_gen_base_rfc6733 +@inherits diameter_etsi_es283_035 +@inherits diameter_rfc4005_nasreq ;; only attributes required by other applications are defined @@ -32,7 +34,7 @@ Visited-Network-Identifier 600 OctetString MV Public-Identity 601 UTF8String MV Server-Name 602 UTF8String MV -;; Server-Capabilities 603 Grouped MV + Server-Capabilities 603 Grouped MV Mandatory-Capability 604 Unsigned32 MV Optional-Capability 605 Unsigned32 MV User-Data 606 OctetString MV @@ -41,10 +43,10 @@ SIP-Authenticate 609 OctetString MV SIP-Authorization 610 OctetString MV SIP-Authentication-Context 611 OctetString MV -;; SIP-Auth-Data-Item 612 Grouped MV + SIP-Auth-Data-Item 612 Grouped MV SIP-Item-Number 613 Unsigned32 MV Server-Assignment-Type 614 Enumerated MV -;; Deregistration-Reason 615 Grouped MV + Deregistration-Reason 615 Grouped MV Reason-Code 616 Enumerated MV Reason-Info 617 UTF8String MV Charging-Information 618 Grouped MV @@ -60,38 +62,50 @@ Feature-List-ID 629 Unsigned32 V Feature-List 630 Unsigned32 V Supported-Applications 631 Grouped V -;; Associated-Identities 632 Grouped V + Associated-Identities 632 Grouped V Originating-Request 633 Enumerated MV Wildcarded-Public-Identity 634 UTF8String V -;; SIP-Digest-Authenticate 635 Grouped V + SIP-Digest-Authenticate 635 Grouped V Digest-Realm 104 UTF8String M ;; RFC-4590 Digest-Algorithm 111 UTF8String M ;; RFC-4590 Digest-QoP 110 UTF8String M ;; RFC-4590 Digest-HA1 121 UTF8String M ;; RFC-4590 UAR-Flags 637 Unsigned32 V Loose-Route-Indication 638 Enumerated V -;; SCSCF-Restoration-Info 639 Grouped V + SCSCF-Restoration-Info 639 Grouped V Path 640 OctetString V Contact 641 OctetString V -;; Subscription-Info 642 Grouped V + Subscription-Info 642 Grouped V Call-ID-SIP-Header 643 OctetString V From-SIP-Header 644 OctetString V To-SIP-Header 645 OctetString V Record-Route 646 OctetString V -;; Associated-Registered-Identities 647 Grouped V + Associated-Registered-Identities 647 Grouped V Multiple-Registration-Indication 648 Enumerated V -;; Restoration-Info 649 Grouped V + Restoration-Info 649 Grouped V Session-Priority 650 Enumerated V -;; Identity-with-Emergency-Registration 651 Grouped V + Identity-with-Emergency-Registration 651 Grouped V Priviledged-Sender-Indication 652 Enumerated V LIA-Flags 653 Unsigned32 V ;; OC-Supported-Features TBD Grouped - ;; IETF draft-ietf-dime-02 ;; OC-OLR TBD Grouped - ;; IETF draft-ietf-dime-02 Initial-CSeq-Sequence-Number 654 Unsigned32 V SAR-Flags 655 Unsigned32 V + Allowed-WAF-WWSF-Identities 656 Grouped V + RTR-Flags 659 Unsigned32 V + P-CSCF-Subscription-Info 660 Grouped V + Registration-Time-Out 661 Time V + PCSCF-FQDN 665 DiameterIdentity V @grouped +;; 6.3.4 Server-Capabilities AVP + Server-Capabilities ::= + *[Mandatory-Capability] + *[Optional-Capability] + *[Server-Name] + *[AVP] + Charging-Information ::= < AVP Header : 618 > [ Primary-Event-Charging-Function-Name ] [ Secondary-Event-Charging-Function-Name ] @@ -110,3 +124,109 @@ *[ Acct-Application-Id ] *[ Vendor-Specific-Application-Id ] *[ AVP ] + +;; 6.3.13 + SIP-Auth-Data-Item ::= < AVP Header: 612 10415 > + [ SIP-Item-Number ] + [ SIP-Authentication-Scheme ] + [ SIP-Authenticate ] + [ SIP-Authorization ] + [ SIP-Authentication-Context ] + [ Confidentiality-Key ] + [ Integrity-Key ] + [ SIP-Digest-Authenticate ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Framed-Interface-Id ] + *[ Line-Identifier ] + *[AVP] + +;; 6.3.16 + Deregistration-Reason ::= < AVP Header: 615 10415 > + { Reason-Code } + [ Reason-Info ] + * [AVP] + +;; 6.3.33 Associated-Identities + Associated-Identities ::= < AVP Header: 632 10415 > + *[ User-Name ] + *[ AVP ] + +;; 6.3.36 + SIP-Digest-Authenticate ::= < AVP Header: 635 10415> + { Digest-Realm } + { Digest-QoP } + { Digest-HA1} + [ Digest-Algorithm ] + *[ AVP ] + +;; 6.3.46 SCSCF-Restoration-Info AVP + SCSCF-Restoration-Info ::= < AVP Header: 639 10415> + { User-Name } + 1* { Restoration-Info } + [ Registration-Time-Out ] + [ SIP-Authentication-Scheme ] + *[ AVP ] + +;; 6.3.49 Subscription-Info AVP + Subscription-Info ::= < AVP Header: 642 10415> + { Call-ID-SIP-Header } + { From-SIP-Header } + { To-SIP-Header } + { Record-Route } + {Contact} + *[ AVP ] + +;; 6.3.50 Associated-Registered-Identities +Associated-Registered-Identities ::= < AVP Header: 647 10415 > + *[ User-Name ] + *[ AVP ] + +;; 6.3.52 Restoration-Info AVP + Restoration-Info ::= < AVP Header: 649 10415> + { Path } + { Contact } + [ Initial-CSeq-Sequence-Number ] + [ Call-ID-SIP-Header ] + [ Subscription-Info ] + [ P-CSCF-Subscription-Info ] + *[ AVP ] + +;; 6.3.57 Identity-with-Emergency-Registration + Identity-with-Emergency-Registration ::= < AVP Header: 651 10415 > + { User-Name } + { Public-Identity } + *[ AVP ] + +;; 6.3.64 Allowed-WAF-WWSF-Identities AVP + Allowed-WAF-WWSF-Identities ::= < AVP Header: 656 10415 > + ;; *[ WebRTC-Authentication-Function-Name ] + ;; *[ WebRTC-Web-Server-Function-Name ] + *[ AVP] + +;; 6.3.70 P-CSCF-Subscription-Info AVP + P-CSCF-Subscription-Info ::= < AVP Header: 660 10415> + { Call-ID-SIP-Header } + { From-SIP-Header } + { To-SIP-Header } + { Contact } + *[ AVP ] + +;; 6.3.15 +@enum Server-Assignment-Type + NO_ASSIGNMENT 0 + REGISTRATION 1 + RE_REGISTRATION 2 + UNREGISTERED_USER 3 + TIMEOUT_DEREGISTRATION 4 + USER_DEREGISTRATION 5 + TIMEOUT_DEREGISTRATION_STORE_SERVER_NAME 6 + USER_DEREGISTRATION_STORE_SERVER_NAME 7 + ADMINISTRATIVE_DEREGISTRATION 8 + AUTHENTICATION_FAILURE 9 + AUTHENTICATION_TIMEOUT 10 + DEREGISTRATION_TOO_MUCH_DATA 11 + AAA_USER_DATA_REQUEST 12 + PGW_UPDATE 13 + RESTORATION 14 + diff --git a/dia/diameter_3gpp_ts29_229_cx.dia b/dia/diameter_3gpp_ts29_229_cx.dia new file mode 100644 index 0000000..2f0fc7b --- /dev/null +++ b/dia/diameter_3gpp_ts29_229_cx.dia @@ -0,0 +1,326 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright (C) 2023 by Alexander Couzens +;; +;; This resembles 3GPP TS 29.272 version 17.2.0 Release 17 +;; +;; Licensed under the Apache License, Version 2.0 (the "License"); +;; you may not use this file except in compliance with the License. +;; You may obtain a copy of the License at +;; +;; http://www.apache.org/licenses/LICENSE-2.0 +;; +;; Unless required by applicable law or agreed to in writing, software +;; distributed under the License is distributed on an "AS IS" BASIS, +;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;; See the License for the specific language governing permissions and +;; limitations under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; Edits: +;; +;; + + +@id 16777216 +@name diameter_3gpp_ts29_229_cx +@vendor 10415 3GPP + +@inherits diameter_gen_base_rfc6733 +@inherits diameter_3gpp_base +@inherits diameter_3gpp_break_circles +@inherits diameter_3gpp_ts29_212 +@inherits diameter_3gpp_ts29_214 +@inherits diameter_3gpp_ts29_229 +@inherits diameter_3gpp_ts29_272 +@inherits diameter_3gpp_ts32_299 +@inherits diameter_etsi_es283_034 +@inherits diameter_rfc4006_cc +@inherits diameter_rfc5447 +@inherits diameter_rfc5778 +@inherits diameter_rfc7683 +@inherits diameter_rfc7944 +@inherits diameter_rfc8583 + +@avp_types + + ;; 6.3.74 + Failed-PCSCF 664 Grouped MV + ;; 6.3.76 + PCSCF-IP-Address 666 Address V + ;; 6.3.16 + +@grouped +Failed-PCSCF ::= < AVP Header: 664> + [ PCSCF-FQDN ] + *[ PCSCF-IP-Address ] + *[ AVP ] + + + +@messages + +;; 6.1.1 User-Authorization-Request (UAR) Command + UAR ::= < Diameter Header: 300, REQ, PXY > + < Session-Id > + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { User-Name } + { Vendor-Specific-Application-Id } + { Public-Identity } + { Visited-Network-Identifier } + [ Destination-Host ] + [ DRMP ] + [ OC-Supported-Features ] + * [ Supported-Features ] + [ User-Authorization-Type ] + [ UAR-Flags ] + * [ AVP ] + * [ Proxy-Info ] + * [ Route-Record ] + +;; 6.1.2 User-Authorization-Answer (UAA) Command + UAA ::= < Diameter Header: 300, PXY > + < Session-Id > + { Vendor-Specific-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ DRMP ] + [ Result-Code ] + [ Experimental-Result ] + [ OC-Supported-Features ] + [ OC-OLR ] + * [ Load ] + * [ Supported-Features ] + [ Server-Name ] + [ Server-Capabilities ] + * [ AVP ] + [ Failed-AVP ] + * [ Proxy-Info ] + * [ Route-Record ] + +;; 6.1.3 Server-Assignment-Request (SAR) Command + SAR ::= < Diameter Header: 301, REQ, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Server-Name } + { Server-Assignment-Type } + { User-Data-Already-Available } + [ DRMP ] + [ Destination-Host ] + [ User-Name ] + [ OC-Supported-Features ] + *[ Supported-Features ] + *[ Public-Identity ] + [ Wildcarded-Public-Identity ] + [ SCSCF-Restoration-Info ] + [ Multiple-Registration-Indication ] + [ Session-Priority ] + [ SAR-Flags ] + [ Failed-PCSCF ] + *[ AVP ] + *[ Proxy-Info ] + *[ Route-Record ] + + +;; 6.1.4 Server-Assignment-Answer (SAA) Command + SAA ::= < Diameter Header: 301, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { Origin-Realm } + { Origin-Host } + { Auth-Session-State } + [ Wildcarded-Public-Identity ] + [ User-Name ] + [ User-Data ] + [ Server-Name ] + [ Result-Code ] + [ Priviledged-Sender-Indication ] + [ OC-Supported-Features ] + [ OC-OLR ] + [ Loose-Route-Indication ] + [ Failed-AVP ] + [ Experimental-Result ] + [ DRMP ] + [ Charging-Information ] + [ Associated-Registered-Identities ] + [ Associated-Identities ] + [ Allowed-WAF-WWSF-Identities ] + *[ Supported-Features ] + *[ SCSCF-Restoration-Info ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ Load ] + *[ AVP ] + +;; 6.1.5 Location-Info-Request (LIR) Command + LIR ::= < Diameter Header: 302, REQ, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { Public-Identity } + { Origin-Realm } + { Origin-Host } + { Destination-Realm } + { Auth-Session-State } + [ User-Authorization-Type ] + [ Session-Priority ] + [ Originating-Request ] + [ OC-Supported-Features ] + [ Destination-Host ] + [ DRMP ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ AVP ] + + +;; 6.1.6 Location-Info-Answer (LIA) Command + LAI ::= < Diameter Header: 302, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { Origin-Realm } + { Origin-Host } + { Auth-Session-State } + [ Wildcarded-Public-Identity ] + [ Server-Name ] + [ Server-Capabilities ] + [ Result-Code ] + [ OC-Supported-Features ] + [ OC-OLR ] + [ LIA-Flags ] + [ Failed-AVP ] + [ Experimental-Result ] + [ DRMP ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ Load ] + *[ AVP ] + +;; 6.1.7 Multimedia-Auth-Request (MAR) Command + MAR ::= < Diameter Header: 303, REQ, PXY > + < Session-Id > + { Vendor-Specific-Application-Id } + { User-Name } + { Server-Name } + { SIP-Number-Auth-Items } + { SIP-Auth-Data-Item } + { Public-Identity } + { Origin-Realm } + { Origin-Host } + { Destination-Realm } + { Auth-Session-State } + [ OC-Supported-Features ] + [ Destination-Host ] + [ DRMP ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ AVP ] + +;; 6.1.8 Multimedia-Auth-Answer (MAA) Command + MAA ::= < Diameter Header: 303, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { Origin-Realm } + { Origin-Host } + { Auth-Session-State } + [ User-Name ] + [ SIP-Number-Auth-Items ] + [ Result-Code ] + [ Public-Identity ] + [ OC-Supported-Features ] + [ OC-OLR ] + [ Failed-AVP ] + [ Experimental-Result ] + [ DRMP ] + *[SIP-Auth-Data-Item ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ Load ] + *[ AVP ] + +;; 6.1.9 Registration-Termination-Request (RTR) Command + RTR ::= < Diameter Header: 304, REQ, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { User-Name } + { Origin-Realm } + { Origin-Host } + { Destination-Realm } + { Deregistration-Reason } + { Auth-Session-State } + [ RTR-Flags ] + [ DRMP ] + [ Associated-Identities ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Public-Identity ] + *[ Proxy-Info ] + *[ AVP ] + +;; 6.1.10 Registration-Termination-Answer (RTA) Command + RTA ::= < Diameter Header: 304, PXY > + < Session-Id > + { Vendor-Specific-Application-Id } + { Origin-Realm } + { Origin-Host } + { Auth-Session-State } + [ Result-Code ] + [ Failed-AVP ] + [ Experimental-Result ] + [ DRMP ] + [ Associated-Identities ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ Identity-with-Emergency-Registration ] + *[ AVP ] + +;; 6.1.11 Push-Profile-Request (PPR) Command + PPR ::= < Diameter Header: 305, REQ, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { User-Name } + { Origin-Realm } + { Origin-Host } + { Destination-Realm } + { Destination-Host } + { Auth-Session-State } + [ User-Data ] + [ SIP-Auth-Data-Item ] + [ DRMP ] + [ Charging-Information ] + [ Allowed-WAF-WWSF-Identities ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ AVP ] + +;; 6.1.12 Push-Profile-Answer (PPA) Command + PAA::= < Diameter Header: 305, PXY> + < Session-Id > + { Vendor-Specific-Application-Id } + { Origin-Realm } + { Origin-Host } + { Auth-Session-State } + [Result-Code ] + [ Failed-AVP ] + [ Experimental-Result ] + [ DRMP ] + *[ Supported-Features ] + *[ Route-Record ] + *[ Proxy-Info ] + *[ AVP ] diff --git a/dia/diameter_etsi_es283_035.dia b/dia/diameter_etsi_es283_035.dia new file mode 100644 index 0000000..c0baff2 --- /dev/null +++ b/dia/diameter_etsi_es283_035.dia @@ -0,0 +1,75 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright (C) 2023 by sysmocom - s.f.m.c. GmbH +;; Author: Alexander Couzens +;; +;; This resembles 3GPP TS 29.273 version 15.4.0 Release 15 +;; +;; Licensed under the Apache License, Version 2.0 (the "License"); +;; you may not use this file except in compliance with the License. +;; You may obtain a copy of the License at +;; +;; http://www.apache.org/licenses/LICENSE-2.0 +;; +;; Unless required by applicable law or agreed to in writing, software +;; distributed under the License is distributed on an "AS IS" BASIS, +;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;; See the License for the specific language governing permissions and +;; limitations under the License. +;; +;; %CopyrightEnd% +;; + +@id 16777231 +@name diameter_etsi_es283_035 +@prefix diameter_e4 +@vendor 13019 ETSI + +@inherits diameter_gen_base_rfc6733 + +;; only attributes required by other applications are defined + +@avp_types + + Location-Information 350 Grouped V ;; 7.3.1 + Policy-Control-Contact-Point 351 DiameterIdentity V ;; 7.3.2 + Terminal-Type 352 OctetString V ;; 7.3.3 + Requested-Information 353 Enumerated V ;; 7.3.4 + Event-Type 354 Enumerated V ;; 7.3.6 + Line-Identifier 500 OctetString V ;; 7.3.5 + Civic-Location 355 OctetString V ;; 7.3.1.A + Geospatial-Location 356 OctetString V ;; 7.3.1.B + +@grouped +;; 7.3.1 + Location-Information ::= < AVP Header: 350 13019 > + [Line-Identifier] + [Civic-Location] + [Geospatial-Location] + *[AVP] + +;; 7.3.4 +@enum Requested-Information + IP-CONNECTIVITY-USER-ID 0 + LOCATION-INFORMATION 1 + POLICY-CONTROL-CONTACT-POINT 2 + ACCESS-NETWORK-TYPE 3 + TERMINAL-TYPE 4 + LOGICAL-ACCESS-ID 5 + PHYSICAL-ACCESS-ID 6 + +;; 7.3.6 +@enum Event-Type + USER-LOGON 0 + LOCATION-INFORMATION-CHANGED 1 + POLICY-CONTROL-CONTACT-POINT-CHANGED 2 + ACCESS-NETWORK-TYPE-CHANGED 3 + TERMINAL-TYPE-CHANGED 4 + LOGICAL-ACCESS-ID-CHANGED 5 + PHYSICAL-ACCESS-ID-CHANGED 6 + IP-ADDRESS-CHANGED 7 + INITIAL-GATE-SETTING-CHANGED 8 + QOS-PROFILE-CHANGED 9 + USER-LOGOFF 10 + diff --git a/dia/diameter_rfc4740.dia b/dia/diameter_rfc4740.dia new file mode 100644 index 0000000..5515cb7 --- /dev/null +++ b/dia/diameter_rfc4740.dia @@ -0,0 +1,42 @@ +;; +;; %CopyrightBegin% +;; +;; Transcribed from RFC 4740 by Alexander Couzens +;; +;; Licensed under the Apache License, Version 2.0 (the "License"); +;; you may not use this file except in compliance with the License. +;; You may obtain a copy of the License at +;; +;; http://www.apache.org/licenses/LICENSE-2.0 +;; +;; Unless required by applicable law or agreed to in writing, software +;; distributed under the License is distributed on an "AS IS" BASIS, +;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;; See the License for the specific language governing permissions and +;; limitations under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4740, Diameter Session Initiation Protocol (SIP) Application +;; + +@id 1 + +@inherits diameter_gen_base_rfc6733 + +;; =========================================================================== + +@avp_types + + ERP-RK-Request 618 Grouped - + ERP-Realm 619 DiameterIdentity - + +;; =========================================================================== + +@grouped + +ERP-RK-Request ::= < AVP Header: 618 > + { ERP-Realm } + * [ AVP ] diff --git a/dia/diameter_rfc8583.dia b/dia/diameter_rfc8583.dia new file mode 100644 index 0000000..59df542 --- /dev/null +++ b/dia/diameter_rfc8583.dia @@ -0,0 +1,54 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright (C) 2023 by sysmocom - s.f.m.c. GmbH +;; Author: Alexander Couzens +;; +;; This resembles 3GPP TS 29.273 version 15.4.0 Release 15 +;; +;; Licensed under the Apache License, Version 2.0 (the "License"); +;; you may not use this file except in compliance with the License. +;; You may obtain a copy of the License at +;; +;; http://www.apache.org/licenses/LICENSE-2.0 +;; +;; Unless required by applicable law or agreed to in writing, software +;; distributed under the License is distributed on an "AS IS" BASIS, +;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;; See the License for the specific language governing permissions and +;; limitations under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; Edits: +;; +;; + +@id 1 +@inherits diameter_gen_base_rfc6733 + +;; only used AVP are defined here. + +;; =========================================================================== + +@avp_types + + SourceID 649 DiameterIdentity - ;; 7.4 + Load 650 Grouped - ;; 7.1 + Load-Type 651 Enumerated - ;; 7.2 + Load-Value 652 Unsigned64 - ;; 7.3 + +@grouped +;; 7.1 + Load ::= < AVP Header: 650 > + [ Load-Type ] + [ Load-Value ] + [ SourceID ] + * [ AVP ] + +@enum Load-Type + HOST 0 ;; The load report is for a host. + PEER 1 ;; The load report is for a peer. + diff --git a/src/osmo_cx2gsup.erl b/src/osmo_cx2gsup.erl new file mode 100644 index 0000000..cce7560 --- /dev/null +++ b/src/osmo_cx2gsup.erl @@ -0,0 +1,131 @@ +-module(osmo_cx2gsup). +-behavior(gen_server). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/include/diameter_gen_base_rfc6733.hrl"). + +-export([main/1]). + +% API +-export([start_link/0]). +-export([start/0, stop/0]). + +% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2]). +-export([code_change/3, terminate/2]). + +-define(SERVER, ?MODULE). + +% Diameter application definitions + +-define(VENDOR_ID_3GPP, 10415). +-define(VENDOR_ID_3GPP2, 5535). +-define(VENDOR_ID_ETSI, 13019). + +-define(DIA_STATS_TAB, iwf_stats). +-define(DIA_STATS_COUNTERS, [event_OK, event_ERR]). + +-define(SVC_NAME, ?MODULE). +-define(APP_ALIAS, ?MODULE). +-define(CALLBACK_MOD, osmo_cx2gsup_cb). +-define(DIAMETER_DICT_CX, diameter_3gpp_ts29_292_cx). + +-define(APPID_CX, #'diameter_base_Vendor-Specific-Application-Id'{'Vendor-Id'=10415, 'Auth-Application-Id'=[16777216]}). +-define(SERVICE(Name), [{'Origin-Host', application:get_env(osmo_cx2gsup, origin_host, "hss.localdomain")}, + {'Origin-Realm', application:get_env(osmo_cx2gsup, origin_realm, "localdomain")}, + {'Vendor-Id', application:get_env(osmo_cx2gsup, vendor_id, 0)}, + {'Origin-State-Id', diameter:origin_state_id()}, + {'Product-Name', "osmo_dia2gsup"}, + {'Auth-Application-Id', []}, + {'Vendor-Specific-Application-Id', [?APPID_CX]}, + {'Supported-Vendor-Id', [?VENDOR_ID_3GPP, ?VENDOR_ID_ETSI, ?VENDOR_ID_3GPP2]}, + {application, + [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_CX}, + {module, ?CALLBACK_MOD}] + }]). + + + +%% ------------------------------------------------------------------ +%% API +%% ------------------------------------------------------------------ + +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +start() -> + application:ensure_all_started(?MODULE), + start_link(). + +stop() -> + gen_server:cast(?SERVER, stop). + +main(_Args) -> + application:ensure_all_started(?MODULE), + timer:sleep(infinity). + +%% ------------------------------------------------------------------ +%% gen_server Function Definitions +%% ------------------------------------------------------------------ + +%% @callback gen_server +init(State) -> + % DIAMETER side + SvcName = ?MODULE, + diameter:start_service(SvcName, ?SERVICE(SvcName)), + + Ip = application:get_env(osmo_cx2gsup, diameter_ip, "127.0.0.9"), + Port = application:get_env(osmo_cx2gsup, diameter_port, 3868), + Proto = application:get_env(osmo_cx2gsup, diameter_proto, sctp), + ConnectTimer = application:get_env(osmo_cx2gsup, diameter_connect_timer, 30000), + listen(?SVC_NAME, {address, Proto, element(2,inet:parse_address(Ip)), Port}, {timer, ConnectTimer}), + lager:info("Diameter HSS Application started on IP ~s, ~p port ~p~n", [Ip, Proto, Port]), + {ok, State}. + +%% @callback gen_server +handle_call(_Req, _From, State) -> + {noreply, State}. + +%% @callback gen_server +handle_cast(stop, State) -> + {stop, normal, State}; +handle_cast(_req, State) -> + {noreply, State}. + + +%% @callback gen_server +handle_info(_Info, State) -> + {noreply, State}. + +%% @callback gen_server +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%% @callback gen_server +terminate(normal, _State) -> + diameter:stop_service(?SVC_NAME), + lager:info("Diameter HSS Application stopped.~n"), + ok; +terminate(shutdown, _State) -> + ok; +terminate({shutdown, _Reason}, _State) -> + ok; +terminate(_Reason, _State) -> + ok. + + + +%% ------------------------------------------------------------------ +%% Internal Function Definitions +%% ------------------------------------------------------------------ + +listen(Name, {address, Protocol, IPAddr, Port}, {timer, ConnectTimer}) -> + TransOpts = [{transport_module, tmod(Protocol)}, + {transport_config, [{reuseaddr, true}, + {ip, IPAddr}, {port, Port}]}, + {connect_timer, ConnectTimer}], + {ok, _} = diameter:add_transport(Name, {listen, TransOpts}). + +tmod(tcp) -> diameter_tcp; +tmod(sctp) -> diameter_sctp. diff --git a/src/osmo_cx2gsup_cb.erl b/src/osmo_cx2gsup_cb.erl new file mode 100644 index 0000000..85cb9b3 --- /dev/null +++ b/src/osmo_cx2gsup_cb.erl @@ -0,0 +1,217 @@ +-module(osmo_cx2gsup_cb). + + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/include/diameter_gen_base_rfc6733.hrl"). +-include_lib("diameter_3gpp_ts29_229_cx.hrl"). +-include_lib("osmo_gsup/include/gsup_protocol.hrl"). + +-define(DIA_VENDOR_3GPP, 10415). + +%% diameter callbacks +-export([peer_up/3, peer_down/3, pick_peer/4, prepare_request/3, prepare_retransmit/3, + handle_answer/4, handle_error/4, handle_request/3]). + +-define(UNEXPECTED, erlang:error({unexpected, ?MODULE, ?LINE})). + +peer_up(_SvcName, {PeerRef, Caps}, State) -> + lager:info("Peer up ~p - ~p~n", [PeerRef, lager:pr(Caps, ?MODULE)]), + State. + +peer_down(_SvcName, {PeerRef, Caps}, State) -> + lager:info("Peer down ~p - ~p~n", [PeerRef, lager:pr(Caps, ?MODULE)]), + State. + +pick_peer(_, _, _SvcName, _State) -> + ?UNEXPECTED. + +prepare_request(_, _SvcName, _Peer) -> + ?UNEXPECTED. + +prepare_retransmit(_Packet, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_answer(_Packet, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_error(_Reason, _Request, _SvcName, _Peer) -> + lager:error("Request error: ~p~n", [_Reason]), + ?UNEXPECTED. + + +% transient (only in Experimental-Result-Code) +-define(DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE, 4181). +-define(DIAMETER_ERROR_CAMEL_SUBSCRIPTION_PRESENT, 4182). +% permanent (only in Experimental-Result-Code) +-define(DIAMETER_ERROR_USER_UNKNOWN, 5001). +-define(DIAMETER_AUTHORIZATION_REJECTED, 5003). +-define(DIAMETER_ERROR_ROAMING_NOT_ALLOWED, 5004). +-define(DIAMETER_MISSING_AVP, 5005). +-define(DIAMETER_UNABLE_TO_COMPLY, 5012). +-define(DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION, 5420). +-define(DIAMETER_ERROR_RAT_NOT_ALLOWED, 5421). +-define(DIAMETER_ERROR_EQUIPMENT_UNKNOWN, 5422). +-define(DIAMETER_ERROR_UNKOWN_SERVING_NODE, 5423). + +% 10.5.5.14 +-define(GMM_CAUSE_IMSI_UNKNOWN, 16#02). +-define(GMM_CAUSE_ILLEGAL_MS, 16#03). +-define(GMM_CAUSE_GPRS_NOTALLOWED, 16#07). +-define(GMM_CAUSE_PLMN_NOTALLOWED, 16#0b). +-define(GMM_CAUSE_LA_NOTALLOWED, 16#0c). +-define(GMM_CAUSE_ROAMING_NOTALLOWED, 16#0d). +-define(GMM_CAUSE_NO_SUIT_CELL_IN_LA, 16#0f). +-define(GMM_CAUSE_NET_FAIL, 16#11). +-define(GMM_CAUSE_CONGESTION, 16#16). +-define(GMM_CAUSE_GSM_AUTH_UNACCEPT, 16#17). +-define(GMM_CAUSE_INV_MAND_INFO, 16#60). +-define(GMM_CAUSE_PROTO_ERR_UNSPEC, 16#6f). + +-define(EXP_RES(Exp), #'Experimental-Result'{'Vendor-Id'=?DIA_VENDOR_3GPP, 'Experimental-Result-Code'=Exp}). + +%% see 29.272 Annex A/B +-type empty_or_intl() :: [] | [integer()]. +-spec gsup_cause2dia(integer()) -> {empty_or_intl(), empty_or_intl()}. +gsup_cause2dia(?GMM_CAUSE_IMSI_UNKNOWN) -> {[], [?EXP_RES(?DIAMETER_ERROR_USER_UNKNOWN)]}; +gsup_cause2dia(?GMM_CAUSE_ILLEGAL_MS) -> {[], [?EXP_RES(?DIAMETER_ERROR_USER_UNKNOWN)]}; +gsup_cause2dia(?GMM_CAUSE_PLMN_NOTALLOWED) -> {[], [?EXP_RES(?DIAMETER_ERROR_ROAMING_NOT_ALLOWED)]}; +gsup_cause2dia(?GMM_CAUSE_GPRS_NOTALLOWED) -> {[], [?EXP_RES(?DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION)]}; + +gsup_cause2dia(?GMM_CAUSE_LA_NOTALLOWED) -> {[?DIAMETER_AUTHORIZATION_REJECTED], []}; +gsup_cause2dia(?GMM_CAUSE_ROAMING_NOTALLOWED) -> {[], [?EXP_RES(?DIAMETER_ERROR_ROAMING_NOT_ALLOWED)]}; +gsup_cause2dia(?GMM_CAUSE_NO_SUIT_CELL_IN_LA) -> {[], [?EXP_RES(?DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION)]}; +gsup_cause2dia(?GMM_CAUSE_NET_FAIL) -> {[?DIAMETER_UNABLE_TO_COMPLY], []}; +gsup_cause2dia(?GMM_CAUSE_CONGESTION) -> {[?DIAMETER_UNABLE_TO_COMPLY], []}; +gsup_cause2dia(?GMM_CAUSE_INV_MAND_INFO) -> {[?DIAMETER_MISSING_AVP], []}; +gsup_cause2dia(?GMM_CAUSE_PROTO_ERR_UNSPEC) -> {[?DIAMETER_UNABLE_TO_COMPLY], []}; +gsup_cause2dia(_) -> {[?DIAMETER_UNABLE_TO_COMPLY], []}. + +% get the value for a tiven key in Map1. If not found, try same key in Map2. If not found, return Default +-spec twomap_get(atom(), map(), map(), any()) -> any(). +twomap_get(Key, Map1, Map2, Default) -> + maps:get(Key, Map1, maps:get(Key, Map2, Default)). + +dia_sip2gsup(#'SIP-Auth-Data-Item'{'SIP-Authenticate' = [Authenticate], 'SIP-Authorization' = [Authorization], + 'Confidentiality-Key' = [CKey], 'Integrity-Key' = [IKey]}) -> + #{rand => list_to_binary(lists:sublist(Authenticate, 1, 16)), + autn=> list_to_binary(lists:sublist(Authenticate, 17, 16)), + res=> list_to_binary(Authorization), + ik=> list_to_binary(IKey), + ck=> list_to_binary(CKey)}. + +-spec gsup_tuple2dia_sip('GSUPAuthTuple'(), integer()) -> #'E-UTRAN-Vector'{}. +gsup_tuple2dia_sip(#{autn:=Autn, ck:=Ck, ik:=Ik, rand:=Rand, res:=Res}, Idx) -> + #'SIP-Auth-Data-Item'{ + 'SIP-Item-Number' = Idx, + 'Confidentiality-Key' = Ck, + 'Integrity-Key' = Ik, + 'SIP-Authenticate' = lists:merge(Rand, Autn), + 'SIP-Authorization' = Res + }. + +-spec gsup_tuples2dia_sip(['GSUPAuthTuple'()]) -> [#'E-UTRAN-Vector'{}]. +gsup_tuples2dia_sip(List) -> gsup_tuples2dia_sip(List, [], 1). +gsup_tuples2dia_sip([], Out, _Idx) -> Out; +gsup_tuples2dia_sip([Head|Tail], Out, Ctr) -> + Dia = gsup_tuple2dia_sip(Head, Ctr), + gsup_tuples2dia_sip(Tail, [Dia|Out], Ctr+1). + +-type int_or_false() :: false | integer(). +-spec gsup_tuples2dia(['GSUPAuthTuple'()], int_or_false()) -> #'Authentication-Info'{}. +gsup_tuples2dia(Tuples, NumEutran) -> + case NumEutran of + false -> EutranVecs = []; + 0 -> EutranVecs = []; + _ -> EutranVecs = gsup_tuples2dia_sip(lists:sublist(Tuples, NumEutran)) + end, + [EutranVecs]. + +-type binary_or_false() :: false | binary(). +-spec req_resynchronization_info([tuple()]) -> binary_or_false(). +req_resynchronization_info(#'SIP-Auth-Data-Item'{'SIP-Authorization'=[]}) -> + false; +req_resynchronization_info(#'SIP-Auth-Data-Item'{'SIP-Authorization'=[Auth]}) -> + list_to_binary(Auth); +req_resynchronization_info(_) -> + false. + +% Cx +handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) when is_record(Req, 'UAR') -> + % extract relevant fields from DIAMETER ULR + #diameter_caps{origin_host = {OH,_}, origin_realm = {OR,_}} = Caps, + #'UAR'{'Session-Id' = SessionId, + 'UAR-Flags' = UarFlags, + 'User-Name' = UserName} = Req, + ServerName = "sip:scscf.core.osmocom.org:6060", + + Resp = #'UAA'{'Session-Id'= SessionId, 'Auth-Session-State'=1, + 'Origin-Host'=OH, 'Origin-Realm'=OR, + 'Experimental-Result'=2001, + 'Server-Name'=ServerName}, + lager:info("UAA Resp: ~p~n", [Resp]), + {reply, Resp}; + + +% Server Assignement Request +handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) when is_record(Req, 'SAR') -> + % extract relevant fields from DIAMETER ULR + #diameter_caps{origin_host = {OH,_}, origin_realm = {OR,_}} = Caps, + #'SAR'{'Session-Id' = SessionId, + 'User-Name' = UserName, + 'Server-Name' = ServerName, + 'Server-Assignment-Type' = Type} = Req, + % TODO: Type == 0 + ServerName = "sip:scscf.core.osmocom.org:6060", + Resp = #'SAA'{'Session-Id'= SessionId, 'Auth-Session-State'=1, + 'Origin-Host'=OH, 'Origin-Realm'=OR, + 'Experimental-Result'=2001, + 'User-Name' = UserName, + 'Server-Name'=ServerName}, + lager:info("SAA Resp: ~p~n", [Resp]), + {reply, Resp}; + + +% Multimedia Authentication Request +handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) when is_record(Req, 'MAR') -> + #diameter_caps{origin_host = {OH,_}, origin_realm = {OR,_}} = Caps, + #'MAR'{'Session-Id' = SessionId, + 'User-Name' = UserName, + 'Server-Name' = ServerName, + 'Public-Identity' = PublicIdentity, + 'SIP-Auth-Data-Item' = AuthData, + 'SIP-Number-Auth-Items' = NumAuthData} = Req, + % TODO: parse User-Name and Public-Identity, get the MNC/MCC from it + GsupTx1 = #{message_type => send_auth_info_req, imsi => list_to_binary(UserName), + supported_rat_types => [rat_eutran_sgs], current_rat_type => rat_eutran_sgs}, + ResyncInfo = req_resynchronization_info(Req), + case ResyncInfo of + false -> + GsupTx2 = #{}; + ValidResyncInfo -> + GsupTx2 = #{rand => binary:part(ValidResyncInfo, 0, 16), + auts => binary:part(ValidResyncInfo, 16, 14)} + end, + GsupTx = maps:merge(GsupTx1, GsupTx2), + GsupRx = gen_server:call(gsup_client, {transceive_gsup, GsupTx, send_auth_info_res, send_auth_info_err}), + lager:info("GsupRx: ~p~n", [GsupRx]), + case GsupRx of + #{message_type:=send_auth_info_res, auth_tuples:=GsupAuthTuples} -> + AuthInfo = gsup_tuples2dia(GsupAuthTuples, NumAuthData), + Resp = #'MAA'{'Session-Id'=SessionId, 'Origin-Host'=OH, 'Origin-Realm'=OR, + 'Experimental-Result'=2001, 'Auth-Session-State'=1, + 'SIP-Auth-Data-Item'=AuthInfo}; + #{message_type := send_auth_info_err, cause:=Cause} -> + {Res, ExpRes} = gsup_cause2dia(Cause), + Resp = #'MAA'{'Session-Id'=SessionId, 'Origin-Host'=OH, 'Origin-Realm'=OR, + 'Result-Code'=Res, 'Experimental-Result'=ExpRes, + 'Auth-Session-State'=1}; + timeout -> + Resp = #'MAA'{'Session-Id'=SessionId, 'Origin-Host'=OH, 'Origin-Realm'=OR, + 'Result-Code'=4181, 'Auth-Session-State'=1} + end, + lager:info("Resp: ~p~n", [Resp]), + {reply, Resp}; + +handle_request(Packet, _SvcName, {_,_}) -> + lager:error("Unsuppoerted message: ~p~n", [Packet]), + discard. diff --git a/src/osmo_dia2gsup_sup.erl b/src/osmo_dia2gsup_sup.erl index 03c780d..6047fac 100644 --- a/src/osmo_dia2gsup_sup.erl +++ b/src/osmo_dia2gsup_sup.erl @@ -15,9 +15,14 @@ init([]) -> Args = [{local, gsup_client}, gsup_client, [HlrIp, HlrPort, "HSS-00-00-00-00-00-00"], [{debug, [trace]}]], GsupChild = {gsup_client, {gen_server, start_link, Args}, permanent, 2000, worker, [gsup_client]}, % DIAMETER side - DiaServer = {osmo_dia2gsup,{osmo_dia2gsup,start_link,[]}, + S6a = {osmo_dia2gsup,{osmo_dia2gsup,start_link,[]}, permanent, 5000, worker, [server_cb]}, - {ok, { {one_for_one, 5, 10}, [DiaServer, GsupChild]} }. + Cx = {osmo_cx2gsup, {osmo_cx2gsup,start_link,[]}, + permanent, + 5000, + worker, + [osmo_cx2gsup_cb]}, + {ok, { {one_for_one, 5, 10}, [S6a, Cx, GsupChild]} }.