blob: 130e4c30f1084ca12d7b1c3a8acdc1ec45e04b50 [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 *
Harald Welte323d39d2017-11-13 01:09:21 +090011 * SPDX-License-Identifier: GPL-2.0+
12
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020023 */
24
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020025#include "internal.h"
26
27#include <stdio.h>
28#include <string.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020029#include <errno.h>
30
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020031#include <osmocom/core/linuxlist.h>
32#include <osmocom/core/logging.h>
Harald Welte71d87b22011-07-18 14:49:56 +020033#include <osmocom/core/talloc.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020034#include <osmocom/core/msgb.h>
35#include <osmocom/core/timer.h>
Andreas Eversberga7ff0012011-09-26 11:29:30 +020036#include <osmocom/abis/lapd.h>
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020037#include <osmocom/abis/lapd_pcap.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020038
Andreas Eversberga7ff0012011-09-26 11:29:30 +020039#define LAPD_ADDR2(sapi, cr) ((((sapi) & 0x3f) << 2) | (((cr) & 0x1) << 1))
40#define LAPD_ADDR3(tei) ((((tei) & 0x7f) << 1) | 0x1)
41
42#define LAPD_ADDR_SAPI(addr) ((addr) >> 2)
43#define LAPD_ADDR_CR(addr) (((addr) >> 1) & 0x1)
44#define LAPD_ADDR_EA(addr) ((addr) & 0x1)
45#define LAPD_ADDR_TEI(addr) ((addr) >> 1)
46
47#define LAPD_CTRL_I4(ns) (((ns) & 0x7f) << 1)
48#define LAPD_CTRL_I5(nr, p) ((((nr) & 0x7f) << 1) | ((p) & 0x1))
49#define LAPD_CTRL_S4(s) ((((s) & 0x3) << 2) | 0x1)
50#define LAPD_CTRL_S5(nr, p) ((((nr) & 0x7f) << 1) | ((p) & 0x1))
51#define LAPD_CTRL_U4(u, p) ((((u) & 0x1c) << (5-2)) | (((p) & 0x1) << 4) | (((u) & 0x3) << 2) | 0x3)
52
53#define LAPD_CTRL_is_I(ctrl) (((ctrl) & 0x1) == 0)
54#define LAPD_CTRL_is_S(ctrl) (((ctrl) & 0x3) == 1)
55#define LAPD_CTRL_is_U(ctrl) (((ctrl) & 0x3) == 3)
56
57#define LAPD_CTRL_U_BITS(ctrl) ((((ctrl) & 0xC) >> 2) | ((ctrl) & 0xE0) >> 3)
58#define LAPD_CTRL_U_PF(ctrl) (((ctrl) >> 4) & 0x1)
59
60#define LAPD_CTRL_S_BITS(ctrl) (((ctrl) & 0xC) >> 2)
61#define LAPD_CTRL_S_PF(ctrl) (ctrl & 0x1)
62
63#define LAPD_CTRL_I_Ns(ctrl) (((ctrl) & 0xFE) >> 1)
64#define LAPD_CTRL_I_P(ctrl) (ctrl & 0x1)
65#define LAPD_CTRL_Nr(ctrl) (((ctrl) & 0xFE) >> 1)
66
67#define LAPD_LEN(len) ((len << 2) | 0x1)
68#define LAPD_EL 0x1
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020069
Andreas Eversberg3c460442011-09-28 02:46:16 +020070#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}
71
Harald Welteb9031882020-05-02 21:09:15 +020072#define LOGLI(li, level, fmt, args ...) \
Harald Weltea8643782021-11-13 09:54:17 +010073 LOGP(DLLAPD, level, "(%s): " fmt, (li)->name, ## args)
Harald Welteb9031882020-05-02 21:09:15 +020074
75#define LOGTEI(teip, level, fmt, args ...) \
76 LOGP(DLLAPD, level, "(%s-T%u): " fmt, (teip)->li->name, (teip)->tei, ## args)
77
78#define LOGSAP(sap, level, fmt, args ...) \
Harald Weltea8643782021-11-13 09:54:17 +010079 LOGP(DLLAPD, level, "(%s): " fmt, (sap)->dl.name, ## args)
Harald Welteb9031882020-05-02 21:09:15 +020080
Harald Welte47c247b2020-07-03 19:05:44 +020081#define DLSAP_MSGB_SIZE 128
Harald Welteea7da442020-07-03 19:05:07 +020082#define DLSAP_MSGB_HEADROOM 56
83
Andreas Eversberg3744b872011-09-27 12:12:36 +020084const struct lapd_profile lapd_profile_isdn = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +010085 .k = LAPD_SET_K(7,7),
86 .n200 = 3,
87 .n201 = 260,
88 .n202 = 3,
89 .t200_sec = 1, .t200_usec = 0,
90 .t201_sec = 1, .t201_usec = 0,
91 .t202_sec = 2, .t202_usec = 0,
92 .t203_sec = 10, .t203_usec = 0,
93 .short_address = 0
Andreas Eversberg3744b872011-09-27 12:12:36 +020094};
95
96const struct lapd_profile lapd_profile_abis = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +010097 .k = LAPD_SET_K(2,1),
98 .n200 = 3,
99 .n201 = 260,
100 .n202 = 0, /* infinite */
101 .t200_sec = 0, .t200_usec = 240000,
102 .t201_sec = 1, .t201_usec = 0,
103 .t202_sec = 2, .t202_usec = 0,
104 .t203_sec = 10, .t203_usec = 0,
105 .short_address = 0
Andreas Eversberg3744b872011-09-27 12:12:36 +0200106};
107
Philipp0c7d5f42016-10-19 18:38:58 +0200108/* Ericssons OM2000 lapd dialect requires a sabm frame retransmission
109 * timeout of exactly 300 msek. Shorter or longer retransmission will
110 * cause the link establishment to fail permanently. Since the BTS is
111 * periodically scanning through all timeslots to find the timeslot
112 * where the bsc is transmitting its sabm frames the normal maximum
113 * retransmission (n200) of 3 is not enough. In order not to miss
Philipp Maierd75bac42017-02-01 13:51:03 +0100114 * the bts, n200 has been increased to 50, which is an educated
Philipp0c7d5f42016-10-19 18:38:58 +0200115 * guess. */
116
117const struct lapd_profile lapd_profile_abis_ericsson = {
118 .k = LAPD_SET_K(2,1),
Philipp Maierd75bac42017-02-01 13:51:03 +0100119 .n200 = 50,
Philipp0c7d5f42016-10-19 18:38:58 +0200120 .n201 = 260,
121 .n202 = 0, /* infinite */
122 .t200_sec = 0, .t200_usec = 300000,
123 .t201_sec = 1, .t201_usec = 0,
124 .t202_sec = 2, .t202_usec = 0,
125 .t203_sec = 10, .t203_usec = 0,
126 .short_address = 0
127};
128
Andreas Eversberg3744b872011-09-27 12:12:36 +0200129const struct lapd_profile lapd_profile_sat = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100130 .k = LAPD_SET_K(15,15),
131 .n200 = 5,
132 .n201 = 260,
133 .n202 = 5,
134 .t200_sec = 2, .t200_usec = 400000,
135 .t201_sec = 2, .t201_usec = 400000,
136 .t202_sec = 2, .t202_usec = 400000,
Holger Hans Peter Freyther4b6860d2013-03-09 17:32:33 +0100137 .t203_sec = 20, .t203_usec = 0,
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100138 .short_address = 1
Andreas Eversberg3744b872011-09-27 12:12:36 +0200139};
140
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200141typedef enum {
142 LAPD_TEI_NONE = 0,
143 LAPD_TEI_ASSIGNED,
144 LAPD_TEI_ACTIVE,
145} lapd_tei_state;
146
147const char *lapd_tei_states[] = {
148 "NONE",
149 "ASSIGNED",
150 "ACTIVE",
151};
152
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200153/* Structure representing an allocated TEI within a LAPD instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200154struct lapd_tei {
155 struct llist_head list;
156 struct lapd_instance *li;
157 uint8_t tei;
158 lapd_tei_state state;
159
160 struct llist_head sap_list;
161};
162
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200163/* Structure representing a SAP within a TEI. It includes exactly one datalink
164 * instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200165struct lapd_sap {
166 struct llist_head list;
167 struct lapd_tei *tei;
168 uint8_t sapi;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200169
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200170 struct lapd_datalink dl;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200171};
172
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200173/* Resolve TEI structure from given numeric TEI */
174static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei)
175{
176 struct lapd_tei *lt;
177
178 llist_for_each_entry(lt, &li->tei_list, list) {
179 if (lt->tei == tei)
180 return lt;
181 }
182 return NULL;
183};
184
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200185/* Change state of TEI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200186static void lapd_tei_set_state(struct lapd_tei *teip, int newstate)
187{
Harald Welteb9031882020-05-02 21:09:15 +0200188 LOGTEI(teip, LOGL_INFO, "LAPD state change on TEI %d: %s -> %s\n",
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200189 teip->tei, lapd_tei_states[teip->state],
190 lapd_tei_states[newstate]);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200191 teip->state = newstate;
192};
193
194/* Allocate a new TEI */
195struct lapd_tei *lapd_tei_alloc(struct lapd_instance *li, uint8_t tei)
196{
197 struct lapd_tei *teip;
198
199 teip = talloc_zero(li, struct lapd_tei);
200 if (!teip)
201 return NULL;
202
203 teip->li = li;
204 teip->tei = tei;
205 llist_add(&teip->list, &li->tei_list);
206 INIT_LLIST_HEAD(&teip->sap_list);
207
208 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
209
210 return teip;
211}
212
213/* Find a SAP within a given TEI */
214static struct lapd_sap *lapd_sap_find(struct lapd_tei *teip, uint8_t sapi)
215{
216 struct lapd_sap *sap;
217
218 llist_for_each_entry(sap, &teip->sap_list, list) {
219 if (sap->sapi == sapi)
220 return sap;
221 }
222
223 return NULL;
224}
225
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200226static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg);
227static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200228
229/* Allocate a new SAP within a given TEI */
230static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi)
231{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200232 struct lapd_sap *sap;
233 struct lapd_datalink *dl;
Harald Welteb9031882020-05-02 21:09:15 +0200234 struct lapd_instance *li = teip->li;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200235 struct lapd_profile *profile;
Harald Welteb9031882020-05-02 21:09:15 +0200236 char name[256];
Andreas Eversberg3744b872011-09-27 12:12:36 +0200237 int k;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200238
Harald Weltea8643782021-11-13 09:54:17 +0100239 snprintf(name, sizeof(name), "%s-T%u-S%u", li->name, teip->tei, sapi);
Harald Welteb9031882020-05-02 21:09:15 +0200240
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200241 sap = talloc_zero(teip, struct lapd_sap);
242 if (!sap)
243 return NULL;
244
Philipp Maier027e1192016-12-08 17:17:33 +0100245 LOGP(DLLAPD, LOGL_NOTICE,
Harald Weltea8643782021-11-13 09:54:17 +0100246 "(%s): LAPD Allocating SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
Harald Welteb9031882020-05-02 21:09:15 +0200247 name, sapi, teip->tei, &sap->dl, sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200248
249 sap->sapi = sapi;
250 sap->tei = teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200251 dl = &sap->dl;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200252 profile = &li->profile;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200253
Andreas Eversberg3c460442011-09-28 02:46:16 +0200254 k = profile->k[sapi & 0x3f];
Harald Weltea8643782021-11-13 09:54:17 +0100255 LOGP(DLLAPD, LOGL_NOTICE, "(%s): k=%d N200=%d N201=%d T200=%d.%d T203=%d.%d\n",
Harald Welteb9031882020-05-02 21:09:15 +0200256 name, k, profile->n200, profile->n201, profile->t200_sec,
Andreas Eversberg3c460442011-09-28 02:46:16 +0200257 profile->t200_usec, profile->t203_sec, profile->t203_usec);
Pau Espin Pedrolffc92d52020-07-15 15:27:40 +0200258 lapd_dl_init2(dl, k, 128, profile->n201, name);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200259 dl->use_sabme = 1; /* use SABME instead of SABM (GSM) */
260 dl->send_ph_data_req = send_ph_data_req;
261 dl->send_dlsap = send_dlsap;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200262 dl->n200 = profile->n200;
263 dl->n200_est_rel = profile->n200;
264 dl->t200_sec = profile->t200_sec; dl->t200_usec = profile->t200_usec;
265 dl->t203_sec = profile->t203_sec; dl->t203_usec = profile->t203_usec;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200266 dl->lctx.dl = &sap->dl;
267 dl->lctx.sapi = sapi;
268 dl->lctx.tei = teip->tei;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200269 dl->lctx.n201 = profile->n201;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200270
271 lapd_set_mode(&sap->dl, (teip->li->network_side) ? LAPD_MODE_NETWORK
272 : LAPD_MODE_USER);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200273
274 llist_add(&sap->list, &teip->sap_list);
275
276 return sap;
277}
278
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200279/* Free SAP instance, including the datalink */
280static void lapd_sap_free(struct lapd_sap *sap)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200281{
Harald Welteb9031882020-05-02 21:09:15 +0200282 LOGSAP(sap, LOGL_NOTICE,
Philipp Maier027e1192016-12-08 17:17:33 +0100283 "LAPD Freeing SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
284 sap->sapi, sap->tei->tei, &sap->dl, sap);
285
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200286 /* free datalink structures and timers */
287 lapd_dl_exit(&sap->dl);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200288
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200289 llist_del(&sap->list);
290 talloc_free(sap);
291}
292
293/* Free TEI instance */
294static void lapd_tei_free(struct lapd_tei *teip)
295{
296 struct lapd_sap *sap, *sap2;
297
298 llist_for_each_entry_safe(sap, sap2, &teip->sap_list, list) {
299 lapd_sap_free(sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200300 }
301
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200302 llist_del(&teip->list);
303 talloc_free(teip);
304}
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200305
306/* Input function into TEI manager */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200307static int lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200308{
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200309 uint8_t entity;
310 uint8_t ref;
311 uint8_t mt;
312 uint8_t action;
313 uint8_t e;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200314 uint8_t resp[8];
315 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200316 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200317
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200318 if (len < 5) {
Harald Welteb9031882020-05-02 21:09:15 +0200319 LOGLI(li, LOGL_ERROR, "LAPD TEIMGR frame receive len %d < 5"
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200320 ", ignoring\n", len);
321 return -EINVAL;
322 };
323
324 entity = data[0];
325 ref = data[1];
326 mt = data[3];
327 action = data[4] >> 1;
328 e = data[4] & 1;
329
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200330 DEBUGP(DLLAPD, "LAPD TEIMGR: entity %x, ref %x, mt %x, action %x, "
331 "e %x\n", entity, ref, mt, action, e);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200332
333 switch (mt) {
334 case 0x01: /* IDENTITY REQUEST */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200335 DEBUGP(DLLAPD, "LAPD TEIMGR: identity request for TEI %u\n",
336 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200337
338 teip = teip_from_tei(li, action);
339 if (!teip) {
Harald Welteb9031882020-05-02 21:09:15 +0200340 LOGLI(li, LOGL_INFO, "TEI MGR: New TEI %u\n",
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200341 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200342 teip = lapd_tei_alloc(li, action);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200343 if (!teip)
344 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200345 }
346
347 /* Send ACCEPT */
348 memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8);
349 resp[7] = (action << 1) | 1;
Harald Welteea7da442020-07-03 19:05:07 +0200350 msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL EST");
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200351 msg->l2h = msgb_push(msg, 8);
352 memcpy(msg->l2h, resp, 8);
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200353
354 /* write to PCAP file, if enabled. */
355 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
356
Harald Welteb9031882020-05-02 21:09:15 +0200357 LOGTEI(teip, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200358 li->transmit_cb(msg, li->transmit_cbdata);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200359
360 if (teip->state == LAPD_TEI_NONE)
361 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
362 break;
363 default:
Harald Welteb9031882020-05-02 21:09:15 +0200364 LOGLI(li, LOGL_NOTICE, "LAPD TEIMGR: unknown mt %x action %x\n", mt, action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200365 break;
366 };
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200367
368 return 0;
369}
370
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200371/* General input function for any data received for this LAPD instance */
372int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200373{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200374 int i;
375 struct lapd_msg_ctx lctx;
376 int rc;
377 struct lapd_sap *sap;
378 struct lapd_tei *teip;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200379
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200380 /* write to PCAP file, if enabled. */
381 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_INPUT, msg);
382
Harald Welteb9031882020-05-02 21:09:15 +0200383 LOGLI(li, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msg->data, msg->len));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200384 if (msg->len < 2) {
Harald Welteb9031882020-05-02 21:09:15 +0200385 LOGLI(li, LOGL_ERROR, "LAPD frame receive len %d < 2, ignoring\n", msg->len);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200386 *error = LAPD_ERR_BAD_LEN;
387 return -EINVAL;
388 };
389 msg->l2h = msg->data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200390
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200391 memset(&lctx, 0, sizeof(lctx));
392
393 i = 0;
394 /* adress field */
395 lctx.sapi = LAPD_ADDR_SAPI(msg->l2h[i]);
396 lctx.cr = LAPD_ADDR_CR(msg->l2h[i]);
397 lctx.lpd = 0;
398 if (!LAPD_ADDR_EA(msg->l2h[i])) {
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200399 if (msg->len < 3) {
Harald Welteb9031882020-05-02 21:09:15 +0200400 LOGLI(li, LOGL_ERROR, "LAPD frame with TEI receive "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200401 "len %d < 3, ignoring\n", msg->len);
402 *error = LAPD_ERR_BAD_LEN;
403 return -EINVAL;
404 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200405 i++;
406 lctx.tei = LAPD_ADDR_TEI(msg->l2h[i]);
407 }
408 i++;
409 /* control field */
410 if (LAPD_CTRL_is_I(msg->l2h[i])) {
411 lctx.format = LAPD_FORM_I;
412 lctx.n_send = LAPD_CTRL_I_Ns(msg->l2h[i]);
413 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200414 if (msg->len < 3 && i == 2) {
Harald Welteb9031882020-05-02 21:09:15 +0200415 LOGLI(li, LOGL_ERROR, "LAPD I frame without TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200416 "receive len %d < 3, ignoring\n", msg->len);
417 *error = LAPD_ERR_BAD_LEN;
418 return -EINVAL;
419 };
420 if (msg->len < 4 && i == 3) {
Harald Welteb9031882020-05-02 21:09:15 +0200421 LOGLI(li, LOGL_ERROR, "LAPD I frame with TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200422 "receive len %d < 4, ignoring\n", msg->len);
423 *error = LAPD_ERR_BAD_LEN;
424 return -EINVAL;
425 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200426 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
427 lctx.p_f = LAPD_CTRL_I_P(msg->l2h[i]);
428 } else if (LAPD_CTRL_is_S(msg->l2h[i])) {
429 lctx.format = LAPD_FORM_S;
430 lctx.s_u = LAPD_CTRL_S_BITS(msg->l2h[i]);
431 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200432 if (msg->len < 3 && i == 2) {
Harald Welteb9031882020-05-02 21:09:15 +0200433 LOGLI(li, LOGL_ERROR, "LAPD S frame without TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200434 "receive len %d < 3, ignoring\n", msg->len);
435 *error = LAPD_ERR_BAD_LEN;
436 return -EINVAL;
437 };
438 if (msg->len < 4 && i == 3) {
Harald Welteb9031882020-05-02 21:09:15 +0200439 LOGLI(li, LOGL_ERROR, "LAPD S frame with TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200440 "receive len %d < 4, ignoring\n", msg->len);
441 *error = LAPD_ERR_BAD_LEN;
442 return -EINVAL;
443 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200444 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
445 lctx.p_f = LAPD_CTRL_S_PF(msg->l2h[i]);
446 } else if (LAPD_CTRL_is_U(msg->l2h[i])) {
447 lctx.format = LAPD_FORM_U;
448 lctx.s_u = LAPD_CTRL_U_BITS(msg->l2h[i]);
449 lctx.p_f = LAPD_CTRL_U_PF(msg->l2h[i]);
450 } else
451 lctx.format = LAPD_FORM_UKN;
452 i++;
453 /* length */
454 msg->l3h = msg->l2h + i;
455 msgb_pull(msg, i);
456 lctx.length = msg->len;
457
458 /* perform TEI assignment, if received */
459 if (lctx.tei == 127) {
460 rc = lapd_tei_receive(li, msg->data, msg->len);
461 msgb_free(msg);
462 return rc;
463 }
464
465 /* resolve TEI and SAPI */
466 teip = teip_from_tei(li, lctx.tei);
467 if (!teip) {
Harald Welteb9031882020-05-02 21:09:15 +0200468 LOGLI(li, LOGL_NOTICE, "LAPD Unknown TEI %u\n", lctx.tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200469 *error = LAPD_ERR_UNKNOWN_TEI;
470 msgb_free(msg);
471 return -EINVAL;
472 }
473 sap = lapd_sap_find(teip, lctx.sapi);
474 if (!sap) {
Harald Welteb9031882020-05-02 21:09:15 +0200475 LOGTEI(teip, LOGL_INFO, "LAPD No SAP for TEI=%u / SAPI=%u, "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200476 "allocating\n", lctx.tei, lctx.sapi);
477 sap = lapd_sap_alloc(teip, lctx.sapi);
478 if (!sap) {
479 *error = LAPD_ERR_NO_MEM;
480 msgb_free(msg);
481 return -ENOMEM;
482 }
483 }
484 lctx.dl = &sap->dl;
485 lctx.n201 = lctx.dl->maxf;
486
487 if (msg->len > lctx.n201) {
Harald Welteb9031882020-05-02 21:09:15 +0200488 LOGSAP(sap, LOGL_ERROR, "message len %d > N201(%d) "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200489 "(discarding)\n", msg->len, lctx.n201);
490 msgb_free(msg);
491 *error = LAPD_ERR_BAD_LEN;
492 return -EINVAL;
493 }
494
495 /* send to LAPD */
496 return lapd_ph_data_ind(msg, &lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200497}
498
499/* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
500int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
501{
502 struct lapd_sap *sap;
503 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200504 struct osmo_dlsap_prim dp;
505 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200506
507 teip = teip_from_tei(li, tei);
508 if (!teip)
509 teip = lapd_tei_alloc(li, tei);
510
511 sap = lapd_sap_find(teip, sapi);
512 if (sap)
513 return -EEXIST;
514
515 sap = lapd_sap_alloc(teip, sapi);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200516 if (!sap)
517 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200518
Harald Welteb9031882020-05-02 21:09:15 +0200519 LOGSAP(sap, LOGL_NOTICE, "LAPD DL-ESTABLISH request TEI=%d SAPI=%d\n", tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200520
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200521 /* prepare prim */
Harald Welteea7da442020-07-03 19:05:07 +0200522 msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL EST");
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200523 msg->l3h = msg->data;
524 osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg);
525
526 /* send to L2 */
527 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200528}
529
530/* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
531int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
532{
533 struct lapd_tei *teip;
534 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200535 struct osmo_dlsap_prim dp;
536 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200537
538 teip = teip_from_tei(li, tei);
539 if (!teip)
540 return -ENODEV;
541
542 sap = lapd_sap_find(teip, sapi);
543 if (!sap)
544 return -ENODEV;
545
Harald Welteb9031882020-05-02 21:09:15 +0200546 LOGSAP(sap, LOGL_NOTICE, "LAPD DL-RELEASE request TEI=%d SAPI=%d\n", tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200547
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200548 /* prepare prim */
Harald Welteea7da442020-07-03 19:05:07 +0200549 msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL REL");
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200550 msg->l3h = msg->data;
551 osmo_prim_init(&dp.oph, 0, PRIM_DL_REL, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200552
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200553 /* send to L2 */
554 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200555}
556
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200557/* Transmit Data (DL-DATA request) on the given LAPD Instance / TEI / SAPI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200558void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200559 struct msgb *msg)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200560{
561 struct lapd_tei *teip = teip_from_tei(li, tei);
562 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200563 struct osmo_dlsap_prim dp;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200564
565 if (!teip) {
Harald Welteb9031882020-05-02 21:09:15 +0200566 LOGLI(li, LOGL_ERROR, "LAPD Cannot transmit on non-existing TEI %u\n", tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200567 msgb_free(msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200568 return;
569 }
570
571 sap = lapd_sap_find(teip, sapi);
572 if (!sap) {
Harald Welteb9031882020-05-02 21:09:15 +0200573 LOGTEI(teip, LOGL_INFO, "LAPD Tx on unknown SAPI=%u in TEI=%u\n", sapi, tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200574 msgb_free(msg);
575 return;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200576 }
577
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200578 /* prepare prim */
579 msg->l3h = msg->data;
580 osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200581
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200582 /* send to L2 */
583 lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200584};
585
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200586static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg)
587{
588 struct lapd_datalink *dl = lctx->dl;
589 struct lapd_sap *sap =
590 container_of(dl, struct lapd_sap, dl);
591 struct lapd_instance *li = sap->tei->li;
592 int format = lctx->format;
593 int addr_len;
594
595 /* control field */
596 switch (format) {
597 case LAPD_FORM_I:
598 msg->l2h = msgb_push(msg, 2);
599 msg->l2h[0] = LAPD_CTRL_I4(lctx->n_send);
600 msg->l2h[1] = LAPD_CTRL_I5(lctx->n_recv, lctx->p_f);
601 break;
602 case LAPD_FORM_S:
603 msg->l2h = msgb_push(msg, 2);
604 msg->l2h[0] = LAPD_CTRL_S4(lctx->s_u);
605 msg->l2h[1] = LAPD_CTRL_S5(lctx->n_recv, lctx->p_f);
606 break;
607 case LAPD_FORM_U:
608 msg->l2h = msgb_push(msg, 1);
609 msg->l2h[0] = LAPD_CTRL_U4(lctx->s_u, lctx->p_f);
610 break;
611 default:
612 msgb_free(msg);
613 return -EINVAL;
614 }
615 /* address field */
Andreas Eversberg3744b872011-09-27 12:12:36 +0200616 if (li->profile.short_address && lctx->tei == 0)
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200617 addr_len = 1;
618 else
619 addr_len = 2;
620 msg->l2h = msgb_push(msg, addr_len);
621 msg->l2h[0] = LAPD_ADDR2(lctx->sapi, lctx->cr);
622 if (addr_len == 1)
623 msg->l2h[0] |= 0x1;
624 else
625 msg->l2h[1] = LAPD_ADDR3(lctx->tei);
626
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200627 /* write to PCAP file, if enabled. */
628 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
629
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200630 /* forward frame to L1 */
Harald Welteb9031882020-05-02 21:09:15 +0200631 LOGDL(dl, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200632 li->transmit_cb(msg, li->transmit_cbdata);
633
634 return 0;
635}
636
637/* A DL-SAP message is received from datalink instance and forwarded to L3 */
638static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
639{
640 struct lapd_datalink *dl = lctx->dl;
641 struct lapd_sap *sap =
642 container_of(dl, struct lapd_sap, dl);
643 struct lapd_instance *li;
644 uint8_t tei, sapi;
Pau Espin Pedrol6ffeb9a2020-07-15 15:27:16 +0200645 char *op = (dp->oph.operation == PRIM_OP_INDICATION) ? "indication"
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200646 : "confirm";
647
648 li = sap->tei->li;
649 tei = lctx->tei;
650 sapi = lctx->sapi;
651
652 switch (dp->oph.primitive) {
653 case PRIM_DL_EST:
Harald Welteb9031882020-05-02 21:09:15 +0200654 LOGDL(dl, LOGL_NOTICE, "LAPD DL-ESTABLISH %s TEI=%d "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200655 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
656 break;
657 case PRIM_DL_REL:
Harald Welteb9031882020-05-02 21:09:15 +0200658 LOGDL(dl, LOGL_NOTICE, "LAPD DL-RELEASE %s TEI=%d "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200659 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
660 lapd_sap_free(sap);
661 /* note: sap and dl is now gone, don't use it anymore */
662 break;
663 default:
664 ;
665 }
666
667 li->receive_cb(dp, tei, sapi, li->receive_cbdata);
668
669 return 0;
670}
671
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200672/* Allocate a new LAPD instance */
Harald Welteb9031882020-05-02 21:09:15 +0200673struct lapd_instance *lapd_instance_alloc2(int network_side,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200674 void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata,
Harald Welteb9031882020-05-02 21:09:15 +0200675 void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200676 void *rx_cbdata), void *rx_cbdata,
Harald Welteb9031882020-05-02 21:09:15 +0200677 const struct lapd_profile *profile, const char *name)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200678{
679 struct lapd_instance *li;
680
681 li = talloc_zero(NULL, struct lapd_instance);
682 if (!li)
683 return NULL;
684
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200685 li->network_side = network_side;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200686 li->transmit_cb = tx_cb;
687 li->transmit_cbdata = tx_cbdata;
688 li->receive_cb = rx_cb;
689 li->receive_cbdata = rx_cbdata;
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200690 li->pcap_fd = -1;
Harald Welteb9031882020-05-02 21:09:15 +0200691 li->name = talloc_strdup(li, name);
Andreas Eversberg3744b872011-09-27 12:12:36 +0200692 memcpy(&li->profile, profile, sizeof(li->profile));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200693
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200694 INIT_LLIST_HEAD(&li->tei_list);
695
696 return li;
697}
Harald Welte14078ea2011-08-24 09:45:11 +0200698
Harald Welteb9031882020-05-02 21:09:15 +0200699struct lapd_instance *lapd_instance_alloc(int network_side,
700 void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata,
701 void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi,
702 void *rx_cbdata), void *rx_cbdata,
703 const struct lapd_profile *profile)
704{
705 return lapd_instance_alloc2(network_side, tx_cbdata, tx_cb, rx_cb, rx_cbdata, profile, NULL);
706}
707
708
Philipp0c7d5f42016-10-19 18:38:58 +0200709/* Change lapd-profile on the fly (use with caution!) */
710void lapd_instance_set_profile(struct lapd_instance *li,
711 const struct lapd_profile *profile)
712{
713 memcpy(&li->profile, profile, sizeof(li->profile));
714}
715
Harald Welte14078ea2011-08-24 09:45:11 +0200716void lapd_instance_free(struct lapd_instance *li)
717{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200718 struct lapd_tei *teip, *teip2;
Harald Weltef350e252011-08-26 07:55:26 +0200719
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200720 /* Free all TEI instances */
721 llist_for_each_entry_safe(teip, teip2, &li->tei_list, list) {
722 lapd_tei_free(teip);
Harald Weltef350e252011-08-26 07:55:26 +0200723 }
724
Harald Welte14078ea2011-08-24 09:45:11 +0200725 talloc_free(li);
726}