blob: 4b5077be13721da0cd7531d3a1eec0f641a90787 [file] [log] [blame]
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02001/* OpenBSC minimal LAPD implementation */
2
3/* (C) 2009 by oystein@homelien.no
4 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2010 by Digium and Matthew Fredrickson <creslin@digium.com>
6 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
Andreas Eversberga7ff0012011-09-26 11:29:30 +02007 * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02008 *
9 * All Rights Reserved
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 *
25 */
26
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020027#include "internal.h"
28
29#include <stdio.h>
30#include <string.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020031#include <errno.h>
32
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020033#include <osmocom/core/linuxlist.h>
34#include <osmocom/core/logging.h>
Harald Welte71d87b22011-07-18 14:49:56 +020035#include <osmocom/core/talloc.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020036#include <osmocom/core/msgb.h>
37#include <osmocom/core/timer.h>
Andreas Eversberga7ff0012011-09-26 11:29:30 +020038#include <osmocom/abis/lapd.h>
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020039#include <osmocom/abis/lapd_pcap.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020040
Andreas Eversberga7ff0012011-09-26 11:29:30 +020041#define LAPD_ADDR2(sapi, cr) ((((sapi) & 0x3f) << 2) | (((cr) & 0x1) << 1))
42#define LAPD_ADDR3(tei) ((((tei) & 0x7f) << 1) | 0x1)
43
44#define LAPD_ADDR_SAPI(addr) ((addr) >> 2)
45#define LAPD_ADDR_CR(addr) (((addr) >> 1) & 0x1)
46#define LAPD_ADDR_EA(addr) ((addr) & 0x1)
47#define LAPD_ADDR_TEI(addr) ((addr) >> 1)
48
49#define LAPD_CTRL_I4(ns) (((ns) & 0x7f) << 1)
50#define LAPD_CTRL_I5(nr, p) ((((nr) & 0x7f) << 1) | ((p) & 0x1))
51#define LAPD_CTRL_S4(s) ((((s) & 0x3) << 2) | 0x1)
52#define LAPD_CTRL_S5(nr, p) ((((nr) & 0x7f) << 1) | ((p) & 0x1))
53#define LAPD_CTRL_U4(u, p) ((((u) & 0x1c) << (5-2)) | (((p) & 0x1) << 4) | (((u) & 0x3) << 2) | 0x3)
54
55#define LAPD_CTRL_is_I(ctrl) (((ctrl) & 0x1) == 0)
56#define LAPD_CTRL_is_S(ctrl) (((ctrl) & 0x3) == 1)
57#define LAPD_CTRL_is_U(ctrl) (((ctrl) & 0x3) == 3)
58
59#define LAPD_CTRL_U_BITS(ctrl) ((((ctrl) & 0xC) >> 2) | ((ctrl) & 0xE0) >> 3)
60#define LAPD_CTRL_U_PF(ctrl) (((ctrl) >> 4) & 0x1)
61
62#define LAPD_CTRL_S_BITS(ctrl) (((ctrl) & 0xC) >> 2)
63#define LAPD_CTRL_S_PF(ctrl) (ctrl & 0x1)
64
65#define LAPD_CTRL_I_Ns(ctrl) (((ctrl) & 0xFE) >> 1)
66#define LAPD_CTRL_I_P(ctrl) (ctrl & 0x1)
67#define LAPD_CTRL_Nr(ctrl) (((ctrl) & 0xFE) >> 1)
68
69#define LAPD_LEN(len) ((len << 2) | 0x1)
70#define LAPD_EL 0x1
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020071
Andreas Eversberg3c460442011-09-28 02:46:16 +020072#define LAPD_SET_K(n, o) {n,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}
73
Andreas Eversberg3744b872011-09-27 12:12:36 +020074const struct lapd_profile lapd_profile_isdn = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +010075 .k = LAPD_SET_K(7,7),
76 .n200 = 3,
77 .n201 = 260,
78 .n202 = 3,
79 .t200_sec = 1, .t200_usec = 0,
80 .t201_sec = 1, .t201_usec = 0,
81 .t202_sec = 2, .t202_usec = 0,
82 .t203_sec = 10, .t203_usec = 0,
83 .short_address = 0
Andreas Eversberg3744b872011-09-27 12:12:36 +020084};
85
86const struct lapd_profile lapd_profile_abis = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +010087 .k = LAPD_SET_K(2,1),
88 .n200 = 3,
89 .n201 = 260,
90 .n202 = 0, /* infinite */
91 .t200_sec = 0, .t200_usec = 240000,
92 .t201_sec = 1, .t201_usec = 0,
93 .t202_sec = 2, .t202_usec = 0,
94 .t203_sec = 10, .t203_usec = 0,
95 .short_address = 0
Andreas Eversberg3744b872011-09-27 12:12:36 +020096};
97
Philipp0c7d5f42016-10-19 18:38:58 +020098/* Ericssons OM2000 lapd dialect requires a sabm frame retransmission
99 * timeout of exactly 300 msek. Shorter or longer retransmission will
100 * cause the link establishment to fail permanently. Since the BTS is
101 * periodically scanning through all timeslots to find the timeslot
102 * where the bsc is transmitting its sabm frames the normal maximum
103 * retransmission (n200) of 3 is not enough. In order not to miss
Philipp Maierd75bac42017-02-01 13:51:03 +0100104 * the bts, n200 has been increased to 50, which is an educated
Philipp0c7d5f42016-10-19 18:38:58 +0200105 * guess. */
106
107const struct lapd_profile lapd_profile_abis_ericsson = {
108 .k = LAPD_SET_K(2,1),
Philipp Maierd75bac42017-02-01 13:51:03 +0100109 .n200 = 50,
Philipp0c7d5f42016-10-19 18:38:58 +0200110 .n201 = 260,
111 .n202 = 0, /* infinite */
112 .t200_sec = 0, .t200_usec = 300000,
113 .t201_sec = 1, .t201_usec = 0,
114 .t202_sec = 2, .t202_usec = 0,
115 .t203_sec = 10, .t203_usec = 0,
116 .short_address = 0
117};
118
Andreas Eversberg3744b872011-09-27 12:12:36 +0200119const struct lapd_profile lapd_profile_sat = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100120 .k = LAPD_SET_K(15,15),
121 .n200 = 5,
122 .n201 = 260,
123 .n202 = 5,
124 .t200_sec = 2, .t200_usec = 400000,
125 .t201_sec = 2, .t201_usec = 400000,
126 .t202_sec = 2, .t202_usec = 400000,
Holger Hans Peter Freyther4b6860d2013-03-09 17:32:33 +0100127 .t203_sec = 20, .t203_usec = 0,
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100128 .short_address = 1
Andreas Eversberg3744b872011-09-27 12:12:36 +0200129};
130
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200131typedef enum {
132 LAPD_TEI_NONE = 0,
133 LAPD_TEI_ASSIGNED,
134 LAPD_TEI_ACTIVE,
135} lapd_tei_state;
136
137const char *lapd_tei_states[] = {
138 "NONE",
139 "ASSIGNED",
140 "ACTIVE",
141};
142
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200143/* Structure representing an allocated TEI within a LAPD instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200144struct lapd_tei {
145 struct llist_head list;
146 struct lapd_instance *li;
147 uint8_t tei;
148 lapd_tei_state state;
149
150 struct llist_head sap_list;
151};
152
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200153/* Structure representing a SAP within a TEI. It includes exactly one datalink
154 * instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200155struct lapd_sap {
156 struct llist_head list;
157 struct lapd_tei *tei;
158 uint8_t sapi;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200159
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200160 struct lapd_datalink dl;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200161};
162
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200163/* Resolve TEI structure from given numeric TEI */
164static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei)
165{
166 struct lapd_tei *lt;
167
168 llist_for_each_entry(lt, &li->tei_list, list) {
169 if (lt->tei == tei)
170 return lt;
171 }
172 return NULL;
173};
174
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200175/* Change state of TEI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200176static void lapd_tei_set_state(struct lapd_tei *teip, int newstate)
177{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200178 LOGP(DLLAPD, LOGL_INFO, "LAPD state change on TEI %d: %s -> %s\n",
179 teip->tei, lapd_tei_states[teip->state],
180 lapd_tei_states[newstate]);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200181 teip->state = newstate;
182};
183
184/* Allocate a new TEI */
185struct lapd_tei *lapd_tei_alloc(struct lapd_instance *li, uint8_t tei)
186{
187 struct lapd_tei *teip;
188
189 teip = talloc_zero(li, struct lapd_tei);
190 if (!teip)
191 return NULL;
192
193 teip->li = li;
194 teip->tei = tei;
195 llist_add(&teip->list, &li->tei_list);
196 INIT_LLIST_HEAD(&teip->sap_list);
197
198 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
199
200 return teip;
201}
202
203/* Find a SAP within a given TEI */
204static struct lapd_sap *lapd_sap_find(struct lapd_tei *teip, uint8_t sapi)
205{
206 struct lapd_sap *sap;
207
208 llist_for_each_entry(sap, &teip->sap_list, list) {
209 if (sap->sapi == sapi)
210 return sap;
211 }
212
213 return NULL;
214}
215
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200216static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg);
217static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200218
219/* Allocate a new SAP within a given TEI */
220static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi)
221{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200222 struct lapd_sap *sap;
223 struct lapd_datalink *dl;
224 struct lapd_instance *li;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200225 struct lapd_profile *profile;
226 int k;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200227
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200228 sap = talloc_zero(teip, struct lapd_sap);
229 if (!sap)
230 return NULL;
231
Philipp Maier027e1192016-12-08 17:17:33 +0100232 LOGP(DLLAPD, LOGL_NOTICE,
233 "LAPD Allocating SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
234 sapi, teip->tei, &sap->dl, sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200235
236 sap->sapi = sapi;
237 sap->tei = teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200238 dl = &sap->dl;
239 li = teip->li;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200240 profile = &li->profile;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200241
Andreas Eversberg3c460442011-09-28 02:46:16 +0200242 k = profile->k[sapi & 0x3f];
243 LOGP(DLLAPD, LOGL_NOTICE, "k=%d N200=%d N201=%d T200=%d.%d T203=%d.%d"
244 "\n", k, profile->n200, profile->n201, profile->t200_sec,
245 profile->t200_usec, profile->t203_sec, profile->t203_usec);
Andreas Eversberg3744b872011-09-27 12:12:36 +0200246 lapd_dl_init(dl, k, 128, profile->n201);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200247 dl->use_sabme = 1; /* use SABME instead of SABM (GSM) */
248 dl->send_ph_data_req = send_ph_data_req;
249 dl->send_dlsap = send_dlsap;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200250 dl->n200 = profile->n200;
251 dl->n200_est_rel = profile->n200;
252 dl->t200_sec = profile->t200_sec; dl->t200_usec = profile->t200_usec;
253 dl->t203_sec = profile->t203_sec; dl->t203_usec = profile->t203_usec;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200254 dl->lctx.dl = &sap->dl;
255 dl->lctx.sapi = sapi;
256 dl->lctx.tei = teip->tei;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200257 dl->lctx.n201 = profile->n201;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200258
259 lapd_set_mode(&sap->dl, (teip->li->network_side) ? LAPD_MODE_NETWORK
260 : LAPD_MODE_USER);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200261
262 llist_add(&sap->list, &teip->sap_list);
263
264 return sap;
265}
266
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200267/* Free SAP instance, including the datalink */
268static void lapd_sap_free(struct lapd_sap *sap)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200269{
Philipp Maier027e1192016-12-08 17:17:33 +0100270 LOGP(DLLAPD, LOGL_NOTICE,
271 "LAPD Freeing SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
272 sap->sapi, sap->tei->tei, &sap->dl, sap);
273
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200274 /* free datalink structures and timers */
275 lapd_dl_exit(&sap->dl);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200276
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200277 llist_del(&sap->list);
278 talloc_free(sap);
279}
280
281/* Free TEI instance */
282static void lapd_tei_free(struct lapd_tei *teip)
283{
284 struct lapd_sap *sap, *sap2;
285
286 llist_for_each_entry_safe(sap, sap2, &teip->sap_list, list) {
287 lapd_sap_free(sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200288 }
289
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200290 llist_del(&teip->list);
291 talloc_free(teip);
292}
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200293
294/* Input function into TEI manager */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200295static int lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200296{
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200297 uint8_t entity;
298 uint8_t ref;
299 uint8_t mt;
300 uint8_t action;
301 uint8_t e;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200302 uint8_t resp[8];
303 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200304 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200305
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200306 if (len < 5) {
307 LOGP(DLLAPD, LOGL_ERROR, "LAPD TEIMGR frame receive len %d < 5"
308 ", ignoring\n", len);
309 return -EINVAL;
310 };
311
312 entity = data[0];
313 ref = data[1];
314 mt = data[3];
315 action = data[4] >> 1;
316 e = data[4] & 1;
317
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200318 DEBUGP(DLLAPD, "LAPD TEIMGR: entity %x, ref %x, mt %x, action %x, "
319 "e %x\n", entity, ref, mt, action, e);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200320
321 switch (mt) {
322 case 0x01: /* IDENTITY REQUEST */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200323 DEBUGP(DLLAPD, "LAPD TEIMGR: identity request for TEI %u\n",
324 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200325
326 teip = teip_from_tei(li, action);
327 if (!teip) {
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200328 LOGP(DLLAPD, LOGL_INFO, "TEI MGR: New TEI %u\n",
329 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200330 teip = lapd_tei_alloc(li, action);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200331 if (!teip)
332 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200333 }
334
335 /* Send ACCEPT */
336 memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8);
337 resp[7] = (action << 1) | 1;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200338 msg = msgb_alloc_headroom(56, 56, "DL EST");
339 msg->l2h = msgb_push(msg, 8);
340 memcpy(msg->l2h, resp, 8);
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200341
342 /* write to PCAP file, if enabled. */
343 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
344
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200345 LOGP(DLLAPD, LOGL_DEBUG, "TX: %s\n",
346 osmo_hexdump(msg->data, msg->len));
347 li->transmit_cb(msg, li->transmit_cbdata);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200348
349 if (teip->state == LAPD_TEI_NONE)
350 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
351 break;
352 default:
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200353 LOGP(DLLAPD, LOGL_NOTICE, "LAPD TEIMGR: unknown mt %x "
354 "action %x\n", mt, action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200355 break;
356 };
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200357
358 return 0;
359}
360
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200361/* General input function for any data received for this LAPD instance */
362int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200363{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200364 int i;
365 struct lapd_msg_ctx lctx;
366 int rc;
367 struct lapd_sap *sap;
368 struct lapd_tei *teip;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200369
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200370 /* write to PCAP file, if enabled. */
371 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_INPUT, msg);
372
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200373 LOGP(DLLAPD, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msg->data, msg->len));
374 if (msg->len < 2) {
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200375 LOGP(DLLAPD, LOGL_ERROR, "LAPD frame receive len %d < 2, "
376 "ignoring\n", msg->len);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200377 *error = LAPD_ERR_BAD_LEN;
378 return -EINVAL;
379 };
380 msg->l2h = msg->data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200381
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200382 memset(&lctx, 0, sizeof(lctx));
383
384 i = 0;
385 /* adress field */
386 lctx.sapi = LAPD_ADDR_SAPI(msg->l2h[i]);
387 lctx.cr = LAPD_ADDR_CR(msg->l2h[i]);
388 lctx.lpd = 0;
389 if (!LAPD_ADDR_EA(msg->l2h[i])) {
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200390 if (msg->len < 3) {
391 LOGP(DLLAPD, LOGL_ERROR, "LAPD frame with TEI receive "
392 "len %d < 3, ignoring\n", msg->len);
393 *error = LAPD_ERR_BAD_LEN;
394 return -EINVAL;
395 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200396 i++;
397 lctx.tei = LAPD_ADDR_TEI(msg->l2h[i]);
398 }
399 i++;
400 /* control field */
401 if (LAPD_CTRL_is_I(msg->l2h[i])) {
402 lctx.format = LAPD_FORM_I;
403 lctx.n_send = LAPD_CTRL_I_Ns(msg->l2h[i]);
404 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200405 if (msg->len < 3 && i == 2) {
406 LOGP(DLLAPD, LOGL_ERROR, "LAPD I frame without TEI "
407 "receive len %d < 3, ignoring\n", msg->len);
408 *error = LAPD_ERR_BAD_LEN;
409 return -EINVAL;
410 };
411 if (msg->len < 4 && i == 3) {
412 LOGP(DLLAPD, LOGL_ERROR, "LAPD I frame with TEI "
413 "receive len %d < 4, ignoring\n", msg->len);
414 *error = LAPD_ERR_BAD_LEN;
415 return -EINVAL;
416 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200417 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
418 lctx.p_f = LAPD_CTRL_I_P(msg->l2h[i]);
419 } else if (LAPD_CTRL_is_S(msg->l2h[i])) {
420 lctx.format = LAPD_FORM_S;
421 lctx.s_u = LAPD_CTRL_S_BITS(msg->l2h[i]);
422 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200423 if (msg->len < 3 && i == 2) {
424 LOGP(DLLAPD, LOGL_ERROR, "LAPD S frame without TEI "
425 "receive len %d < 3, ignoring\n", msg->len);
426 *error = LAPD_ERR_BAD_LEN;
427 return -EINVAL;
428 };
429 if (msg->len < 4 && i == 3) {
430 LOGP(DLLAPD, LOGL_ERROR, "LAPD S frame with TEI "
431 "receive len %d < 4, ignoring\n", msg->len);
432 *error = LAPD_ERR_BAD_LEN;
433 return -EINVAL;
434 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200435 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
436 lctx.p_f = LAPD_CTRL_S_PF(msg->l2h[i]);
437 } else if (LAPD_CTRL_is_U(msg->l2h[i])) {
438 lctx.format = LAPD_FORM_U;
439 lctx.s_u = LAPD_CTRL_U_BITS(msg->l2h[i]);
440 lctx.p_f = LAPD_CTRL_U_PF(msg->l2h[i]);
441 } else
442 lctx.format = LAPD_FORM_UKN;
443 i++;
444 /* length */
445 msg->l3h = msg->l2h + i;
446 msgb_pull(msg, i);
447 lctx.length = msg->len;
448
449 /* perform TEI assignment, if received */
450 if (lctx.tei == 127) {
451 rc = lapd_tei_receive(li, msg->data, msg->len);
452 msgb_free(msg);
453 return rc;
454 }
455
456 /* resolve TEI and SAPI */
457 teip = teip_from_tei(li, lctx.tei);
458 if (!teip) {
459 LOGP(DLLAPD, LOGL_NOTICE, "LAPD Unknown TEI %u\n", lctx.tei);
460 *error = LAPD_ERR_UNKNOWN_TEI;
461 msgb_free(msg);
462 return -EINVAL;
463 }
464 sap = lapd_sap_find(teip, lctx.sapi);
465 if (!sap) {
466 LOGP(DLLAPD, LOGL_INFO, "LAPD No SAP for TEI=%u / SAPI=%u, "
467 "allocating\n", lctx.tei, lctx.sapi);
468 sap = lapd_sap_alloc(teip, lctx.sapi);
469 if (!sap) {
470 *error = LAPD_ERR_NO_MEM;
471 msgb_free(msg);
472 return -ENOMEM;
473 }
474 }
475 lctx.dl = &sap->dl;
476 lctx.n201 = lctx.dl->maxf;
477
478 if (msg->len > lctx.n201) {
479 LOGP(DLLAPD, LOGL_ERROR, "message len %d > N201(%d) "
480 "(discarding)\n", msg->len, lctx.n201);
481 msgb_free(msg);
482 *error = LAPD_ERR_BAD_LEN;
483 return -EINVAL;
484 }
485
486 /* send to LAPD */
487 return lapd_ph_data_ind(msg, &lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200488}
489
490/* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
491int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
492{
493 struct lapd_sap *sap;
494 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200495 struct osmo_dlsap_prim dp;
496 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200497
498 teip = teip_from_tei(li, tei);
499 if (!teip)
500 teip = lapd_tei_alloc(li, tei);
501
502 sap = lapd_sap_find(teip, sapi);
503 if (sap)
504 return -EEXIST;
505
506 sap = lapd_sap_alloc(teip, sapi);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200507 if (!sap)
508 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200509
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200510 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-ESTABLISH request TEI=%d SAPI=%d\n",
511 tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200512
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200513 /* prepare prim */
514 msg = msgb_alloc_headroom(56, 56, "DL EST");
515 msg->l3h = msg->data;
516 osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg);
517
518 /* send to L2 */
519 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200520}
521
522/* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
523int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
524{
525 struct lapd_tei *teip;
526 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200527 struct osmo_dlsap_prim dp;
528 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200529
530 teip = teip_from_tei(li, tei);
531 if (!teip)
532 return -ENODEV;
533
534 sap = lapd_sap_find(teip, sapi);
535 if (!sap)
536 return -ENODEV;
537
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200538 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-RELEASE request TEI=%d SAPI=%d\n",
539 tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200540
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200541 /* prepare prim */
542 msg = msgb_alloc_headroom(56, 56, "DL REL");
543 msg->l3h = msg->data;
544 osmo_prim_init(&dp.oph, 0, PRIM_DL_REL, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200545
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200546 /* send to L2 */
547 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200548}
549
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200550/* Transmit Data (DL-DATA request) on the given LAPD Instance / TEI / SAPI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200551void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200552 struct msgb *msg)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200553{
554 struct lapd_tei *teip = teip_from_tei(li, tei);
555 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200556 struct osmo_dlsap_prim dp;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200557
558 if (!teip) {
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200559 LOGP(DLLAPD, LOGL_ERROR, "LAPD Cannot transmit on "
Harald Welte4ca16c72011-08-16 14:01:49 +0200560 "non-existing TEI %u\n", tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200561 msgb_free(msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200562 return;
563 }
564
565 sap = lapd_sap_find(teip, sapi);
566 if (!sap) {
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200567 LOGP(DLLAPD, LOGL_INFO, "LAPD Tx on unknown SAPI=%u "
568 "in TEI=%u\n", sapi, tei);
569 msgb_free(msg);
570 return;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200571 }
572
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200573 /* prepare prim */
574 msg->l3h = msg->data;
575 osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200576
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200577 /* send to L2 */
578 lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200579};
580
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200581static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg)
582{
583 struct lapd_datalink *dl = lctx->dl;
584 struct lapd_sap *sap =
585 container_of(dl, struct lapd_sap, dl);
586 struct lapd_instance *li = sap->tei->li;
587 int format = lctx->format;
588 int addr_len;
589
590 /* control field */
591 switch (format) {
592 case LAPD_FORM_I:
593 msg->l2h = msgb_push(msg, 2);
594 msg->l2h[0] = LAPD_CTRL_I4(lctx->n_send);
595 msg->l2h[1] = LAPD_CTRL_I5(lctx->n_recv, lctx->p_f);
596 break;
597 case LAPD_FORM_S:
598 msg->l2h = msgb_push(msg, 2);
599 msg->l2h[0] = LAPD_CTRL_S4(lctx->s_u);
600 msg->l2h[1] = LAPD_CTRL_S5(lctx->n_recv, lctx->p_f);
601 break;
602 case LAPD_FORM_U:
603 msg->l2h = msgb_push(msg, 1);
604 msg->l2h[0] = LAPD_CTRL_U4(lctx->s_u, lctx->p_f);
605 break;
606 default:
607 msgb_free(msg);
608 return -EINVAL;
609 }
610 /* address field */
Andreas Eversberg3744b872011-09-27 12:12:36 +0200611 if (li->profile.short_address && lctx->tei == 0)
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200612 addr_len = 1;
613 else
614 addr_len = 2;
615 msg->l2h = msgb_push(msg, addr_len);
616 msg->l2h[0] = LAPD_ADDR2(lctx->sapi, lctx->cr);
617 if (addr_len == 1)
618 msg->l2h[0] |= 0x1;
619 else
620 msg->l2h[1] = LAPD_ADDR3(lctx->tei);
621
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200622 /* write to PCAP file, if enabled. */
623 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
624
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200625 /* forward frame to L1 */
626 LOGP(DLLAPD, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
627 li->transmit_cb(msg, li->transmit_cbdata);
628
629 return 0;
630}
631
632/* A DL-SAP message is received from datalink instance and forwarded to L3 */
633static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
634{
635 struct lapd_datalink *dl = lctx->dl;
636 struct lapd_sap *sap =
637 container_of(dl, struct lapd_sap, dl);
638 struct lapd_instance *li;
639 uint8_t tei, sapi;
640 char *op = (dp->oph.operation == PRIM_OP_INDICATION) ? "indication"
641 : "confirm";
642
643 li = sap->tei->li;
644 tei = lctx->tei;
645 sapi = lctx->sapi;
646
647 switch (dp->oph.primitive) {
648 case PRIM_DL_EST:
649 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-ESTABLISH %s TEI=%d "
650 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
651 break;
652 case PRIM_DL_REL:
653 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-RELEASE %s TEI=%d "
654 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
655 lapd_sap_free(sap);
656 /* note: sap and dl is now gone, don't use it anymore */
657 break;
658 default:
659 ;
660 }
661
662 li->receive_cb(dp, tei, sapi, li->receive_cbdata);
663
664 return 0;
665}
666
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200667/* Allocate a new LAPD instance */
668struct lapd_instance *lapd_instance_alloc(int network_side,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200669 void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata,
670 void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi,
671 void *rx_cbdata), void *rx_cbdata,
Andreas Eversberg3744b872011-09-27 12:12:36 +0200672 const struct lapd_profile *profile)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200673{
674 struct lapd_instance *li;
675
676 li = talloc_zero(NULL, struct lapd_instance);
677 if (!li)
678 return NULL;
679
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200680 li->network_side = network_side;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200681 li->transmit_cb = tx_cb;
682 li->transmit_cbdata = tx_cbdata;
683 li->receive_cb = rx_cb;
684 li->receive_cbdata = rx_cbdata;
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200685 li->pcap_fd = -1;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200686 memcpy(&li->profile, profile, sizeof(li->profile));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200687
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200688 INIT_LLIST_HEAD(&li->tei_list);
689
690 return li;
691}
Harald Welte14078ea2011-08-24 09:45:11 +0200692
Philipp0c7d5f42016-10-19 18:38:58 +0200693/* Change lapd-profile on the fly (use with caution!) */
694void lapd_instance_set_profile(struct lapd_instance *li,
695 const struct lapd_profile *profile)
696{
697 memcpy(&li->profile, profile, sizeof(li->profile));
698}
699
Harald Welte14078ea2011-08-24 09:45:11 +0200700void lapd_instance_free(struct lapd_instance *li)
701{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200702 struct lapd_tei *teip, *teip2;
Harald Weltef350e252011-08-26 07:55:26 +0200703
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200704 /* Free all TEI instances */
705 llist_for_each_entry_safe(teip, teip2, &li->tei_list, list) {
706 lapd_tei_free(teip);
Harald Weltef350e252011-08-26 07:55:26 +0200707 }
708
Harald Welte14078ea2011-08-24 09:45:11 +0200709 talloc_free(li);
710}