Use the app_info->name instead of the hostname
[osmocom-bb.git] / src / gsm0808.c
1 /* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
2  * (C) 2009,2010 by On-Waves
3  * All Rights Reserved
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (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 along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  */
20
21 #include <osmocore/gsm0808.h>
22 #include <osmocore/protocol/gsm_08_08.h>
23 #include <osmocore/gsm48.h>
24
25 #include <arpa/inet.h>
26
27 #define BSSMAP_MSG_SIZE 512
28 #define BSSMAP_MSG_HEADROOM 128
29
30 static void put_data_16(uint8_t *data, const uint16_t val)
31 {
32         memcpy(data, &val, sizeof(val));
33 }
34
35 struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, uint16_t _ci)
36 {
37         uint8_t *data;
38         uint8_t *ci;
39         struct msgb* msg;
40         struct gsm48_loc_area_id *lai;
41
42         msg  = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
43                                    "bssmap cmpl l3");
44         if (!msg)
45                 return NULL;
46
47         /* create the bssmap header */
48         msg->l3h = msgb_put(msg, 2);
49         msg->l3h[0] = 0x0;
50
51         /* create layer 3 header */
52         data = msgb_put(msg, 1);
53         data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3;
54
55         /* create the cell header */
56         data = msgb_put(msg, 3);
57         data[0] = GSM0808_IE_CELL_IDENTIFIER;
58         data[1] = 1 + sizeof(*lai) + 2;
59         data[2] = CELL_IDENT_WHOLE_GLOBAL;
60
61         lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
62         gsm48_generate_lai(lai, cc, nc, lac);
63
64         ci = msgb_put(msg, 2);
65         put_data_16(ci, htons(_ci));
66
67         /* copy the layer3 data */
68         data = msgb_put(msg, msgb_l3len(msg_l3) + 2);
69         data[0] = GSM0808_IE_LAYER_3_INFORMATION;
70         data[1] = msgb_l3len(msg_l3);
71         memcpy(&data[2], msg_l3->l3h, data[1]);
72
73         /* update the size */
74         msg->l3h[1] = msgb_l3len(msg) - 2;
75
76         return msg;
77 }
78
79 struct msgb *gsm0808_create_reset(void)
80 {
81         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
82                                                "bssmap: reset");
83         if (!msg)
84                 return NULL;
85
86         msg->l3h = msgb_put(msg, 6);
87         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
88         msg->l3h[1] = 0x04;
89         msg->l3h[2] = 0x30;
90         msg->l3h[3] = 0x04;
91         msg->l3h[4] = 0x01;
92         msg->l3h[5] = 0x20;
93         return msg;
94 }
95
96 struct msgb *gsm0808_create_clear_complete(void)
97 {
98         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
99                                                "bssmap: clear complete");
100         if (!msg)
101                 return NULL;
102
103         msg->l3h = msgb_put(msg, 3);
104         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
105         msg->l3h[1] = 1;
106         msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
107
108         return msg;
109 }
110
111 struct msgb *gsm0808_create_clear_command(uint8_t reason)
112 {
113         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
114                                                "bssmap: clear command");
115         if (!msg)
116                 return NULL;
117
118         msg->l3h = msgb_tv_put(msg, BSSAP_MSG_BSS_MANAGEMENT, 4);
119         msgb_v_put(msg, BSS_MAP_MSG_CLEAR_CMD);
120         msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &reason);
121         return msg;
122 }
123
124 struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id)
125 {
126         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
127                                                "cipher-complete");
128         if (!msg)
129                 return NULL;
130
131         /* send response with BSS override for A5/1... cheating */
132         msg->l3h = msgb_put(msg, 3);
133         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
134         msg->l3h[1] = 0xff;
135         msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE;
136
137         /* include layer3 in case we have at least two octets */
138         if (layer3 && msgb_l3len(layer3) > 2) {
139                 msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2);
140                 msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS;
141                 msg->l4h[1] = msgb_l3len(layer3);
142                 memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3));
143         }
144
145         /* and the optional BSS message */
146         msg->l4h = msgb_put(msg, 2);
147         msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
148         msg->l4h[1] = alg_id;
149
150         /* update the size */
151         msg->l3h[1] = msgb_l3len(msg) - 2;
152         return msg;
153 }
154
155 struct msgb *gsm0808_create_cipher_reject(uint8_t cause)
156 {
157         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
158                                                "bssmap: clear complete");
159         if (!msg)
160                 return NULL;
161
162         msg->l3h = msgb_put(msg, 3);
163         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
164         msg->l3h[1] = 2;
165         msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
166         msg->l3h[3] = cause;
167
168         return msg;
169 }
170
171 struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length)
172 {
173         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
174                                                "classmark-update");
175         if (!msg)
176                 return NULL;
177
178         msg->l3h = msgb_put(msg, 3);
179         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
180         msg->l3h[1] = 0xff;
181         msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
182
183         msg->l4h = msgb_put(msg, length);
184         memcpy(msg->l4h, classmark_data, length);
185
186         /* update the size */
187         msg->l3h[1] = msgb_l3len(msg) - 2;
188         return msg;
189 }
190
191 struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
192 {
193         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
194                                                "bssmap: sapi 'n' reject");
195         if (!msg)
196                 return NULL;
197
198         msg->l3h = msgb_put(msg, 5);
199         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
200         msg->l3h[1] = 3;
201         msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
202         msg->l3h[3] = link_id;
203         msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
204
205         return msg;
206 }
207
208 struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause,
209                                                  uint8_t chosen_channel, uint8_t encr_alg_id,
210                                                  uint8_t speech_mode)
211 {
212         uint8_t *data;
213
214         struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
215         if (!msg)
216                 return NULL;
217
218         msg->l3h = msgb_put(msg, 3);
219         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
220         msg->l3h[1] = 0xff;
221         msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
222
223         /* write 3.2.2.22 */
224         data = msgb_put(msg, 2);
225         data[0] = GSM0808_IE_RR_CAUSE;
226         data[1] = rr_cause;
227
228         /* write cirtcuit identity  code 3.2.2.2 */
229         /* write cell identifier 3.2.2.17 */
230         /* write chosen channel 3.2.2.33 when BTS picked it */
231         data = msgb_put(msg, 2);
232         data[0] = GSM0808_IE_CHOSEN_CHANNEL;
233         data[1] = chosen_channel;
234
235         /* write chosen encryption algorithm 3.2.2.44 */
236         data = msgb_put(msg, 2);
237         data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
238         data[1] = encr_alg_id;
239
240         /* write circuit pool 3.2.2.45 */
241         /* write speech version chosen: 3.2.2.51 when BTS picked it */
242         if (speech_mode != 0) {
243                 data = msgb_put(msg, 2);
244                 data[0] = GSM0808_IE_SPEECH_VERSION;
245                 data[1] = speech_mode;
246         }
247
248         /* write LSA identifier 3.2.2.15 */
249
250
251         /* update the size */
252         msg->l3h[1] = msgb_l3len(msg) - 2;
253         return msg;
254 }
255
256 struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
257 {
258         uint8_t *data;
259         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
260                                                "bssmap: ass fail");
261         if (!msg)
262                 return NULL;
263
264         msg->l3h = msgb_put(msg, 6);
265         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
266         msg->l3h[1] = 0xff;
267         msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
268         msg->l3h[3] = GSM0808_IE_CAUSE;
269         msg->l3h[4] = 1;
270         msg->l3h[5] = cause;
271
272         /* RR cause 3.2.2.22 */
273         if (rr_cause) {
274                 data = msgb_put(msg, 2);
275                 data[0] = GSM0808_IE_RR_CAUSE;
276                 data[1] = *rr_cause;
277         }
278
279         /* Circuit pool 3.22.45 */
280         /* Circuit pool list 3.2.2.46 */
281
282         /* update the size */
283         msg->l3h[1] = msgb_l3len(msg) - 2;
284         return msg;
285 }
286
287 struct msgb *gsm0808_create_clear_rqst(uint8_t cause)
288 {
289         struct msgb *msg;
290
291         msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
292                                   "bssmap: clear rqst");
293         if (!msg)
294                 return NULL;
295
296         msg->l3h = msgb_put(msg, 2 + 4);
297         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
298         msg->l3h[1] = 4;
299
300         msg->l3h[2] = BSS_MAP_MSG_CLEAR_RQST;
301         msg->l3h[3] = GSM0808_IE_CAUSE;
302         msg->l3h[4] = 1;
303         msg->l3h[5] = cause;
304         return msg;
305 }
306
307 void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id)
308 {
309         uint8_t *hh = msgb_push(msg, 3);
310         hh[0] = BSSAP_MSG_DTAP;
311         hh[1] = link_id;
312         hh[2] = msg->len - 3;
313 }
314
315 struct msgb *gsm0808_create_dtap(struct msgb *msg_l3, uint8_t link_id)
316 {
317         struct dtap_header *header;
318         uint8_t *data;
319         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
320                                                "dtap");
321         if (!msg)
322                 return NULL;
323
324         /* DTAP header */
325         msg->l3h = msgb_put(msg, sizeof(*header));
326         header = (struct dtap_header *) &msg->l3h[0];
327         header->type = BSSAP_MSG_DTAP;
328         header->link_id = link_id;
329         header->length = msgb_l3len(msg_l3);
330
331         /* Payload */
332         data = msgb_put(msg, header->length);
333         memcpy(data, msg_l3->l3h, header->length);
334
335         return msg;
336 }
337
338 static const struct tlv_definition bss_att_tlvdef = {
339         .def = {
340                 [GSM0808_IE_IMSI]                   = { TLV_TYPE_TLV },
341                 [GSM0808_IE_TMSI]                   = { TLV_TYPE_TLV },
342                 [GSM0808_IE_CELL_IDENTIFIER_LIST]   = { TLV_TYPE_TLV },
343                 [GSM0808_IE_CHANNEL_NEEDED]         = { TLV_TYPE_TV },
344                 [GSM0808_IE_EMLPP_PRIORITY]         = { TLV_TYPE_TV },
345                 [GSM0808_IE_CHANNEL_TYPE]           = { TLV_TYPE_TLV },
346                 [GSM0808_IE_PRIORITY]               = { TLV_TYPE_TLV },
347                 [GSM0808_IE_CIRCUIT_IDENTITY_CODE]  = { TLV_TYPE_FIXED, 2 },
348                 [GSM0808_IE_DOWNLINK_DTX_FLAG]      = { TLV_TYPE_TV },
349                 [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
350                 [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
351                 [GSM0808_IE_GROUP_CALL_REFERENCE]   = { TLV_TYPE_TLV },
352                 [GSM0808_IE_TALKER_FLAG]            = { TLV_TYPE_T },
353                 [GSM0808_IE_CONFIG_EVO_INDI]        = { TLV_TYPE_TV },
354                 [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR]  = { TLV_TYPE_TV },
355                 [GSM0808_IE_SERVICE_HANDOVER]       = { TLV_TYPE_TLV },
356                 [GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
357                 [GSM0808_IE_CIPHER_RESPONSE_MODE]   = { TLV_TYPE_TV },
358                 [GSM0808_IE_CELL_IDENTIFIER]        = { TLV_TYPE_TLV },
359                 [GSM0808_IE_CHOSEN_CHANNEL]         = { TLV_TYPE_TV },
360                 [GSM0808_IE_LAYER_3_INFORMATION]    = { TLV_TYPE_TLV },
361                 [GSM0808_IE_SPEECH_VERSION]         = { TLV_TYPE_TV },
362                 [GSM0808_IE_CHOSEN_ENCR_ALG]        = { TLV_TYPE_TV },
363         },
364 };
365
366 const struct tlv_definition *gsm0808_att_tlvdef()
367 {
368         return &bss_att_tlvdef;
369 }