blob: 77cc8caf97bcb7b392871e076bb3875dcb82d0c1 [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) */
85static struct gbprox_peer *peer_by_rac(uint8_t *ra)
86{
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) */
96static struct gbprox_peer *peer_by_lac(uint8_t *la)
97{
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{
154 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
155 struct tlv_parsed tp;
156 uint8_t pdu_type = bgph->pdu_type;
157 int data_len = msgb_l3len(msg) - sizeof(*bgph);
158 struct gbprox_peer *from_peer;
159
160 if (ns_bvci != 0) {
161 LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci);
162 return -EINVAL;
163 }
164
165 /* we actually should never see those two for BVCI == 0, but double-check
166 * just to make sure */
167 if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
168 pdu_type == BSSGP_PDUT_DL_UNITDATA) {
169 LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n");
170 return -EINVAL;
171 }
172
173 bssgp_tlv_parse(&tp, bgph->data, data_len);
174
175 switch (pdu_type) {
176 case BSSGP_PDUT_SUSPEND:
177 case BSSGP_PDUT_RESUME:
178 /* RAC snooping for SUSPEND/RESUME */
179 if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
180 goto err_mand_ie;
181 from_peer = peer_by_nsvc(nsvc);
182 if (!from_peer)
183 goto err_no_peer;
184 memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
185 sizeof(&from_peer->ra));
186 /* FIXME: This only supports one BSS per RA */
187 break;
188 }
189
190 /* Normally, we can simply pass on all signalling messages from BSS to SGSN */
191 return gbprox_tx2peer(msg, gbprox_peer_sgsn, ns_bvci);
192err_no_peer:
193err_mand_ie:
194 /* FIXME: do something */
195 ;
196}
197
198/* Receive paging request from SGSN, we need to relay to proper BSS */
199static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp,
200 struct gprs_nsvc *nsvc, uint16_t ns_bvci)
201{
202 struct gbprox_peer *peer;
203
204 if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
205 uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
206 return gbprox_tx2bvci(msg, bvci, ns_bvci);
207 } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
208 peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
209 return gbprox_tx2peer(msg, peer, ns_bvci);
210 } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
211 peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA));
212 return gbprox_tx2peer(msg, peer, ns_bvci);
213 } else
214 return -EINVAL;
215}
216
217/* Receive an incoming signalling message from the SGSN-side NS-VC */
218static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc,
219 uint16_t ns_bvci)
220{
221 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
222 struct tlv_parsed tp;
223 uint8_t pdu_type = bgph->pdu_type;
224 int data_len = msgb_l3len(msg) - sizeof(*bgph);
225 struct gbprox_peer *peer;
226 uint16_t bvci;
227 int rc = 0;
228
229 if (ns_bvci != 0) {
230 LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci);
231 return -EINVAL;
232 }
233
234 /* we actually should never see those two for BVCI == 0, but double-check
235 * just to make sure */
236 if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
237 pdu_type == BSSGP_PDUT_DL_UNITDATA) {
238 LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n");
239 return -EINVAL;
240 }
241
242 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
243
244 switch (pdu_type) {
245 case BSSGP_PDUT_FLUSH_LL:
246 case BSSGP_PDUT_BVC_BLOCK_ACK:
247 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
248 case BSSGP_PDUT_BVC_RESET:
249 case BSSGP_PDUT_BVC_RESET_ACK:
250 /* simple case: BVCI IE is mandatory */
251 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
252 goto err_mand_ie;
253 bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
254 rc = gbprox_tx2bvci(msg, bvci, ns_bvci);
255 break;
256 case BSSGP_PDUT_PAGING_PS:
257 case BSSGP_PDUT_PAGING_CS:
258 /* process the paging request (LAC/RAC lookup) */
259 rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci);
260 break;
261 case BSSGP_PDUT_STATUS:
262 /* FIXME: Some exception has occurred */
263 LOGP(DGPRS, LOGL_NOTICE, "STATUS not implemented yet\n");
264 break;
265 /* those only exist in the SGSN -> BSS direction */
266 case BSSGP_PDUT_SUSPEND_ACK:
267 case BSSGP_PDUT_SUSPEND_NACK:
268 case BSSGP_PDUT_RESUME_ACK:
269 case BSSGP_PDUT_RESUME_NACK:
270 /* RAC IE is mandatory */
271 if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
272 goto err_mand_ie;
273 peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
274 if (!peer)
275 goto err_no_peer;
276 rc = gbprox_tx2peer(msg, peer, ns_bvci);
277 break;
278 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
279 LOGP(DGPRS, LOGL_ERROR, "SGSN INVOKE TRACE not supported\n");
280 break;
281 default:
282 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type);
283 break;
284 }
285
286 return rc;
287err_mand_ie:
288 ; /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */
289 //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
290err_no_peer:
291 ; /* FIXME */
292}
293
294/* Main input function for Gb proxy */
295int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci)
296{
297 struct gbprox_peer *peer;
298
299 /* Only BVCI=0 messages need special treatment */
300 if (ns_bvci == 0 || ns_bvci == 1) {
301 if (nsvc->remote_end_is_sgsn)
302 return gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci);
303 else
304 return gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci);
305 }
306
307 /* All other BVCI are PTP and thus can be simply forwarded */
308 peer = peer_by_bvci(ns_bvci);
309 if (!peer) {
310 LOGP(DGPRS, LOGL_ERROR, "Couldn't find peer for BVCI %u\n", ns_bvci);
311 return -EIO;
312 }
313
314 return gbprox_tx2peer(msg, peer, ns_bvci);
315}