blob: b71feef1c05eb58a2cdb1f728edd3bf814a90e45 [file] [log] [blame]
Harald Welte1f0b8c22011-06-27 10:51:37 +02001#ifndef _OSMOCOM_LAPDM_H
2#define _OSMOCOM_LAPDM_H
3
4#include <stdint.h>
5
6#include <osmocom/core/timer.h>
7#include <osmocom/core/msgb.h>
8#include <osmocom/gsm/prim.h>
9
Harald Welte6bdf0b12011-08-17 18:22:08 +020010/*! \defgroup lapdm LAPDm implementation according to GSM TS 04.06
11 * @{
12 */
13
14/*! \file lapdm.h */
15
Harald Welte1f0b8c22011-06-27 10:51:37 +020016/* primitive related sutff */
17
Harald Welte6bdf0b12011-08-17 18:22:08 +020018/*! \brief LAPDm related primitives */
Harald Welte1f0b8c22011-06-27 10:51:37 +020019enum osmo_ph_prim {
Harald Welte6bdf0b12011-08-17 18:22:08 +020020 PRIM_PH_DATA, /*!< \brief PH-DATA */
21 PRIM_PH_RACH, /*!< \brief PH-RANDOM_ACCESS */
22 PRIM_PH_CONN, /*!< \brief PH-CONNECT */
23 PRIM_PH_EMPTY_FRAME, /*!< \brief PH-EMPTY_FRAME */
24 PRIM_PH_RTS, /*!< \brief PH-RTS */
Harald Welte1f0b8c22011-06-27 10:51:37 +020025};
26
Harald Welte6bdf0b12011-08-17 18:22:08 +020027/*! \brief for PH-RANDOM_ACCESS.req */
Harald Welte1f0b8c22011-06-27 10:51:37 +020028struct ph_rach_req_param {
Harald Welte6bdf0b12011-08-17 18:22:08 +020029 uint8_t ra; /*!< \brief Random Access */
30 uint8_t ta; /*!< \brief Timing Advance */
31 uint8_t tx_power; /*!< \brief Transmit Power */
32 uint8_t is_combined_ccch;/*!< \brief Are we using a combined CCCH? */
33 uint16_t offset; /*!< \brief Timing Offset */
Harald Welte1f0b8c22011-06-27 10:51:37 +020034};
35
Harald Welte6bdf0b12011-08-17 18:22:08 +020036/*! \brief for PH-RANDOM_ACCESS.ind */
Harald Welte1f0b8c22011-06-27 10:51:37 +020037struct ph_rach_ind_param {
Harald Welte6bdf0b12011-08-17 18:22:08 +020038 uint8_t ra; /*!< \brief Random Access */
39 uint8_t acc_delay; /*!< \brief Delay in bit periods */
40 uint32_t fn; /*!< \brief GSM Frame Number at time of RA */
Harald Welte1f0b8c22011-06-27 10:51:37 +020041};
42
Harald Welte6bdf0b12011-08-17 18:22:08 +020043/*! \brief for PH-[UNIT]DATA.{req,ind} */
Harald Welte1f0b8c22011-06-27 10:51:37 +020044struct ph_data_param {
Harald Welte6bdf0b12011-08-17 18:22:08 +020045 uint8_t link_id; /*!< \brief Link Identifier (Like RSL) */
46 uint8_t chan_nr; /*!< \brief Channel Number (Like RSL) */
Harald Welte1f0b8c22011-06-27 10:51:37 +020047};
48
Harald Welte6bdf0b12011-08-17 18:22:08 +020049/*! \brief for PH-CONN.ind */
Harald Welte1f0b8c22011-06-27 10:51:37 +020050struct ph_conn_ind_param {
Harald Welte6bdf0b12011-08-17 18:22:08 +020051 uint32_t fn; /*!< \brief GSM Frame Number */
Harald Welte1f0b8c22011-06-27 10:51:37 +020052};
53
Harald Welte6bdf0b12011-08-17 18:22:08 +020054/*! \brief primitive header for LAPDm PH-SAP primitives */
Harald Welte1f0b8c22011-06-27 10:51:37 +020055struct osmo_phsap_prim {
Harald Welte6bdf0b12011-08-17 18:22:08 +020056 struct osmo_prim_hdr oph; /*!< \brief generic primitive header */
Harald Welte1f0b8c22011-06-27 10:51:37 +020057 union {
58 struct ph_data_param data;
59 struct ph_rach_req_param rach_req;
60 struct ph_rach_ind_param rach_ind;
61 struct ph_conn_ind_param conn_ind;
Harald Welte6bdf0b12011-08-17 18:22:08 +020062 } u; /*!< \brief request-specific data */
Harald Welte1f0b8c22011-06-27 10:51:37 +020063};
64
Harald Welte6bdf0b12011-08-17 18:22:08 +020065/*! \brief LAPDm mode/role */
Harald Welte1f0b8c22011-06-27 10:51:37 +020066enum lapdm_mode {
Harald Welte6bdf0b12011-08-17 18:22:08 +020067 LAPDM_MODE_MS, /*!< \brief behave like a MS (mobile phone) */
68 LAPDM_MODE_BTS, /*!< \brief behave like a BTS (network) */
Harald Welte1f0b8c22011-06-27 10:51:37 +020069};
70
Harald Welte6bdf0b12011-08-17 18:22:08 +020071/*! \brief LAPDm state */
Harald Welte1f0b8c22011-06-27 10:51:37 +020072enum lapdm_state {
73 LAPDm_STATE_NULL = 0,
74 LAPDm_STATE_IDLE,
75 LAPDm_STATE_SABM_SENT,
76 LAPDm_STATE_MF_EST,
77 LAPDm_STATE_TIMER_RECOV,
78 LAPDm_STATE_DISC_SENT,
79};
80
81struct lapdm_entity;
82
Harald Welte6bdf0b12011-08-17 18:22:08 +020083/*! \brief LAPDm message context */
Harald Welte1f0b8c22011-06-27 10:51:37 +020084struct lapdm_msg_ctx {
85 struct lapdm_datalink *dl;
86 int lapdm_fmt;
87 uint8_t n201;
88 uint8_t chan_nr;
89 uint8_t link_id;
90 uint8_t addr;
91 uint8_t ctrl;
92 uint8_t ta_ind;
93 uint8_t tx_power_ind;
94};
95
Harald Welte6bdf0b12011-08-17 18:22:08 +020096/*! \brief LAPDm datalink like TS 04.06 / Section 3.5.2 */
Harald Welte1f0b8c22011-06-27 10:51:37 +020097struct lapdm_datalink {
Harald Welte6bdf0b12011-08-17 18:22:08 +020098 uint8_t V_send; /*!< \brief seq nr of next I frame to be transmitted */
99 uint8_t V_ack; /*!< \brief last frame ACKed by peer */
100 uint8_t N_send; /*!< \brief ? set to V_send at Tx time*/
101 uint8_t V_recv; /*!< \brief seq nr of next I frame expected to be received */
102 uint8_t N_recv; /*!< \brief expected send seq nr of the next received I frame */
103 uint32_t state; /*!< \brief LAPDm state (\ref lapdm_state) */
104 int seq_err_cond; /*!< \brief condition of sequence error */
105 uint8_t own_busy; /*!< \brief receiver busy on our side */
106 uint8_t peer_busy; /*!< \brief receiver busy on remote side */
107 struct osmo_timer_list t200; /*!< \brief T200 timer */
108 uint8_t retrans_ctr; /*!< \brief re-transmission counter */
109 struct llist_head send_queue; /*!< \brief frames from L3 */
110 struct msgb *send_buffer; /*!< \brief current frame transmitting */
111 int send_out; /*!< \brief how much was sent from send_buffer */
112 uint8_t tx_hist[8][200]; /*!< \brief tx history buffer */
113 int tx_length[8]; /*!< \brief length in history buffer */
114 struct llist_head tx_queue; /*!< \brief frames to L1 */
115 struct lapdm_msg_ctx mctx; /*!< \brief context of established connection */
116 struct msgb *rcv_buffer; /*!< \brief buffer to assemble the received message */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200117
Harald Welte6bdf0b12011-08-17 18:22:08 +0200118 struct lapdm_entity *entity; /*!< \brief LAPDm entity we are part of */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200119};
120
Harald Welte6bdf0b12011-08-17 18:22:08 +0200121/*! \brief LAPDm datalink SAPIs */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200122enum lapdm_dl_sapi {
Harald Welte6bdf0b12011-08-17 18:22:08 +0200123 DL_SAPI0 = 0, /*!< \brief SAPI 0 */
124 DL_SAPI3 = 1, /*!< \brief SAPI 1 */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200125 _NR_DL_SAPI
126};
127
128typedef int (*lapdm_cb_t)(struct msgb *msg, struct lapdm_entity *le, void *ctx);
129
130struct lapdm_cr_ent {
131 uint8_t cmd;
132 uint8_t resp;
133};
134
135#define LAPDM_ENT_F_EMPTY_FRAME 0x0001
136#define LAPDM_ENT_F_POLLING_ONLY 0x0002
137
Harald Welte6bdf0b12011-08-17 18:22:08 +0200138/*! \brief a LAPDm Entity */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200139struct lapdm_entity {
Harald Welte6bdf0b12011-08-17 18:22:08 +0200140 /*! \brief the SAPIs of the LAPDm entity */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200141 struct lapdm_datalink datalink[_NR_DL_SAPI];
Harald Welte6bdf0b12011-08-17 18:22:08 +0200142 int last_tx_dequeue; /*!< \brief last entity that was dequeued */
143 int tx_pending; /*!< \brief currently a pending frame not confirmed by L1 */
144 enum lapdm_mode mode; /*!< \brief are we in BTS mode or MS mode */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200145 unsigned int flags;
146
147 struct {
Harald Welte6bdf0b12011-08-17 18:22:08 +0200148 /*! \brief filled-in once we set the lapdm_mode above */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200149 struct lapdm_cr_ent loc2rem;
150 struct lapdm_cr_ent rem2loc;
151 } cr;
152
Harald Welte6bdf0b12011-08-17 18:22:08 +0200153 void *l1_ctx; /*!< \brief context for layer1 instance */
154 void *l3_ctx; /*!< \brief context for layer3 instance */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200155
Harald Welte6bdf0b12011-08-17 18:22:08 +0200156 osmo_prim_cb l1_prim_cb;/*!< \brief callback for sending prims to L1 */
157 lapdm_cb_t l3_cb; /*!< \brief callback for sending stuff to L3 */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200158
Harald Welte6bdf0b12011-08-17 18:22:08 +0200159 /*! \brief pointer to \ref lapdm_channel of which we're part */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200160 struct lapdm_channel *lapdm_ch;
161};
162
Harald Welte6bdf0b12011-08-17 18:22:08 +0200163/*! \brief the two lapdm_entities that form a GSM logical channel (ACCH + DCCH) */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200164struct lapdm_channel {
Harald Welte6bdf0b12011-08-17 18:22:08 +0200165 struct llist_head list; /*!< \brief internal linked list */
166 char *name; /*!< \brief human-readable name */
167 struct lapdm_entity lapdm_acch; /*!< \brief Associated Control Channel */
168 struct lapdm_entity lapdm_dcch; /*!< \brief Dedicated Control Channel */
Harald Welte1f0b8c22011-06-27 10:51:37 +0200169};
170
171const char *get_rsl_name(int value);
172extern const char *lapdm_state_names[];
173
174/* initialize a LAPDm entity */
175void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode);
176void lapdm_channel_init(struct lapdm_channel *lc, enum lapdm_mode mode);
177
178/* deinitialize a LAPDm entity */
179void lapdm_entity_exit(struct lapdm_entity *le);
180void lapdm_channel_exit(struct lapdm_channel *lc);
181
182/* input into layer2 (from layer 1) */
183int lapdm_phsap_up(struct osmo_prim_hdr *oph, struct lapdm_entity *le);
184
185/* input into layer2 (from layer 3) */
186int lapdm_rslms_recvmsg(struct msgb *msg, struct lapdm_channel *lc);
187
188void lapdm_channel_set_l3(struct lapdm_channel *lc, lapdm_cb_t cb, void *ctx);
189void lapdm_channel_set_l1(struct lapdm_channel *lc, osmo_prim_cb cb, void *ctx);
190
191int lapdm_entity_set_mode(struct lapdm_entity *le, enum lapdm_mode mode);
192int lapdm_channel_set_mode(struct lapdm_channel *lc, enum lapdm_mode mode);
193
194void lapdm_entity_reset(struct lapdm_entity *le);
195void lapdm_channel_reset(struct lapdm_channel *lc);
196
197void lapdm_entity_set_flags(struct lapdm_entity *le, unsigned int flags);
198void lapdm_channel_set_flags(struct lapdm_channel *lc, unsigned int flags);
199
200int lapdm_phsap_dequeue_prim(struct lapdm_entity *le, struct osmo_phsap_prim *pp);
201
Harald Welte6bdf0b12011-08-17 18:22:08 +0200202/*! }@ */
203
Harald Welte1f0b8c22011-06-27 10:51:37 +0200204#endif /* _OSMOCOM_LAPDM_H */