mncc: Support IPv6 addresses (new version mncc 7)
Change-Id: I3b1bebbcc9e36be43d8d055c8d28cbb38ff21b37
This commit is contained in:
parent
f678caa819
commit
b6cb607d12
|
@ -7,6 +7,7 @@
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
struct sip_agent;
|
struct sip_agent;
|
||||||
struct mncc_connection;
|
struct mncc_connection;
|
||||||
|
@ -49,8 +50,7 @@ struct call_leg {
|
||||||
/**
|
/**
|
||||||
* RTP data
|
* RTP data
|
||||||
*/
|
*/
|
||||||
uint32_t ip;
|
struct sockaddr_storage addr;
|
||||||
uint16_t port;
|
|
||||||
uint32_t payload_type;
|
uint32_t payload_type;
|
||||||
uint32_t payload_msg_type;
|
uint32_t payload_msg_type;
|
||||||
|
|
||||||
|
|
29
src/mncc.c
29
src/mncc.c
|
@ -174,7 +174,7 @@ static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other)
|
||||||
{
|
{
|
||||||
struct gsm_mncc_rtp mncc = { 0, };
|
struct gsm_mncc_rtp mncc = { 0, };
|
||||||
int rc;
|
int rc;
|
||||||
char ip_addr[INET_ADDRSTRLEN];
|
char ip_addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send RTP CONNECT and we handle the general failure of it by
|
* Send RTP CONNECT and we handle the general failure of it by
|
||||||
|
@ -182,16 +182,15 @@ static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other)
|
||||||
*/
|
*/
|
||||||
mncc.msg_type = MNCC_RTP_CONNECT;
|
mncc.msg_type = MNCC_RTP_CONNECT;
|
||||||
mncc.callref = leg->callref;
|
mncc.callref = leg->callref;
|
||||||
mncc.ip = ntohl(other->ip);
|
mncc.addr = other->addr;
|
||||||
mncc.port = other->port;
|
|
||||||
mncc.payload_type = other->payload_type;
|
mncc.payload_type = other->payload_type;
|
||||||
/*
|
/*
|
||||||
* FIXME: mncc.payload_msg_type should already be compatible.. but
|
* FIXME: mncc.payload_msg_type should already be compatible.. but
|
||||||
* payload_type should be different..
|
* payload_type should be different..
|
||||||
*/
|
*/
|
||||||
struct in_addr net = { .s_addr = other->ip };
|
LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n",
|
||||||
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
|
osmo_sockaddr_ntop((const struct sockaddr*)&other->addr, ip_addr),
|
||||||
LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n", ip_addr, mncc.port);
|
osmo_sockaddr_port((const struct sockaddr*)&other->addr));
|
||||||
rc = write(leg->conn->fd.fd, &mncc, sizeof(mncc));
|
rc = write(leg->conn->fd.fd, &mncc, sizeof(mncc));
|
||||||
if (rc != sizeof(mncc)) {
|
if (rc != sizeof(mncc)) {
|
||||||
LOGP(DMNCC, LOGL_ERROR, "Failed to send message for call(%u)\n",
|
LOGP(DMNCC, LOGL_ERROR, "Failed to send message for call(%u)\n",
|
||||||
|
@ -272,7 +271,8 @@ static void mncc_call_leg_ring(struct call_leg *_leg)
|
||||||
* FIXME: We would like to keep this as recvonly...
|
* FIXME: We would like to keep this as recvonly...
|
||||||
*/
|
*/
|
||||||
other_leg = call_leg_other(&leg->base);
|
other_leg = call_leg_other(&leg->base);
|
||||||
if (other_leg && other_leg->port != 0 && other_leg->ip != 0)
|
if (other_leg && other_leg->addr.ss_family != AF_UNSPEC &&
|
||||||
|
osmo_sockaddr_port((const struct sockaddr *)&other_leg->addr) != 0)
|
||||||
send_rtp_connect(leg, other_leg);
|
send_rtp_connect(leg, other_leg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +397,9 @@ static void check_rtp_connect(struct mncc_connection *conn, const char *buf, int
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract information about where the RTP is */
|
/* extract information about where the RTP is */
|
||||||
if (rtp->ip != 0 || rtp->port != 0 || rtp->payload_type != 0)
|
if (rtp->addr.ss_family != AF_UNSPEC ||
|
||||||
|
osmo_sockaddr_port((const struct sockaddr *)&rtp->addr) != 0 ||
|
||||||
|
rtp->payload_type != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOGP(DMNCC, LOGL_ERROR, "leg(%u) rtp connect failed\n", rtp->callref);
|
LOGP(DMNCC, LOGL_ERROR, "leg(%u) rtp connect failed\n", rtp->callref);
|
||||||
|
@ -412,7 +414,7 @@ static void check_rtp_create(struct mncc_connection *conn, const char *buf, int
|
||||||
{
|
{
|
||||||
const struct gsm_mncc_rtp *rtp;
|
const struct gsm_mncc_rtp *rtp;
|
||||||
struct mncc_call_leg *leg;
|
struct mncc_call_leg *leg;
|
||||||
char ip_addr[INET_ADDRSTRLEN];
|
char ip_addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
if (rc < sizeof(*rtp)) {
|
if (rc < sizeof(*rtp)) {
|
||||||
LOGP(DMNCC, LOGL_ERROR, "gsm_mncc_rtp of wrong size %d < %zu\n",
|
LOGP(DMNCC, LOGL_ERROR, "gsm_mncc_rtp of wrong size %d < %zu\n",
|
||||||
|
@ -428,17 +430,16 @@ static void check_rtp_create(struct mncc_connection *conn, const char *buf, int
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract information about where the RTP is */
|
/* extract information about where the RTP is */
|
||||||
leg->base.ip = htonl(rtp->ip);
|
leg->base.addr = rtp->addr;
|
||||||
leg->base.port = rtp->port;
|
|
||||||
leg->base.payload_type = rtp->payload_type;
|
leg->base.payload_type = rtp->payload_type;
|
||||||
leg->base.payload_msg_type = rtp->payload_msg_type;
|
leg->base.payload_msg_type = rtp->payload_msg_type;
|
||||||
|
|
||||||
/* TODO.. now we can continue with the call */
|
/* TODO.. now we can continue with the call */
|
||||||
struct in_addr net = { .s_addr = leg->base.ip };
|
|
||||||
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
|
|
||||||
LOGP(DMNCC, LOGL_INFO,
|
LOGP(DMNCC, LOGL_INFO,
|
||||||
"RTP continue leg(%u) ip(%s), port(%u) pt(%u) ptm(%u)\n",
|
"RTP continue leg(%u) ip(%s), port(%u) pt(%u) ptm(%u)\n",
|
||||||
leg->callref, ip_addr, leg->base.port,
|
leg->callref,
|
||||||
|
osmo_sockaddr_ntop((const struct sockaddr*)&leg->base.addr, ip_addr),
|
||||||
|
osmo_sockaddr_port((const struct sockaddr*)&leg->base.addr),
|
||||||
leg->base.payload_type, leg->base.payload_msg_type);
|
leg->base.payload_type, leg->base.payload_msg_type);
|
||||||
stop_cmd_timer(leg, MNCC_RTP_CREATE);
|
stop_cmd_timer(leg, MNCC_RTP_CREATE);
|
||||||
continue_call(leg);
|
continue_call(leg);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
|
/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
|
||||||
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
|
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
|
||||||
|
|
||||||
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
|
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
#include <osmocom/gsm/mncc.h>
|
#include <osmocom/gsm/mncc.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
struct gsm_network;
|
struct gsm_network;
|
||||||
struct msgb;
|
struct msgb;
|
||||||
|
@ -169,7 +170,7 @@ struct gsm_data_frame {
|
||||||
unsigned char data[0];
|
unsigned char data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MNCC_SOCK_VERSION 6
|
#define MNCC_SOCK_VERSION 7
|
||||||
struct gsm_mncc_hello {
|
struct gsm_mncc_hello {
|
||||||
uint32_t msg_type;
|
uint32_t msg_type;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
|
@ -188,8 +189,7 @@ struct gsm_mncc_hello {
|
||||||
struct gsm_mncc_rtp {
|
struct gsm_mncc_rtp {
|
||||||
uint32_t msg_type;
|
uint32_t msg_type;
|
||||||
uint32_t callref;
|
uint32_t callref;
|
||||||
uint32_t ip;
|
struct sockaddr_storage addr;
|
||||||
uint16_t port;
|
|
||||||
uint32_t payload_type;
|
uint32_t payload_type;
|
||||||
uint32_t payload_msg_type;
|
uint32_t payload_msg_type;
|
||||||
char sdp[1024];
|
char sdp[1024];
|
||||||
|
|
53
src/sdp.c
53
src/sdp.c
|
@ -32,6 +32,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/socket.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the media mode attribute exists in SDP, in this
|
* Check if the media mode attribute exists in SDP, in this
|
||||||
* case update the passed pointer with the media mode
|
* case update the passed pointer with the media mode
|
||||||
|
@ -136,6 +138,7 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec)
|
||||||
sdp_parser_t *parser;
|
sdp_parser_t *parser;
|
||||||
sdp_media_t *media;
|
sdp_media_t *media;
|
||||||
const char *sdp_data;
|
const char *sdp_data;
|
||||||
|
uint16_t port;
|
||||||
bool found_conn = false, found_map = false;
|
bool found_conn = false, found_map = false;
|
||||||
|
|
||||||
if (!sip->sip_payload || !sip->sip_payload->pl_data) {
|
if (!sip->sip_payload || !sip->sip_payload->pl_data) {
|
||||||
|
@ -159,13 +162,22 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (conn = sdp->sdp_connection; conn; conn = conn->c_next) {
|
for (conn = sdp->sdp_connection; conn; conn = conn->c_next) {
|
||||||
struct in_addr addr;
|
switch (conn->c_addrtype) {
|
||||||
|
case sdp_addr_ip4:
|
||||||
if (conn->c_addrtype != sdp_addr_ip4)
|
leg->base.addr.ss_family = AF_INET;
|
||||||
|
inet_pton(AF_INET, conn->c_address,
|
||||||
|
&((struct sockaddr_in*)&leg->base.addr)->sin_addr);
|
||||||
|
found_conn = true;
|
||||||
|
break;
|
||||||
|
case sdp_addr_ip6:
|
||||||
|
leg->base.addr.ss_family = AF_INET6;
|
||||||
|
inet_pton(AF_INET6, conn->c_address,
|
||||||
|
&((struct sockaddr_in6*)&leg->base.addr)->sin6_addr);
|
||||||
|
found_conn = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
continue;
|
continue;
|
||||||
inet_aton(conn->c_address, &addr);
|
}
|
||||||
leg->base.ip = addr.s_addr;
|
|
||||||
found_conn = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +193,7 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec)
|
||||||
if (!any_codec && strcasecmp(map->rm_encoding, leg->wanted_codec) != 0)
|
if (!any_codec && strcasecmp(map->rm_encoding, leg->wanted_codec) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
leg->base.port = media->m_port;
|
port = media->m_port;
|
||||||
leg->base.payload_type = map->rm_pt;
|
leg->base.payload_type = map->rm_pt;
|
||||||
found_map = true;
|
found_map = true;
|
||||||
break;
|
break;
|
||||||
|
@ -198,18 +210,30 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (leg->base.addr.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
((struct sockaddr_in*)&leg->base.addr)->sin_port = htons(port);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
((struct sockaddr_in6*)&leg->base.addr)->sin6_port = htons(port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSMO_ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
sdp_parser_free(parser);
|
sdp_parser_free(parser);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *sdp_create_file(struct sip_call_leg *leg, struct call_leg *other, sdp_mode_t mode)
|
char *sdp_create_file(struct sip_call_leg *leg, struct call_leg *other, sdp_mode_t mode)
|
||||||
{
|
{
|
||||||
struct in_addr net = { .s_addr = other->ip };
|
|
||||||
char *fmtp_str = NULL, *sdp;
|
char *fmtp_str = NULL, *sdp;
|
||||||
char *mode_attribute;
|
char *mode_attribute;
|
||||||
char ip_addr[INET_ADDRSTRLEN];
|
char ip_addr[INET6_ADDRSTRLEN];
|
||||||
|
char ipv;
|
||||||
|
|
||||||
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
|
osmo_sockaddr_ntop((const struct sockaddr*)&other->addr, ip_addr);
|
||||||
|
ipv = other->addr.ss_family == AF_INET6 ? '6' : '4';
|
||||||
leg->wanted_codec = app_media_name(other->payload_msg_type);
|
leg->wanted_codec = app_media_name(other->payload_msg_type);
|
||||||
|
|
||||||
if (strcmp(leg->wanted_codec, "AMR") == 0)
|
if (strcmp(leg->wanted_codec, "AMR") == 0)
|
||||||
|
@ -235,16 +259,17 @@ char *sdp_create_file(struct sip_call_leg *leg, struct call_leg *other, sdp_mode
|
||||||
|
|
||||||
sdp = talloc_asprintf(leg,
|
sdp = talloc_asprintf(leg,
|
||||||
"v=0\r\n"
|
"v=0\r\n"
|
||||||
"o=Osmocom 0 0 IN IP4 %s\r\n"
|
"o=Osmocom 0 0 IN IP%c %s\r\n"
|
||||||
"s=GSM Call\r\n"
|
"s=GSM Call\r\n"
|
||||||
"c=IN IP4 %s\r\n"
|
"c=IN IP%c %s\r\n"
|
||||||
"t=0 0\r\n"
|
"t=0 0\r\n"
|
||||||
"m=audio %d RTP/AVP %d\r\n"
|
"m=audio %d RTP/AVP %d\r\n"
|
||||||
"%s"
|
"%s"
|
||||||
"a=rtpmap:%d %s/8000\r\n"
|
"a=rtpmap:%d %s/8000\r\n"
|
||||||
"%s",
|
"%s",
|
||||||
ip_addr, ip_addr,
|
ipv, ip_addr, ipv, ip_addr,
|
||||||
other->port, other->payload_type,
|
osmo_sockaddr_port((const struct sockaddr *)&other->addr),
|
||||||
|
other->payload_type,
|
||||||
fmtp_str ? fmtp_str : "",
|
fmtp_str ? fmtp_str : "",
|
||||||
other->payload_type,
|
other->payload_type,
|
||||||
leg->wanted_codec,
|
leg->wanted_codec,
|
||||||
|
|
30
src/sip.c
30
src/sip.c
|
@ -25,6 +25,7 @@
|
||||||
#include "sdp.h"
|
#include "sdp.h"
|
||||||
|
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/socket.h>
|
||||||
|
|
||||||
#include <sofia-sip/sip_status.h>
|
#include <sofia-sip/sip_status.h>
|
||||||
#include <sofia-sip/su_log.h>
|
#include <sofia-sip/su_log.h>
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
#include <talloc.h>
|
#include <talloc.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
extern void *tall_mncc_ctx;
|
extern void *tall_mncc_ctx;
|
||||||
|
|
||||||
|
@ -110,7 +112,7 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
|
||||||
struct call *call;
|
struct call *call;
|
||||||
struct sip_call_leg *leg;
|
struct sip_call_leg *leg;
|
||||||
const char *from = NULL, *to = NULL;
|
const char *from = NULL, *to = NULL;
|
||||||
char ip_addr[INET_ADDRSTRLEN];
|
char ip_addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
LOGP(DSIP, LOGL_INFO, "Incoming call(%s) handle(%p)\n", sip->sip_call_id->i_id, nh);
|
LOGP(DSIP, LOGL_INFO, "Incoming call(%s) handle(%p)\n", sip->sip_call_id->i_id, nh);
|
||||||
|
|
||||||
|
@ -159,11 +161,9 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
|
||||||
call_leg_release(&leg->base);
|
call_leg_release(&leg->base);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct in_addr net = { .s_addr = leg->base.ip };
|
|
||||||
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
|
|
||||||
LOGP(DSIP, LOGL_INFO, "SDP Extracted: IP=(%s) PORT=(%u) PAYLOAD=(%u).\n",
|
LOGP(DSIP, LOGL_INFO, "SDP Extracted: IP=(%s) PORT=(%u) PAYLOAD=(%u).\n",
|
||||||
ip_addr,
|
osmo_sockaddr_ntop((const struct sockaddr *)&leg->base.addr, ip_addr),
|
||||||
leg->base.port,
|
osmo_sockaddr_port((const struct sockaddr *)&leg->base.addr),
|
||||||
leg->base.payload_type);
|
leg->base.payload_type);
|
||||||
|
|
||||||
leg->base.release_call = sip_release_call;
|
leg->base.release_call = sip_release_call;
|
||||||
|
@ -186,9 +186,8 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons
|
||||||
|
|
||||||
char *sdp;
|
char *sdp;
|
||||||
sdp_mode_t mode = sdp_sendrecv;
|
sdp_mode_t mode = sdp_sendrecv;
|
||||||
uint32_t ip = leg->base.ip;
|
char ip_addr[INET6_ADDRSTRLEN];
|
||||||
uint16_t port = leg->base.port;
|
struct sockaddr_storage prev_addr = leg->base.addr;
|
||||||
char ip_addr[INET_ADDRSTRLEN];
|
|
||||||
|
|
||||||
LOGP(DSIP, LOGL_INFO, "re-INVITE for call %s\n", sip->sip_call_id->i_id);
|
LOGP(DSIP, LOGL_INFO, "re-INVITE for call %s\n", sip->sip_call_id->i_id);
|
||||||
|
|
||||||
|
@ -214,9 +213,9 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct in_addr net = { .s_addr = leg->base.ip };
|
LOGP(DSIP, LOGL_DEBUG, "pre re-INVITE have IP:port (%s:%u)\n",
|
||||||
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
|
osmo_sockaddr_ntop((struct sockaddr*)&leg->base.addr, ip_addr),
|
||||||
LOGP(DSIP, LOGL_DEBUG, "pre re-INVITE have IP:port (%s:%u)\n", ip_addr, leg->base.port);
|
osmo_sockaddr_port((struct sockaddr*)&leg->base.addr));
|
||||||
|
|
||||||
if (mode == sdp_sendonly) {
|
if (mode == sdp_sendonly) {
|
||||||
/* SIP side places call on HOLD */
|
/* SIP side places call on HOLD */
|
||||||
|
@ -231,10 +230,11 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons
|
||||||
call_leg_release(&leg->base);
|
call_leg_release(&leg->base);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct in_addr net = { .s_addr = leg->base.ip };
|
LOGP(DSIP, LOGL_DEBUG, "Media IP:port in re-INVITE: (%s:%u)\n",
|
||||||
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
|
osmo_sockaddr_ntop((struct sockaddr*)&leg->base.addr, ip_addr),
|
||||||
LOGP(DSIP, LOGL_DEBUG, "Media IP:port in re-INVITE: (%s:%u)\n", ip_addr, leg->base.port);
|
osmo_sockaddr_port((struct sockaddr*)&leg->base.addr));
|
||||||
if (ip != leg->base.ip || port != leg->base.port) {
|
if (osmo_sockaddr_cmp((struct osmo_sockaddr *)&prev_addr,
|
||||||
|
(struct osmo_sockaddr *)&leg->base)) {
|
||||||
LOGP(DSIP, LOGL_INFO, "re-INVITE changes media connection.\n");
|
LOGP(DSIP, LOGL_INFO, "re-INVITE changes media connection.\n");
|
||||||
if (other->update_rtp)
|
if (other->update_rtp)
|
||||||
other->update_rtp(leg->base.call->remote);
|
other->update_rtp(leg->base.call->remote);
|
||||||
|
|
Loading…
Reference in New Issue