blob: de57d25dfbf5ad4eaccfeaa7b56a0648efa0ef9e [file] [log] [blame]
Harald Welte9ba50052010-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;
40
41/* Chapter 11.3.9 / Table 11.10: Cause coding */
42static const char *bssgp_cause_strings[] = {
43 [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload",
44 [BSSGP_CAUSE_EQUIP_FAIL] = "Equipment Failure",
45 [BSSGP_CAUSE_TRASIT_NET_FAIL] = "Transit netowkr service failure",
46 [BSSGP_CAUSE_CAPA_GREATER_0KPBS]= "Transmission capacity modified",
47 [BSSGP_CAUSE_UNKNOWN_MS] = "Unknown MS",
48 [BSSGP_CAUSE_UNKNOWN_BVCI] = "Unknown BVCI",
49 [BSSGP_CAUSE_CELL_TRAF_CONG] = "Cell traffic congestion",
50 [BSSGP_CAUSE_SGSN_CONG] = "SGSN congestion",
51 [BSSGP_CAUSE_OML_INTERV] = "O&M intervention",
52 [BSSGP_CAUSE_BVCI_BLOCKED] = "BVCI blocked",
53 [BSSGP_CAUSE_PFC_CREATE_FAIL] = "PFC create failure",
54 [BSSGP_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU",
55 [BSSGP_CAUSE_INV_MAND_INF] = "Invalid mandatory information",
56 [BSSGP_CAUSE_MISSING_MAND_IE] = "Missing mandatory IE",
57 [BSSGP_CAUSE_MISSING_COND_IE] = "Missing conditional IE",
58 [BSSGP_CAUSE_UNEXP_COND_IE] = "Unexpected conditional IE",
59 [BSSGP_CAUSE_COND_IE_ERR] = "Conditional IE error",
60 [BSSGP_CAUSE_PDU_INCOMP_STATE] = "PDU incompatible with protocol state",
61 [BSSGP_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error - unspecified",
62 [BSSGP_CAUSE_PDU_INCOMP_FEAT] = "PDU not compatible with feature set",
63};
64
65static const char *bssgp_cause_str(enum gprs_bssgp_cause cause)
66{
67 if (cause >= ARRAY_SIZE(bssgp_cause_strings))
68 return "undefined";
69
70 if (bssgp_cause_strings[cause])
71 return bssgp_cause_strings[cause];
72
73 return "undefined";
74}
75
76static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len)
77{
78 return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
79}
80
81static inline struct msgb *bssgp_msgb_alloc(void)
82{
83 return msgb_alloc_headroom(4096, 128, "BSSGP");
84}
85
86/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */
87static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t bvci, u_int16_t ns_bvci)
88{
89 struct msgb *msg = bssgp_msgb_alloc();
90 struct bssgp_normal_hdr *bgph =
91 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
92 u_int16_t _bvci;
93
94 bgph->pdu_type = pdu_type;
95 _bvci = htons(bvci);
96 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci);
97
98 return gprs_ns_sendmsg(NULL, ns_bvci, msg);
99}
100
101/* Chapter 10.4.5: Flow Control BVC ACK */
102static int bssgp_tx_fc_bvc_ack(u_int8_t tag, u_int16_t ns_bvci)
103{
104 struct msgb *msg = bssgp_msgb_alloc();
105 struct bssgp_normal_hdr *bgph =
106 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
107
108 bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;
109 msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
110
111 return gprs_ns_sendmsg(NULL, ns_bvci, msg);
112}
113
114/* Chapter 10.4.14: Status */
115static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg)
116{
117 struct msgb *msg = bssgp_msgb_alloc();
118 struct bssgp_normal_hdr *bgph =
119 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
120
121 DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause));
122
123 bgph->pdu_type = BSSGP_PDUT_STATUS;
124 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
125 if (bvci) {
126 u_int16_t _bvci = htons(*bvci);
127 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci);
128 }
129 if (orig_msg)
130 msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR,
131 msgb_l3len(orig_msg), orig_msg->l3h);
132
133 return gprs_ns_sendmsg(NULL, 0, msg);
134}
135
136/* Uplink unit-data */
137static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci)
138{
139 struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h;
140 struct gsm_bts *bts;
141 int data_len = msgb_l3len(msg) - sizeof(*budh);
142 struct tlv_parsed tp;
143 int rc;
144
145 DEBUGP(DGPRS, "BSSGP UL-UD\n");
146
147 msg->tlli = ntohl(budh->tlli);
148 rc = bssgp_tlv_parse(&tp, budh->data, data_len);
149
150 /* Cell ID and LLC_PDU are the only mandatory IE */
151 if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) ||
152 !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU))
153 return -EIO;
154
155 /* Determine the BTS based on the Cell ID */
156 bts = gsm48_bts_by_ra_id(bsc_gsmnet,
157 TLVP_VAL(&tp, BSSGP_IE_CELL_ID),
158 TLVP_LEN(&tp, BSSGP_IE_CELL_ID));
159 if (bts)
160 msg->trx = bts->c0;
161
162 msg->llch = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU);
163
164 return gprs_llc_rcvmsg(msg, &tp);
165}
166
167static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci)
168{
169 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
170 int data_len = msgb_l3len(msg) - sizeof(*bgph);
171 struct tlv_parsed tp;
172 int rc;
173
174 DEBUGP(DGPRS, "BSSGP SUSPEND\n");
175
176 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
177 if (rc < 0)
178 return rc;
179
180 if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
181 !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
182 return -EIO;
183
184 /* SEND SUSPEND_ACK or SUSPEND_NACK */
185 /* FIXME */
186}
187
188static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci)
189{
190 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
191 int data_len = msgb_l3len(msg) - sizeof(*bgph);
192 struct tlv_parsed tp;
193 int rc;
194
195 DEBUGP(DGPRS, "BSSGP RESUME\n");
196
197 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
198 if (rc < 0)
199 return rc;
200
201 if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
202 !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) ||
203 !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR))
204 return -EIO;
205
206 /* SEND RESUME_ACK or RESUME_NACK */
207 /* FIXME */
208}
209
210static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp,
211 u_int16_t ns_bvci)
212{
213
214 DEBUGP(DGPRS, "BSSGP FC BVC\n");
215
216 if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) ||
217 !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) ||
218 !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) ||
219 !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) ||
220 !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS))
221 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
222
223 /* Send FLOW_CONTROL_BVC_ACK */
224 return bssgp_tx_fc_bvc_ack(*TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci);
225}
226/* We expect msg->l3h to point to the BSSGP header */
227int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci)
228{
229 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
230 struct tlv_parsed tp;
231 u_int8_t pdu_type = bgph->pdu_type;
232 int data_len = msgb_l3len(msg) - sizeof(*bgph);
233 u_int16_t bvci;
234 int rc = 0;
235
236 if (pdu_type != BSSGP_PDUT_UL_UNITDATA &&
237 pdu_type != BSSGP_PDUT_DL_UNITDATA)
238 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
239
240 switch (pdu_type) {
241 case BSSGP_PDUT_UL_UNITDATA:
242 /* some LLC data from the MS */
243 rc = bssgp_rx_ul_ud(msg, ns_bvci);
244 break;
245 case BSSGP_PDUT_RA_CAPABILITY:
246 /* BSS requests RA capability or IMSI */
247 DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n");
248 /* FIXME: send RA_CAPA_UPDATE_ACK */
249 break;
250 case BSSGP_PDUT_RADIO_STATUS:
251 DEBUGP(DGPRS, "BSSGP RADIO STATUS\n");
252 /* BSS informs us of some exception */
253 break;
254 case BSSGP_PDUT_SUSPEND:
255 /* MS wants to suspend */
256 rc = bssgp_rx_suspend(msg, ns_bvci);
257 break;
258 case BSSGP_PDUT_RESUME:
259 /* MS wants to resume */
260 rc = bssgp_rx_resume(msg, ns_bvci);
261 break;
262 case BSSGP_PDUT_FLUSH_LL:
263 /* BSS informs MS has moved to one cell to other cell */
264 DEBUGP(DGPRS, "BSSGP FLUSH LL\n");
265 /* Send FLUSH_LL_ACK */
266 break;
267 case BSSGP_PDUT_LLC_DISCARD:
268 /* BSS informs that some LLC PDU's have been discarded */
269 DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n");
270 break;
271 case BSSGP_PDUT_FLOW_CONTROL_BVC:
272 /* BSS informs us of available bandwidth in Gb interface */
273 rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci);
274 break;
275 case BSSGP_PDUT_FLOW_CONTROL_MS:
276 /* BSS informs us of available bandwidth to one MS */
277 DEBUGP(DGPRS, "BSSGP FC MS\n");
278 /* Send FLOW_CONTROL_MS_ACK */
279 break;
280 case BSSGP_PDUT_BVC_BLOCK:
281 /* BSS tells us that BVC shall be blocked */
282 DEBUGP(DGPRS, "BSSGP BVC BLOCK ");
283 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
284 !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
285 goto err_mand_ie;
286 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
287 DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci,
288 bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
289 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK,
290 bvci, ns_bvci);
291 break;
292 case BSSGP_PDUT_BVC_UNBLOCK:
293 /* BSS tells us that BVC shall be unblocked */
294 DEBUGP(DGPRS, "BSSGP BVC UNBLOCK ");
295 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
296 goto err_mand_ie;
297 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
298 DEBUGPC(DGPRS, "BVCI=%u\n", bvci);
299 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK,
300 bvci, ns_bvci);
301 break;
302 case BSSGP_PDUT_BVC_RESET:
303 /* BSS tells us that BVC init is required */
304 DEBUGP(DGPRS, "BSSGP BVC RESET ");
305 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
306 !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
307 goto err_mand_ie;
308 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
309 DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci,
310 bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
311 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
312 bvci, ns_bvci);
313 break;
314 case BSSGP_PDUT_STATUS:
315 /* Some exception has occurred */
316 case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
317 case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
318 case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
319 case BSSGP_PDUT_MODIFY_BSS_PFC:
320 case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
321 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n",
322 pdu_type);
323 break;
324 /* those only exist in the SGSN -> BSS direction */
325 case BSSGP_PDUT_DL_UNITDATA:
326 case BSSGP_PDUT_PAGING_PS:
327 case BSSGP_PDUT_PAGING_CS:
328 case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
329 case BSSGP_PDUT_SUSPEND_ACK:
330 case BSSGP_PDUT_SUSPEND_NACK:
331 case BSSGP_PDUT_RESUME_ACK:
332 case BSSGP_PDUT_RESUME_NACK:
333 case BSSGP_PDUT_FLUSH_LL_ACK:
334 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
335 case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
336 case BSSGP_PDUT_BVC_BLOCK_ACK:
337 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
338 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
339 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n",
340 pdu_type);
341 rc = -EINVAL;
342 break;
343 default:
344 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type);
345 break;
346 }
347
348 return rc;
349err_mand_ie:
350 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
351}
352
353int gprs_bssgp_tx_dl_ud(struct msgb *msg)
354{
355 struct gsm_bts *bts;
356 struct bssgp_ud_hdr *budh;
357 u_int8_t llc_pdu_tlv_hdr_len = 2;
358 u_int8_t *llc_pdu_tlv, *qos_profile;
359 u_int16_t pdu_lifetime = 1000; /* centi-seconds */
360 u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 };
361 u_int16_t msg_len = msg->len;
362
363 if (!msg->trx) {
364 DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n");
365 return -EINVAL;
366 }
367
368 bts = msg->trx->bts;
369
370 if (msg->len > TVLV_MAX_ONEBYTE)
371 llc_pdu_tlv_hdr_len += 1;
372
373 /* prepend the tag and length of the LLC-PDU TLV */
374 llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len);
375 llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU;
376 if (llc_pdu_tlv_hdr_len > 2) {
377 llc_pdu_tlv[1] = msg_len >> 8;
378 llc_pdu_tlv[2] = msg_len & 0xff;
379 } else {
380 llc_pdu_tlv[1] = msg_len & 0x3f;
381 llc_pdu_tlv[1] |= 0x80;
382 }
383
384 /* FIXME: optional elements */
385
386 /* prepend the pdu lifetime */
387 pdu_lifetime = htons(pdu_lifetime);
388 msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime);
389
390 /* prepend the QoS profile, TLLI and pdu type */
391 budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh));
392 memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default));
393 budh->tlli = htonl(msg->tlli);
394 budh->pdu_type = BSSGP_PDUT_DL_UNITDATA;
395
396 return gprs_ns_sendmsg(NULL, bts->gprs.cell.bvci, msg);
397}