blob: a2181b124eb8b5984f8008b457494ed2bb1159fd [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
141/* Uplink unit-data */
142static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci)
143{
144 struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h;
145 struct gsm_bts *bts;
146 int data_len = msgb_l3len(msg) - sizeof(*budh);
147 struct tlv_parsed tp;
148 int rc;
149
150 DEBUGP(DGPRS, "BSSGP UL-UD\n");
151
Harald Welte943c5bc2010-04-30 16:33:12 +0200152 msgb_tlli(msg) = ntohl(budh->tlli);
Harald Welte9b455bf2010-03-14 15:45:01 +0800153 rc = bssgp_tlv_parse(&tp, budh->data, data_len);
154
155 /* Cell ID and LLC_PDU are the only mandatory IE */
156 if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) ||
157 !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU))
158 return -EIO;
159
160 /* Determine the BTS based on the Cell ID */
161 bts = gsm48_bts_by_ra_id(bsc_gsmnet,
162 TLVP_VAL(&tp, BSSGP_IE_CELL_ID),
163 TLVP_LEN(&tp, BSSGP_IE_CELL_ID));
164 if (bts)
165 msg->trx = bts->c0;
166
Harald Welte943c5bc2010-04-30 16:33:12 +0200167 msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU);
Harald Welte9b455bf2010-03-14 15:45:01 +0800168
169 return gprs_llc_rcvmsg(msg, &tp);
170}
171
172static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci)
173{
174 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
175 int data_len = msgb_l3len(msg) - sizeof(*bgph);
176 struct tlv_parsed tp;
177 int rc;
178
179 DEBUGP(DGPRS, "BSSGP SUSPEND\n");
180
181 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
182 if (rc < 0)
183 return rc;
184
185 if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
186 !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
187 return -EIO;
188
189 /* SEND SUSPEND_ACK or SUSPEND_NACK */
190 /* FIXME */
191}
192
193static int bssgp_rx_resume(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 RESUME\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 !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR))
209 return -EIO;
210
211 /* SEND RESUME_ACK or RESUME_NACK */
212 /* FIXME */
213}
214
215static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp,
216 u_int16_t ns_bvci)
217{
218
219 DEBUGP(DGPRS, "BSSGP FC BVC\n");
220
221 if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) ||
222 !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) ||
223 !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) ||
224 !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) ||
225 !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS))
226 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
227
228 /* Send FLOW_CONTROL_BVC_ACK */
Harald Welte44f1c272010-04-30 19:54:29 +0200229 return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG),
230 ns_bvci);
Harald Welte9b455bf2010-03-14 15:45:01 +0800231}
232/* We expect msg->l3h to point to the BSSGP header */
233int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci)
234{
235 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
236 struct tlv_parsed tp;
237 u_int8_t pdu_type = bgph->pdu_type;
238 int data_len = msgb_l3len(msg) - sizeof(*bgph);
239 u_int16_t bvci;
240 int rc = 0;
241
242 if (pdu_type != BSSGP_PDUT_UL_UNITDATA &&
243 pdu_type != BSSGP_PDUT_DL_UNITDATA)
244 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
245
246 switch (pdu_type) {
247 case BSSGP_PDUT_UL_UNITDATA:
248 /* some LLC data from the MS */
249 rc = bssgp_rx_ul_ud(msg, ns_bvci);
250 break;
251 case BSSGP_PDUT_RA_CAPABILITY:
252 /* BSS requests RA capability or IMSI */
253 DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n");
254 /* FIXME: send RA_CAPA_UPDATE_ACK */
255 break;
256 case BSSGP_PDUT_RADIO_STATUS:
257 DEBUGP(DGPRS, "BSSGP RADIO STATUS\n");
258 /* BSS informs us of some exception */
259 break;
260 case BSSGP_PDUT_SUSPEND:
261 /* MS wants to suspend */
262 rc = bssgp_rx_suspend(msg, ns_bvci);
263 break;
264 case BSSGP_PDUT_RESUME:
265 /* MS wants to resume */
266 rc = bssgp_rx_resume(msg, ns_bvci);
267 break;
268 case BSSGP_PDUT_FLUSH_LL:
269 /* BSS informs MS has moved to one cell to other cell */
270 DEBUGP(DGPRS, "BSSGP FLUSH LL\n");
271 /* Send FLUSH_LL_ACK */
272 break;
273 case BSSGP_PDUT_LLC_DISCARD:
274 /* BSS informs that some LLC PDU's have been discarded */
275 DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n");
276 break;
277 case BSSGP_PDUT_FLOW_CONTROL_BVC:
278 /* BSS informs us of available bandwidth in Gb interface */
279 rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci);
280 break;
281 case BSSGP_PDUT_FLOW_CONTROL_MS:
282 /* BSS informs us of available bandwidth to one MS */
283 DEBUGP(DGPRS, "BSSGP FC MS\n");
284 /* Send FLOW_CONTROL_MS_ACK */
285 break;
286 case BSSGP_PDUT_BVC_BLOCK:
287 /* BSS tells us that BVC shall be blocked */
288 DEBUGP(DGPRS, "BSSGP BVC BLOCK ");
289 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
290 !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
291 goto err_mand_ie;
292 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
293 DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci,
294 bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
295 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK,
Harald Welte44f1c272010-04-30 19:54:29 +0200296 msgb_nsei(msg), bvci, ns_bvci);
Harald Welte9b455bf2010-03-14 15:45:01 +0800297 break;
298 case BSSGP_PDUT_BVC_UNBLOCK:
299 /* BSS tells us that BVC shall be unblocked */
300 DEBUGP(DGPRS, "BSSGP BVC UNBLOCK ");
301 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
302 goto err_mand_ie;
303 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
304 DEBUGPC(DGPRS, "BVCI=%u\n", bvci);
305 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK,
Harald Welte44f1c272010-04-30 19:54:29 +0200306 msgb_nsei(msg), bvci, ns_bvci);
Harald Welte9b455bf2010-03-14 15:45:01 +0800307 break;
308 case BSSGP_PDUT_BVC_RESET:
309 /* BSS tells us that BVC init is required */
310 DEBUGP(DGPRS, "BSSGP BVC RESET ");
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_RESET_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_STATUS:
321 /* Some exception has occurred */
322 case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
323 case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
324 case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
325 case BSSGP_PDUT_MODIFY_BSS_PFC:
326 case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
327 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n",
328 pdu_type);
329 break;
330 /* those only exist in the SGSN -> BSS direction */
331 case BSSGP_PDUT_DL_UNITDATA:
332 case BSSGP_PDUT_PAGING_PS:
333 case BSSGP_PDUT_PAGING_CS:
334 case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
335 case BSSGP_PDUT_SUSPEND_ACK:
336 case BSSGP_PDUT_SUSPEND_NACK:
337 case BSSGP_PDUT_RESUME_ACK:
338 case BSSGP_PDUT_RESUME_NACK:
339 case BSSGP_PDUT_FLUSH_LL_ACK:
340 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
341 case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
342 case BSSGP_PDUT_BVC_BLOCK_ACK:
343 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
344 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
345 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n",
346 pdu_type);
347 rc = -EINVAL;
348 break;
349 default:
350 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type);
351 break;
352 }
353
354 return rc;
355err_mand_ie:
356 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
357}
358
359int gprs_bssgp_tx_dl_ud(struct msgb *msg)
360{
361 struct gsm_bts *bts;
362 struct bssgp_ud_hdr *budh;
363 u_int8_t llc_pdu_tlv_hdr_len = 2;
364 u_int8_t *llc_pdu_tlv, *qos_profile;
365 u_int16_t pdu_lifetime = 1000; /* centi-seconds */
366 u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 };
367 u_int16_t msg_len = msg->len;
368
369 if (!msg->trx) {
370 DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n");
371 return -EINVAL;
372 }
373
374 bts = msg->trx->bts;
375
376 if (msg->len > TVLV_MAX_ONEBYTE)
377 llc_pdu_tlv_hdr_len += 1;
378
379 /* prepend the tag and length of the LLC-PDU TLV */
380 llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len);
381 llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU;
382 if (llc_pdu_tlv_hdr_len > 2) {
383 llc_pdu_tlv[1] = msg_len >> 8;
384 llc_pdu_tlv[2] = msg_len & 0xff;
385 } else {
386 llc_pdu_tlv[1] = msg_len & 0x3f;
387 llc_pdu_tlv[1] |= 0x80;
388 }
389
390 /* FIXME: optional elements */
391
392 /* prepend the pdu lifetime */
393 pdu_lifetime = htons(pdu_lifetime);
394 msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime);
395
396 /* prepend the QoS profile, TLLI and pdu type */
397 budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh));
398 memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default));
Harald Welte943c5bc2010-04-30 16:33:12 +0200399 budh->tlli = htonl(msgb_tlli(msg));
Harald Welte9b455bf2010-03-14 15:45:01 +0800400 budh->pdu_type = BSSGP_PDUT_DL_UNITDATA;
401
Harald Welte44f1c272010-04-30 19:54:29 +0200402 msgb_nsei(msg) = bts->gprs.nse.nsei;
403 msgb_bvci(msg) = bts->gprs.cell.bvci;
404
405 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9b455bf2010-03-14 15:45:01 +0800406}