Add GSM0808 utilities to Osmocore.
[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 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_reject(uint8_t cause)
107 {
108         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
109                                                "bssmap: clear complete");
110         if (!msg)
111                 return NULL;
112
113         msg->l3h = msgb_put(msg, 3);
114         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
115         msg->l3h[1] = 2;
116         msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
117         msg->l3h[3] = cause;
118
119         return msg;
120 }
121
122 struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, u_int8_t length)
123 {
124         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
125                                                "classmark-update");
126         if (!msg)
127                 return NULL;
128
129         msg->l3h = msgb_put(msg, 3);
130         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
131         msg->l3h[1] = 0xff;
132         msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
133
134         msg->l4h = msgb_put(msg, length);
135         memcpy(msg->l4h, classmark_data, length);
136
137         /* update the size */
138         msg->l3h[1] = msgb_l3len(msg) - 2;
139         return msg;
140 }
141
142 struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
143 {
144         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
145                                                "bssmap: sapi 'n' reject");
146         if (!msg)
147                 return NULL;
148
149         msg->l3h = msgb_put(msg, 5);
150         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
151         msg->l3h[1] = 3;
152         msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
153         msg->l3h[3] = link_id;
154         msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
155
156         return msg;
157 }
158
159 struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
160 {
161         uint8_t *data;
162         struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
163                                                "bssmap: ass fail");
164         if (!msg)
165                 return NULL;
166
167         msg->l3h = msgb_put(msg, 6);
168         msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
169         msg->l3h[1] = 0xff;
170         msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
171         msg->l3h[3] = GSM0808_IE_CAUSE;
172         msg->l3h[4] = 1;
173         msg->l3h[5] = cause;
174
175         /* RR cause 3.2.2.22 */
176         if (rr_cause) {
177                 data = msgb_put(msg, 2);
178                 data[0] = GSM0808_IE_RR_CAUSE;
179                 data[1] = *rr_cause;
180         }
181
182         /* Circuit pool 3.22.45 */
183         /* Circuit pool list 3.2.2.46 */
184
185         /* update the size */
186         msg->l3h[1] = msgb_l3len(msg) - 2;
187         return msg;
188 }