mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-04 05:53:26 +00:00 
			
		
		
		
	nat: Return the SCCP connection, change order of patching and updating
* Return the SCCP connection. This will be needed to store the assigned timeslot in there. * Update code to work with this change * This uncovered a bug in the CC handling, at the time the BSC was passed it was still a null pointer and the code would have failed.
This commit is contained in:
		@@ -156,9 +156,9 @@ struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg);
 | 
				
			|||||||
 * SCCP patching and handling
 | 
					 * SCCP patching and handling
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
 | 
					int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
 | 
				
			||||||
int update_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
 | 
					int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *parsed);
 | 
				
			||||||
void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
 | 
					void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
 | 
				
			||||||
struct bsc_connection *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
 | 
					struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
 | 
				
			||||||
struct bsc_connection *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
 | 
					struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -168,7 +168,8 @@ static void bsc_write(struct bsc_connection *bsc, const u_int8_t *data, unsigned
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int forward_sccp_to_bts(struct msgb *msg)
 | 
					static int forward_sccp_to_bts(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bsc_connection *bsc = NULL;
 | 
						struct sccp_connections *con;
 | 
				
			||||||
 | 
						struct bsc_connection *bsc;
 | 
				
			||||||
	struct bsc_nat_parsed *parsed;
 | 
						struct bsc_nat_parsed *parsed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* filter, drop, patch the message? */
 | 
						/* filter, drop, patch the message? */
 | 
				
			||||||
@@ -191,12 +192,12 @@ static int forward_sccp_to_bts(struct msgb *msg)
 | 
				
			|||||||
		case SCCP_MSG_TYPE_RLSD:
 | 
							case SCCP_MSG_TYPE_RLSD:
 | 
				
			||||||
		case SCCP_MSG_TYPE_CREF:
 | 
							case SCCP_MSG_TYPE_CREF:
 | 
				
			||||||
		case SCCP_MSG_TYPE_DT1:
 | 
							case SCCP_MSG_TYPE_DT1:
 | 
				
			||||||
			bsc = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
 | 
								con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SCCP_MSG_TYPE_CC:
 | 
							case SCCP_MSG_TYPE_CC:
 | 
				
			||||||
			if (update_sccp_src_ref(bsc, msg, parsed) != 0)
 | 
								con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
 | 
				
			||||||
 | 
								if (!con || update_sccp_src_ref(con, parsed) != 0)
 | 
				
			||||||
				goto exit;
 | 
									goto exit;
 | 
				
			||||||
			bsc = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SCCP_MSG_TYPE_RLC:
 | 
							case SCCP_MSG_TYPE_RLC:
 | 
				
			||||||
			LOGP(DNAT, LOGL_ERROR, "Unexpected release complete from MSC.\n");
 | 
								LOGP(DNAT, LOGL_ERROR, "Unexpected release complete from MSC.\n");
 | 
				
			||||||
@@ -210,14 +211,14 @@ static int forward_sccp_to_bts(struct msgb *msg)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(parsed);
 | 
						talloc_free(parsed);
 | 
				
			||||||
	if (!bsc)
 | 
						if (!con)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	if (!bsc->authenticated) {
 | 
						if (!con->bsc->authenticated) {
 | 
				
			||||||
		LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n");
 | 
							LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bsc_write(bsc, msg->data, msg->len);
 | 
						bsc_write(con->bsc, msg->data, msg->len);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
send_to_all:
 | 
					send_to_all:
 | 
				
			||||||
@@ -365,7 +366,7 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
 | 
					static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bsc_connection *found_bsc = NULL;
 | 
						struct sccp_connections *con;
 | 
				
			||||||
	struct bsc_nat_parsed *parsed;
 | 
						struct bsc_nat_parsed *parsed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!bsc->authenticated) {
 | 
						if (!bsc->authenticated) {
 | 
				
			||||||
@@ -391,29 +392,34 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
 | 
				
			|||||||
		case SCCP_MSG_TYPE_CR:
 | 
							case SCCP_MSG_TYPE_CR:
 | 
				
			||||||
			if (create_sccp_src_ref(bsc, msg, parsed) != 0)
 | 
								if (create_sccp_src_ref(bsc, msg, parsed) != 0)
 | 
				
			||||||
				goto exit2;
 | 
									goto exit2;
 | 
				
			||||||
			found_bsc = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
								con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SCCP_MSG_TYPE_RLSD:
 | 
							case SCCP_MSG_TYPE_RLSD:
 | 
				
			||||||
		case SCCP_MSG_TYPE_CREF:
 | 
							case SCCP_MSG_TYPE_CREF:
 | 
				
			||||||
		case SCCP_MSG_TYPE_DT1:
 | 
							case SCCP_MSG_TYPE_DT1:
 | 
				
			||||||
		case SCCP_MSG_TYPE_CC:
 | 
							case SCCP_MSG_TYPE_CC:
 | 
				
			||||||
			found_bsc = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
								con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SCCP_MSG_TYPE_RLC:
 | 
							case SCCP_MSG_TYPE_RLC:
 | 
				
			||||||
			found_bsc = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
								con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
				
			||||||
			remove_sccp_src_ref(bsc, msg, parsed);
 | 
								remove_sccp_src_ref(bsc, msg, parsed);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SCCP_MSG_TYPE_UDT:
 | 
							case SCCP_MSG_TYPE_UDT:
 | 
				
			||||||
			/* simply forward everything */
 | 
								/* simply forward everything */
 | 
				
			||||||
 | 
								con = NULL;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			LOGP(DNAT, LOGL_ERROR, "Not forwarding to msc sccp type: 0x%x\n", parsed->sccp_type);
 | 
								LOGP(DNAT, LOGL_ERROR, "Not forwarding to msc sccp type: 0x%x\n", parsed->sccp_type);
 | 
				
			||||||
 | 
								con = NULL;
 | 
				
			||||||
			goto exit2;
 | 
								goto exit2;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							LOGP(DNAT, LOGL_ERROR, "Not forwarding unknown stream id: 0x%x\n", parsed->ipa_proto);
 | 
				
			||||||
 | 
							goto exit2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (found_bsc != bsc) {
 | 
						if (con && con->bsc != bsc) {
 | 
				
			||||||
		LOGP(DNAT, LOGL_ERROR, "Found the wrong entry.\n");
 | 
							LOGP(DNAT, LOGL_ERROR, "Found the wrong entry.\n");
 | 
				
			||||||
		goto exit2;
 | 
							goto exit2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,32 +108,19 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int update_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
 | 
					int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *parsed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sccp_connections *conn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!parsed->dest_local_ref || !parsed->src_local_ref) {
 | 
						if (!parsed->dest_local_ref || !parsed->src_local_ref) {
 | 
				
			||||||
		LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n");
 | 
							LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
 | 
						sccp->remote_ref = *parsed->src_local_ref;
 | 
				
			||||||
		if (conn->bsc != bsc)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (memcmp(parsed->dest_local_ref,
 | 
					 | 
				
			||||||
			   &conn->patched_ref, sizeof(conn->patched_ref)) != 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		conn->remote_ref = *parsed->src_local_ref;
 | 
					 | 
				
			||||||
	LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n",
 | 
						LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n",
 | 
				
			||||||
		     sccp_src_ref_to_int(&conn->patched_ref),
 | 
						     sccp_src_ref_to_int(&sccp->patched_ref),
 | 
				
			||||||
		     sccp_src_ref_to_int(&conn->remote_ref), bsc);
 | 
						     sccp_src_ref_to_int(&sccp->remote_ref), sccp->bsc);
 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DNAT, LOGL_ERROR, "Referenced connection not found on BSC: %p\n", bsc);
 | 
						return 0;
 | 
				
			||||||
	return -1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
 | 
					void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
 | 
				
			||||||
@@ -165,7 +152,7 @@ void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bs
 | 
				
			|||||||
 * an address that was assigned by the MUX, we need to update the
 | 
					 * an address that was assigned by the MUX, we need to update the
 | 
				
			||||||
 * dest reference to the real network.
 | 
					 * dest reference to the real network.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct bsc_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg,
 | 
					struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *msg,
 | 
				
			||||||
						   struct bsc_nat_parsed *parsed,
 | 
											   struct bsc_nat_parsed *parsed,
 | 
				
			||||||
						   struct bsc_nat *nat)
 | 
											   struct bsc_nat *nat)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -183,7 +170,7 @@ struct bsc_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* Change the dest address to the real one */
 | 
							/* Change the dest address to the real one */
 | 
				
			||||||
		*parsed->dest_local_ref = conn->real_ref;
 | 
							*parsed->dest_local_ref = conn->real_ref;
 | 
				
			||||||
		return conn->bsc;
 | 
							return conn;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
@@ -197,7 +184,7 @@ struct bsc_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg,
 | 
				
			|||||||
 * in all other cases we need to work by the destination local
 | 
					 * in all other cases we need to work by the destination local
 | 
				
			||||||
 * reference..
 | 
					 * reference..
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct bsc_connection *patch_sccp_src_ref_to_msc(struct msgb *msg,
 | 
					struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *msg,
 | 
				
			||||||
						   struct bsc_nat_parsed *parsed,
 | 
											   struct bsc_nat_parsed *parsed,
 | 
				
			||||||
						   struct bsc_nat *nat)
 | 
											   struct bsc_nat *nat)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -207,11 +194,11 @@ struct bsc_connection *patch_sccp_src_ref_to_msc(struct msgb *msg,
 | 
				
			|||||||
		if (parsed->src_local_ref) {
 | 
							if (parsed->src_local_ref) {
 | 
				
			||||||
			if (equal(parsed->src_local_ref, &conn->real_ref)) {
 | 
								if (equal(parsed->src_local_ref, &conn->real_ref)) {
 | 
				
			||||||
				*parsed->src_local_ref = conn->patched_ref;
 | 
									*parsed->src_local_ref = conn->patched_ref;
 | 
				
			||||||
				return conn->bsc;
 | 
									return conn;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if (parsed->dest_local_ref) {
 | 
							} else if (parsed->dest_local_ref) {
 | 
				
			||||||
			if (equal(parsed->dest_local_ref, &conn->remote_ref))
 | 
								if (equal(parsed->dest_local_ref, &conn->remote_ref))
 | 
				
			||||||
				return conn->bsc;
 | 
									return conn;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			LOGP(DNAT, LOGL_ERROR, "Header has neither loc/dst ref.\n");
 | 
								LOGP(DNAT, LOGL_ERROR, "Header has neither loc/dst ref.\n");
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -189,7 +189,7 @@ static void copy_to_msg(struct msgb *msg, const u_int8_t *data, unsigned int len
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VERIFY(con_found, con, msg, ver, str) \
 | 
					#define VERIFY(con_found, con, msg, ver, str) \
 | 
				
			||||||
	if (con_found != con) { \
 | 
						if (!con_found || con_found->bsc != con) { \
 | 
				
			||||||
		fprintf(stderr, "Failed to find the con: %p\n", con_found); \
 | 
							fprintf(stderr, "Failed to find the con: %p\n", con_found); \
 | 
				
			||||||
		abort(); \
 | 
							abort(); \
 | 
				
			||||||
	} \
 | 
						} \
 | 
				
			||||||
@@ -203,7 +203,8 @@ static void test_contrack()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct bsc_nat *nat;
 | 
						struct bsc_nat *nat;
 | 
				
			||||||
	struct bsc_connection *con, *con_found;
 | 
						struct bsc_connection *con;
 | 
				
			||||||
 | 
						struct sccp_connections *con_found;
 | 
				
			||||||
	struct bsc_nat_parsed *parsed;
 | 
						struct bsc_nat_parsed *parsed;
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -226,7 +227,7 @@ static void test_contrack()
 | 
				
			|||||||
		abort();
 | 
							abort();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
						con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
				
			||||||
	if (con_found != con) {
 | 
						if (!con_found || con_found->bsc != con) {
 | 
				
			||||||
		fprintf(stderr, "Failed to find the con: %p\n", con_found);
 | 
							fprintf(stderr, "Failed to find the con: %p\n", con_found);
 | 
				
			||||||
		abort();
 | 
							abort();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -239,12 +240,12 @@ static void test_contrack()
 | 
				
			|||||||
	/* 2.) get the cc */
 | 
						/* 2.) get the cc */
 | 
				
			||||||
	copy_to_msg(msg, msc_cc, sizeof(msc_cc));
 | 
						copy_to_msg(msg, msc_cc, sizeof(msc_cc));
 | 
				
			||||||
	parsed = bsc_nat_parse(msg);
 | 
						parsed = bsc_nat_parse(msg);
 | 
				
			||||||
	if (update_sccp_src_ref(con, msg, parsed) != 0) {
 | 
						con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
 | 
				
			||||||
 | 
						VERIFY(con_found, con, msg, msc_cc_patched, "MSC CC");
 | 
				
			||||||
 | 
						if (update_sccp_src_ref(con_found, parsed) != 0) {
 | 
				
			||||||
		fprintf(stderr, "Failed to update the SCCP con.\n");
 | 
							fprintf(stderr, "Failed to update the SCCP con.\n");
 | 
				
			||||||
		abort();
 | 
							abort();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
 | 
					 | 
				
			||||||
	VERIFY(con_found, con, msg, msc_cc_patched, "MSC CC");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 3.) send some data */
 | 
						/* 3.) send some data */
 | 
				
			||||||
	copy_to_msg(msg, bsc_dtap, sizeof(bsc_dtap));
 | 
						copy_to_msg(msg, bsc_dtap, sizeof(bsc_dtap));
 | 
				
			||||||
@@ -268,7 +269,7 @@ static void test_contrack()
 | 
				
			|||||||
	copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
 | 
						copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
 | 
				
			||||||
	parsed = bsc_nat_parse(msg);
 | 
						parsed = bsc_nat_parse(msg);
 | 
				
			||||||
	con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
						con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
 | 
				
			||||||
	if (con_found != con) {
 | 
						if (!con_found || con_found->bsc != con) {
 | 
				
			||||||
		fprintf(stderr, "Failed to find the con: %p\n", con_found);
 | 
							fprintf(stderr, "Failed to find the con: %p\n", con_found);
 | 
				
			||||||
		abort();
 | 
							abort();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user