diff --git a/include/osmocom/mgcp/mgcp.h b/include/osmocom/mgcp/mgcp.h index 4c541cb3a..2005e4f5f 100644 --- a/include/osmocom/mgcp/mgcp.h +++ b/include/osmocom/mgcp/mgcp.h @@ -160,7 +160,8 @@ struct mgcp_config { /* Osmux usage policy: */ enum osmux_usage osmux_use; /* addr to bind the server to */ - char osmux_addr[INET6_ADDRSTRLEN]; + char *osmux_addr_v4; + char *osmux_addr_v6; /* The BSC-NAT may ask for enabling osmux on demand. This tells us if * the osmux socket is already initialized. */ diff --git a/include/osmocom/mgcp/mgcp_network.h b/include/osmocom/mgcp/mgcp_network.h index 349ff9480..a3d57f018 100644 --- a/include/osmocom/mgcp/mgcp_network.h +++ b/include/osmocom/mgcp/mgcp_network.h @@ -157,7 +157,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state, struct mgcp_rtp_end *rtp_end, struct osmo_sockaddr *addr, struct msgb *msg); -void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn); +int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn); /* payload processing default functions */ int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c index 401bb090c..41e6ffce3 100644 --- a/src/libosmo-mgcp/mgcp_network.c +++ b/src/libosmo-mgcp/mgcp_network.c @@ -81,12 +81,13 @@ bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end) /*! Determine the local rtp bind IP-address. * \param[out] addr caller provided memory to store the resulting IP-Address. * \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters. + * \ returns 0 on success, -1 if no local address could be provided. * * The local bind IP-address is automatically selected by probing the * IP-Address of the interface that is pointing towards the remote IP-Address, * if no remote IP-Address is known yet, the statically configured * IP-Addresses are used as fallback. */ -void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn) +int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn) { struct mgcp_endpoint *endp; @@ -99,12 +100,30 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn) /* Osmux: No smart IP addresses allocation is supported yet. Simply * return the one set in VTY config: */ if (mgcp_conn_rtp_is_osmux(conn)) { - bind_addr = conn->conn->endp->trunk->cfg->osmux_addr; - LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, - "using configured osmux bind ip as local bind ip %s\n", + if (rem_addr_set) { + /* Match IP version with what was requested from remote: */ + bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ? + conn->conn->endp->trunk->cfg->osmux_addr_v6 : + conn->conn->endp->trunk->cfg->osmux_addr_v4; + } else { + /* Choose any of the bind addresses, preferring v6 over v4 if available: */ + bind_addr = conn->conn->endp->trunk->cfg->osmux_addr_v6; + if (!bind_addr) + bind_addr = conn->conn->endp->trunk->cfg->osmux_addr_v4; + } + if (!bind_addr) { + LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR, + "Unable to locate local Osmux address, check your configuration! v4=%u v6=%u remote_known=%s\n", + !!conn->conn->endp->trunk->cfg->osmux_addr_v4, + !!conn->conn->endp->trunk->cfg->osmux_addr_v6, + rem_addr_set ? osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf) : "no"); + return -1; + } + LOGPCONN(conn->conn, DOSMUX, LOGL_DEBUG, + "Using configured osmux bind ip as local bind ip %s\n", bind_addr); osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN); - return; + return 0; } /* Try probing the local IP-Address */ @@ -117,7 +136,7 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn) LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, "selected local rtp bind ip %s by probing using remote ip %s\n", addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf)); - return; + return 0; } } @@ -147,6 +166,7 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn) "using mgcp bind ip as local rtp bind ip: %s\n", bind_addr); } osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN); + return 0; } /* This does not need to be a precision timestamp and diff --git a/src/libosmo-mgcp/mgcp_osmux.c b/src/libosmo-mgcp/mgcp_osmux.c index de0bc38db..3be6d78fe 100644 --- a/src/libosmo-mgcp/mgcp_osmux.c +++ b/src/libosmo-mgcp/mgcp_osmux.c @@ -30,7 +30,8 @@ #include #include -static struct osmo_fd osmux_fd; +static struct osmo_fd osmux_fd_v4; +static struct osmo_fd osmux_fd_v6; static LLIST_HEAD(osmux_handle_list); @@ -76,20 +77,22 @@ static void osmux_deliver_cb(struct msgb *batch_msg, void *data) { struct osmux_handle *handle = data; socklen_t dest_len; - int rc; - struct mgcp_trunk *trunk = (struct mgcp_trunk *)osmux_fd.data; + int rc, fd; + struct mgcp_trunk *trunk = (struct mgcp_trunk *)osmux_fd_v4.data; struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats; switch (handle->rem_addr.u.sa.sa_family) { case AF_INET6: dest_len = sizeof(handle->rem_addr.u.sin6); + fd = osmux_fd_v6.fd; break; case AF_INET: default: dest_len = sizeof(handle->rem_addr.u.sin); + fd = osmux_fd_v4.fd; break; } - rc = sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0, + rc = sendto(fd, batch_msg->data, batch_msg->len, 0, (struct sockaddr *)&handle->rem_addr.u.sa, dest_len); if (rc < 0) { char errbuf[129]; @@ -187,11 +190,6 @@ osmux_handle_find_or_create(struct mgcp_conn_rtp *conn, const struct osmo_sockad { struct osmux_handle *h; - if (rem_addr->u.sa.sa_family != AF_INET) { - LOGP(DOSMUX, LOGL_DEBUG, "IPv6 not supported in osmux yet!\n"); - return NULL; - } - h = osmux_handle_find_get(rem_addr); if (h != NULL) return h->in; @@ -450,27 +448,46 @@ int osmux_init(int role, struct mgcp_trunk *trunk) /* So far we only support running on one trunk: */ OSMO_ASSERT(trunk == mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID)); - osmo_fd_setup(&osmux_fd, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0); + osmo_fd_setup(&osmux_fd_v4, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0); + osmo_fd_setup(&osmux_fd_v6, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0); - ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port, - cfg->endp_dscp, cfg->endp_priority); - if (ret < 0) { - LOGP(DOSMUX, LOGL_ERROR, "cannot bind OSMUX socket to %s:%u\n", - cfg->osmux_addr, cfg->osmux_port); - return ret; + if (cfg->osmux_addr_v4) { + ret = mgcp_create_bind(cfg->osmux_addr_v4, &osmux_fd_v4, cfg->osmux_port, + cfg->endp_dscp, cfg->endp_priority); + if (ret < 0) { + LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n", + cfg->osmux_addr_v4, cfg->osmux_port); + return ret; + } + + ret = osmo_fd_register(&osmux_fd_v4); + if (ret < 0) { + LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n", + osmo_sock_get_name2(osmux_fd_v4.fd)); + return ret; + } + LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n", + osmo_sock_get_name2(osmux_fd_v4.fd)); } + if (cfg->osmux_addr_v6) { + ret = mgcp_create_bind(cfg->osmux_addr_v6, &osmux_fd_v6, cfg->osmux_port, + cfg->endp_dscp, cfg->endp_priority); + if (ret < 0) { + LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to %s:%u\n", + cfg->osmux_addr_v6, cfg->osmux_port); + return ret; + } - ret = osmo_fd_register(&osmux_fd); - if (ret < 0) { - LOGP(DOSMUX, LOGL_ERROR, "cannot register OSMUX socket %s\n", - osmo_sock_get_name2(osmux_fd.fd)); - return ret; + ret = osmo_fd_register(&osmux_fd_v6); + if (ret < 0) { + LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n", + osmo_sock_get_name2(osmux_fd_v6.fd)); + return ret; + } + LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n", + osmo_sock_get_name2(osmux_fd_v6.fd)); } cfg->osmux_initialized = true; - - LOGP(DOSMUX, LOGL_INFO, "OSMUX socket listening on %s\n", - osmo_sock_get_name2(osmux_fd.fd)); - return 0; } @@ -647,7 +664,7 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn) osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), osmo_sockaddr_port(&conn->end.addr.u.sa), conn->osmux.remote_cid); - return mgcp_udp_send(osmux_fd.fd, &conn->end.addr, (char *)osmuxh, buf_len); + return mgcp_udp_send(osmux_fd_v4.fd, &conn->end.addr, (char *)osmuxh, buf_len); } /* bsc-nat allocates/releases the Osmux circuit ID. +7 to round up to 8 bit boundary. */ diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c index a257ffef3..46e1d6bee 100644 --- a/src/libosmo-mgcp/mgcp_protocol.c +++ b/src/libosmo-mgcp/mgcp_protocol.c @@ -1067,7 +1067,10 @@ mgcp_header_done: /* Find a local address for conn based on policy and initial SDP remote information, then find a free port for it */ - mgcp_get_local_addr(conn->end.local_addr, conn); + if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) { + rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT)); + goto error2; + } if (allocate_port(endp, conn) != 0) { rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT)); goto error2; @@ -1279,7 +1282,10 @@ mgcp_header_done: to update our announced IP addr and re-bind our local end. This can happen for instance if MGW initially provided an IPv4 during CRCX ACK, and now MDCX tells us the remote has an IPv6 address. */ - mgcp_get_local_addr(new_local_addr, conn); + if (mgcp_get_local_addr(new_local_addr, conn) < 0) { + rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT)); + goto error3; + } if (strcmp(new_local_addr, conn->end.local_addr)) { osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr)); mgcp_free_rtp_port(&conn->end); @@ -1627,7 +1633,6 @@ struct mgcp_config *mgcp_config_alloc(void) cfg->source_port = 2427; osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr)); - osmo_strlcpy(cfg->osmux_addr, "0.0.0.0", sizeof(cfg->osmux_addr)); cfg->rtp_processing_cb = &mgcp_rtp_processing_default; cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default; diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c index 1bf87897b..bc2673da0 100644 --- a/src/libosmo-mgcp/mgcp_vty.c +++ b/src/libosmo-mgcp/mgcp_vty.c @@ -142,8 +142,12 @@ static int config_write_mgcp(struct vty *vty) break; } if (g_cfg->osmux_use != OSMUX_USAGE_OFF) { - vty_out(vty, " osmux bind-ip %s%s", - g_cfg->osmux_addr, VTY_NEWLINE); + if (g_cfg->osmux_addr_v4) + vty_out(vty, " osmux bind-ip %s%s", + g_cfg->osmux_addr_v4, VTY_NEWLINE); + if (g_cfg->osmux_addr_v6) + vty_out(vty, " osmux bind-ip-v6 %s%s", + g_cfg->osmux_addr_v6, VTY_NEWLINE); vty_out(vty, " osmux batch-factor %d%s", g_cfg->osmux_batch, VTY_NEWLINE); vty_out(vty, " osmux batch-size %u%s", @@ -1584,12 +1588,21 @@ DEFUN(cfg_mgcp_osmux, DEFUN(cfg_mgcp_osmux_ip, cfg_mgcp_osmux_ip_cmd, - "osmux bind-ip " VTY_IPV46_CMD, + "osmux bind-ip " VTY_IPV4_CMD, + OSMUX_STR IP_STR + "IPv4 Address to bind to\n") +{ + osmo_talloc_replace_string(g_cfg, &g_cfg->osmux_addr_v4, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_osmux_ip_v6, + cfg_mgcp_osmux_ip_v6_cmd, + "osmux bind-ip-v6 " VTY_IPV6_CMD, OSMUX_STR IP_STR - "IPv4 Address to bind to\n" "IPv6 Address to bind to\n") { - osmo_strlcpy(g_cfg->osmux_addr, argv[0], sizeof(g_cfg->osmux_addr)); + osmo_talloc_replace_string(g_cfg, &g_cfg->osmux_addr_v6, argv[0]); return CMD_SUCCESS; } @@ -1718,6 +1731,7 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd); install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_v6_cmd); install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd); install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd); install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);