blob: dc555bf9ff2f92213e489bb6e442485baff5c7f7 [file] [log] [blame]
Harald Welte90256ba2015-12-23 20:16:36 +01001/* Mapper between RUA ContextID (24 bit, per HNB) and the SUA/SCCP
2 * Connection ID (32bit, per signalling link) */
3
4/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
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/* an expired mapping is destroyed after 1..2 * EXPIRY_TIMER_SECS */
23#define EXPIRY_TIMER_SECS 23
24
25#include <osmocom/core/timer.h>
26
Neels Hofmeyrdf63de22016-08-18 13:13:55 +020027#include <osmocom/iuh/hnbgw.h>
28#include <osmocom/iuh/context_map.h>
Harald Welte90256ba2015-12-23 20:16:36 +010029
Neels Hofmeyr9e17e052017-12-25 00:35:05 +010030const struct value_string hnbgw_context_map_state_names[] = {
31 {MAP_S_NULL , "not-initialized"},
32 {MAP_S_ACTIVE , "active"},
33 {MAP_S_RESERVED1, "inactive-reserved"},
34 {MAP_S_RESERVED2, "inactive-discard"},
35 {0, NULL}
36};
37
Harald Welte90256ba2015-12-23 20:16:36 +010038/* is a given SCCP USER SAP Connection ID in use for a given CN link? */
39static int cn_id_in_use(struct hnbgw_cnlink *cn, uint32_t id)
40{
41 struct hnbgw_context_map *map;
42
43 llist_for_each_entry(map, &cn->map_list, cn_list) {
44 if (map->scu_conn_id == id)
45 return 1;
46 }
47 return 0;
48}
49
50/* try to allocate a new SCCP User SAP Connection ID */
51static int alloc_cn_conn_id(struct hnbgw_cnlink *cn, uint32_t *id_out)
52{
53 uint32_t i;
54 uint32_t id;
55
56 for (i = 0; i < 0xffffffff; i++) {
57 id = cn->next_conn_id++;
58 if (!cn_id_in_use(cn, id)) {
59 *id_out = id;
60 return 1;
61 }
62 }
63 return -1;
64}
65
66/* Map from a HNB + ContextID to the SCCP-side Connection ID */
67struct hnbgw_context_map *
68context_map_alloc_by_hnb(struct hnb_context *hnb, uint32_t rua_ctx_id,
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020069 bool is_ps,
Harald Welte90256ba2015-12-23 20:16:36 +010070 struct hnbgw_cnlink *cn_if_new)
71{
72 struct hnbgw_context_map *map;
73 uint32_t new_scu_conn_id;
74
75 llist_for_each_entry(map, &hnb->map_list, hnb_list) {
76 if (map->state != MAP_S_ACTIVE)
77 continue;
Daniel Willmanndefd2992016-01-14 15:10:05 +010078 if (map->cn_link != cn_if_new) {
79 continue;
80 }
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020081 if (map->rua_ctx_id == rua_ctx_id
82 && map->is_ps == is_ps) {
Harald Welte90256ba2015-12-23 20:16:36 +010083 return map;
84 }
85 }
86
Harald Welte37166a22015-12-24 10:12:09 +010087 if (alloc_cn_conn_id(cn_if_new, &new_scu_conn_id) < 0) {
88 LOGP(DMAIN, LOGL_ERROR, "Unable to allocate CN connection ID\n");
Harald Welte90256ba2015-12-23 20:16:36 +010089 return NULL;
Harald Welte37166a22015-12-24 10:12:09 +010090 }
Harald Welte90256ba2015-12-23 20:16:36 +010091
Harald Welte49287972015-12-29 19:00:35 +010092 LOGP(DMAIN, LOGL_INFO, "Creating new Mapping RUA CTX %p/%u <-> SCU Conn ID %p/%u\n",
93 hnb, rua_ctx_id, cn_if_new, new_scu_conn_id);
94
Harald Welte90256ba2015-12-23 20:16:36 +010095 /* alloate a new map entry */
96 map = talloc_zero(hnb, struct hnbgw_context_map);
97 map->state = MAP_S_NULL;
98 map->cn_link = cn_if_new;
99 map->hnb_ctx = hnb;
100 map->rua_ctx_id = rua_ctx_id;
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200101 map->is_ps = is_ps;
Harald Welte4009b362015-12-26 23:39:05 +0100102 map->scu_conn_id = new_scu_conn_id;
Harald Welte90256ba2015-12-23 20:16:36 +0100103
104 /* put it into both lists */
105 llist_add_tail(&map->hnb_list, &hnb->map_list);
106 llist_add_tail(&map->cn_list, &cn_if_new->map_list);
107 map->state = MAP_S_ACTIVE;
108
109 return map;
110}
111
112/* Map from a CN + Connection ID to HNB + Context ID */
113struct hnbgw_context_map *
114context_map_by_cn(struct hnbgw_cnlink *cn, uint32_t scu_conn_id)
115{
116 struct hnbgw_context_map *map;
117
Harald Welte90256ba2015-12-23 20:16:36 +0100118 llist_for_each_entry(map, &cn->map_list, cn_list) {
119 if (map->state != MAP_S_ACTIVE)
120 continue;
121 if (map->scu_conn_id == scu_conn_id) {
122 return map;
123 }
124 }
125 /* we don't allocate new mappings in the CN->HNB
126 * direction, as the RUA=SCCP=SUA connections are always
Harald Welte37166a22015-12-24 10:12:09 +0100127 * established from HNB towards CN. */
128 LOGP(DMAIN, LOGL_NOTICE, "Unable to resolve map for CN "
Harald Welte49287972015-12-29 19:00:35 +0100129 "connection ID %p/%u\n", cn, scu_conn_id);
Harald Welte90256ba2015-12-23 20:16:36 +0100130 return NULL;
131}
132
133void context_map_deactivate(struct hnbgw_context_map *map)
134{
135 /* set the state to reserved. We still show up in the list and
136 * avoid re-allocation of the context-id until we are cleaned up
137 * by the context_map garbage collector timer */
138
139 if (map->state != MAP_S_RESERVED2)
140 map->state = MAP_S_RESERVED1;
141}
142
143static struct osmo_timer_list context_map_tmr;
144
145static void context_map_tmr_cb(void *data)
146{
147 struct hnb_gw *gw = data;
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200148 struct hnbgw_cnlink *cn = gw->sccp.cnlink;
Neels Hofmeyraa3e9eb2017-12-24 21:47:59 +0100149 struct hnbgw_context_map *map, *next_map;
Harald Welte90256ba2015-12-23 20:16:36 +0100150
Harald Welte37166a22015-12-24 10:12:09 +0100151 DEBUGP(DMAIN, "Running context mapper garbage collection\n");
Neels Hofmeyraa3e9eb2017-12-24 21:47:59 +0100152 llist_for_each_entry_safe(map, next_map, &cn->map_list, cn_list) {
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200153 switch (map->state) {
154 case MAP_S_RESERVED1:
155 /* first time we see this reserved
156 * entry: mark it for stage 2 */
157 map->state = MAP_S_RESERVED2;
158 break;
159 case MAP_S_RESERVED2:
Neels Hofmeyre045da02017-12-24 20:34:38 +0100160 /* second time we see this reserved
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200161 * entry: remove it */
162 map->state = MAP_S_NULL;
163 llist_del(&map->cn_list);
164 llist_del(&map->hnb_list);
165 talloc_free(map);
166 break;
167 default:
168 break;
Harald Welte90256ba2015-12-23 20:16:36 +0100169 }
170 }
171 /* re-schedule this timer */
172 osmo_timer_schedule(&context_map_tmr, EXPIRY_TIMER_SECS, 0);
173}
174
175int context_map_init(struct hnb_gw *gw)
176{
177 context_map_tmr.cb = context_map_tmr_cb;
178 context_map_tmr.data = gw;
179 osmo_timer_schedule(&context_map_tmr, EXPIRY_TIMER_SECS, 0);
Harald Welteda86fe52017-11-21 08:14:37 +0100180
181 return 0;
Harald Welte90256ba2015-12-23 20:16:36 +0100182}