Merge commit '816e24cb4296d6b7110da4a89661bbac8dc7af21' into libosmocore
[osmocom-bb.git] / src / shared / libosmocore / 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 struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, int _ci)
31 {
32         uint8_t *data;
33         uint16_t *ci;
34         struct msgb* msg;
35         struct gsm48_loc_area_id *lai;
36
37         msg  = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
38                                    "bssmap cmpl l3");
39         if (!msg)
40                 return NULL;
41
42         /* create the bssmap header */
43         msg->l3h = msgb_put(msg, 2);
44         msg->l3h[0] = 0x0;
45
46         /* create layer 3 header */
47         data = msgb_put(msg, 1);
48         data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3;
49
50         /* create the cell header */
51         data = msgb_put(msg, 3);
52         data[0] = GSM0808_IE_CELL_IDENTIFIER;
53         data[1] = 1 + sizeof(*lai) + 2;
54         data[2] = CELL_IDENT_WHOLE_GLOBAL;
55
56         lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
57         gsm48_generate_lai(lai, cc, nc, lac);
58
59         ci = (uint16_t *) msgb_put(msg, 2);
60         *ci = htons(_ci);
61
62         /* copy the layer3 data */
63         data = msgb_put(msg, msgb_l3len(msg_l3) + 2);
64         data[0] = GSM0808_IE_LAYER_3_INFORMATION;
65         data[1] = msgb_l3len(msg_l3);
66         memcpy(&data[2], msg_l3->l3h, data[1]);
67
68         /* update the size */
69         msg->l3h[1] = msgb_l3len(msg) - 2;
70
71         return msg;
72 }
73
74 struct msgb *gsm0808_create_reset(void)
75 {
76         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
77                                                "bssmap: reset");
78         if (!msg)
79                 return NULL;
80
81         msg->l3h = msgb_put(msg, 6);
82         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
83         msg->l3h[1] = 0x04;
84         msg->l3h[2] = 0x30;
85         msg->l3h[3] = 0x04;
86         msg->l3h[4] = 0x01;
87         msg->l3h[5] = 0x20;
88         return msg;
89 }
90
91 struct msgb *gsm0808_create_clear_complete(void)
92 {
93         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
94                                                "bssmap: clear complete");
95         if (!msg)
96                 return NULL;
97
98         msg->l3h = msgb_put(msg, 3);
99         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
100         msg->l3h[1] = 1;
101         msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
102
103         return msg;
104 }
105
106 struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id)
107 {
108         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
109                                                "cipher-complete");
110         if (!msg)
111                 return NULL;
112
113         /* send response with BSS override for A5/1... cheating */
114         msg->l3h = msgb_put(msg, 3);
115         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
116         msg->l3h[1] = 0xff;
117         msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE;
118
119         /* include layer3 in case we have at least two octets */
120         if (layer3 && msgb_l3len(layer3) > 2) {
121                 msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2);
122                 msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS;
123                 msg->l4h[1] = msgb_l3len(layer3);
124                 memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3));
125         }
126
127         /* and the optional BSS message */
128         msg->l4h = msgb_put(msg, 2);
129         msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
130         msg->l4h[1] = alg_id;
131
132         /* update the size */
133         msg->l3h[1] = msgb_l3len(msg) - 2;
134         return msg;
135 }
136
137 struct msgb *gsm0808_create_cipher_reject(uint8_t cause)
138 {
139         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
140                                                "bssmap: clear complete");
141         if (!msg)
142                 return NULL;
143
144         msg->l3h = msgb_put(msg, 3);
145         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
146         msg->l3h[1] = 2;
147         msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
148         msg->l3h[3] = cause;
149
150         return msg;
151 }
152
153 struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length)
154 {
155         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
156                                                "classmark-update");
157         if (!msg)
158                 return NULL;
159
160         msg->l3h = msgb_put(msg, 3);
161         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
162         msg->l3h[1] = 0xff;
163         msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
164
165         msg->l4h = msgb_put(msg, length);
166         memcpy(msg->l4h, classmark_data, length);
167
168         /* update the size */
169         msg->l3h[1] = msgb_l3len(msg) - 2;
170         return msg;
171 }
172
173 struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
174 {
175         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
176                                                "bssmap: sapi 'n' reject");
177         if (!msg)
178                 return NULL;
179
180         msg->l3h = msgb_put(msg, 5);
181         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
182         msg->l3h[1] = 3;
183         msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
184         msg->l3h[3] = link_id;
185         msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
186
187         return msg;
188 }
189
190 struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
191                                                  uint8_t chosen_channel, uint8_t encr_alg_id,
192                                                  uint8_t speech_mode)
193 {
194         uint8_t *data;
195
196         struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
197         if (!msg)
198                 return NULL;
199
200         msg->l3h = msgb_put(msg, 3);
201         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
202         msg->l3h[1] = 0xff;
203         msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
204
205         /* write 3.2.2.22 */
206         data = msgb_put(msg, 2);
207         data[0] = GSM0808_IE_RR_CAUSE;
208         data[1] = rr_cause;
209
210         /* write cirtcuit identity  code 3.2.2.2 */
211         /* write cell identifier 3.2.2.17 */
212         /* write chosen channel 3.2.2.33 when BTS picked it */
213         data = msgb_put(msg, 2);
214         data[0] = GSM0808_IE_CHOSEN_CHANNEL;
215         data[1] = chosen_channel;
216
217         /* write chosen encryption algorithm 3.2.2.44 */
218         data = msgb_put(msg, 2);
219         data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
220         data[1] = encr_alg_id;
221
222         /* write circuit pool 3.2.2.45 */
223         /* write speech version chosen: 3.2.2.51 when BTS picked it */
224         if (speech_mode != 0) {
225                 data = msgb_put(msg, 2);
226                 data[0] = GSM0808_IE_SPEECH_VERSION;
227                 data[1] = speech_mode;
228         }
229
230         /* write LSA identifier 3.2.2.15 */
231
232
233         /* update the size */
234         msg->l3h[1] = msgb_l3len(msg) - 2;
235         return msg;
236 }
237
238 struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
239 {
240         uint8_t *data;
241         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
242                                                "bssmap: ass fail");
243         if (!msg)
244                 return NULL;
245
246         msg->l3h = msgb_put(msg, 6);
247         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
248         msg->l3h[1] = 0xff;
249         msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
250         msg->l3h[3] = GSM0808_IE_CAUSE;
251         msg->l3h[4] = 1;
252         msg->l3h[5] = cause;
253
254         /* RR cause 3.2.2.22 */
255         if (rr_cause) {
256                 data = msgb_put(msg, 2);
257                 data[0] = GSM0808_IE_RR_CAUSE;
258                 data[1] = *rr_cause;
259         }
260
261         /* Circuit pool 3.22.45 */
262         /* Circuit pool list 3.2.2.46 */
263
264         /* update the size */
265         msg->l3h[1] = msgb_l3len(msg) - 2;
266         return msg;
267 }
268
269 void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id)
270 {
271         uint8_t *hh = msgb_push(msg, 3);
272         hh[0] = BSSAP_MSG_DTAP;
273         hh[1] = link_id;
274         hh[2] = msg->len - 3;
275 }
276
277 static const struct tlv_definition bss_att_tlvdef = {
278         .def = {
279                 [GSM0808_IE_IMSI]                   = { TLV_TYPE_TLV },
280                 [GSM0808_IE_TMSI]                   = { TLV_TYPE_TLV },
281                 [GSM0808_IE_CELL_IDENTIFIER_LIST]   = { TLV_TYPE_TLV },
282                 [GSM0808_IE_CHANNEL_NEEDED]         = { TLV_TYPE_TV },
283                 [GSM0808_IE_EMLPP_PRIORITY]         = { TLV_TYPE_TV },
284                 [GSM0808_IE_CHANNEL_TYPE]           = { TLV_TYPE_TLV },
285                 [GSM0808_IE_PRIORITY]               = { TLV_TYPE_TLV },
286                 [GSM0808_IE_CIRCUIT_IDENTITY_CODE]  = { TLV_TYPE_TV },
287                 [GSM0808_IE_DOWNLINK_DTX_FLAG]      = { TLV_TYPE_TV },
288                 [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
289                 [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
290                 [GSM0808_IE_GROUP_CALL_REFERENCE]   = { TLV_TYPE_TLV },
291                 [GSM0808_IE_TALKER_FLAG]            = { TLV_TYPE_T },
292                 [GSM0808_IE_CONFIG_EVO_INDI]        = { TLV_TYPE_TV },
293                 [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR]  = { TLV_TYPE_TV },
294                 [GSM0808_IE_SERVICE_HANDOVER]       = { TLV_TYPE_TV},
295                 [GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
296                 [GSM0808_IE_CIPHER_RESPONSE_MODE]   = { TLV_TYPE_TV },
297                 [GSM0808_IE_CELL_IDENTIFIER]        = { TLV_TYPE_TLV },
298                 [GSM0808_IE_CHOSEN_CHANNEL]         = { TLV_TYPE_TV },
299                 [GSM0808_IE_LAYER_3_INFORMATION]    = { TLV_TYPE_TLV },
300         },
301 };
302
303 const struct tlv_definition *gsm0808_att_tlvdef()
304 {
305         return &bss_att_tlvdef;
306 }