blob: 4d8f27f01f3c7e848279c19418d07728f92896c6 [file] [log] [blame]
Harald Welted1991e72010-04-30 20:26:32 +02001/* NS-over-IP proxy */
2
3/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2010 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 General Public License as published by
9 * the Free Software Foundation; either version 2 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 General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <unistd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <errno.h>
29#include <sys/fcntl.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32
33#include <osmocore/talloc.h>
34#include <osmocore/select.h>
35
36#include <openbsc/signal.h>
37#include <openbsc/debug.h>
38#include <openbsc/gprs_ns.h>
39#include <openbsc/gprs_bssgp.h>
40
41struct gbprox_peer {
42 struct llist_head list;
43
44 /* NS-VC over which we send/receive data to this BVC */
45 struct gprs_nsvc *nsvc;
46
47 /* BVCI used for Point-to-Point to this peer */
48 uint16_t bvci;
49
50 /* Routeing Area that this peer is part of (raw 04.08 encoding) */
51 uint8_t ra[6];
52};
53
54/* Linked list of all Gb peers (except SGSN) */
55static LLIST_HEAD(gbprox_bts_peers);
56
57/* Pointer to the SGSN peer */
58struct gbprox_peer *gbprox_peer_sgsn;
59
60/* The NS protocol stack instance we're using */
61extern struct gprs_ns_inst *gbprox_nsi;
62
63/* Find the gbprox_peer by its BVCI */
64static struct gbprox_peer *peer_by_bvci(uint16_t bvci)
65{
66 struct gbprox_peer *peer;
67 llist_for_each_entry(peer, &gbprox_bts_peers, list) {
68 if (peer->bvci == bvci)
69 return peer;
70 }
71 return NULL;
72}
73
74static struct gbprox_peer *peer_by_nsvc(struct gprs_nsvc *nsvc)
75{
76 struct gbprox_peer *peer;
77 llist_for_each_entry(peer, &gbprox_bts_peers, list) {
78 if (peer->nsvc == nsvc)
79 return peer;
80 }
81 return NULL;
82}
83
84/* look-up a peer by its Routeing Area Code (RAC) */
Harald Weltee49c8292010-05-01 12:10:57 +020085static struct gbprox_peer *peer_by_rac(const uint8_t *ra)
Harald Welted1991e72010-04-30 20:26:32 +020086{
87 struct gbprox_peer *peer;
88 llist_for_each_entry(peer, &gbprox_bts_peers, list) {
89 if (!memcmp(&peer->ra, ra, 6))
90 return peer;
91 }
92 return NULL;
93}
94
95/* look-up a peer by its Location Area Code (LAC) */
Harald Weltee49c8292010-05-01 12:10:57 +020096static struct gbprox_peer *peer_by_lac(const uint8_t *la)
Harald Welted1991e72010-04-30 20:26:32 +020097{
98 struct gbprox_peer *peer;
99 llist_for_each_entry(peer, &gbprox_bts_peers, list) {
100 if (!memcmp(&peer->ra, la, 5))
101 return peer;
102 }
103 return NULL;
104}
105
106static struct gbprox_peer *peer_alloc(uint16_t bvci)
107{
108 struct gbprox_peer *peer;
109
110 peer = talloc_zero(tall_bsc_ctx, struct gbprox_peer);
111 if (!peer)
112 return NULL;
113
114 peer->bvci = bvci;
115 llist_add(&peer->list, &gbprox_bts_peers);
116
117 return peer;
118}
119
120static void peer_free(struct gbprox_peer *peer)
121{
122 llist_del(&peer->list);
123 talloc_free(peer);
124}
125
126/* feed a message down the NS-VC associated with the specified peer */
127static int gbprox_tx2peer(struct msgb *msg, struct gbprox_peer *peer,
128 uint16_t ns_bvci)
129{
130 msgb_bvci(msg) = ns_bvci;
131 msgb_nsei(msg) = peer->nsvc->nsei;
132
133 return gprs_ns_sendmsg(gbprox_nsi, msg);
134}
135
136/* Send a message to a peer identified by ptp_bvci but using ns_bvci
137 * in the NS hdr */
138static int gbprox_tx2bvci(struct msgb *msg, uint16_t ptp_bvci,
139 uint16_t ns_bvci)
140{
141 struct gbprox_peer *peer;
142
143 peer = peer_by_bvci(ptp_bvci);
144 if (!peer)
145 return -ENOENT;
146
147 return gbprox_tx2peer(msg, peer, ns_bvci);
148}
149
150/* Receive an incoming signalling message from a BSS-side NS-VC */
151static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc,
152 uint16_t ns_bvci)
153{
Harald Welte2ac2e912010-05-03 16:30:59 +0200154 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welted1991e72010-04-30 20:26:32 +0200155 struct tlv_parsed tp;
156 uint8_t pdu_type = bgph->pdu_type;
Harald Welte2ac2e912010-05-03 16:30:59 +0200157 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welted1991e72010-04-30 20:26:32 +0200158 struct gbprox_peer *from_peer;
Harald Weltee49c8292010-05-01 12:10:57 +0200159 struct gprs_ra_id raid;
Harald Welted1991e72010-04-30 20:26:32 +0200160
161 if (ns_bvci != 0) {
Harald Weltee49c8292010-05-01 12:10:57 +0200162 LOGP(DGPRS, LOGL_NOTICE, "BVCI %u is not signalling\n", ns_bvci);
Harald Welted1991e72010-04-30 20:26:32 +0200163 return -EINVAL;
164 }
165
166 /* we actually should never see those two for BVCI == 0, but double-check
167 * just to make sure */
168 if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
169 pdu_type == BSSGP_PDUT_DL_UNITDATA) {
170 LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n");
171 return -EINVAL;
172 }
173
174 bssgp_tlv_parse(&tp, bgph->data, data_len);
175
176 switch (pdu_type) {
177 case BSSGP_PDUT_SUSPEND:
178 case BSSGP_PDUT_RESUME:
Harald Weltee49c8292010-05-01 12:10:57 +0200179 /* We implement RAC snooping during SUSPEND/RESUME, since
180 * it establishes a relationsip between BVCI/peer and the
181 * routeing area code. The snooped information is then
182 * used for routing the {SUSPEND,RESUME}_[N]ACK back to
183 * the correct BSSGP */
Harald Welted1991e72010-04-30 20:26:32 +0200184 if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
185 goto err_mand_ie;
186 from_peer = peer_by_nsvc(nsvc);
187 if (!from_peer)
188 goto err_no_peer;
189 memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
190 sizeof(&from_peer->ra));
Harald Weltee49c8292010-05-01 12:10:57 +0200191 gsm48_parse_ra(&raid, &from_peer->ra);
192 DEBUGP(DGPRS, "RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, "
193 "NSVCI=%u, NSEI=%u\n", raid.mcc, raid.mnc, raid.lac,
194 raid.rac , from_peer->bvci, nsvc->nsvci, nsvc->nsei);
Harald Welted1991e72010-04-30 20:26:32 +0200195 /* FIXME: This only supports one BSS per RA */
196 break;
197 }
198
199 /* Normally, we can simply pass on all signalling messages from BSS to SGSN */
200 return gbprox_tx2peer(msg, gbprox_peer_sgsn, ns_bvci);
201err_no_peer:
202err_mand_ie:
203 /* FIXME: do something */
204 ;
205}
206
207/* Receive paging request from SGSN, we need to relay to proper BSS */
208static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp,
209 struct gprs_nsvc *nsvc, uint16_t ns_bvci)
210{
211 struct gbprox_peer *peer;
212
213 if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
214 uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
215 return gbprox_tx2bvci(msg, bvci, ns_bvci);
216 } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
217 peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
218 return gbprox_tx2peer(msg, peer, ns_bvci);
219 } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
220 peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA));
221 return gbprox_tx2peer(msg, peer, ns_bvci);
222 } else
223 return -EINVAL;
224}
225
226/* Receive an incoming signalling message from the SGSN-side NS-VC */
227static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc,
228 uint16_t ns_bvci)
229{
Harald Welte2ac2e912010-05-03 16:30:59 +0200230 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
Harald Welted1991e72010-04-30 20:26:32 +0200231 struct tlv_parsed tp;
232 uint8_t pdu_type = bgph->pdu_type;
Harald Welte2ac2e912010-05-03 16:30:59 +0200233 int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
Harald Welted1991e72010-04-30 20:26:32 +0200234 struct gbprox_peer *peer;
235 uint16_t bvci;
236 int rc = 0;
237
238 if (ns_bvci != 0) {
Harald Weltee49c8292010-05-01 12:10:57 +0200239 LOGP(DGPRS, LOGL_NOTICE, "BVCI %u is not signalling\n", ns_bvci);
Harald Welted1991e72010-04-30 20:26:32 +0200240 return -EINVAL;
241 }
242
243 /* we actually should never see those two for BVCI == 0, but double-check
244 * just to make sure */
245 if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
246 pdu_type == BSSGP_PDUT_DL_UNITDATA) {
247 LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n");
248 return -EINVAL;
249 }
250
251 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
252
253 switch (pdu_type) {
254 case BSSGP_PDUT_FLUSH_LL:
255 case BSSGP_PDUT_BVC_BLOCK_ACK:
256 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
257 case BSSGP_PDUT_BVC_RESET:
258 case BSSGP_PDUT_BVC_RESET_ACK:
259 /* simple case: BVCI IE is mandatory */
260 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
261 goto err_mand_ie;
262 bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
263 rc = gbprox_tx2bvci(msg, bvci, ns_bvci);
264 break;
265 case BSSGP_PDUT_PAGING_PS:
266 case BSSGP_PDUT_PAGING_CS:
267 /* process the paging request (LAC/RAC lookup) */
268 rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci);
269 break;
270 case BSSGP_PDUT_STATUS:
271 /* FIXME: Some exception has occurred */
272 LOGP(DGPRS, LOGL_NOTICE, "STATUS not implemented yet\n");
273 break;
274 /* those only exist in the SGSN -> BSS direction */
275 case BSSGP_PDUT_SUSPEND_ACK:
276 case BSSGP_PDUT_SUSPEND_NACK:
277 case BSSGP_PDUT_RESUME_ACK:
278 case BSSGP_PDUT_RESUME_NACK:
279 /* RAC IE is mandatory */
280 if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
281 goto err_mand_ie;
282 peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
283 if (!peer)
284 goto err_no_peer;
285 rc = gbprox_tx2peer(msg, peer, ns_bvci);
286 break;
287 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
288 LOGP(DGPRS, LOGL_ERROR, "SGSN INVOKE TRACE not supported\n");
289 break;
290 default:
291 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type);
292 break;
293 }
294
295 return rc;
296err_mand_ie:
297 ; /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */
298 //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
299err_no_peer:
300 ; /* FIXME */
301}
302
303/* Main input function for Gb proxy */
304int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci)
305{
306 struct gbprox_peer *peer;
307
308 /* Only BVCI=0 messages need special treatment */
309 if (ns_bvci == 0 || ns_bvci == 1) {
310 if (nsvc->remote_end_is_sgsn)
311 return gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci);
312 else
313 return gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci);
314 }
315
316 /* All other BVCI are PTP and thus can be simply forwarded */
317 peer = peer_by_bvci(ns_bvci);
318 if (!peer) {
Harald Weltee49c8292010-05-01 12:10:57 +0200319 if (!nsvc->remote_end_is_sgsn) {
320 LOGP(DGPRS, LOGL_NOTICE, "Allocationg new peer for "
321 "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci,
322 nsvc->nsvci, nsvc->nsei);
323 peer = peer_alloc(ns_bvci);
324 peer->nsvc = nsvc;
325 } else {
326 LOGP(DGPRS, LOGL_ERROR, "Couldn't find peer for "
327 "BVCI %u\n", ns_bvci);
328 /* FIXME: do we really have to free the message here? */
329 msgb_free(msg);
330 return -EIO;
331 }
Harald Welted1991e72010-04-30 20:26:32 +0200332 }
333
334 return gbprox_tx2peer(msg, peer, ns_bvci);
335}