Merge branch 'zecke/m3ua'
This commit is contained in:
commit
5c25c78ec7
|
@ -1,4 +1,4 @@
|
||||||
noinst_HEADERS = mtp_level3.h mtp_data.h ipaccess.h thread.h mtp_pcap.h \
|
noinst_HEADERS = mtp_data.h ipaccess.h thread.h mtp_pcap.h \
|
||||||
mgcp_ss7.h bss_patch.h bssap_sccp.h bsc_data.h udp_input.h \
|
mgcp_ss7.h bss_patch.h bssap_sccp.h bsc_data.h udp_input.h \
|
||||||
snmp_mtp.h cellmgr_debug.h bsc_sccp.h bsc_ussd.h sctp_m2ua.h \
|
snmp_mtp.h cellmgr_debug.h bsc_sccp.h bsc_ussd.h sctp_m2ua.h \
|
||||||
isup_types.h counter.h msc_connection.h ss7_application.h \
|
isup_types.h counter.h msc_connection.h ss7_application.h \
|
||||||
|
|
|
@ -41,6 +41,7 @@ enum ss7_link_type {
|
||||||
SS7_LTYPE_NONE,
|
SS7_LTYPE_NONE,
|
||||||
SS7_LTYPE_UDP,
|
SS7_LTYPE_UDP,
|
||||||
SS7_LTYPE_M2UA,
|
SS7_LTYPE_M2UA,
|
||||||
|
SS7_LTYPE_M3UA_CLIENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,12 +140,14 @@ struct mtp_link {
|
||||||
struct rate_ctr_group *ctrg;
|
struct rate_ctr_group *ctrg;
|
||||||
|
|
||||||
/* callback's to implement */
|
/* callback's to implement */
|
||||||
int (*start)(struct mtp_link *);
|
|
||||||
int (*write)(struct mtp_link *, struct msgb *msg);
|
int (*write)(struct mtp_link *, struct msgb *msg);
|
||||||
int (*shutdown)(struct mtp_link *);
|
int (*shutdown)(struct mtp_link *);
|
||||||
int (*reset)(struct mtp_link *data);
|
int (*reset)(struct mtp_link *data);
|
||||||
int (*clear_queue)(struct mtp_link *data);
|
int (*clear_queue)(struct mtp_link *data);
|
||||||
|
|
||||||
|
/* for M3UA and others.. */
|
||||||
|
int skip_link_test;
|
||||||
|
|
||||||
/* private data */
|
/* private data */
|
||||||
enum ss7_link_type type;
|
enum ss7_link_type type;
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -191,4 +194,7 @@ struct mtp_link_set *mtp_link_set_num(struct bsc_data *bsc, int num);
|
||||||
struct mtp_link *mtp_link_alloc(struct mtp_link_set *set);
|
struct mtp_link *mtp_link_alloc(struct mtp_link_set *set);
|
||||||
struct mtp_link *mtp_link_num(struct mtp_link_set *set, int num);
|
struct mtp_link *mtp_link_num(struct mtp_link_set *set, int num);
|
||||||
|
|
||||||
|
/* linkset handling */
|
||||||
|
int mtp_link_verified(struct mtp_link *link);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,180 +0,0 @@
|
||||||
/* Q.701-Q.704, Q.706, Q.707 handling code */
|
|
||||||
/*
|
|
||||||
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
|
||||||
* (C) 2010 by On-Waves
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef mtp_level3_h
|
|
||||||
#define mtp_level3_h
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <endian.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pssible service information octets..
|
|
||||||
*/
|
|
||||||
#define MTP_NI_NATION_NET 0x02
|
|
||||||
|
|
||||||
#define MTP_SI_MNT_SNM_MSG 0x00
|
|
||||||
#define MTP_SI_MNT_REG_MSG 0x01
|
|
||||||
#define MTP_SI_MNT_SCCP 0x03
|
|
||||||
#define MTP_SI_MNT_ISUP 0x05
|
|
||||||
|
|
||||||
/*
|
|
||||||
* h0 contains the group, h1 the semantic of it
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MTP_TST_MSG_GRP 0x01
|
|
||||||
#define MTP_PROHIBIT_MSG_GRP 0x04
|
|
||||||
#define MTP_SROUTE_MSG_GRP 0x05
|
|
||||||
#define MTP_TRF_RESTR_MSG_GRP 0x07
|
|
||||||
|
|
||||||
/* h1 values for different groups */
|
|
||||||
#define MTP_TST_MSG_SLTM 0x01
|
|
||||||
#define MTP_TST_MSG_SLTA 0x02
|
|
||||||
|
|
||||||
#define MTP_RESTR_MSG_ALLWED 0x01
|
|
||||||
|
|
||||||
/* For the prohibit group */
|
|
||||||
#define MTP_PROHIBIT_MSG_SIG 0x01
|
|
||||||
#define MTP_PROHIBIT_MSG_TFA 0x05
|
|
||||||
|
|
||||||
/* For the Signalling-route-set-test */
|
|
||||||
#define MTP_SROUTE_MSG_TEST 0x01
|
|
||||||
|
|
||||||
|
|
||||||
#define SCCP_SST 0x03
|
|
||||||
#define SCCP_SSP 0x02
|
|
||||||
#define SCCP_SSA 0x01
|
|
||||||
|
|
||||||
#define MTP_LINK_MASK 0x0F
|
|
||||||
#define MTP_ADDR_MASK 0x3FFF
|
|
||||||
#define MTP_APOC_MASK 0x3f
|
|
||||||
|
|
||||||
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
#define MTP_LINK_SLS(addr) ((addr >>28) & MTP_LINK_MASK)
|
|
||||||
#define MTP_ADDR(link, dpc, opc) \
|
|
||||||
(((dpc) & MTP_ADDR_MASK) << 0 | \
|
|
||||||
((opc) & MTP_ADDR_MASK) << 14| \
|
|
||||||
((link) & MTP_LINK_MASK) << 28)
|
|
||||||
#define MTP_MAKE_APOC(apoc) \
|
|
||||||
(apoc & 0x3fff)
|
|
||||||
#define MTP_ADDR_DPC(addr) \
|
|
||||||
(addr & MTP_ADDR_MASK)
|
|
||||||
#define MTP_ADDR_OPC(addr) \
|
|
||||||
((addr >> 14) & MTP_ADDR_MASK)
|
|
||||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
static inline uint32_t c_swap_32(uint32_t in)
|
|
||||||
{
|
|
||||||
return (((in & 0x000000ff) << 24) |
|
|
||||||
((in & 0x0000ff00) << 8) |
|
|
||||||
((in & 0x00ff0000) >> 8) |
|
|
||||||
((in & 0xff000000) >> 24));
|
|
||||||
}
|
|
||||||
static inline uint16_t c_swap_16(uint16_t in)
|
|
||||||
{
|
|
||||||
return (((in & 0x00ff) << 8) |
|
|
||||||
(in & 0xff00) >> 8);
|
|
||||||
}
|
|
||||||
#define MTP_LINK_SLS(addr) ((c_swap_32(addr)>>28) & MTP_LINK_MASK)
|
|
||||||
#define MTP_ADDR(link, dpc, opc) \
|
|
||||||
c_swap_32(((dpc) & MTP_ADDR_MASK) << 0 | \
|
|
||||||
((opc) & MTP_ADDR_MASK) << 14| \
|
|
||||||
((link) & MTP_LINK_MASK) << 28)
|
|
||||||
#define MTP_MAKE_APOC(apoc) \
|
|
||||||
c_swap_16((apoc & 0x3fff))
|
|
||||||
#define MTP_ADDR_DPC(addr) \
|
|
||||||
(c_swap_32(addr) & MTP_ADDR_MASK)
|
|
||||||
#define MTP_ADDR_OPC(addr) \
|
|
||||||
((c_swap_32(addr) >> 14) & MTP_ADDR_MASK)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* not the on wire address...
|
|
||||||
*/
|
|
||||||
struct mtp_addr {
|
|
||||||
uint16_t dpc;
|
|
||||||
uint16_t opc;
|
|
||||||
uint8_t link;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* the struct is defined in Q.704 and can be seen in the
|
|
||||||
* wireshark dissectors too
|
|
||||||
*/
|
|
||||||
struct mtp_level_3_hdr {
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
uint8_t ser_ind : 4,
|
|
||||||
spare : 2,
|
|
||||||
ni : 2;
|
|
||||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
uint8_t ni : 2,
|
|
||||||
spare : 2,
|
|
||||||
ser_ind : 4;
|
|
||||||
#endif
|
|
||||||
uint32_t addr;
|
|
||||||
uint8_t data[0];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct mtp_level_3_cmn {
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
uint8_t h0 : 4,
|
|
||||||
h1 : 4;
|
|
||||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
uint8_t h1 : 4,
|
|
||||||
h0 : 4;
|
|
||||||
#endif
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct mtp_level_3_mng {
|
|
||||||
struct mtp_level_3_cmn cmn;
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
uint8_t spare : 4,
|
|
||||||
length : 4;
|
|
||||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
uint8_t length : 4,
|
|
||||||
spare : 4;
|
|
||||||
#endif
|
|
||||||
uint8_t data[0];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct mtp_level_3_prohib {
|
|
||||||
struct mtp_level_3_cmn cmn;
|
|
||||||
|
|
||||||
uint16_t apoc;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct sccp_con_ctrl_prt_mgt {
|
|
||||||
uint8_t sst;
|
|
||||||
uint8_t assn; /* affected sub system number */
|
|
||||||
uint16_t apoc;
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
uint8_t mul_ind : 2,
|
|
||||||
spare : 6;
|
|
||||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
uint8_t spare : 6,
|
|
||||||
mul_ind : 2;
|
|
||||||
#endif
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Represet M3UA client (and later server) links
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mtp_data.h"
|
||||||
|
|
||||||
|
#include <osmocom/core/write_queue.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
struct mtp_m3ua_client_link {
|
||||||
|
struct mtp_link *base;
|
||||||
|
|
||||||
|
struct osmo_wqueue queue;
|
||||||
|
struct osmo_timer_list connect_timer;
|
||||||
|
|
||||||
|
char *source;
|
||||||
|
struct sockaddr_in local;
|
||||||
|
|
||||||
|
char *dest;
|
||||||
|
struct sockaddr_in remote;
|
||||||
|
int link_index;
|
||||||
|
int routing_context;
|
||||||
|
|
||||||
|
|
||||||
|
/* state of the link */
|
||||||
|
int aspsm_active;
|
||||||
|
int asptm_active;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mtp_m3ua_client_link *mtp_m3ua_client_link_init(struct mtp_link *link);
|
|
@ -26,7 +26,7 @@ osmo_stp_SOURCES = main_stp.c mtp_layer3.c thread.c pcap.c link_udp.c snmp_mtp.c
|
||||||
bss_patch.c bssap_sccp.c bsc_sccp.c bsc_ussd.c input/ipaccess.c \
|
bss_patch.c bssap_sccp.c bsc_sccp.c bsc_ussd.c input/ipaccess.c \
|
||||||
mtp_link.c counter.c bsc.c ss7_application.c \
|
mtp_link.c counter.c bsc.c ss7_application.c \
|
||||||
vty_interface.c vty_interface_cmds.c mgcp_patch.c \
|
vty_interface.c vty_interface_cmds.c mgcp_patch.c \
|
||||||
mgcp_callagent.c isup_filter.c
|
mgcp_callagent.c isup_filter.c sctp_m3ua_client.c
|
||||||
osmo_stp_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
|
osmo_stp_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
|
||||||
$(LIBOSMOSCCP_LIBS) $(NEXUSWARE_C7_LIBS) \
|
$(LIBOSMOSCCP_LIBS) $(NEXUSWARE_C7_LIBS) \
|
||||||
-lpthread -lnetsnmp -lcrypto -lxua -lsctp
|
-lpthread -lnetsnmp -lcrypto -lxua -lsctp
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <isup_types.h>
|
#include <isup_types.h>
|
||||||
#include <cellmgr_debug.h>
|
#include <cellmgr_debug.h>
|
||||||
#include <mtp_data.h>
|
#include <mtp_data.h>
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
|
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/gsm/tlv.h>
|
#include <osmocom/gsm/tlv.h>
|
||||||
|
|
|
@ -223,12 +223,6 @@ static int udp_link_write(struct mtp_link *link, struct msgb *msg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int udp_link_start(struct mtp_link *link)
|
|
||||||
{
|
|
||||||
do_start(link);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int link_udp_init(struct mtp_udp_link *link, char *remote, int port)
|
int link_udp_init(struct mtp_udp_link *link, char *remote, int port)
|
||||||
{
|
{
|
||||||
/* prepare the remote */
|
/* prepare the remote */
|
||||||
|
@ -383,7 +377,6 @@ struct mtp_udp_link *mtp_udp_link_init(struct mtp_link *blnk)
|
||||||
lnk->base->clear_queue = udp_link_dummy;
|
lnk->base->clear_queue = udp_link_dummy;
|
||||||
|
|
||||||
lnk->base->reset = udp_link_reset;
|
lnk->base->reset = udp_link_reset;
|
||||||
lnk->base->start = udp_link_start;
|
|
||||||
lnk->base->write = udp_link_write;
|
lnk->base->write = udp_link_write;
|
||||||
|
|
||||||
/* prepare the remote */
|
/* prepare the remote */
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <cellmgr_debug.h>
|
#include <cellmgr_debug.h>
|
||||||
#include <msc_connection.h>
|
#include <msc_connection.h>
|
||||||
#include <mtp_data.h>
|
#include <mtp_data.h>
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
#include <mtp_pcap.h>
|
#include <mtp_pcap.h>
|
||||||
#include <snmp_mtp.h>
|
#include <snmp_mtp.h>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include <mtp_data.h>
|
#include <mtp_data.h>
|
||||||
#include <msc_connection.h>
|
#include <msc_connection.h>
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <bss_patch.h>
|
#include <bss_patch.h>
|
||||||
#include <bssap_sccp.h>
|
#include <bssap_sccp.h>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <mtp_data.h>
|
#include <mtp_data.h>
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
#include <mtp_pcap.h>
|
#include <mtp_pcap.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <bsc_data.h>
|
#include <bsc_data.h>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <mtp_data.h>
|
#include <mtp_data.h>
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
#include <bsc_data.h>
|
#include <bsc_data.h>
|
||||||
#include <cellmgr_debug.h>
|
#include <cellmgr_debug.h>
|
||||||
#include <isup_types.h>
|
#include <isup_types.h>
|
||||||
|
@ -231,7 +231,7 @@ static int send_tfa(struct mtp_link *link, int opc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int linkset_up(struct mtp_link *link)
|
int mtp_link_verified(struct mtp_link *link)
|
||||||
{
|
{
|
||||||
struct mtp_link_set *set = link->set;
|
struct mtp_link_set *set = link->set;
|
||||||
|
|
||||||
|
@ -368,9 +368,9 @@ static int mtp_link_regular_msg(struct mtp_link *link, struct mtp_level_3_hdr *h
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
|
if (MTP_READ_DPC(hdr->addr) != link->set->opc) {
|
||||||
LOGP(DINP, LOGL_ERROR, "MSG for OPC %d not handled on %d/%s\n",
|
LOGP(DINP, LOGL_ERROR, "MSG for OPC %d not handled on %d/%s\n",
|
||||||
MTP_ADDR_DPC(hdr->addr), link->set->nr, link->set->name);
|
MTP_READ_DPC(hdr->addr), link->set->nr, link->set->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ static int mtp_link_regular_msg(struct mtp_link *link, struct mtp_level_3_hdr *h
|
||||||
case MTP_TST_MSG_SLTA:
|
case MTP_TST_MSG_SLTA:
|
||||||
/* If this link is proven set it up */
|
/* If this link is proven set it up */
|
||||||
if (mtp_link_slta(link, l3_len, mng) == 0)
|
if (mtp_link_slta(link, l3_len, mng) == 0)
|
||||||
linkset_up(link);
|
mtp_link_verified(link);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <mtp_data.h>
|
#include <mtp_data.h>
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
#include <cellmgr_debug.h>
|
#include <cellmgr_debug.h>
|
||||||
#include <counter.h>
|
#include <counter.h>
|
||||||
|
|
||||||
|
@ -132,6 +132,15 @@ void mtp_link_start_link_test(struct mtp_link *link)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (link->skip_link_test) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Skipping starting linktest on %d/%s of %d/%s.\n",
|
||||||
|
link->nr, link->name, link->set->nr, link->set->name);
|
||||||
|
link->sltm_pending = 0;
|
||||||
|
link->was_up = 1;
|
||||||
|
mtp_link_verified(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mtp_sltm_t2_timeout(link);
|
mtp_sltm_t2_timeout(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +233,6 @@ struct mtp_link *mtp_link_alloc(struct mtp_link_set *set)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure a unconfigured link does not crash */
|
/* make sure a unconfigured link does not crash */
|
||||||
link->start = dummy_arg1;
|
|
||||||
link->write = dummy_arg2;
|
link->write = dummy_arg2;
|
||||||
link->shutdown = dummy_arg1;
|
link->shutdown = dummy_arg1;
|
||||||
link->reset = dummy_arg1;
|
link->reset = dummy_arg1;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include <mtp_data.h>
|
#include <mtp_data.h>
|
||||||
#include <msc_connection.h>
|
#include <msc_connection.h>
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
#include <bss_patch.h>
|
#include <bss_patch.h>
|
||||||
#include <bssap_sccp.h>
|
#include <bssap_sccp.h>
|
||||||
#include <bsc_data.h>
|
#include <bsc_data.h>
|
||||||
|
|
|
@ -734,14 +734,6 @@ static int sctp_m2ua_dummy(struct mtp_link *link)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sctp_m2ua_start(struct mtp_link *_link)
|
|
||||||
{
|
|
||||||
struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
|
|
||||||
|
|
||||||
link->transport->started = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sctp_m2ua_reset(struct mtp_link *_link)
|
static int sctp_m2ua_reset(struct mtp_link *_link)
|
||||||
{
|
{
|
||||||
struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
|
struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
|
||||||
|
@ -843,7 +835,6 @@ struct mtp_m2ua_link *mtp_m2ua_link_init(struct mtp_link *blnk)
|
||||||
lnk->base->shutdown = sctp_m2ua_reset;
|
lnk->base->shutdown = sctp_m2ua_reset;
|
||||||
lnk->base->clear_queue = sctp_m2ua_dummy;
|
lnk->base->clear_queue = sctp_m2ua_dummy;
|
||||||
lnk->base->reset = sctp_m2ua_reset;
|
lnk->base->reset = sctp_m2ua_reset;
|
||||||
lnk->base->start = sctp_m2ua_start;
|
|
||||||
lnk->base->write = sctp_m2ua_write;
|
lnk->base->write = sctp_m2ua_write;
|
||||||
|
|
||||||
lnk->transport = trans;
|
lnk->transport = trans;
|
||||||
|
|
|
@ -0,0 +1,566 @@
|
||||||
|
/* Run M3UA over SCTP here */
|
||||||
|
/* (C) 2015 by Holger Hans Peter Freyther
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sctp_m3ua.h>
|
||||||
|
#include <cellmgr_debug.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <bsc_data.h>
|
||||||
|
|
||||||
|
#include <osmocom/sigtran/xua_msg.h>
|
||||||
|
#include <osmocom/sigtran/m3ua_types.h>
|
||||||
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/talloc.h>
|
||||||
|
|
||||||
|
#include <netinet/sctp.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define SCTP_PPID_M3UA 3
|
||||||
|
|
||||||
|
#define notImplemented() \
|
||||||
|
LOGP(DINP, LOGL_NOTICE, "%s not implemented.\n", __func__)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State machine code
|
||||||
|
*/
|
||||||
|
static void m3ua_handle_aspsm(struct mtp_m3ua_client_link *link, struct xua_msg *msg);
|
||||||
|
static void m3ua_handle_asptm(struct mtp_m3ua_client_link *link, struct xua_msg *msg);
|
||||||
|
static void m3ua_handle_trans(struct mtp_m3ua_client_link *link, struct xua_msg *msg);
|
||||||
|
static void m3ua_send_daud(struct mtp_m3ua_client_link *link, uint32_t pc);
|
||||||
|
static void m3ua_send_aspup(struct mtp_m3ua_client_link *link);
|
||||||
|
static void m3ua_send_aspac(struct mtp_m3ua_client_link *link);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* boilerplate
|
||||||
|
*/
|
||||||
|
static int m3ua_shutdown(struct mtp_link *mtp_link);
|
||||||
|
static void m3ua_start(void *data);
|
||||||
|
|
||||||
|
static void schedule_restart(struct mtp_m3ua_client_link *link)
|
||||||
|
{
|
||||||
|
link->connect_timer.data = link;
|
||||||
|
link->connect_timer.cb = m3ua_start;
|
||||||
|
osmo_timer_schedule(&link->connect_timer, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fail_link(struct mtp_m3ua_client_link *link)
|
||||||
|
{
|
||||||
|
/* We need to fail the link */
|
||||||
|
m3ua_shutdown(link->base);
|
||||||
|
mtp_link_down(link->base);
|
||||||
|
schedule_restart(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_conn_handle(struct mtp_m3ua_client_link *link,
|
||||||
|
struct msgb *msg, struct sctp_sndrcvinfo *info)
|
||||||
|
{
|
||||||
|
struct xua_msg *m3ua;
|
||||||
|
m3ua = xua_from_msg(M3UA_VERSION, msg->len, msg->data);
|
||||||
|
if (!m3ua) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to parse the message.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m3ua->hdr.msg_class) {
|
||||||
|
case M3UA_CLS_ASPSM:
|
||||||
|
m3ua_handle_aspsm(link, m3ua);
|
||||||
|
break;
|
||||||
|
case M3UA_CLS_ASPTM:
|
||||||
|
m3ua_handle_asptm(link, m3ua);
|
||||||
|
break;
|
||||||
|
case M3UA_CLS_TRANS:
|
||||||
|
m3ua_handle_trans(link, m3ua);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Unhandled msg_class %d\n",
|
||||||
|
m3ua->hdr.msg_class);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xua_msg_free(m3ua);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_conn_write(struct osmo_fd *fd, struct msgb *msg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct sctp_sndrcvinfo info;
|
||||||
|
memcpy(&info, msg->data, sizeof(info));
|
||||||
|
|
||||||
|
ret = sctp_send(fd->fd, msg->l2h, msgb_l2len(msg),
|
||||||
|
&info, 0);
|
||||||
|
|
||||||
|
if (ret != msgb_l2len(msg))
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to send %d.\n", ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_conn_send(struct mtp_m3ua_client_link *link,
|
||||||
|
struct xua_msg *m3ua,
|
||||||
|
struct sctp_sndrcvinfo *info)
|
||||||
|
{
|
||||||
|
struct msgb *msg;
|
||||||
|
msg = xua_to_msg(M3UA_VERSION, m3ua);
|
||||||
|
if (!msg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* save the OOB data in front of the message */
|
||||||
|
msg->l2h = msg->data;
|
||||||
|
msgb_push(msg, sizeof(*info));
|
||||||
|
memcpy(msg->data, info, sizeof(*info));
|
||||||
|
|
||||||
|
if (osmo_wqueue_enqueue(&link->queue, msg) != 0) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to enqueue.\n");
|
||||||
|
msgb_free(msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_conn_read(struct osmo_fd *fd)
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
struct sctp_sndrcvinfo info;
|
||||||
|
socklen_t len = sizeof(addr);
|
||||||
|
struct mtp_m3ua_client_link *link = fd->data;
|
||||||
|
struct msgb *msg;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
msg = msgb_alloc(2048, "m3ua buffer");
|
||||||
|
if (!msg) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to allocate buffer.\n");
|
||||||
|
fail_link(link);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
rc = sctp_recvmsg(fd->fd, msg->data, msg->data_len,
|
||||||
|
(struct sockaddr *) &addr, &len, &info, NULL);
|
||||||
|
if (rc <= 0) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to read.\n");
|
||||||
|
msgb_free(msg);
|
||||||
|
fail_link(link);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ntohl(info.sinfo_ppid) != SCTP_PPID_M3UA) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Only M3UA is allowed on this socket: %d\n",
|
||||||
|
ntohl(info.sinfo_ppid));
|
||||||
|
msgb_free(msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgb_put(msg, rc);
|
||||||
|
LOGP(DINP, LOGL_DEBUG, "Read %d on stream: %d ssn: %d assoc: %d\n",
|
||||||
|
rc, info.sinfo_stream, info.sinfo_ssn, info.sinfo_assoc_id);
|
||||||
|
m3ua_conn_handle(link, msg, &info);
|
||||||
|
msgb_free(msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void m3ua_start(void *data)
|
||||||
|
{
|
||||||
|
int sctp, ret;
|
||||||
|
struct sockaddr_in loc_addr, rem_addr;
|
||||||
|
struct mtp_m3ua_client_link *link = data;
|
||||||
|
struct sctp_event_subscribe events;
|
||||||
|
|
||||||
|
sctp = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
|
||||||
|
if (!sctp) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to create socket.\n");
|
||||||
|
return fail_link(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&events, 0, sizeof(events));
|
||||||
|
events.sctp_data_io_event = 1;
|
||||||
|
ret = setsockopt(sctp, SOL_SCTP, SCTP_EVENTS, &events, sizeof(events));
|
||||||
|
if (ret != 0) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to enable SCTP Events. Closing socket.\n");
|
||||||
|
close(sctp);
|
||||||
|
return fail_link(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
loc_addr = link->local;
|
||||||
|
loc_addr.sin_family = AF_INET;
|
||||||
|
if (bind(sctp, (struct sockaddr *) &loc_addr, sizeof(loc_addr)) != 0) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to bind.\n");
|
||||||
|
close(sctp);
|
||||||
|
return fail_link(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
rem_addr = link->remote;
|
||||||
|
rem_addr.sin_family = AF_INET;
|
||||||
|
if (connect(sctp, (struct sockaddr *) &rem_addr, sizeof(rem_addr)) != 0) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to connect\n");
|
||||||
|
close(sctp);
|
||||||
|
return fail_link(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
link->queue.bfd.fd = sctp;
|
||||||
|
link->queue.bfd.data = link;
|
||||||
|
link->queue.bfd.when = BSC_FD_READ;
|
||||||
|
link->queue.read_cb = m3ua_conn_read;
|
||||||
|
link->queue.write_cb = m3ua_conn_write;
|
||||||
|
|
||||||
|
if (osmo_fd_register(&link->queue.bfd) != 0) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to register fd\n");
|
||||||
|
close(sctp);
|
||||||
|
return fail_link(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* begin the messages for bring-up */
|
||||||
|
m3ua_send_aspup(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_write(struct mtp_link *mtp_link, struct msgb *msg)
|
||||||
|
{
|
||||||
|
struct mtp_m3ua_client_link *link = mtp_link->data;
|
||||||
|
struct sctp_sndrcvinfo info;
|
||||||
|
struct xua_msg *m3ua;
|
||||||
|
struct mtp_level_3_hdr *mtp_hdr;
|
||||||
|
struct m3ua_protocol_data proto_data;
|
||||||
|
uint8_t *proto_start;
|
||||||
|
|
||||||
|
if (!link->asptm_active) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "ASP not ready for %d/%s of %d/%s.\n",
|
||||||
|
mtp_link->nr, mtp_link->name, mtp_link->set->nr,
|
||||||
|
mtp_link->set->name);
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO.. we could enhance the structure of mtp_link to
|
||||||
|
* have function pointers for operations like SLTM instead
|
||||||
|
* of doing what we do here.
|
||||||
|
* The entire m3ua episode (code + reading the spec) had a
|
||||||
|
* budget of < 2 man days so the amount of architecture changes
|
||||||
|
* we can do.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO.. need to terminate MTPL3 locally... */
|
||||||
|
|
||||||
|
/* TODO.. extract MTP information.. */
|
||||||
|
mtp_hdr = (struct mtp_level_3_hdr *) msg->l2h;
|
||||||
|
switch (mtp_hdr->ser_ind) {
|
||||||
|
case MTP_SI_MNT_SNM_MSG:
|
||||||
|
case MTP_SI_MNT_REG_MSG:
|
||||||
|
LOGP(DINP, LOGL_ERROR,
|
||||||
|
"Dropping SNM/REG message %d\n", mtp_hdr->ser_ind);
|
||||||
|
goto clean;
|
||||||
|
break;
|
||||||
|
case MTP_SI_MNT_ISUP:
|
||||||
|
case MTP_SI_MNT_SCCP:
|
||||||
|
default:
|
||||||
|
memset(&proto_data, 0, sizeof(proto_data));
|
||||||
|
proto_data.opc = htonl(MTP_READ_OPC(mtp_hdr->addr));
|
||||||
|
proto_data.dpc = htonl(MTP_READ_DPC(mtp_hdr->addr));
|
||||||
|
proto_data.sls = MTP_LINK_SLS(mtp_hdr->addr);
|
||||||
|
proto_data.si = mtp_hdr->ser_ind;
|
||||||
|
proto_data.ni = mtp_link->set->ni;
|
||||||
|
|
||||||
|
msg->l3h = mtp_hdr->data;
|
||||||
|
msgb_pull_to_l3(msg);
|
||||||
|
proto_start = msgb_push(msg, sizeof(proto_data));
|
||||||
|
memcpy(proto_start, &proto_data, sizeof(proto_data));
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
m3ua = xua_msg_alloc();
|
||||||
|
if (!m3ua)
|
||||||
|
goto clean;
|
||||||
|
|
||||||
|
mtp_handle_pcap(mtp_link, NET_OUT, msg->data, msg->len);
|
||||||
|
|
||||||
|
m3ua->hdr.msg_class = M3UA_CLS_TRANS;
|
||||||
|
m3ua->hdr.msg_type = M3UA_TRANS_DATA;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modify the data...to create a true protocol data..
|
||||||
|
*/
|
||||||
|
xua_msg_add_data(m3ua, M3UA_TAG_PROTO_DATA, msg->len, msg->data);
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.sinfo_stream = 1;
|
||||||
|
info.sinfo_assoc_id = 1;
|
||||||
|
info.sinfo_ppid = htonl(SCTP_PPID_M3UA);
|
||||||
|
|
||||||
|
m3ua_conn_send(link, m3ua, &info);
|
||||||
|
xua_msg_free(m3ua);
|
||||||
|
|
||||||
|
clean:
|
||||||
|
msgb_free(msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_shutdown(struct mtp_link *mtp_link)
|
||||||
|
{
|
||||||
|
struct mtp_m3ua_client_link *link = mtp_link->data;
|
||||||
|
|
||||||
|
if (link->queue.bfd.fd >= 0) {
|
||||||
|
osmo_fd_unregister(&link->queue.bfd);
|
||||||
|
close(link->queue.bfd.fd);
|
||||||
|
link->queue.bfd.fd = -1;
|
||||||
|
}
|
||||||
|
osmo_wqueue_clear(&link->queue);
|
||||||
|
link->aspsm_active = 0;
|
||||||
|
link->asptm_active = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_reset(struct mtp_link *mtp_link)
|
||||||
|
{
|
||||||
|
struct mtp_m3ua_client_link *link = mtp_link->data;
|
||||||
|
|
||||||
|
/* stop things in case they run.. */
|
||||||
|
m3ua_shutdown(mtp_link);
|
||||||
|
schedule_restart(link);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m3ua_clear_queue(struct mtp_link *mtp_link)
|
||||||
|
{
|
||||||
|
struct mtp_m3ua_client_link *link = mtp_link->data;
|
||||||
|
osmo_wqueue_clear(&link->queue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mtp_m3ua_client_link *mtp_m3ua_client_link_init(struct mtp_link *blnk)
|
||||||
|
{
|
||||||
|
struct mtp_m3ua_client_link *lnk;
|
||||||
|
|
||||||
|
lnk = talloc_zero(blnk, struct mtp_m3ua_client_link);
|
||||||
|
if (!lnk) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to allocate.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure we can resolve it both ways */
|
||||||
|
lnk->base = blnk;
|
||||||
|
blnk->data = lnk;
|
||||||
|
blnk->type = SS7_LTYPE_M3UA_CLIENT;
|
||||||
|
|
||||||
|
/* do some checks for lower layer handling */
|
||||||
|
blnk->skip_link_test = 1;
|
||||||
|
|
||||||
|
lnk->base->write = m3ua_write;
|
||||||
|
lnk->base->shutdown = m3ua_shutdown;
|
||||||
|
lnk->base->reset = m3ua_reset;
|
||||||
|
lnk->base->clear_queue = m3ua_clear_queue;
|
||||||
|
|
||||||
|
osmo_wqueue_init(&lnk->queue, 10);
|
||||||
|
lnk->queue.bfd.fd = -1;
|
||||||
|
return lnk;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* asp handling
|
||||||
|
*/
|
||||||
|
static void m3ua_send_aspup(struct mtp_m3ua_client_link *link)
|
||||||
|
{
|
||||||
|
struct sctp_sndrcvinfo info;
|
||||||
|
struct xua_msg *aspup;
|
||||||
|
uint32_t asp_ident;
|
||||||
|
|
||||||
|
aspup = xua_msg_alloc();
|
||||||
|
if (!aspup) {
|
||||||
|
fail_link(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.sinfo_stream = 0;
|
||||||
|
info.sinfo_assoc_id = 1;
|
||||||
|
info.sinfo_ppid = htonl(SCTP_PPID_M3UA);
|
||||||
|
|
||||||
|
aspup->hdr.msg_class = M3UA_CLS_ASPSM;
|
||||||
|
aspup->hdr.msg_type = M3UA_ASPSM_UP;
|
||||||
|
|
||||||
|
asp_ident = htonl(link->link_index);
|
||||||
|
xua_msg_add_data(aspup, MUA_TAG_ASP_IDENT, 4, (uint8_t *) &asp_ident);
|
||||||
|
|
||||||
|
m3ua_conn_send(link, aspup, &info);
|
||||||
|
xua_msg_free(aspup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void m3ua_send_aspac(struct mtp_m3ua_client_link *link)
|
||||||
|
{
|
||||||
|
struct sctp_sndrcvinfo info;
|
||||||
|
struct xua_msg *aspac;
|
||||||
|
uint32_t routing_ctx;
|
||||||
|
uint32_t traffic_mode;
|
||||||
|
|
||||||
|
aspac = xua_msg_alloc();
|
||||||
|
if (!aspac) {
|
||||||
|
fail_link(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.sinfo_stream = 0;
|
||||||
|
info.sinfo_assoc_id = 1;
|
||||||
|
info.sinfo_ppid = htonl(SCTP_PPID_M3UA);
|
||||||
|
|
||||||
|
aspac->hdr.msg_class = M3UA_CLS_ASPTM;
|
||||||
|
aspac->hdr.msg_type = M3UA_ASPTM_ACTIV;
|
||||||
|
|
||||||
|
traffic_mode = htonl(2);
|
||||||
|
xua_msg_add_data(aspac, 11, 4, (uint8_t *) &traffic_mode);
|
||||||
|
|
||||||
|
routing_ctx = htonl(link->routing_context);
|
||||||
|
xua_msg_add_data(aspac, MUA_TAG_ROUTING_CTX, 4, (uint8_t *) &routing_ctx);
|
||||||
|
|
||||||
|
m3ua_conn_send(link, aspac, &info);
|
||||||
|
xua_msg_free(aspac);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void m3ua_send_daud(struct mtp_m3ua_client_link *link, uint32_t dpc)
|
||||||
|
{
|
||||||
|
struct sctp_sndrcvinfo info;
|
||||||
|
struct xua_msg *daud;
|
||||||
|
uint32_t routing_ctx;
|
||||||
|
|
||||||
|
daud = xua_msg_alloc();
|
||||||
|
if (!daud) {
|
||||||
|
fail_link(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.sinfo_stream = 0;
|
||||||
|
info.sinfo_assoc_id = 1;
|
||||||
|
info.sinfo_ppid = htonl(SCTP_PPID_M3UA);
|
||||||
|
|
||||||
|
daud->hdr.msg_class = M3UA_CLS_SSNM;
|
||||||
|
daud->hdr.msg_type = M3UA_SSNM_DAUD;
|
||||||
|
|
||||||
|
routing_ctx = htonl(link->routing_context);
|
||||||
|
xua_msg_add_data(daud, MUA_TAG_ROUTING_CTX, 4, (uint8_t *) &routing_ctx);
|
||||||
|
|
||||||
|
dpc = htonl(dpc);
|
||||||
|
xua_msg_add_data(daud, MUA_TAG_AFF_PC, 4, (uint8_t *) &dpc);
|
||||||
|
|
||||||
|
m3ua_conn_send(link, daud, &info);
|
||||||
|
xua_msg_free(daud);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void m3ua_handle_aspsm(struct mtp_m3ua_client_link *link, struct xua_msg *m3ua)
|
||||||
|
{
|
||||||
|
switch (m3ua->hdr.msg_type) {
|
||||||
|
case M3UA_ASPSM_UP_ACK:
|
||||||
|
LOGP(DINP, LOGL_NOTICE, "Received ASP_UP_ACK.. sending ASPAC\n");
|
||||||
|
link->aspsm_active = 1;
|
||||||
|
m3ua_send_aspac(link);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
|
||||||
|
m3ua->hdr.msg_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void m3ua_handle_asptm(struct mtp_m3ua_client_link *link, struct xua_msg *m3ua)
|
||||||
|
{
|
||||||
|
switch (m3ua->hdr.msg_type) {
|
||||||
|
case M3UA_ASPTM_ACTIV_ACK:
|
||||||
|
LOGP(DINP, LOGL_NOTICE, "Received ASPAC_ACK.. taking link up\n");
|
||||||
|
link->asptm_active = 1;
|
||||||
|
mtp_link_up(link->base);
|
||||||
|
m3ua_send_daud(link, link->base->set->dpc);
|
||||||
|
if (link->base->set->sccp_dpc != -1)
|
||||||
|
m3ua_send_daud(link, link->base->set->sccp_dpc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
|
||||||
|
m3ua->hdr.msg_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void m3ua_handle_trans(struct mtp_m3ua_client_link *link, struct xua_msg *m3ua)
|
||||||
|
{
|
||||||
|
struct msgb *msg;
|
||||||
|
struct xua_msg_part *data;
|
||||||
|
struct mtp_link *mtp_link;
|
||||||
|
struct m3ua_protocol_data *proto;
|
||||||
|
struct mtp_level_3_hdr *mtp_hdr;
|
||||||
|
uint32_t opc, dpc;
|
||||||
|
uint8_t sls, si;
|
||||||
|
|
||||||
|
mtp_link = link->base;
|
||||||
|
|
||||||
|
/* ignore everything if the link is blocked */
|
||||||
|
if (mtp_link->blocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m3ua->hdr.msg_type != M3UA_TRANS_DATA) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "msg_type(%d) is not known. Ignoring\n",
|
||||||
|
m3ua->hdr.msg_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = xua_msg_find_tag(m3ua, M3UA_TAG_PROTO_DATA);
|
||||||
|
if (!data) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "No PROTO_DATA in DATA message.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->len > 2048) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "TOO much data for us to handle.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->len < sizeof(struct m3ua_protocol_data)) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Too little data..\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = msgb_alloc(2048, "m3ua-data");
|
||||||
|
if (!msg) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "Failed to allocate storage.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->l2h = msgb_put(msg, data->len);
|
||||||
|
memcpy(msg->l2h, data->dat, data->len);
|
||||||
|
|
||||||
|
proto = (struct m3ua_protocol_data *) msg->l2h;
|
||||||
|
opc = ntohl(proto->opc);
|
||||||
|
dpc = ntohl(proto->dpc);
|
||||||
|
sls = proto->sls;
|
||||||
|
si = proto->si;
|
||||||
|
LOGP(DINP, LOGL_DEBUG, "Got data for OPC(%d)/DPC(%d)/SLS(%d) len(%d)\n",
|
||||||
|
opc, dpc, sls, msgb_l2len(msg) - sizeof(*proto));
|
||||||
|
|
||||||
|
|
||||||
|
/* put a MTP3 header in front */
|
||||||
|
msg->l3h = proto->data;
|
||||||
|
msgb_pull_to_l3(msg);
|
||||||
|
msg->l2h = msgb_push(msg, sizeof(*mtp_hdr));
|
||||||
|
mtp_hdr = (struct mtp_level_3_hdr *) msg->l2h;
|
||||||
|
mtp_hdr->ser_ind = si;
|
||||||
|
mtp_hdr->addr = MTP_ADDR(sls % 16, dpc, opc);
|
||||||
|
|
||||||
|
mtp_handle_pcap(mtp_link, NET_IN, msg->l2h, msgb_l2len(msg));
|
||||||
|
mtp_link_set_data(mtp_link, msg);
|
||||||
|
msgb_free(msg);
|
||||||
|
}
|
|
@ -23,6 +23,7 @@
|
||||||
#include <mtp_pcap.h>
|
#include <mtp_pcap.h>
|
||||||
#include <msc_connection.h>
|
#include <msc_connection.h>
|
||||||
#include <sctp_m2ua.h>
|
#include <sctp_m2ua.h>
|
||||||
|
#include <sctp_m3ua.h>
|
||||||
#include <ss7_application.h>
|
#include <ss7_application.h>
|
||||||
#include <ss7_vty.h>
|
#include <ss7_vty.h>
|
||||||
#include <cellmgr_debug.h>
|
#include <cellmgr_debug.h>
|
||||||
|
@ -157,6 +158,7 @@ static void write_link(struct vty *vty, struct mtp_link *link)
|
||||||
const char *name = link->name ? link->name : "";
|
const char *name = link->name ? link->name : "";
|
||||||
struct mtp_udp_link *ulnk;
|
struct mtp_udp_link *ulnk;
|
||||||
struct mtp_m2ua_link *m2ua;
|
struct mtp_m2ua_link *m2ua;
|
||||||
|
struct mtp_m3ua_client_link *m3ua_client;
|
||||||
|
|
||||||
vty_out(vty, " link %d%s", link->nr, VTY_NEWLINE);
|
vty_out(vty, " link %d%s", link->nr, VTY_NEWLINE);
|
||||||
vty_out(vty, " description %s%s", name, VTY_NEWLINE);
|
vty_out(vty, " description %s%s", name, VTY_NEWLINE);
|
||||||
|
@ -179,11 +181,27 @@ static void write_link(struct vty *vty, struct mtp_link *link)
|
||||||
vty_out(vty, " ss7-transport m2ua%s", VTY_NEWLINE);
|
vty_out(vty, " ss7-transport m2ua%s", VTY_NEWLINE);
|
||||||
|
|
||||||
if (m2ua->as)
|
if (m2ua->as)
|
||||||
vty_out(vty, " m2ua application-server %s%s",
|
vty_out(vty, " m2ua application-server-index %s%s",
|
||||||
m2ua->as, VTY_NEWLINE);
|
m2ua->as, VTY_NEWLINE);
|
||||||
vty_out(vty, " m2ua link-index %d%s",
|
vty_out(vty, " m2ua link-index %d%s",
|
||||||
m2ua->link_index, VTY_NEWLINE);
|
m2ua->link_index, VTY_NEWLINE);
|
||||||
break;
|
break;
|
||||||
|
case SS7_LTYPE_M3UA_CLIENT:
|
||||||
|
m3ua_client = (struct mtp_m3ua_client_link *) link->data;
|
||||||
|
vty_out(vty, " ss7-transport m3ua-client%s", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " m3ua-client source ip %s%s",
|
||||||
|
inet_ntoa(m3ua_client->local.sin_addr), VTY_NEWLINE);
|
||||||
|
vty_out(vty, " m3ua-client source port %d%s",
|
||||||
|
ntohs(m3ua_client->local.sin_port), VTY_NEWLINE);
|
||||||
|
vty_out(vty, " m3ua-client dest ip %s%s",
|
||||||
|
inet_ntoa(m3ua_client->remote.sin_addr), VTY_NEWLINE);
|
||||||
|
vty_out(vty, " m3ua-client dest port %d%s",
|
||||||
|
ntohs(m3ua_client->remote.sin_port), VTY_NEWLINE);
|
||||||
|
vty_out(vty, " m3ua-client link-index %d%s",
|
||||||
|
m3ua_client->link_index, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " m3ua-client routing-context %d%s",
|
||||||
|
m3ua_client->routing_context, VTY_NEWLINE);
|
||||||
|
break;
|
||||||
case SS7_LTYPE_NONE:
|
case SS7_LTYPE_NONE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -573,7 +591,7 @@ DEFUN(cfg_linkset_link, cfg_linkset_link_cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(cfg_link_ss7_transport, cfg_link_ss7_transport_cmd,
|
DEFUN(cfg_link_ss7_transport, cfg_link_ss7_transport_cmd,
|
||||||
"ss7-transport (none|udp|m2ua)",
|
"ss7-transport (none|udp|m2ua|m3ua-client)",
|
||||||
"SS7 transport for the link\n"
|
"SS7 transport for the link\n"
|
||||||
"No transport\n" "MTP over UDP\n" "SCTP M2UA\n")
|
"No transport\n" "MTP over UDP\n" "SCTP M2UA\n")
|
||||||
{
|
{
|
||||||
|
@ -586,6 +604,8 @@ DEFUN(cfg_link_ss7_transport, cfg_link_ss7_transport_cmd,
|
||||||
wanted = SS7_LTYPE_UDP;
|
wanted = SS7_LTYPE_UDP;
|
||||||
else if (strcmp("m2ua", argv[0]) == 0)
|
else if (strcmp("m2ua", argv[0]) == 0)
|
||||||
wanted = SS7_LTYPE_M2UA;
|
wanted = SS7_LTYPE_M2UA;
|
||||||
|
else if (strcmp("m3ua-client", argv[0]) == 0)
|
||||||
|
wanted = SS7_LTYPE_M3UA_CLIENT;
|
||||||
|
|
||||||
if (link->type != wanted && link->type != SS7_LTYPE_NONE) {
|
if (link->type != wanted && link->type != SS7_LTYPE_NONE) {
|
||||||
vty_out(vty, "%%Can not change the type of a link.\n");
|
vty_out(vty, "%%Can not change the type of a link.\n");
|
||||||
|
@ -599,6 +619,9 @@ DEFUN(cfg_link_ss7_transport, cfg_link_ss7_transport_cmd,
|
||||||
case SS7_LTYPE_M2UA:
|
case SS7_LTYPE_M2UA:
|
||||||
link->data = mtp_m2ua_link_init(link);
|
link->data = mtp_m2ua_link_init(link);
|
||||||
break;
|
break;
|
||||||
|
case SS7_LTYPE_M3UA_CLIENT:
|
||||||
|
link->data = mtp_m3ua_client_link_init(link);
|
||||||
|
break;
|
||||||
case SS7_LTYPE_NONE:
|
case SS7_LTYPE_NONE:
|
||||||
/* nothing */
|
/* nothing */
|
||||||
break;
|
break;
|
||||||
|
@ -735,6 +758,131 @@ DEFUN(cfg_link_m2ua_link_index, cfg_link_m2ua_link_index_cmd,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEFUN(cfg_link_m3ua_client_source_ip, cfg_link_m3ua_client_source_ip_cmd,
|
||||||
|
"m3ua-client source ip HOST_NAME",
|
||||||
|
"M3UA Client\n" "Source Address\n" "IP\n" "Hostname or IPv4 address\n")
|
||||||
|
{
|
||||||
|
struct hostent *hosts;
|
||||||
|
|
||||||
|
struct mtp_link *link = vty->index;
|
||||||
|
struct mtp_m3ua_client_link *m3ua_link;
|
||||||
|
|
||||||
|
if (link->type != SS7_LTYPE_M3UA_CLIENT) {
|
||||||
|
vty_out(vty, "%%This only applies to UDP links.%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
m3ua_link = link->data;
|
||||||
|
|
||||||
|
talloc_free(m3ua_link->source);
|
||||||
|
m3ua_link->source = talloc_strdup(m3ua_link, argv[0]);
|
||||||
|
|
||||||
|
hosts = gethostbyname(m3ua_link->source);
|
||||||
|
if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
|
||||||
|
vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
m3ua_link->local.sin_addr = * (struct in_addr *) hosts->h_addr_list[0];
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_link_m3ua_client_source_port, cfg_link_m3ua_client_source_port_cmd,
|
||||||
|
"m3ua-client source port <1-65535>",
|
||||||
|
"M3UA Client\n" "Source Address\n" "Port\n" "Number\n")
|
||||||
|
{
|
||||||
|
struct mtp_link *link = vty->index;
|
||||||
|
struct mtp_m3ua_client_link *m3ua_link;
|
||||||
|
|
||||||
|
if (link->type != SS7_LTYPE_M3UA_CLIENT) {
|
||||||
|
vty_out(vty, "%%This only applies to UDP links.%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
m3ua_link = link->data;
|
||||||
|
m3ua_link->local.sin_port = htons(atoi(argv[0]));
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_link_m3ua_client_dest_ip, cfg_link_m3ua_client_dest_ip_cmd,
|
||||||
|
"m3ua-client dest ip HOST_NAME",
|
||||||
|
"M3UA Client\n" "Destination Address\n" "IP\n" "Hostname or IPv4 address\n")
|
||||||
|
{
|
||||||
|
struct hostent *hosts;
|
||||||
|
|
||||||
|
struct mtp_link *link = vty->index;
|
||||||
|
struct mtp_m3ua_client_link *m3ua_link;
|
||||||
|
|
||||||
|
if (link->type != SS7_LTYPE_M3UA_CLIENT) {
|
||||||
|
vty_out(vty, "%%This only applies to M3UA client links.%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
m3ua_link = link->data;
|
||||||
|
|
||||||
|
talloc_free(m3ua_link->dest);
|
||||||
|
m3ua_link->dest = talloc_strdup(m3ua_link, argv[0]);
|
||||||
|
|
||||||
|
hosts = gethostbyname(m3ua_link->dest);
|
||||||
|
if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
|
||||||
|
vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
m3ua_link->remote.sin_addr = * (struct in_addr *) hosts->h_addr_list[0];
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_link_m3ua_client_dest_port, cfg_link_m3ua_client_dest_port_cmd,
|
||||||
|
"m3ua-client dest port <1-65535>",
|
||||||
|
"M3UA Client\n" "Destination Address\n" "Port\n" "Number\n")
|
||||||
|
{
|
||||||
|
struct mtp_link *link = vty->index;
|
||||||
|
struct mtp_m3ua_client_link *m3ua_link;
|
||||||
|
|
||||||
|
if (link->type != SS7_LTYPE_M3UA_CLIENT) {
|
||||||
|
vty_out(vty, "%%This only applies to M3UA client links.%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
m3ua_link = link->data;
|
||||||
|
m3ua_link->remote.sin_port = htons(atoi(argv[0]));
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_link_m3ua_client_link_index, cfg_link_m3ua_client_link_index_cmd,
|
||||||
|
"m3ua-client link-index <0-65535>",
|
||||||
|
"M3UA Client\n" "Link index\n" "Index\n")
|
||||||
|
{
|
||||||
|
struct mtp_link *link = vty->index;
|
||||||
|
struct mtp_m3ua_client_link *m3ua_link;
|
||||||
|
|
||||||
|
if (link->type != SS7_LTYPE_M3UA_CLIENT) {
|
||||||
|
vty_out(vty, "%%This only applies to M3UA client links.%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
m3ua_link = link->data;
|
||||||
|
m3ua_link->link_index = atoi(argv[0]);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_link_m3ua_client_routing_ctx, cfg_link_m3ua_client_routing_ctx_cmd,
|
||||||
|
"m3ua-client routing-context <0-65535>",
|
||||||
|
"M3UA Client\n" "Routing Context\n" "Nunber\n")
|
||||||
|
{
|
||||||
|
struct mtp_link *link = vty->index;
|
||||||
|
struct mtp_m3ua_client_link *m3ua_link;
|
||||||
|
|
||||||
|
if (link->type != SS7_LTYPE_M3UA_CLIENT) {
|
||||||
|
vty_out(vty, "%%This only applies to M3UA client links.%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
m3ua_link = link->data;
|
||||||
|
m3ua_link->routing_context = atoi(argv[0]);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN(cfg_ss7_msc, cfg_ss7_msc_cmd,
|
DEFUN(cfg_ss7_msc, cfg_ss7_msc_cmd,
|
||||||
"msc <0-100>",
|
"msc <0-100>",
|
||||||
"MSC Connection\n" "MSC Number\n")
|
"MSC Connection\n" "MSC Number\n")
|
||||||
|
@ -1151,6 +1299,12 @@ void cell_vty_init(void)
|
||||||
install_element(LINK_NODE, &cfg_link_udp_link_index_cmd);
|
install_element(LINK_NODE, &cfg_link_udp_link_index_cmd);
|
||||||
install_element(LINK_NODE, &cfg_link_m2ua_as_cmd);
|
install_element(LINK_NODE, &cfg_link_m2ua_as_cmd);
|
||||||
install_element(LINK_NODE, &cfg_link_m2ua_link_index_cmd);
|
install_element(LINK_NODE, &cfg_link_m2ua_link_index_cmd);
|
||||||
|
install_element(LINK_NODE, &cfg_link_m3ua_client_source_ip_cmd);
|
||||||
|
install_element(LINK_NODE, &cfg_link_m3ua_client_source_port_cmd);
|
||||||
|
install_element(LINK_NODE, &cfg_link_m3ua_client_dest_ip_cmd);
|
||||||
|
install_element(LINK_NODE, &cfg_link_m3ua_client_dest_port_cmd);
|
||||||
|
install_element(LINK_NODE, &cfg_link_m3ua_client_link_index_cmd);
|
||||||
|
install_element(LINK_NODE, &cfg_link_m3ua_client_routing_ctx_cmd);
|
||||||
|
|
||||||
install_element(SS7_NODE, &cfg_ss7_msc_cmd);
|
install_element(SS7_NODE, &cfg_ss7_msc_cmd);
|
||||||
install_node(&msc_node, config_write_msc);
|
install_node(&msc_node, config_write_msc);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -Wall
|
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -Wall
|
||||||
noinst_PROGRAMS = mtp_parse_test
|
noinst_PROGRAMS = mtp_parse_test
|
||||||
|
|
||||||
EXTRA_DIST = mtp_parse_test.ok
|
EXTRA_DIST = mtp_parse_test.ok
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* MTP Layer3 parsing tests */
|
/* MTP Layer3 parsing tests */
|
||||||
#include <mtp_level3.h>
|
#include <osmocom/mtp/mtp_level3.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
@ -590,14 +590,14 @@ int main(int argc, char **argv)
|
||||||
tests[2].prohib.apoc = MTP_MAKE_APOC(86);
|
tests[2].prohib.apoc = MTP_MAKE_APOC(86);
|
||||||
|
|
||||||
addr = MTP_ADDR(0x00, 0x2AAA, 0x1555);
|
addr = MTP_ADDR(0x00, 0x2AAA, 0x1555);
|
||||||
if (MTP_ADDR_OPC(addr) != 0x1555) {
|
if (MTP_READ_OPC(addr) != 0x1555) {
|
||||||
fprintf(stderr, "Failed to extract OPC: %d\n",
|
fprintf(stderr, "Failed to extract OPC: %d\n",
|
||||||
MTP_ADDR_OPC(addr));
|
MTP_READ_OPC(addr));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
if (MTP_ADDR_DPC(addr) != 0x2AAA) {
|
if (MTP_READ_DPC(addr) != 0x2AAA) {
|
||||||
fprintf(stderr, "Failed to extract DPC: %d\n",
|
fprintf(stderr, "Failed to extract DPC: %d\n",
|
||||||
MTP_ADDR_DPC(addr));
|
MTP_READ_DPC(addr));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue