Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 1 | /* The routines to handle the state */ |
| 2 | /* |
| 3 | * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org> |
| 4 | * (C) 2010-2011 by On-Waves |
| 5 | * All Rights Reserved |
| 6 | * |
| 7 | * This program is free software: you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU Affero General Public License as published by |
| 9 | * the Free Software Foundation, either version 3 of the License, or |
| 10 | * (at your option) any later version. |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU Affero General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU Affero General Public License |
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | * |
| 20 | */ |
| 21 | |
| 22 | #include <mtp_data.h> |
Holger Hans Peter Freyther | 84ec871 | 2011-02-15 20:01:47 +0100 | [diff] [blame] | 23 | #include <msc_connection.h> |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 24 | #include <mtp_level3.h> |
| 25 | #include <bss_patch.h> |
| 26 | #include <bssap_sccp.h> |
| 27 | #include <bsc_data.h> |
| 28 | #include <cellmgr_debug.h> |
| 29 | #include <bsc_sccp.h> |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 30 | #include <bsc_ussd.h> |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 31 | #include <ss7_application.h> |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 32 | |
| 33 | #include <osmocore/talloc.h> |
| 34 | |
| 35 | #include <osmocom/vty/vty.h> |
| 36 | #include <osmocom/vty/telnet_interface.h> |
| 37 | |
| 38 | #include <sys/stat.h> |
| 39 | #include <sys/types.h> |
| 40 | |
| 41 | #include <fcntl.h> |
| 42 | #include <signal.h> |
| 43 | #include <stdio.h> |
| 44 | #include <stdlib.h> |
| 45 | #include <string.h> |
| 46 | #include <assert.h> |
| 47 | #include <unistd.h> |
| 48 | |
| 49 | static void send_reset_ack(struct mtp_link_set *link, int sls); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 50 | static void handle_local_sccp(struct mtp_link_set *link, struct msgb *inp, struct sccp_parse_result *res, int sls); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 51 | static void send_local_rlsd(struct mtp_link_set *link, struct sccp_parse_result *res); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 52 | static void update_con_state(struct ss7_application *ss7, int rc, struct sccp_parse_result *result, struct msgb *msg, int from_msc, int sls); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 53 | |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 54 | /* |
| 55 | * methods called from the MTP Level3 part |
| 56 | */ |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 57 | void app_forward_sccp(struct ss7_application *app, struct msgb *_msg, int sls) |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 58 | { |
| 59 | int rc; |
| 60 | struct sccp_parse_result result; |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 61 | struct msc_connection *msc; |
| 62 | struct mtp_link_set *set; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 63 | |
Holger Hans Peter Freyther | 2cdb73c | 2011-02-15 21:27:20 +0100 | [diff] [blame] | 64 | struct msgb *msg; |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 65 | |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 66 | set = app->route_src.set; |
| 67 | msc = app->route_dst.msc; |
Holger Hans Peter Freyther | dd32ae5 | 2011-02-10 20:07:30 +0100 | [diff] [blame] | 68 | |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 69 | if (app->forward_only) { |
| 70 | msc_send_direct(msc, _msg); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 71 | return; |
| 72 | } |
Holger Hans Peter Freyther | dd32ae5 | 2011-02-10 20:07:30 +0100 | [diff] [blame] | 73 | |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 74 | rc = bss_patch_filter_msg(_msg, &result); |
| 75 | if (rc == BSS_FILTER_RESET) { |
| 76 | LOGP(DMSC, LOGL_NOTICE, "Filtering BSS Reset from the BSC\n"); |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 77 | msc_mgcp_reset(msc); |
| 78 | send_reset_ack(set, sls); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 79 | return; |
| 80 | } |
| 81 | |
| 82 | /* special responder */ |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 83 | if (msc->msc_link_down) { |
| 84 | if (rc == BSS_FILTER_RESET_ACK && app->reset_count > 0) { |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 85 | LOGP(DMSC, LOGL_ERROR, "Received reset ack for closing.\n"); |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 86 | app_clear_connections(app); |
| 87 | app_resources_released(app); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 88 | return; |
| 89 | } |
| 90 | |
| 91 | if (rc != 0 && rc != BSS_FILTER_RLSD && rc != BSS_FILTER_RLC) { |
| 92 | LOGP(DMSC, LOGL_ERROR, "Ignoring unparsable msg during closedown.\n"); |
| 93 | return; |
| 94 | } |
| 95 | |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 96 | return handle_local_sccp(set, _msg, &result, sls); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | /* update the connection state */ |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 100 | update_con_state(app, rc, &result, _msg, 0, sls); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 101 | |
| 102 | if (rc == BSS_FILTER_CLEAR_COMPL) { |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 103 | send_local_rlsd(set, &result); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 104 | } else if (rc == BSS_FILTER_RLC || rc == BSS_FILTER_RLSD) { |
| 105 | LOGP(DMSC, LOGL_DEBUG, "Not forwarding RLC/RLSD to the MSC.\n"); |
| 106 | return; |
| 107 | } |
| 108 | |
Holger Hans Peter Freyther | 2cdb73c | 2011-02-15 21:27:20 +0100 | [diff] [blame] | 109 | /* now send it out */ |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 110 | bsc_ussd_handle_out_msg(msc, &result, _msg); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 111 | |
Holger Hans Peter Freyther | 2cdb73c | 2011-02-15 21:27:20 +0100 | [diff] [blame] | 112 | msg = msgb_alloc_headroom(4096, 128, "SCCP to MSC"); |
| 113 | if (!msg) { |
| 114 | LOGP(DMSC, LOGL_ERROR, "Failed to alloc MSC msg.\n"); |
| 115 | return; |
| 116 | } |
| 117 | |
| 118 | bss_rewrite_header_for_msc(rc, msg, _msg, &result); |
Holger Hans Peter Freyther | 64b7d56 | 2011-02-16 23:00:50 +0100 | [diff] [blame] | 119 | msc_send_direct(msc, msg); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | /* |
| 123 | * handle local message in close down mode |
| 124 | */ |
| 125 | static void handle_local_sccp(struct mtp_link_set *link, struct msgb *inpt, struct sccp_parse_result *result, int sls) |
| 126 | { |
| 127 | /* Handle msg with a reject */ |
| 128 | if (inpt->l2h[0] == SCCP_MSG_TYPE_CR) { |
| 129 | struct sccp_connection_request *cr; |
| 130 | struct msgb *msg; |
| 131 | |
| 132 | LOGP(DINP, LOGL_NOTICE, "Handling CR localy.\n"); |
| 133 | cr = (struct sccp_connection_request *) inpt->l2h; |
| 134 | msg = create_sccp_refuse(&cr->source_local_reference); |
| 135 | if (msg) { |
| 136 | mtp_link_set_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg)); |
| 137 | msgb_free(msg); |
| 138 | } |
| 139 | return; |
| 140 | } else if (inpt->l2h[0] == SCCP_MSG_TYPE_DT1 && result->data_len >= 3) { |
| 141 | struct active_sccp_con *con; |
| 142 | struct sccp_data_form1 *form1; |
| 143 | struct msgb *msg; |
| 144 | |
| 145 | if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_CLEAR_COMPLETE) { |
| 146 | LOGP(DINP, LOGL_DEBUG, "Received Clear Complete. Sending Release.\n"); |
| 147 | |
| 148 | form1 = (struct sccp_data_form1 *) inpt->l2h; |
| 149 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 150 | llist_for_each_entry(con, &link->app->sccp_connections, entry) { |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 151 | if (memcmp(&form1->destination_local_reference, |
| 152 | &con->dst_ref, sizeof(con->dst_ref)) == 0) { |
| 153 | LOGP(DINP, LOGL_DEBUG, "Sending a release request now.\n"); |
| 154 | msg = create_sccp_rlsd(&con->dst_ref, &con->src_ref); |
| 155 | if (msg) { |
| 156 | mtp_link_set_submit_sccp_data(link, con->sls, msg->l2h, msgb_l2len(msg)); |
| 157 | msgb_free(msg); |
| 158 | } |
| 159 | return; |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | LOGP(DINP, LOGL_ERROR, "Could not find connection for the Clear Command.\n"); |
| 164 | } |
| 165 | } else if (inpt->l2h[0] == SCCP_MSG_TYPE_UDT && result->data_len >= 3) { |
| 166 | if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_RESET_ACKNOWLEDGE) { |
| 167 | LOGP(DINP, LOGL_NOTICE, "Reset ACK. Connecting to the MSC again.\n"); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 168 | app_resources_released(link->app); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 169 | return; |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | |
| 174 | /* Update the state, maybe the connection was released? */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 175 | update_con_state(link->app, 0, result, inpt, 0, sls); |
| 176 | if (llist_empty(&link->app->sccp_connections)) |
| 177 | app_resources_released(link->app); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 178 | return; |
| 179 | } |
| 180 | |
Holger Hans Peter Freyther | c5200fc | 2011-02-16 22:35:30 +0100 | [diff] [blame] | 181 | void app_clear_connections(struct ss7_application *app) |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 182 | { |
| 183 | struct active_sccp_con *tmp, *con; |
| 184 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 185 | llist_for_each_entry_safe(con, tmp, &app->sccp_connections, entry) { |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 186 | free_con(con); |
| 187 | } |
| 188 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 189 | link_clear_all(app->route_src.set); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 190 | } |
| 191 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 192 | void app_resources_released(struct ss7_application *app) |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 193 | { |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 194 | bsc_del_timer(&app->reset_timeout); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 195 | } |
| 196 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 197 | static void bsc_reset_timeout(void *_app) |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 198 | { |
| 199 | struct msgb *msg; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 200 | struct ss7_application *app = _app; |
| 201 | struct mtp_link_set *set = app->route_src.set; |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 202 | |
| 203 | /* no reset */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 204 | if (app->reset_count > 0) { |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 205 | LOGP(DINP, LOGL_ERROR, "The BSC did not answer the GSM08.08 reset. Restart MTP\n"); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 206 | mtp_link_set_stop(app->route_src.set); |
| 207 | app_clear_connections(app); |
| 208 | link_reset_all(app->route_src.set); |
| 209 | app_resources_released(app); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 210 | return; |
| 211 | } |
| 212 | |
| 213 | msg = create_reset(); |
| 214 | if (!msg) { |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 215 | bsc_schedule_timer(&app->reset_timeout, 10, 0); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 216 | return; |
| 217 | } |
| 218 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 219 | ++app->reset_count; |
| 220 | mtp_link_set_submit_sccp_data(set, -1, msg->l2h, msgb_l2len(msg)); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 221 | msgb_free(msg); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 222 | bsc_schedule_timer(&app->reset_timeout, 20, 0); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 223 | } |
| 224 | |
| 225 | /* |
| 226 | * We have lost the connection to the MSC. This is tough. We |
| 227 | * can not just bring down the MTP link as this will disable |
| 228 | * the BTS radio. We will have to do the following: |
| 229 | * |
| 230 | * 1.) Bring down all open SCCP connections. As this will close |
| 231 | * all radio resources |
| 232 | * 2.) Bring down all MGCP endpoints |
| 233 | * 3.) Clear the connection data. |
| 234 | * |
| 235 | * To make things worse we need to buffer the BSC messages... atfer |
| 236 | * everything has been sent we will try to connect to the MSC again. |
| 237 | * |
| 238 | * We will have to veriy that all connections are closed properly.. |
| 239 | * this means we need to parse response message. In the case the |
| 240 | * MTP link is going down while we are sending. We will simply |
| 241 | * reconnect to the MSC. |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 242 | * |
| 243 | * This could be called for the relay type and the cellmgr type, in case |
| 244 | * of the relay type the list of connections should be empty so we can |
| 245 | * avoid branching out. |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 246 | */ |
Holger Hans Peter Freyther | 84ec871 | 2011-02-15 20:01:47 +0100 | [diff] [blame] | 247 | void release_bsc_resources(struct msc_connection *fw) |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 248 | { |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 249 | struct ss7_application *app; |
| 250 | struct mtp_link_set *set; |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 251 | struct active_sccp_con *tmp; |
| 252 | struct active_sccp_con *con; |
| 253 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 254 | if (!fw->app) { |
| 255 | LOGP(DINP, LOGL_ERROR, "No app assigned to the MSC connection %d/%s\n", |
| 256 | fw->nr, fw->name); |
| 257 | return; |
| 258 | } |
| 259 | |
| 260 | app = fw->app; |
| 261 | set = app->route_src.set; |
| 262 | bsc_del_timer(&app->reset_timeout); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 263 | |
| 264 | /* 2. clear the MGCP endpoints */ |
Holger Hans Peter Freyther | c5200fc | 2011-02-16 22:35:30 +0100 | [diff] [blame] | 265 | msc_mgcp_reset(fw); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 266 | |
| 267 | /* 1. send BSSMAP Cleanup.. if we have any connection */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 268 | llist_for_each_entry_safe(con, tmp, &app->sccp_connections, entry) { |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 269 | if (!con->has_dst_ref) { |
| 270 | free_con(con); |
| 271 | continue; |
| 272 | } |
| 273 | |
| 274 | struct msgb *msg = create_clear_command(&con->src_ref); |
| 275 | if (!msg) |
| 276 | continue; |
| 277 | |
| 278 | /* wait for the clear commands */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 279 | mtp_link_set_submit_sccp_data(set, con->sls, msg->l2h, msgb_l2len(msg)); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 280 | msgb_free(msg); |
| 281 | } |
| 282 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 283 | if (llist_empty(&app->sccp_connections)) { |
| 284 | app_resources_released(app); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 285 | } else { |
| 286 | /* Send a reset in 20 seconds if we fail to bring everything down */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 287 | app->reset_timeout.cb = bsc_reset_timeout; |
| 288 | app->reset_timeout.data = app; |
| 289 | app->reset_count = 0; |
| 290 | bsc_schedule_timer(&app->reset_timeout, 10, 0); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 291 | } |
| 292 | } |
| 293 | |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 294 | /** |
| 295 | * update the connection state and helpers below |
| 296 | */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 297 | static void send_rlc_to_bsc(struct mtp_link_set *set, |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 298 | unsigned int sls, struct sccp_source_reference *src, |
| 299 | struct sccp_source_reference *dst) |
| 300 | { |
| 301 | struct msgb *msg; |
| 302 | |
| 303 | msg = create_sccp_rlc(src, dst); |
| 304 | if (!msg) |
| 305 | return; |
| 306 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 307 | mtp_link_set_submit_sccp_data(set, sls, msg->l2h, msgb_l2len(msg)); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 308 | msgb_free(msg); |
| 309 | } |
| 310 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 311 | static void handle_rlsd(struct ss7_application *app, struct sccp_connection_released *rlsd, int from_msc) |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 312 | { |
| 313 | struct active_sccp_con *con; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 314 | struct msc_connection *msc = app->route_dst.msc; |
| 315 | struct mtp_link_set *set = app->route_src.set; |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 316 | |
| 317 | if (from_msc) { |
| 318 | /* search for a connection, reverse src/dest for MSC */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 319 | con = find_con_by_src_dest_ref(app, &rlsd->destination_local_reference, |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 320 | &rlsd->source_local_reference); |
| 321 | if (con) { |
| 322 | LOGP(DINP, LOGL_DEBUG, "RLSD conn still alive: local: 0x%x remote: 0x%x\n", |
| 323 | sccp_src_ref_to_int(&con->src_ref), |
| 324 | sccp_src_ref_to_int(&con->dst_ref)); |
| 325 | con->released_from_msc = 1; |
| 326 | } else { |
| 327 | /* send RLC */ |
| 328 | LOGP(DINP, LOGL_DEBUG, "Sending RLC for MSC: src: 0x%x dst: 0x%x\n", |
| 329 | sccp_src_ref_to_int(&rlsd->destination_local_reference), |
| 330 | sccp_src_ref_to_int(&rlsd->source_local_reference)); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 331 | msc_send_rlc(msc, &rlsd->destination_local_reference, |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 332 | &rlsd->source_local_reference); |
| 333 | } |
| 334 | } else { |
| 335 | unsigned int sls = -1; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 336 | con = find_con_by_src_dest_ref(app, &rlsd->source_local_reference, |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 337 | &rlsd->destination_local_reference); |
| 338 | if (con) { |
| 339 | LOGP(DINP, LOGL_DEBUG, "Timeout on BSC. Sending RLC. src: 0x%x\n", |
| 340 | sccp_src_ref_to_int(&rlsd->source_local_reference)); |
| 341 | |
| 342 | if (con->released_from_msc) |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 343 | msc_send_rlc(msc, &con->src_ref, &con->dst_ref); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 344 | sls = con->sls; |
| 345 | free_con(con); |
| 346 | } else { |
| 347 | LOGP(DINP, LOGL_ERROR, "Timeout on BSC for unknown connection. src: 0x%x\n", |
| 348 | sccp_src_ref_to_int(&rlsd->source_local_reference)); |
| 349 | } |
| 350 | |
| 351 | /* now send a rlc back to the BSC */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 352 | send_rlc_to_bsc(set, sls, &rlsd->destination_local_reference, &rlsd->source_local_reference); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 353 | } |
| 354 | } |
| 355 | |
| 356 | /** |
| 357 | * Update connection state and also send message..... |
| 358 | * |
| 359 | * RLSD from MSC: |
| 360 | * 1.) We don't find the entry in this case we will send a |
| 361 | * forged RLC to the MSC and we are done. |
| 362 | * 2.) We find an entry in this we will need to register that |
| 363 | * we need to send a RLC and we are done for now. |
| 364 | * RLSD from BSC: |
| 365 | * 1.) This is an error we are ignoring for now. |
| 366 | * RLC from BSC: |
| 367 | * 1.) We are destroying the connection, we might send a RLC to |
| 368 | * the MSC if we are waiting for one. |
| 369 | */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 370 | void update_con_state(struct ss7_application *app, int rc, struct sccp_parse_result *res, struct msgb *msg, int from_msc, int sls) |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 371 | { |
| 372 | struct active_sccp_con *con; |
| 373 | struct sccp_connection_request *cr; |
| 374 | struct sccp_connection_confirm *cc; |
| 375 | struct sccp_connection_release_complete *rlc; |
| 376 | struct sccp_connection_refused *cref; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 377 | struct msc_connection *msc; |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 378 | |
| 379 | /* was the header okay? */ |
| 380 | if (rc < 0) |
| 381 | return; |
| 382 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 383 | msc = app->route_dst.msc; |
| 384 | |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 385 | /* the header was size checked */ |
| 386 | switch (msg->l2h[0]) { |
| 387 | case SCCP_MSG_TYPE_CR: |
| 388 | if (from_msc) { |
| 389 | LOGP(DMSC, LOGL_ERROR, "CR from MSC is not handled.\n"); |
| 390 | return; |
| 391 | } |
| 392 | |
| 393 | cr = (struct sccp_connection_request *) msg->l2h; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 394 | con = find_con_by_src_ref(app, &cr->source_local_reference); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 395 | if (con) { |
| 396 | LOGP(DINP, LOGL_ERROR, "Duplicate SRC reference for: 0x%x. Reusing\n", |
| 397 | sccp_src_ref_to_int(&con->src_ref)); |
| 398 | free_con(con); |
| 399 | } |
| 400 | |
| 401 | con = talloc_zero(NULL, struct active_sccp_con); |
| 402 | if (!con) { |
| 403 | LOGP(DINP, LOGL_ERROR, "Failed to allocate\n"); |
| 404 | return; |
| 405 | } |
| 406 | |
| 407 | con->src_ref = cr->source_local_reference; |
| 408 | con->sls = sls; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 409 | con->app = app; |
| 410 | llist_add_tail(&con->entry, &app->sccp_connections); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 411 | LOGP(DINP, LOGL_DEBUG, "Adding CR: local ref: 0x%x\n", sccp_src_ref_to_int(&con->src_ref)); |
| 412 | break; |
| 413 | case SCCP_MSG_TYPE_CC: |
| 414 | if (!from_msc) { |
| 415 | LOGP(DINP, LOGL_ERROR, "CC from BSC is not handled.\n"); |
| 416 | return; |
| 417 | } |
| 418 | |
| 419 | cc = (struct sccp_connection_confirm *) msg->l2h; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 420 | con = find_con_by_src_ref(app, &cc->destination_local_reference); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 421 | if (con) { |
| 422 | con->dst_ref = cc->source_local_reference; |
| 423 | con->has_dst_ref = 1; |
| 424 | LOGP(DINP, LOGL_DEBUG, "Updating CC: local: 0x%x remote: 0x%x\n", |
| 425 | sccp_src_ref_to_int(&con->src_ref), sccp_src_ref_to_int(&con->dst_ref)); |
| 426 | return; |
| 427 | } |
| 428 | |
| 429 | LOGP(DINP, LOGL_ERROR, "CCed connection can not be found: 0x%x\n", |
| 430 | sccp_src_ref_to_int(&cc->destination_local_reference)); |
| 431 | break; |
| 432 | case SCCP_MSG_TYPE_CREF: |
| 433 | if (!from_msc) { |
| 434 | LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n"); |
| 435 | return; |
| 436 | } |
| 437 | |
| 438 | cref = (struct sccp_connection_refused *) msg->l2h; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 439 | con = find_con_by_src_ref(app, &cref->destination_local_reference); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 440 | if (con) { |
| 441 | LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref)); |
| 442 | free_con(con); |
| 443 | return; |
| 444 | } |
| 445 | |
| 446 | LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n"); |
| 447 | break; |
| 448 | case SCCP_MSG_TYPE_RLSD: |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 449 | handle_rlsd(app, (struct sccp_connection_released *) msg->l2h, from_msc); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 450 | break; |
| 451 | case SCCP_MSG_TYPE_RLC: |
| 452 | if (from_msc) { |
| 453 | LOGP(DINP, LOGL_ERROR, "RLC from MSC is wrong.\n"); |
| 454 | return; |
| 455 | } |
| 456 | |
| 457 | rlc = (struct sccp_connection_release_complete *) msg->l2h; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 458 | con = find_con_by_src_dest_ref(app, &rlc->source_local_reference, |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 459 | &rlc->destination_local_reference); |
| 460 | if (con) { |
| 461 | LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref)); |
| 462 | if (con->released_from_msc) |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 463 | msc_send_rlc(msc, &con->src_ref, &con->dst_ref); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 464 | free_con(con); |
| 465 | return; |
| 466 | } |
| 467 | |
| 468 | LOGP(DINP, LOGL_ERROR, "RLC can not be found. 0x%x 0x%x\n", |
| 469 | sccp_src_ref_to_int(&rlc->source_local_reference), |
| 470 | sccp_src_ref_to_int(&rlc->destination_local_reference)); |
| 471 | break; |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | static void send_local_rlsd_for_con(void *data) |
| 476 | { |
| 477 | struct msgb *rlsd; |
| 478 | struct active_sccp_con *con = (struct active_sccp_con *) data; |
Holger Hans Peter Freyther | 4c9dd16 | 2011-02-23 16:11:21 +0100 | [diff] [blame^] | 479 | struct mtp_link_set *set; |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 480 | |
| 481 | /* try again in three seconds */ |
| 482 | con->rlc_timeout.data = con; |
| 483 | con->rlc_timeout.cb = send_local_rlsd_for_con; |
| 484 | bsc_schedule_timer(&con->rlc_timeout, 3, 0); |
| 485 | |
| 486 | /* we send this to the BSC so we need to switch src and dest */ |
| 487 | rlsd = create_sccp_rlsd(&con->dst_ref, &con->src_ref); |
| 488 | if (!rlsd) |
| 489 | return; |
| 490 | |
| 491 | ++con->rls_tries; |
Holger Hans Peter Freyther | 4c9dd16 | 2011-02-23 16:11:21 +0100 | [diff] [blame^] | 492 | |
| 493 | set = con->app->route_src.set; |
| 494 | if (!set) { |
| 495 | LOGP(DINP, LOGL_DEBUG, "Application %d has no linkset\n", con->app->nr); |
| 496 | return; |
| 497 | } |
| 498 | |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 499 | LOGP(DINP, LOGL_DEBUG, "Sending RLSD for 0x%x the %d time.\n", |
| 500 | sccp_src_ref_to_int(&con->src_ref), con->rls_tries); |
Holger Hans Peter Freyther | 4c9dd16 | 2011-02-23 16:11:21 +0100 | [diff] [blame^] | 501 | mtp_link_set_submit_sccp_data(set, con->sls, rlsd->l2h, msgb_l2len(rlsd)); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 502 | msgb_free(rlsd); |
| 503 | } |
| 504 | |
| 505 | static void send_local_rlsd(struct mtp_link_set *link, struct sccp_parse_result *res) |
| 506 | { |
| 507 | struct active_sccp_con *con; |
| 508 | |
| 509 | LOGP(DINP, LOGL_DEBUG, "Received GSM Clear Complete. Sending RLSD locally.\n"); |
| 510 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 511 | con = find_con_by_dest_ref(link->app, res->destination_local_reference); |
Holger Hans Peter Freyther | 43b015a | 2011-02-10 17:35:35 +0100 | [diff] [blame] | 512 | if (!con) |
| 513 | return; |
| 514 | con->rls_tries = 0; |
| 515 | send_local_rlsd_for_con(con); |
| 516 | } |
| 517 | |
| 518 | static void send_reset_ack(struct mtp_link_set *link, int sls) |
| 519 | { |
| 520 | static const uint8_t reset_ack[] = { |
| 521 | 0x09, 0x00, 0x03, 0x05, 0x7, 0x02, 0x42, 0xfe, |
| 522 | 0x02, 0x42, 0xfe, 0x03, |
| 523 | 0x00, 0x01, 0x31 |
| 524 | }; |
| 525 | |
| 526 | mtp_link_set_submit_sccp_data(link, sls, reset_ack, sizeof(reset_ack)); |
| 527 | } |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 528 | |
| 529 | void msc_dispatch_sccp(struct msc_connection *msc, struct msgb *msg) |
| 530 | { |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 531 | struct mtp_link_set *set; |
| 532 | |
| 533 | if (!msc->app) { |
| 534 | LOGP(DINP, LOGL_ERROR, "The MSC Connection %d/%s has no app assigned.\n", |
| 535 | msc->nr, msc->name); |
| 536 | return; |
| 537 | } |
| 538 | |
| 539 | |
| 540 | set = msc->app->route_src.set; |
| 541 | |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 542 | /* we can not forward it right now */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 543 | if (msc->app->forward_only) { |
| 544 | if (!set->sccp_up) |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 545 | return; |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 546 | mtp_link_set_submit_sccp_data(set, -1, |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 547 | msg->l2h, msgb_l2len(msg)); |
| 548 | } else { |
| 549 | struct sccp_parse_result result; |
| 550 | int rc; |
| 551 | |
| 552 | rc = bss_patch_filter_msg(msg, &result); |
| 553 | |
| 554 | if (rc == BSS_FILTER_RESET_ACK) { |
| 555 | LOGP(DMSC, LOGL_NOTICE, "Filtering reset ack from the MSC\n"); |
| 556 | } else if (rc == BSS_FILTER_RLSD) { |
| 557 | LOGP(DMSC, LOGL_DEBUG, "Filtering RLSD from the MSC\n"); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 558 | update_con_state(msc->app, rc, &result, msg, 1, 0); |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 559 | } else if (rc == BSS_FILTER_RLC) { |
| 560 | /* if we receive this we have forwarded a RLSD to the network */ |
| 561 | LOGP(DMSC, LOGL_ERROR, "RLC from the network. BAD!\n"); |
| 562 | } else if (rc == BSS_FILTER_CLEAR_COMPL) { |
| 563 | LOGP(DMSC, LOGL_ERROR, "Clear Complete from the network.\n"); |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 564 | } else if (set->sccp_up) { |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 565 | unsigned int sls; |
| 566 | |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 567 | update_con_state(msc->app, rc, &result, msg, 1, 0); |
| 568 | sls = sls_for_src_ref(msc->app, result.destination_local_reference); |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 569 | |
| 570 | /* Check for Location Update Accept */ |
| 571 | bsc_ussd_handle_in_msg(msc, &result, msg); |
| 572 | |
| 573 | /* patch a possible PC */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 574 | bss_rewrite_header_to_bsc(msg, set->opc, set->dpc); |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 575 | |
| 576 | /* we can not forward it right now */ |
Holger Hans Peter Freyther | a7bc3aa | 2011-02-16 16:12:07 +0100 | [diff] [blame] | 577 | mtp_link_set_submit_sccp_data(set, sls, |
Holger Hans Peter Freyther | 3d4d8c7 | 2011-02-15 21:14:09 +0100 | [diff] [blame] | 578 | msg->l2h, msgb_l2len(msg)); |
| 579 | } |
| 580 | } |
| 581 | } |