blob: 696e194f16d7612af70af3a4da5ae2fb3dc0135c [file] [log] [blame]
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +04001/* bssgp.cpp
2 *
3 * Copyright (C) 2011 Ivan Klyuchnikov
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#include <arpa/inet.h>
21#include <Threads.h>
22#include "GPRSSocket.h"
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +040023#include "gsm_rlcmac.h"
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +040024#include "bssgp.h"
25
26// TODO: We should move this parameters to config file.
27#define SGSN_IP "127.0.0.1"
28#define SGSN_PORT 23000
29#define CELL_ID 3
30#define BVCI 7
31#define NSEI 3
32#define NSVCI 4
33#define MNC 1
34#define MCC 1
35#define LAC 1000
36#define RAC 1
37
38#define QOS_PROFILE 0
39#define BSSGP_HDR_LEN 20
40#define NS_HDR_LEN 4
41#define MAX_LEN_PDU 100
42#define IE_PDU 14
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +040043#define BLOCK_DATA_LEN 19
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +040044
45#define BLOCK_LEN 23
46
47uint16_t bvci = BVCI;
48uint16_t nsei = NSEI;
49uint8_t TFI;
50struct bssgp_bvc_ctx *bctx = btsctx_alloc(bvci, nsei);
51struct gprs_nsvc *nsvc;
52struct gprs_ns_inst *sgsn_nsi;
53struct sgsn_instance *sgsn;
54void *tall_bsc_ctx;
55
56// Send RLC data to OpenBTS.
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +040057void sendRLC(uint32_t tlli, uint8_t *pdu, unsigned startIndex, unsigned endIndex, unsigned bsn, unsigned fbi)
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +040058{
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +040059 unsigned spareLen = 0;
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +040060 BitVector resultVector(BLOCK_LEN*8);
61 resultVector.unhex("2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +040062 RlcMacDownlinkDataBlock_t * dataBlock = (RlcMacDownlinkDataBlock_t *)malloc(sizeof(RlcMacDownlinkDataBlock_t));
63 dataBlock->PAYLOAD_TYPE = 0;
64 dataBlock->RRBP = 0;
65 dataBlock->SP = 1;
66 dataBlock->USF = 1;
67 dataBlock->PR = 0;
68 dataBlock->TFI = 20;
69 dataBlock->FBI = fbi;
70 dataBlock->BSN = bsn;
71 if ((endIndex-startIndex) < 20)
72 {
73 dataBlock->E_1 = 0;
74 dataBlock->LENGTH_INDICATOR[0] = endIndex-startIndex;
75 dataBlock->M[0] = 0;
76 dataBlock->E[0] = 1;
77 spareLen = 19 - dataBlock->LENGTH_INDICATOR[0];
78 }
79 else
80 {
81 dataBlock->E_1 = 1;
82 }
83 unsigned j = 0;
84 for(unsigned i = startIndex; i < endIndex; i++)
85 {
86 dataBlock->RLC_DATA[j] = pdu[i];
87 j++;
88 }
89 for(unsigned i = j; i < j + spareLen; i++)
90 {
91 dataBlock->RLC_DATA[i] = 0x2b;
92 }
93 encode_gsm_rlcmac_downlink_data(&resultVector, dataBlock);
94 free(dataBlock);
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +040095 sendToOpenBTS(&resultVector);
96}
97
98/* Receive a BSSGP PDU from a BSS on a PTP BVCI */
99int gprs_bssgp_bss_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx)
100{
101 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
102 uint8_t pdu_type = bgph->pdu_type;
103 uint8_t pdu[MAX_LEN_PDU];
104 unsigned rc = 0;
105 unsigned dataIndex = 0;
106 unsigned numBlocks = 0;
107 unsigned i = 0;
108 unsigned j = 0;
109 unsigned pduIndex = 0;
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400110 unsigned fbi = 0;
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400111 struct bssgp_ud_hdr *budh;
112
113 /* If traffic is received on a BVC that is marked as blocked, the
114 * received PDU shall not be accepted and a STATUS PDU (Cause value:
115 * BVC Blocked) shall be sent to the peer entity on the signalling BVC */
116 if (bctx->state & BVC_S_BLOCKED && pdu_type != BSSGP_PDUT_STATUS)
117 {
118 uint16_t bvci = msgb_bvci(msg);
119 LOGP(DBSSGP, LOGL_NOTICE, "rx BVC_S_BLOCKED\n");
120 return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &bvci, msg);
121 }
122
123 switch (pdu_type) {
124 case BSSGP_PDUT_DL_UNITDATA:
125 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_DL_UNITDATA\n");
126 budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
127 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP TLLI=0x%08x \n", ntohl(budh->tlli));
128 for (i = 4; i < MAX_LEN_PDU; i++)
129 {
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400130 //LOGP(DBSSGP, LOGL_NOTICE, "SERCH data = -0x%02x\n", budh ->data[i]);
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400131 if(budh ->data[i] == IE_PDU)
132 {
133 pduIndex = i+2;
134 break;
135 }
136 }
137 for (i = pduIndex; i < pduIndex + (budh->data[pduIndex-1]&0x7f); i++)
138 {
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400139 //LOGP(DBSSGP, LOGL_NOTICE, "-0x%02x\n", budh ->data[i]);
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400140 pdu[dataIndex] = budh ->data[i];
141 dataIndex++;
142 }
143 DEBUGP(DBSSGP, "BSSGP Catch from SGSN=%u octets. Send it to OpenBTS.\n", dataIndex);
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400144 sendToGSMTAP(pdu,dataIndex);
145 if (dataIndex > BLOCK_DATA_LEN + 1)
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400146 {
147 int blockDataLen = BLOCK_DATA_LEN;
148 numBlocks = dataIndex/BLOCK_DATA_LEN;
149 int ost = dataIndex%BLOCK_DATA_LEN;
150 int startIndex = 0;
151 int endIndex = 0;
152 if (dataIndex%BLOCK_DATA_LEN > 0)
153 {
154 numBlocks++;
155 }
156 for (i = 0; i < numBlocks; i++)
157 {
158 if (i == numBlocks-1)
159 {
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400160 if (ost > 0)
161 {
162 blockDataLen = ost;
163 }
164 fbi = 1;
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400165 }
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400166 endIndex = startIndex + blockDataLen;
167 sendRLC(ntohl(budh->tlli), pdu, startIndex, endIndex, i, fbi);
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400168 startIndex += blockDataLen;
169 }
170 }
171 else
172 {
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400173 sendRLC(ntohl(budh->tlli), pdu, 0, dataIndex, 0, 1);
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400174 }
175 break;
176 case BSSGP_PDUT_PAGING_PS:
177 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_PAGING_PS\n");
178 break;
179 case BSSGP_PDUT_PAGING_CS:
180 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_PAGING_CS\n");
181 break;
182 case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
183 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_RA_CAPA_UPDATE_ACK\n");
184 break;
185 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
186 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_FLOW_CONTROL_BVC_ACK\n");
187 break;
188 case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
189 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_FLOW_CONTROL_MS_ACK\n");
190 break;
191 default:
192 DEBUGP(DBSSGP, "BSSGP BVCI=%u PDU type 0x%02x unknown\n", bctx->bvci, pdu_type);
193 rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
194 break;
195 }
196 return rc;
197}
198
199/* Receive a BSSGP PDU from a SGSN on a SIGNALLING BVCI */
200int gprs_bssgp_bss_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx)
201{
202 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
203 int rc = 0;
204 switch (bgph->pdu_type) {
205 case BSSGP_PDUT_STATUS:
206 /* Some exception has occurred */
207 DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bctx->bvci);
208 /* FIXME: send NM_STATUS.ind to NM */
209 break;
210 case BSSGP_PDUT_SUSPEND_ACK:
211 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SUSPEND_ACK\n");
212 break;
213 case BSSGP_PDUT_SUSPEND_NACK:
214 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SUSPEND_NACK\n");
215 break;
216 case BSSGP_PDUT_BVC_RESET_ACK:
217 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_BVC_RESET_ACK\n");
218 break;
219 case BSSGP_PDUT_PAGING_PS:
220 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_PAGING_PS\n");
221 break;
222 case BSSGP_PDUT_PAGING_CS:
223 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_PAGING_CS\n");
224 break;
225 case BSSGP_PDUT_RESUME_ACK:
226 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_RESUME_ACK\n");
227 break;
228 case BSSGP_PDUT_RESUME_NACK:
229 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_RESUME_NACK\n");
230 break;
231 case BSSGP_PDUT_FLUSH_LL:
232 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_FLUSH_LL\n");
233 break;
234 case BSSGP_PDUT_BVC_BLOCK_ACK:
235 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SUSPEND_ACK\n");
236 break;
237 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
238 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n");
239 break;
240 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
241 LOGP(DBSSGP, LOGL_NOTICE, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n");
242 break;
243 default:
244 DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n", bctx->bvci, bgph->pdu_type);
245 rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
246 break;
247 }
248 return rc;
249}
250
251int gprs_bssgp_bss_rcvmsg(struct msgb *msg)
252{
253 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
254 struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
255 struct tlv_parsed tp;
256 uint8_t pdu_type = bgph->pdu_type;
257 uint16_t ns_bvci = msgb_bvci(msg);
258 int data_len;
259 int rc = 0;
260
261 /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */
262
263 /* UNITDATA BSSGP headers have TLLI in front */
264 if (pdu_type != BSSGP_PDUT_UL_UNITDATA && pdu_type != BSSGP_PDUT_DL_UNITDATA)
265 {
266 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
267 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
268 }
269 else
270 {
271 data_len = msgb_bssgp_len(msg) - sizeof(*budh);
272 rc = bssgp_tlv_parse(&tp, budh->data, data_len);
273 }
274
275 /* look-up or create the BTS context for this BVC */
276 bctx = btsctx_by_bvci_nsei(ns_bvci, msgb_nsei(msg));
277
278 /* Only a RESET PDU can create a new BVC context */
279 if (!bctx)
280 {
281 bctx = btsctx_alloc(ns_bvci, msgb_nsei(msg));
282 }
283
284 if (!bctx && pdu_type != BSSGP_PDUT_BVC_RESET_ACK)
285 {
286 LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
287 "type %u for unknown BVCI\n", msgb_nsei(msg), ns_bvci,
288 pdu_type);
289 return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg);
290 }
291
292 if (bctx)
293 {
294 log_set_context(BSC_CTX_BVC, bctx);
295 rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_IN]);
296 rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_IN], msgb_bssgp_len(msg));
297 }
298
299 if (ns_bvci == BVCI_SIGNALLING)
300 {
301 LOGP(DBSSGP, LOGL_NOTICE, "rx BVCI_SIGNALLING gprs_bssgp_rx_sign\n");
302 rc = gprs_bssgp_bss_rx_sign(msg, &tp, bctx);
303 }
304 else if (ns_bvci == BVCI_PTM)
305 {
306 LOGP(DBSSGP, LOGL_NOTICE, "rx BVCI_PTM bssgp_tx_status\n");
307 rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
308 }
309 else
310 {
311 LOGP(DBSSGP, LOGL_NOTICE, "rx BVCI_PTP gprs_bssgp_rx_ptp\n");
312 rc = gprs_bssgp_bss_rx_ptp(msg, &tp, bctx);
313 }
314 return rc;
315}
316
317
318int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, struct msgb *msg, uint16_t bvci)
319{
320 int rc = 0;
321 switch (event) {
322 case GPRS_NS_EVT_UNIT_DATA:
323 /* hand the message into the BSSGP implementation */
324 rc = gprs_bssgp_bss_rcvmsg(msg);
325 break;
326 default:
327 LOGP(DGPRS, LOGL_ERROR, "RLCMAC: Unknown event %u from NS\n", event);
328 if (msg)
329 talloc_free(msg);
330 rc = -EIO;
331 break;
332 }
333 return rc;
334}
335
336// Send RLC data to SGSN.
337void sendToSGSN(uint8_t tfi, uint32_t tlli, uint8_t * rlc_data, unsigned dataLen)
338{
339 const uint8_t qos_profile = QOS_PROFILE;
340 struct msgb *llc_pdu;
341 unsigned msgLen = NS_HDR_LEN + BSSGP_HDR_LEN + dataLen;
342 TFI = tfi;
343 bctx->cell_id = CELL_ID;
344 bctx->nsei = NSEI;
345 bctx->ra_id.mnc = MNC;
346 bctx->ra_id.mcc = MCC;
347 bctx->ra_id.lac = LAC;
348 bctx->ra_id.rac = RAC;
349 bctx->bvci = BVCI;
350 LOGP(DBSSGP, LOGL_DEBUG, "Data len %u TLLI 0x%08x , TFI 0x%02x", dataLen, tlli, tfi);
351 //for (unsigned i = 0; i < dataLen; i++)
352 // LOGP(DBSSGP, LOGL_DEBUG, " Data[%u] = %u", i, rlc_data[i]);
353 llc_pdu = msgb_alloc_headroom(msgLen, msgLen,"llc_pdu");
354 msgb_tvlv_push(llc_pdu, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*dataLen, rlc_data);
355 bssgp_tx_ul_ud(bctx, tlli, &qos_profile, llc_pdu);
356}
357
358void RLCMACServer()
359{
360 uint16_t nsvci = NSVCI;
361
362 // Socket for reading BitVectors (RLC/MAC Frames) from OpenBTS application.
363 Thread RLCMACInterface;
364 RLCMACInterface.start(RLCMACSocket,NULL);
365
366 osmo_init_logging(&log_info);
367 sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb);
368 bssgp_nsi = sgsn_nsi;
369
370 if (!bssgp_nsi)
371 {
372 LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
373 exit(1);
374 }
375
376 bctx->cell_id = CELL_ID;
377 bctx->nsei = NSEI;
378 bctx->ra_id.mnc = MNC;
379 bctx->ra_id.mcc = MCC;
380 bctx->ra_id.lac = LAC;
381 bctx->ra_id.rac = RAC;
382 bctx->bvci = BVCI;
383 uint8_t cause = 39;
384 gprs_ns_nsip_listen(sgsn_nsi);
385
386 struct sockaddr_in dest;
387 dest.sin_family = AF_INET;
388 dest.sin_port = htons(SGSN_PORT);
389 inet_aton(SGSN_IP, &dest.sin_addr);
390
391 nsvc = nsip_connect(sgsn_nsi, &dest, nsei, nsvci);
392 unsigned i = 0;
393 while (1)
394 {
395 osmo_select_main(0);
396 if (i == 7)
397 {
Ivan Kluchnikov8aa4c522012-02-20 15:15:12 +0400398 bssgp_tx_bvc_reset(bctx, bvci, cause);
Ivan Kluchnikov5c2f9fb2012-02-05 02:27:17 +0400399 }
400 i++;
401 }
402}