blob: ab6d1a098bee4c6f98b0e2b304b621f39ee27d4f [file] [log] [blame]
Harald Welte9b455bf2010-03-14 15:45:01 +08001/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 *
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 <errno.h>
24#include <sys/types.h>
25
26#include <netinet/in.h>
27
28#include <osmocore/msgb.h>
29#include <osmocore/tlv.h>
30#include <openbsc/debug.h>
31#include <openbsc/gsm_data.h>
32#include <openbsc/gsm_04_08_gprs.h>
33#include <openbsc/gprs_bssgp.h>
34#include <openbsc/gprs_llc.h>
35#include <openbsc/gprs_ns.h>
36
37/* global pointer to the gsm network data structure */
38/* FIXME: this must go! */
39extern struct gsm_network *bsc_gsmnet;
Harald Welte44f1c272010-04-30 19:54:29 +020040struct gprs_ns_inst *bssgp_nsi;
Harald Welte9b455bf2010-03-14 15:45:01 +080041
42/* Chapter 11.3.9 / Table 11.10: Cause coding */
43static const char *bssgp_cause_strings[] = {
44 [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload",
45 [BSSGP_CAUSE_EQUIP_FAIL] = "Equipment Failure",
46 [BSSGP_CAUSE_TRASIT_NET_FAIL] = "Transit netowkr service failure",
47 [BSSGP_CAUSE_CAPA_GREATER_0KPBS]= "Transmission capacity modified",
48 [BSSGP_CAUSE_UNKNOWN_MS] = "Unknown MS",
49 [BSSGP_CAUSE_UNKNOWN_BVCI] = "Unknown BVCI",
50 [BSSGP_CAUSE_CELL_TRAF_CONG] = "Cell traffic congestion",
51 [BSSGP_CAUSE_SGSN_CONG] = "SGSN congestion",
52 [BSSGP_CAUSE_OML_INTERV] = "O&M intervention",
53 [BSSGP_CAUSE_BVCI_BLOCKED] = "BVCI blocked",
54 [BSSGP_CAUSE_PFC_CREATE_FAIL] = "PFC create failure",
55 [BSSGP_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU",
56 [BSSGP_CAUSE_INV_MAND_INF] = "Invalid mandatory information",
57 [BSSGP_CAUSE_MISSING_MAND_IE] = "Missing mandatory IE",
58 [BSSGP_CAUSE_MISSING_COND_IE] = "Missing conditional IE",
59 [BSSGP_CAUSE_UNEXP_COND_IE] = "Unexpected conditional IE",
60 [BSSGP_CAUSE_COND_IE_ERR] = "Conditional IE error",
61 [BSSGP_CAUSE_PDU_INCOMP_STATE] = "PDU incompatible with protocol state",
62 [BSSGP_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error - unspecified",
63 [BSSGP_CAUSE_PDU_INCOMP_FEAT] = "PDU not compatible with feature set",
64};
65
66static const char *bssgp_cause_str(enum gprs_bssgp_cause cause)
67{
68 if (cause >= ARRAY_SIZE(bssgp_cause_strings))
69 return "undefined";
70
71 if (bssgp_cause_strings[cause])
72 return bssgp_cause_strings[cause];
73
74 return "undefined";
75}
76
Harald Welte9b455bf2010-03-14 15:45:01 +080077static inline struct msgb *bssgp_msgb_alloc(void)
78{
79 return msgb_alloc_headroom(4096, 128, "BSSGP");
80}
81
82/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */
Harald Welte44f1c272010-04-30 19:54:29 +020083static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t nsei,
84 u_int16_t bvci, u_int16_t ns_bvci)
Harald Welte9b455bf2010-03-14 15:45:01 +080085{
86 struct msgb *msg = bssgp_msgb_alloc();
87 struct bssgp_normal_hdr *bgph =
88 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
89 u_int16_t _bvci;
90
Harald Welte44f1c272010-04-30 19:54:29 +020091 msgb_nsei(msg) = nsei;
92 msgb_bvci(msg) = ns_bvci;
93
Harald Welte9b455bf2010-03-14 15:45:01 +080094 bgph->pdu_type = pdu_type;
95 _bvci = htons(bvci);
96 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci);
97
Harald Welte44f1c272010-04-30 19:54:29 +020098 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9b455bf2010-03-14 15:45:01 +080099}
100
101/* Chapter 10.4.5: Flow Control BVC ACK */
Harald Welte44f1c272010-04-30 19:54:29 +0200102static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci)
Harald Welte9b455bf2010-03-14 15:45:01 +0800103{
104 struct msgb *msg = bssgp_msgb_alloc();
105 struct bssgp_normal_hdr *bgph =
106 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
107
Harald Welte44f1c272010-04-30 19:54:29 +0200108 msgb_nsei(msg) = nsei;
109 msgb_bvci(msg) = ns_bvci;
110
Harald Welte9b455bf2010-03-14 15:45:01 +0800111 bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;
112 msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
113
Harald Welte44f1c272010-04-30 19:54:29 +0200114 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9b455bf2010-03-14 15:45:01 +0800115}
116
117/* Chapter 10.4.14: Status */
Harald Welte9f75c352010-04-30 20:26:32 +0200118int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg)
Harald Welte9b455bf2010-03-14 15:45:01 +0800119{
120 struct msgb *msg = bssgp_msgb_alloc();
121 struct bssgp_normal_hdr *bgph =
122 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
123
124 DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause));
Harald Welte44f1c272010-04-30 19:54:29 +0200125 msgb_nsei(msg) = msgb_nsei(orig_msg);
126 msgb_bvci(msg) = 0;
Harald Welte9b455bf2010-03-14 15:45:01 +0800127
128 bgph->pdu_type = BSSGP_PDUT_STATUS;
129 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
130 if (bvci) {
131 u_int16_t _bvci = htons(*bvci);
132 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci);
133 }
134 if (orig_msg)
135 msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR,
136 msgb_l3len(orig_msg), orig_msg->l3h);
137
Harald Welte44f1c272010-04-30 19:54:29 +0200138 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9b455bf2010-03-14 15:45:01 +0800139}
140
Harald Welte288be162010-05-01 16:48:27 +0200141/* Chapter 8.4 BVC-Reset Procedure */
142static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp,
143 uint16_t ns_bvci)
144{
145 uint8_t bvci;
146 int rc;
147
148 bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
149 DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci,
150 bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE)));
151
152 /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS
153 * informs us about its RAC + Cell ID, so we can create a mapping */
154
155 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
156 msgb_nsei(msg), bvci, ns_bvci);
157 return 0;
158}
159
Harald Welte9b455bf2010-03-14 15:45:01 +0800160/* Uplink unit-data */
161static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci)
162{
163 struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h;
164 struct gsm_bts *bts;
165 int data_len = msgb_l3len(msg) - sizeof(*budh);
166 struct tlv_parsed tp;
167 int rc;
168
169 DEBUGP(DGPRS, "BSSGP UL-UD\n");
170
Harald Welte943c5bc2010-04-30 16:33:12 +0200171 msgb_tlli(msg) = ntohl(budh->tlli);
Harald Welte9b455bf2010-03-14 15:45:01 +0800172 rc = bssgp_tlv_parse(&tp, budh->data, data_len);
173
174 /* Cell ID and LLC_PDU are the only mandatory IE */
175 if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) ||
176 !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU))
177 return -EIO;
178
Harald Welte288be162010-05-01 16:48:27 +0200179#if 0 //FIXME
Harald Welte9b455bf2010-03-14 15:45:01 +0800180 /* Determine the BTS based on the Cell ID */
181 bts = gsm48_bts_by_ra_id(bsc_gsmnet,
182 TLVP_VAL(&tp, BSSGP_IE_CELL_ID),
183 TLVP_LEN(&tp, BSSGP_IE_CELL_ID));
Harald Welte288be162010-05-01 16:48:27 +0200184#endif
Harald Welte9b455bf2010-03-14 15:45:01 +0800185 if (bts)
186 msg->trx = bts->c0;
187
Harald Welte943c5bc2010-04-30 16:33:12 +0200188 msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU);
Harald Welte9b455bf2010-03-14 15:45:01 +0800189
190 return gprs_llc_rcvmsg(msg, &tp);
191}
192
193static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci)
194{
195 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
196 int data_len = msgb_l3len(msg) - sizeof(*bgph);
197 struct tlv_parsed tp;
198 int rc;
199
200 DEBUGP(DGPRS, "BSSGP SUSPEND\n");
201
202 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
203 if (rc < 0)
204 return rc;
205
206 if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
207 !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
208 return -EIO;
209
210 /* SEND SUSPEND_ACK or SUSPEND_NACK */
211 /* FIXME */
212}
213
214static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci)
215{
216 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
217 int data_len = msgb_l3len(msg) - sizeof(*bgph);
218 struct tlv_parsed tp;
219 int rc;
220
221 DEBUGP(DGPRS, "BSSGP RESUME\n");
222
223 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
224 if (rc < 0)
225 return rc;
226
227 if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
228 !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) ||
229 !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR))
230 return -EIO;
231
232 /* SEND RESUME_ACK or RESUME_NACK */
233 /* FIXME */
234}
235
236static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp,
237 u_int16_t ns_bvci)
238{
239
240 DEBUGP(DGPRS, "BSSGP FC BVC\n");
241
242 if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) ||
243 !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) ||
244 !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) ||
245 !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) ||
246 !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS))
247 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
248
249 /* Send FLOW_CONTROL_BVC_ACK */
Harald Welte44f1c272010-04-30 19:54:29 +0200250 return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG),
251 ns_bvci);
Harald Welte9b455bf2010-03-14 15:45:01 +0800252}
Harald Welte288be162010-05-01 16:48:27 +0200253
Harald Welte9b455bf2010-03-14 15:45:01 +0800254/* We expect msg->l3h to point to the BSSGP header */
255int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci)
256{
257 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
258 struct tlv_parsed tp;
259 u_int8_t pdu_type = bgph->pdu_type;
260 int data_len = msgb_l3len(msg) - sizeof(*bgph);
261 u_int16_t bvci;
262 int rc = 0;
263
264 if (pdu_type != BSSGP_PDUT_UL_UNITDATA &&
265 pdu_type != BSSGP_PDUT_DL_UNITDATA)
266 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
267
268 switch (pdu_type) {
269 case BSSGP_PDUT_UL_UNITDATA:
270 /* some LLC data from the MS */
271 rc = bssgp_rx_ul_ud(msg, ns_bvci);
272 break;
273 case BSSGP_PDUT_RA_CAPABILITY:
274 /* BSS requests RA capability or IMSI */
275 DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n");
276 /* FIXME: send RA_CAPA_UPDATE_ACK */
277 break;
278 case BSSGP_PDUT_RADIO_STATUS:
279 DEBUGP(DGPRS, "BSSGP RADIO STATUS\n");
280 /* BSS informs us of some exception */
281 break;
282 case BSSGP_PDUT_SUSPEND:
283 /* MS wants to suspend */
284 rc = bssgp_rx_suspend(msg, ns_bvci);
285 break;
286 case BSSGP_PDUT_RESUME:
287 /* MS wants to resume */
288 rc = bssgp_rx_resume(msg, ns_bvci);
289 break;
290 case BSSGP_PDUT_FLUSH_LL:
291 /* BSS informs MS has moved to one cell to other cell */
292 DEBUGP(DGPRS, "BSSGP FLUSH LL\n");
293 /* Send FLUSH_LL_ACK */
294 break;
295 case BSSGP_PDUT_LLC_DISCARD:
296 /* BSS informs that some LLC PDU's have been discarded */
297 DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n");
298 break;
299 case BSSGP_PDUT_FLOW_CONTROL_BVC:
300 /* BSS informs us of available bandwidth in Gb interface */
301 rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci);
302 break;
303 case BSSGP_PDUT_FLOW_CONTROL_MS:
304 /* BSS informs us of available bandwidth to one MS */
305 DEBUGP(DGPRS, "BSSGP FC MS\n");
306 /* Send FLOW_CONTROL_MS_ACK */
307 break;
308 case BSSGP_PDUT_BVC_BLOCK:
309 /* BSS tells us that BVC shall be blocked */
310 DEBUGP(DGPRS, "BSSGP BVC BLOCK ");
311 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
312 !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
313 goto err_mand_ie;
314 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
315 DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci,
316 bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
317 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK,
Harald Welte44f1c272010-04-30 19:54:29 +0200318 msgb_nsei(msg), bvci, ns_bvci);
Harald Welte9b455bf2010-03-14 15:45:01 +0800319 break;
320 case BSSGP_PDUT_BVC_UNBLOCK:
321 /* BSS tells us that BVC shall be unblocked */
322 DEBUGP(DGPRS, "BSSGP BVC UNBLOCK ");
323 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
324 goto err_mand_ie;
325 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
326 DEBUGPC(DGPRS, "BVCI=%u\n", bvci);
327 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK,
Harald Welte44f1c272010-04-30 19:54:29 +0200328 msgb_nsei(msg), bvci, ns_bvci);
Harald Welte9b455bf2010-03-14 15:45:01 +0800329 break;
330 case BSSGP_PDUT_BVC_RESET:
331 /* BSS tells us that BVC init is required */
332 DEBUGP(DGPRS, "BSSGP BVC RESET ");
333 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
334 !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
335 goto err_mand_ie;
Harald Welte288be162010-05-01 16:48:27 +0200336 rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci);
Harald Welte9b455bf2010-03-14 15:45:01 +0800337 break;
338 case BSSGP_PDUT_STATUS:
339 /* Some exception has occurred */
340 case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
341 case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
342 case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
343 case BSSGP_PDUT_MODIFY_BSS_PFC:
344 case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
345 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n",
346 pdu_type);
347 break;
348 /* those only exist in the SGSN -> BSS direction */
349 case BSSGP_PDUT_DL_UNITDATA:
350 case BSSGP_PDUT_PAGING_PS:
351 case BSSGP_PDUT_PAGING_CS:
352 case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
353 case BSSGP_PDUT_SUSPEND_ACK:
354 case BSSGP_PDUT_SUSPEND_NACK:
355 case BSSGP_PDUT_RESUME_ACK:
356 case BSSGP_PDUT_RESUME_NACK:
357 case BSSGP_PDUT_FLUSH_LL_ACK:
358 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
359 case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
360 case BSSGP_PDUT_BVC_BLOCK_ACK:
361 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
362 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
363 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n",
364 pdu_type);
365 rc = -EINVAL;
366 break;
367 default:
368 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type);
369 break;
370 }
371
372 return rc;
373err_mand_ie:
374 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
375}
376
377int gprs_bssgp_tx_dl_ud(struct msgb *msg)
378{
379 struct gsm_bts *bts;
380 struct bssgp_ud_hdr *budh;
381 u_int8_t llc_pdu_tlv_hdr_len = 2;
382 u_int8_t *llc_pdu_tlv, *qos_profile;
383 u_int16_t pdu_lifetime = 1000; /* centi-seconds */
384 u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 };
385 u_int16_t msg_len = msg->len;
386
387 if (!msg->trx) {
388 DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n");
389 return -EINVAL;
390 }
391
392 bts = msg->trx->bts;
393
394 if (msg->len > TVLV_MAX_ONEBYTE)
395 llc_pdu_tlv_hdr_len += 1;
396
397 /* prepend the tag and length of the LLC-PDU TLV */
398 llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len);
399 llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU;
400 if (llc_pdu_tlv_hdr_len > 2) {
401 llc_pdu_tlv[1] = msg_len >> 8;
402 llc_pdu_tlv[2] = msg_len & 0xff;
403 } else {
404 llc_pdu_tlv[1] = msg_len & 0x3f;
405 llc_pdu_tlv[1] |= 0x80;
406 }
407
408 /* FIXME: optional elements */
409
410 /* prepend the pdu lifetime */
411 pdu_lifetime = htons(pdu_lifetime);
412 msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime);
413
414 /* prepend the QoS profile, TLLI and pdu type */
415 budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh));
416 memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default));
Harald Welte943c5bc2010-04-30 16:33:12 +0200417 budh->tlli = htonl(msgb_tlli(msg));
Harald Welte9b455bf2010-03-14 15:45:01 +0800418 budh->pdu_type = BSSGP_PDUT_DL_UNITDATA;
419
Harald Welte44f1c272010-04-30 19:54:29 +0200420 msgb_nsei(msg) = bts->gprs.nse.nsei;
421 msgb_bvci(msg) = bts->gprs.cell.bvci;
422
423 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9b455bf2010-03-14 15:45:01 +0800424}