libosmo-gprs/include/osmocom/gprs/llc/llc_private.h

391 lines
12 KiB
C

#pragma once
/* 3GPP TS 44.064, private header */
#include <stdint.h>
#include <stddef.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/msgb.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/gprs/llc/llc_prim.h>
#include <osmocom/gprs/llc/llc.h>
extern int g_llc_log_cat[_OSMO_GPRS_LLC_LOGC_MAX];
#define LOGLLC(lvl, fmt, args...) LOGP(g_llc_log_cat[OSMO_GPRS_LLC_LOGC_LLC], lvl, fmt, ## args)
#define GPRS_LLME_RESET_AGE (0)
/* 3GPP TS 44.064 § 8.3 TLLI assignment procedures */
#define TLLI_UNASSIGNED (0xffffffff)
/* GSM 04.08 - 10.5.1.2 */
#define GSM_KEY_SEQ_INVAL 7
#define CRC24_LENGTH 3
#define UI_HDR_LEN 3
#define N202 4
#define msgb_llc_prim(msg) ((struct osmo_gprs_llc_prim *)(msg)->l1h)
/* Section 6.3.0 Control field formats */
enum gprs_llc_frame_fmt {
OSMO_GPRS_LLC_FMT_I, /* 6.3.1 Information transfer format - I */
OSMO_GPRS_LLC_FMT_S, /* 6.3.2 Supervisory format - S */
OSMO_GPRS_LLC_FMT_UI, /* 6.3.3 Unconfirmed Information format - UI */
OSMO_GPRS_LLC_FMT_U, /* 6.3.4 Unnumbered format - U */
};
extern const struct value_string gprs_llc_frame_fmt_names[];
static inline const char *gprs_llc_frame_fmt_name(enum gprs_llc_frame_fmt val)
{
return get_value_string(gprs_llc_frame_fmt_names, val);
}
/* Section 6.4 Commands and responses */
enum gprs_llc_frame_func {
/* 6.4.1 Unnumbered (U) frames */
OSMO_GPRS_LLC_FUNC_SABM, /* 6.4.1.1 */
OSMO_GPRS_LLC_FUNC_DISC, /* 6.4.1.2 */
OSMO_GPRS_LLC_FUNC_UA, /* 6.4.1.3 */
OSMO_GPRS_LLC_FUNC_DM, /* 6.4.1.4 */
OSMO_GPRS_LLC_FUNC_FRMR, /* 6.4.1.5 */
OSMO_GPRS_LLC_FUNC_XID, /* 6.4.1.6 */
OSMO_GPRS_LLC_FUNC_NULL, /* 6.4.1.7 */
/* 6.4.2 Unconfirmed Information (UI) frame */
OSMO_GPRS_LLC_FUNC_UI, /* 6.4.2.1 */
OSMO_GPRS_LLC_FUNC_UI_DUMMY, /* 6.4.2.2 */
/* 6.4.3 Combined Information (I) and Supervisory (S) frames */
OSMO_GPRS_LLC_FUNC_RR, /* 6.4.3.1 */
OSMO_GPRS_LLC_FUNC_ACK, /* 6.4.3.2 */
OSMO_GPRS_LLC_FUNC_SACK, /* 6.4.3.3 */
OSMO_GPRS_LLC_FUNC_RNR, /* 6.4.3.4 */
};
extern const struct value_string gprs_llc_frame_func_names[];
static inline const char *gprs_llc_frame_func_name(enum gprs_llc_frame_func val)
{
return get_value_string(gprs_llc_frame_func_names, val);
}
/* Section 6.4.1.6 / Table 6 */
enum gprs_llc_xid_type {
OSMO_GPRS_LLC_XID_T_VERSION = 0,
OSMO_GPRS_LLC_XID_T_IOV_UI = 1,
OSMO_GPRS_LLC_XID_T_IOV_I = 2,
OSMO_GPRS_LLC_XID_T_T200 = 3,
OSMO_GPRS_LLC_XID_T_N200 = 4,
OSMO_GPRS_LLC_XID_T_N201_U = 5,
OSMO_GPRS_LLC_XID_T_N201_I = 6,
OSMO_GPRS_LLC_XID_T_mD = 7,
OSMO_GPRS_LLC_XID_T_mU = 8,
OSMO_GPRS_LLC_XID_T_kD = 9,
OSMO_GPRS_LLC_XID_T_kU = 10,
OSMO_GPRS_LLC_XID_T_L3_PAR = 11,
OSMO_GPRS_LLC_XID_T_RESET = 12,
OSMO_GPRS_LLC_XID_T_IIOV_UI = 13,
OSMO_GPRS_LLC_XID_T_IIOV_UI_CNT = 14,
OSMO_GPRS_LLC_XID_T_MAC_IOV_UI = 15,
};
extern const struct value_string gprs_llc_xid_type_names[];
static inline const char *gprs_llc_xid_type_name(enum gprs_llc_xid_type val)
{
return get_value_string(gprs_llc_xid_type_names, val);
}
struct gprs_llc_xid_field {
enum gprs_llc_xid_type type;
/* Fixed-length value */
uint32_t val;
/* Variable-length value */
struct {
uint8_t *val;
uint8_t val_len;
} var;
};
/* Section 4.5.2 Logical Link States + Annex C.2 */
enum gprs_llc_lle_state {
OSMO_GPRS_LLC_LLES_UNASSIGNED = 1, /* No TLLI yet */
OSMO_GPRS_LLC_LLES_ASSIGNED_ADM = 2, /* TLLI assigned */
OSMO_GPRS_LLC_LLES_LOCAL_EST = 3, /* Local Establishment */
OSMO_GPRS_LLC_LLES_REMOTE_EST = 4, /* Remote Establishment */
OSMO_GPRS_LLC_LLES_ABM = 5,
OSMO_GPRS_LLC_LLES_LOCAL_REL = 6, /* Local Release */
OSMO_GPRS_LLC_LLES_TIMER_REC = 7, /* Timer Recovery */
};
extern const struct value_string gprs_llc_lle_state_names[];
static inline const char *gprs_llc_lle_state_name(enum gprs_llc_lle_state val)
{
return get_value_string(gprs_llc_lle_state_names, val);
}
enum gprs_llc_llme_state {
OSMO_GPRS_LLC_LLMS_UNASSIGNED = 1, /* No TLLI yet */
OSMO_GPRS_LLC_LLMS_ASSIGNED = 2, /* TLLI assigned */
};
extern const struct value_string gprs_llc_llme_state_names[];
static inline const char *gprs_llc_llme_state_name(enum gprs_llc_llme_state val)
{
return get_value_string(gprs_llc_llme_state_names, val);
}
/* Section 8.9.9 LLC layer parameter default values */
struct gprs_llc_params {
uint16_t iov_i_exp;
uint16_t t200_201;
uint16_t n200;
uint16_t n201_u;
uint16_t n201_i;
uint16_t mD;
uint16_t mU;
uint16_t kD;
uint16_t kU;
};
#define OSMO_GPRS_LLC_PDU_F_CMD_RSP (1 << 0) /* 6.2.2 Commmand/Response bit (C/R) */
#define OSMO_GPRS_LLC_PDU_F_FOLL_FIN (1 << 1) /* 6.3.5.1 Poll/Final bit (P/F) */
#define OSMO_GPRS_LLC_PDU_F_ACK_REQ (1 << 2) /* 6.3.5.2 Acknowledgement request bit (A) */
#define OSMO_GPRS_LLC_PDU_F_MAC_PRES (1 << 3) /* 6.3.5.2a Integrity Protection bit (IP) */
#define OSMO_GPRS_LLC_PDU_F_ENC_MODE (1 << 4) /* 6.3.5.5.1 Encryption mode bit (E) */
#define OSMO_GPRS_LLC_PDU_F_PROT_MODE (1 << 5) /* 6.3.5.5.2 Protected Mode bit (PM) */
struct gprs_llc_pdu_decoded {
enum osmo_gprs_llc_sapi sapi;
enum gprs_llc_frame_fmt fmt;
enum gprs_llc_frame_func func;
uint32_t flags; /* see OSMO_GPRS_LLC_PDU_F_* above */
uint32_t seq_rx; /* 6.3.5.4.5 Receive sequence number N(R) */
uint32_t seq_tx; /* 6.3.5.4.3 Send sequence number N(S) */
uint32_t fcs; /* 5.5 Frame Check Sequence (FCS) field */
uint32_t mac; /* 5.5a Message Authentication Code (MAC) field */
struct {
uint8_t len; /* Indicates the number of octets in the bitmap */
uint8_t r[32]; /* The R(n) bitmap */
} sack; /* 6.3.5.4.6 SACK bitmap R(n) */
size_t data_len;
uint8_t *data;
};
struct gprs_llc_llme;
/* 3GPP TS 44.064 § 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */
struct gprs_llc_lle {
struct llist_head list;
uint32_t sapi;
struct gprs_llc_llme *llme; /* backpointer to the Logical Link Management Entity */
enum gprs_llc_lle_state state;
struct osmo_timer_list t200;
struct osmo_timer_list t201; /* wait for acknowledgement */
uint16_t v_sent;
uint16_t v_ack;
uint16_t v_recv;
uint16_t vu_send;
uint16_t vu_recv;
/* non-standard LLC state */
uint16_t vu_recv_last;
uint16_t vu_recv_duplicates;
/* Overflow Counter for ABM */
uint32_t oc_i_send;
uint32_t oc_i_recv;
/* Overflow Counter for unconfirmed transfer */
uint32_t oc_ui_send;
uint32_t oc_ui_recv;
unsigned int retrans_ctr;
struct gprs_llc_params params;
/* Copy of the XID fields array we have sent with the last
* network originated XID-Request. Since the phone
* may strip the optional fields in the confirmation
* we need to remeber those fields in order to be
* able to create the compression entity. */
struct gprs_llc_xid_field *xid;
unsigned int xid_len;
/* Copy of last XID-Request fields array received from the peer: We need
to remember it to be able to send an Xid-Response back when SNDCP
provides us with layer3 XID field */
struct gprs_llc_xid_field *rx_xid;
unsigned int rx_xid_len;
};
#define NUM_SAPIS 16
/* 3GPP TS 44.064 § 4.7.3: Logical Link Management Entity: One per TLLI */
struct gprs_llc_llme {
struct llist_head list;
enum gprs_llc_llme_state state;
uint32_t tlli;
uint32_t old_tlli;
/* Crypto parameters */
enum gprs_ciph_algo algo;
uint8_t kc[16];
uint8_t cksn;
/* 3GPP TS 44.064 § 8.9.2: */
uint32_t iov_ui;
/* over which BSSGP BTS ctx do we need to transmit */
uint16_t bvci;
uint16_t nsei;
struct gprs_llc_lle lle[NUM_SAPIS];
/* Internal management */
uint32_t age_timestamp;
};
static inline struct gprs_llc_lle *gprs_llc_llme_get_lle(struct gprs_llc_llme *llme,
enum osmo_gprs_llc_sapi sapi) {
OSMO_ASSERT(sapi < NUM_SAPIS);
return &llme->lle[sapi];
}
struct gprs_llc_ctx {
enum osmo_gprs_llc_location location;
osmo_gprs_llc_prim_up_cb llc_up_cb;
void *llc_up_cb_user_data;
osmo_gprs_llc_prim_down_cb llc_down_cb;
void *llc_down_cb_user_data;
struct llist_head llme_list;
};
extern struct gprs_llc_ctx *g_ctx;
/* llc_bssgp.c */
int gprs_llc_prim_lower_up_bssgp(struct osmo_gprs_llc_prim *llc_prim);
struct osmo_gprs_llc_prim *gprs_llc_prim_alloc_bssgp_dl_unitdata_req(
uint32_t tlli, uint8_t *ll_pdu, size_t ll_pdu_len);
/* llc_grr.c */
int gprs_llc_prim_lower_up_grr(struct osmo_gprs_llc_prim *llc_prim);
/* llc_ll.c */
int gprs_llc_prim_ll_upper_down(struct osmo_gprs_llc_prim *llc_prim);
struct osmo_gprs_llc_prim *gprs_llc_prim_alloc_ll_xid_ind(uint32_t tlli, enum osmo_gprs_llc_sapi ll_sapi,
uint8_t *l3_par, unsigned int l3_par_len);
struct osmo_gprs_llc_prim *gprs_llc_prim_alloc_ll_xid_cnf(uint32_t tlli, enum osmo_gprs_llc_sapi ll_sapi,
uint8_t *l3_par, unsigned int l3_par_len);
struct osmo_gprs_llc_prim *gprs_llc_prim_alloc_ll_unitdata_ind(
uint32_t tlli, enum osmo_gprs_llc_sapi ll_sapi,
uint8_t *l3_pdu, size_t l3_pdu_len);
int gprs_llc_lle_submit_prim_ll_xid_ind(struct gprs_llc_lle *lle,
const struct gprs_llc_xid_field *xid_field_request_l3);
int gprs_llc_lle_submit_prim_ll_xid_cnf(struct gprs_llc_lle *lle,
const struct gprs_llc_xid_field *xid_field_response_l3,
const struct gprs_llc_xid_field *xid_field_request_l3);
/* llc_llgmm.c */
int gprs_llc_prim_llgmm_upper_down(struct osmo_gprs_llc_prim *llc_prim);
/* llc.c */
struct gprs_llc_llme *gprs_llc_llme_alloc(uint32_t tlli);
struct gprs_llc_llme *gprs_llc_find_llme_by_tlli(uint32_t tlli);
struct gprs_llc_lle *gprs_llc_find_lle_by_tlli_sapi(uint32_t tlli, uint8_t sapi);
struct gprs_llc_lle *gprs_llc_lle_for_rx_by_tlli_sapi(const uint32_t tlli,
uint8_t sapi, enum gprs_llc_frame_func cmd);
int gprs_llc_lle_hdr_rx(struct gprs_llc_lle *lle, struct gprs_llc_pdu_decoded *pdu_dec);
void gprs_llc_llme_free(struct gprs_llc_llme *llme);
int gprs_llc_lle_tx_xid(const struct gprs_llc_lle *lle, uint8_t *xid_payload, unsigned int xid_payload_len, bool is_cmd);
int gprs_llc_lle_tx_xid_req(struct gprs_llc_lle *lle, uint8_t *l3par, unsigned int l3par_len);
int gprs_llc_lle_tx_xid_resp(struct gprs_llc_lle *lle, uint8_t *l3par, unsigned int l3par_len);
int gprs_llc_lle_tx_ui(struct gprs_llc_lle *lle, uint8_t *l3_pdu, size_t l3_pdu_len, bool encryptable);
/* llc_prim.c: */
struct osmo_gprs_llc_prim *gprs_llc_prim_alloc(enum osmo_gprs_llc_prim_sap sap, unsigned int type,
enum osmo_prim_operation operation,
unsigned int l3_len);
int gprs_llc_prim_handle_unsupported(struct osmo_gprs_llc_prim *llc_prim);
int gprs_llc_prim_call_down_cb(struct osmo_gprs_llc_prim *llc_prim);
int gprs_llc_prim_call_up_cb(struct osmo_gprs_llc_prim *llc_prim);
/* llc_xid.c: */
bool gprs_llc_xid_field_is_valid(const struct gprs_llc_xid_field *field);
int gprs_llc_xid_decode(struct gprs_llc_xid_field *fields,
unsigned int max_fields,
uint8_t *data, size_t data_len);
int gprs_llc_xid_encode(uint8_t *data, size_t data_len,
const struct gprs_llc_xid_field *fields,
unsigned int num_fields);
struct gprs_llc_xid_field *gprs_llc_xid_deepcopy(void *ctx,
const struct gprs_llc_xid_field *src_xid,
size_t src_xid_len);
/* llc_pdu.c: */
int gprs_llc_pdu_decode(struct gprs_llc_pdu_decoded *pdu,
uint8_t *data, size_t data_len);
int gprs_llc_pdu_encode(struct msgb *msg, const struct gprs_llc_pdu_decoded *pdu);
void gprs_llc_pdu_hdr_dump_buf(char *buf, size_t buf_size,
const struct gprs_llc_pdu_decoded *pdu);
const char *gprs_llc_pdu_hdr_dump(const struct gprs_llc_pdu_decoded *pdu);
uint32_t gprs_llc_fcs(const uint8_t *data, size_t len);
/**
* \short Check if N(U) should be considered a retransmit
*
* Implements the range check as of GSM 04.64 8.4.2
* Receipt of unacknowledged information.
*
* @returns Returns 1 if (V(UR)-32) <= N(U) < V(UR)
* @param nu N(U) unconfirmed sequence number of the UI frame
* @param vur V(UR) unconfirmend received state variable
*/
static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
{
int delta = (vur - nu) & 0x1ff;
return 0 < delta && delta < 32;
}
/* 6.2.2 Command/Response bit (C/R) */
static inline bool gprs_llc_received_cr_is_cmd(uint8_t cr)
{
if (g_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN)
return !cr; /*received from MS */
else
return !!cr; /*received from SGSN */
}
static inline void gprs_llc_encode_is_cmd_as_cr(bool is_cmd, uint32_t *flags)
{
if (g_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN)
*flags |= OSMO_GPRS_LLC_PDU_F_CMD_RSP; /*Transmit to MS */
else
*flags &= ~OSMO_GPRS_LLC_PDU_F_CMD_RSP; /* Transmit to SGSN */
}
#define LOGLLME(llme, level, fmt, args...) \
LOGLLC(level, "LLME(%08x/%08x){%s} " fmt, (llme)->old_tlli, \
(llme)->tlli, gprs_llc_llme_state_name((llme)->state), ## args)
#define LOGLLE(lle, level, fmt, args...) \
LOGLLC(level, "LLE(%08x/%08x,%s){%s} " fmt, \
(lle)->llme->old_tlli, (lle)->llme->tlli, \
osmo_gprs_llc_sapi_name((lle)->sapi), \
gprs_llc_lle_state_name((lle)->state), ## args)