blob: 22eb605d24a643f8a886a8942123b7fcecaa685e [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
27#include "hnbgw.h"
28#include "context_map.h"
29
30/* is a given SCCP USER SAP Connection ID in use for a given CN link? */
31static int cn_id_in_use(struct hnbgw_cnlink *cn, uint32_t id)
32{
33 struct hnbgw_context_map *map;
34
35 llist_for_each_entry(map, &cn->map_list, cn_list) {
36 if (map->scu_conn_id == id)
37 return 1;
38 }
39 return 0;
40}
41
42/* try to allocate a new SCCP User SAP Connection ID */
43static int alloc_cn_conn_id(struct hnbgw_cnlink *cn, uint32_t *id_out)
44{
45 uint32_t i;
46 uint32_t id;
47
48 for (i = 0; i < 0xffffffff; i++) {
49 id = cn->next_conn_id++;
50 if (!cn_id_in_use(cn, id)) {
51 *id_out = id;
52 return 1;
53 }
54 }
55 return -1;
56}
57
58/* Map from a HNB + ContextID to the SCCP-side Connection ID */
59struct hnbgw_context_map *
60context_map_alloc_by_hnb(struct hnb_context *hnb, uint32_t rua_ctx_id,
61 struct hnbgw_cnlink *cn_if_new)
62{
63 struct hnbgw_context_map *map;
64 uint32_t new_scu_conn_id;
65
66 llist_for_each_entry(map, &hnb->map_list, hnb_list) {
67 if (map->state != MAP_S_ACTIVE)
68 continue;
Daniel Willmanndefd2992016-01-14 15:10:05 +010069 if (map->cn_link != cn_if_new) {
70 continue;
71 }
Harald Welte90256ba2015-12-23 20:16:36 +010072 if (map->rua_ctx_id == rua_ctx_id) {
73 return map;
74 }
75 }
76
Harald Welte37166a22015-12-24 10:12:09 +010077 if (alloc_cn_conn_id(cn_if_new, &new_scu_conn_id) < 0) {
78 LOGP(DMAIN, LOGL_ERROR, "Unable to allocate CN connection ID\n");
Harald Welte90256ba2015-12-23 20:16:36 +010079 return NULL;
Harald Welte37166a22015-12-24 10:12:09 +010080 }
Harald Welte90256ba2015-12-23 20:16:36 +010081
Harald Welte49287972015-12-29 19:00:35 +010082 LOGP(DMAIN, LOGL_INFO, "Creating new Mapping RUA CTX %p/%u <-> SCU Conn ID %p/%u\n",
83 hnb, rua_ctx_id, cn_if_new, new_scu_conn_id);
84
Harald Welte90256ba2015-12-23 20:16:36 +010085 /* alloate a new map entry */
86 map = talloc_zero(hnb, struct hnbgw_context_map);
87 map->state = MAP_S_NULL;
88 map->cn_link = cn_if_new;
89 map->hnb_ctx = hnb;
90 map->rua_ctx_id = rua_ctx_id;
Harald Welte4009b362015-12-26 23:39:05 +010091 map->scu_conn_id = new_scu_conn_id;
Harald Welte90256ba2015-12-23 20:16:36 +010092
93 /* put it into both lists */
94 llist_add_tail(&map->hnb_list, &hnb->map_list);
95 llist_add_tail(&map->cn_list, &cn_if_new->map_list);
96 map->state = MAP_S_ACTIVE;
97
98 return map;
99}
100
101/* Map from a CN + Connection ID to HNB + Context ID */
102struct hnbgw_context_map *
103context_map_by_cn(struct hnbgw_cnlink *cn, uint32_t scu_conn_id)
104{
105 struct hnbgw_context_map *map;
106
Harald Welte90256ba2015-12-23 20:16:36 +0100107 llist_for_each_entry(map, &cn->map_list, cn_list) {
108 if (map->state != MAP_S_ACTIVE)
109 continue;
110 if (map->scu_conn_id == scu_conn_id) {
111 return map;
112 }
113 }
114 /* we don't allocate new mappings in the CN->HNB
115 * direction, as the RUA=SCCP=SUA connections are always
Harald Welte37166a22015-12-24 10:12:09 +0100116 * established from HNB towards CN. */
117 LOGP(DMAIN, LOGL_NOTICE, "Unable to resolve map for CN "
Harald Welte49287972015-12-29 19:00:35 +0100118 "connection ID %p/%u\n", cn, scu_conn_id);
Harald Welte90256ba2015-12-23 20:16:36 +0100119 return NULL;
120}
121
122void context_map_deactivate(struct hnbgw_context_map *map)
123{
124 /* set the state to reserved. We still show up in the list and
125 * avoid re-allocation of the context-id until we are cleaned up
126 * by the context_map garbage collector timer */
127
128 if (map->state != MAP_S_RESERVED2)
129 map->state = MAP_S_RESERVED1;
130}
131
132static struct osmo_timer_list context_map_tmr;
133
134static void context_map_tmr_cb(void *data)
135{
136 struct hnb_gw *gw = data;
137 struct hnbgw_cnlink *cn;
138
Harald Welte37166a22015-12-24 10:12:09 +0100139 DEBUGP(DMAIN, "Running context mapper garbage collection\n");
Harald Welte90256ba2015-12-23 20:16:36 +0100140 /* iterate over list of core network (links) */
141 llist_for_each_entry(cn, &gw->cn_list, list) {
142 struct hnbgw_context_map *map;
143
144 llist_for_each_entry(map, &cn->map_list, cn_list) {
145 switch (map->state) {
146 case MAP_S_RESERVED1:
147 /* first time we see this reserved
148 * entry: mark it for stage 2 */
149 map->state = MAP_S_RESERVED2;
150 break;
151 case MAP_S_RESERVED2:
152 /* first time we see this reserved
153 * entry: remove it */
154 map->state = MAP_S_NULL;
155 llist_del(&map->cn_list);
156 llist_del(&map->hnb_list);
157 talloc_free(map);
158 break;
159 default:
160 break;
161 }
162 }
163 }
164 /* re-schedule this timer */
165 osmo_timer_schedule(&context_map_tmr, EXPIRY_TIMER_SECS, 0);
166}
167
168int context_map_init(struct hnb_gw *gw)
169{
170 context_map_tmr.cb = context_map_tmr_cb;
171 context_map_tmr.data = gw;
172 osmo_timer_schedule(&context_map_tmr, EXPIRY_TIMER_SECS, 0);
173}