From b6cb607d1270b76b5fae5af2a00c4414e86d9f83 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Wed, 9 Sep 2020 17:39:09 +0200 Subject: [PATCH] mncc: Support IPv6 addresses (new version mncc 7) Change-Id: I3b1bebbcc9e36be43d8d055c8d28cbb38ff21b37 --- src/call.h | 4 ++-- src/mncc.c | 29 +++++++++++++------------ src/mncc_protocol.h | 8 +++---- src/sdp.c | 53 +++++++++++++++++++++++++++++++++------------ src/sip.c | 30 ++++++++++++------------- 5 files changed, 75 insertions(+), 49 deletions(-) diff --git a/src/call.h b/src/call.h index 7f67066..d1732f9 100644 --- a/src/call.h +++ b/src/call.h @@ -7,6 +7,7 @@ #include #include +#include struct sip_agent; struct mncc_connection; @@ -49,8 +50,7 @@ struct call_leg { /** * RTP data */ - uint32_t ip; - uint16_t port; + struct sockaddr_storage addr; uint32_t payload_type; uint32_t payload_msg_type; diff --git a/src/mncc.c b/src/mncc.c index 16eed96..0725d4c 100644 --- a/src/mncc.c +++ b/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, }; int rc; - char ip_addr[INET_ADDRSTRLEN]; + char ip_addr[INET6_ADDRSTRLEN]; /* * 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.callref = leg->callref; - mncc.ip = ntohl(other->ip); - mncc.port = other->port; + mncc.addr = other->addr; mncc.payload_type = other->payload_type; /* * FIXME: mncc.payload_msg_type should already be compatible.. but * payload_type should be different.. */ - struct in_addr net = { .s_addr = other->ip }; - inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr)); - LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n", ip_addr, mncc.port); + LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n", + osmo_sockaddr_ntop((const struct sockaddr*)&other->addr, ip_addr), + osmo_sockaddr_port((const struct sockaddr*)&other->addr)); rc = write(leg->conn->fd.fd, &mncc, sizeof(mncc)); if (rc != sizeof(mncc)) { 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... */ 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); } @@ -397,7 +397,9 @@ static void check_rtp_connect(struct mncc_connection *conn, const char *buf, int } /* 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; 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; struct mncc_call_leg *leg; - char ip_addr[INET_ADDRSTRLEN]; + char ip_addr[INET6_ADDRSTRLEN]; if (rc < sizeof(*rtp)) { 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 */ - leg->base.ip = htonl(rtp->ip); - leg->base.port = rtp->port; + leg->base.addr = rtp->addr; leg->base.payload_type = rtp->payload_type; leg->base.payload_msg_type = rtp->payload_msg_type; /* 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, "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); stop_cmd_timer(leg, MNCC_RTP_CREATE); continue_call(leg); diff --git a/src/mncc_protocol.h b/src/mncc_protocol.h index b6f6635..5d35191 100644 --- a/src/mncc_protocol.h +++ b/src/mncc_protocol.h @@ -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 */ /* (C) 2008-2009 by Harald Welte @@ -28,6 +28,7 @@ #include #include +#include struct gsm_network; struct msgb; @@ -169,7 +170,7 @@ struct gsm_data_frame { unsigned char data[0]; }; -#define MNCC_SOCK_VERSION 6 +#define MNCC_SOCK_VERSION 7 struct gsm_mncc_hello { uint32_t msg_type; uint32_t version; @@ -188,8 +189,7 @@ struct gsm_mncc_hello { struct gsm_mncc_rtp { uint32_t msg_type; uint32_t callref; - uint32_t ip; - uint16_t port; + struct sockaddr_storage addr; uint32_t payload_type; uint32_t payload_msg_type; char sdp[1024]; diff --git a/src/sdp.c b/src/sdp.c index 46330cd..7f91d3f 100644 --- a/src/sdp.c +++ b/src/sdp.c @@ -32,6 +32,8 @@ #include +#include + /* * Check if the media mode attribute exists in SDP, in this * 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_media_t *media; const char *sdp_data; + uint16_t port; bool found_conn = false, found_map = false; 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) { - struct in_addr addr; - - if (conn->c_addrtype != sdp_addr_ip4) + switch (conn->c_addrtype) { + case 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; - inet_aton(conn->c_address, &addr); - leg->base.ip = addr.s_addr; - found_conn = true; + } 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) continue; - leg->base.port = media->m_port; + port = media->m_port; leg->base.payload_type = map->rm_pt; found_map = true; break; @@ -198,18 +210,30 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec) 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); return true; } 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 *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); 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, "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" - "c=IN IP4 %s\r\n" + "c=IN IP%c %s\r\n" "t=0 0\r\n" "m=audio %d RTP/AVP %d\r\n" "%s" "a=rtpmap:%d %s/8000\r\n" "%s", - ip_addr, ip_addr, - other->port, other->payload_type, + ipv, ip_addr, ipv, ip_addr, + osmo_sockaddr_port((const struct sockaddr *)&other->addr), + other->payload_type, fmtp_str ? fmtp_str : "", other->payload_type, leg->wanted_codec, diff --git a/src/sip.c b/src/sip.c index c635542..ba9730a 100644 --- a/src/sip.c +++ b/src/sip.c @@ -25,6 +25,7 @@ #include "sdp.h" #include +#include #include #include @@ -33,6 +34,7 @@ #include #include +#include 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 sip_call_leg *leg; 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); @@ -159,11 +161,9 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, call_leg_release(&leg->base); 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", - ip_addr, - leg->base.port, + 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.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; sdp_mode_t mode = sdp_sendrecv; - uint32_t ip = leg->base.ip; - uint16_t port = leg->base.port; - char ip_addr[INET_ADDRSTRLEN]; + char ip_addr[INET6_ADDRSTRLEN]; + struct sockaddr_storage prev_addr = leg->base.addr; 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; } - struct in_addr net = { .s_addr = leg->base.ip }; - inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr)); - LOGP(DSIP, LOGL_DEBUG, "pre re-INVITE have IP:port (%s:%u)\n", ip_addr, leg->base.port); + LOGP(DSIP, LOGL_DEBUG, "pre re-INVITE have IP:port (%s:%u)\n", + osmo_sockaddr_ntop((struct sockaddr*)&leg->base.addr, ip_addr), + osmo_sockaddr_port((struct sockaddr*)&leg->base.addr)); if (mode == sdp_sendonly) { /* 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); return; } - struct in_addr net = { .s_addr = leg->base.ip }; - inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr)); - LOGP(DSIP, LOGL_DEBUG, "Media IP:port in re-INVITE: (%s:%u)\n", ip_addr, leg->base.port); - if (ip != leg->base.ip || port != leg->base.port) { + LOGP(DSIP, LOGL_DEBUG, "Media IP:port in re-INVITE: (%s:%u)\n", + osmo_sockaddr_ntop((struct sockaddr*)&leg->base.addr, ip_addr), + osmo_sockaddr_port((struct sockaddr*)&leg->base.addr)); + if (osmo_sockaddr_cmp((struct osmo_sockaddr *)&prev_addr, + (struct osmo_sockaddr *)&leg->base)) { LOGP(DSIP, LOGL_INFO, "re-INVITE changes media connection.\n"); if (other->update_rtp) other->update_rtp(leg->base.call->remote);