diff options
Diffstat (limited to 'src/shared/libosmocore')
31 files changed, 754 insertions, 259 deletions
diff --git a/src/shared/libosmocore/.gitignore b/src/shared/libosmocore/.gitignore index fe022875..82e43e3a 100644 --- a/src/shared/libosmocore/.gitignore +++ b/src/shared/libosmocore/.gitignore @@ -53,6 +53,7 @@ tests/a5/a5_test tests/auth/milenage_test tests/conv/conv_test tests/lapd/lapd_test +tests/gsm0808/gsm0808_test utils/osmo-arfcn utils/osmo-auc-gen diff --git a/src/shared/libosmocore/configure.ac b/src/shared/libosmocore/configure.ac index c38d82f4..0fea115f 100644 --- a/src/shared/libosmocore/configure.ac +++ b/src/shared/libosmocore/configure.ac @@ -1,6 +1,6 @@ AC_INIT([libosmocore], m4_esyscmd([./git-version-gen .tarball-version]), - [openbsc-devel@lists.openbsc.org]) + [openbsc@lists.osmocom.org]) AM_INIT_AUTOMAKE([dist-bzip2]) AC_CONFIG_TESTDIR(tests) @@ -168,6 +168,7 @@ AC_OUTPUT( tests/auth/Makefile tests/conv/Makefile tests/lapd/Makefile + tests/gsm0808/Makefile utils/Makefile Doxyfile.core Doxyfile.gsm diff --git a/src/shared/libosmocore/include/osmocom/core/gsmtap.h b/src/shared/libosmocore/include/osmocom/core/gsmtap.h index dbc3d314..a4e5d420 100644 --- a/src/shared/libosmocore/include/osmocom/core/gsmtap.h +++ b/src/shared/libosmocore/include/osmocom/core/gsmtap.h @@ -77,11 +77,19 @@ #define GSMTAP_CHANNEL_SDCCH8 0x08 #define GSMTAP_CHANNEL_TCH_F 0x09 #define GSMTAP_CHANNEL_TCH_H 0x0a -#define GSMTAP_CHANNEL_CBCH51 0x0b +#define GSMTAP_CHANNEL_PACCH 0x0b #define GSMTAP_CHANNEL_CBCH52 0x0c #define GSMTAP_CHANNEL_PDCH 0x0d #define GSMTAP_CHANNEL_PTCCH 0x0e -#define GSMTAP_CHANNEL_PACCH 0x0f +#define GSMTAP_CHANNEL_CBCH51 0x0f + +/* GPRS Coding Scheme CS1..4 */ +#define GSMTAP_GPRS_CS_BASE 0x20 +#define GSMTAP_GPRS_CS(N) (GSMTAP_GPRS_CS_BASE + N) +/* (E) GPRS Coding Scheme MCS0..9 */ +#define GSMTAP_GPRS_MCS_BASE 0x30 +#define GSMTAP_GPRS_MCS(N) (GSMTAP_GPRS_MCS_BASE + N) + #define GSMTAP_CHANNEL_ACCH 0x80 /* ====== DO NOT MAKE UNAPPROVED MODIFICATIONS HERE ===== */ diff --git a/src/shared/libosmocore/include/osmocom/core/msgb.h b/src/shared/libosmocore/include/osmocom/core/msgb.h index 9f46e6c6..e465ec2b 100644 --- a/src/shared/libosmocore/include/osmocom/core/msgb.h +++ b/src/shared/libosmocore/include/osmocom/core/msgb.h @@ -312,6 +312,32 @@ static inline void msgb_reserve(struct msgb *msg, int len) msg->tail += len; } +/*! \brief Trim the msgb to a given absolute length + * \param[in] msg message buffer + * \param[in] len new total length of buffer + * \returns 0 in case of success, negative in case of error + */ +static inline int msgb_trim(struct msgb *msg, int len) +{ + if (len > msg->data_len) + return -1; + + msg->len = len; + msg->tail = msg->data + len; + + return 0; +} + +/*! \brief Trim the msgb to a given layer3 length + * \pram[in] msg message buffer + * \param[in] l3len new layer3 length + * \returns 0 in case of success, negative in case of error + */ +static inline int msgb_l3trim(struct msgb *msg, int l3len) +{ + return msgb_trim(msg, (msg->l3h - msg->data) + l3len); +} + /*! \brief Allocate message buffer with specified headroom * \param[in] size size in bytes, including headroom * \param[in] headroom headroom in bytes diff --git a/src/shared/libosmocore/include/osmocom/core/socket.h b/src/shared/libosmocore/include/osmocom/core/socket.h index c5288dfc..88214632 100644 --- a/src/shared/libosmocore/include/osmocom/core/socket.h +++ b/src/shared/libosmocore/include/osmocom/core/socket.h @@ -12,6 +12,7 @@ #include <stdint.h> struct sockaddr; +struct osmo_fd; /* flags for osmo_sock_init. */ #define OSMO_SOCK_F_CONNECT (1 << 0) diff --git a/src/shared/libosmocore/include/osmocom/crypt/auth.h b/src/shared/libosmocore/include/osmocom/crypt/auth.h index 30e16e82..67b32009 100644 --- a/src/shared/libosmocore/include/osmocom/crypt/auth.h +++ b/src/shared/libosmocore/include/osmocom/crypt/auth.h @@ -33,6 +33,7 @@ struct osmo_sub_auth_data { uint8_t k[16]; uint8_t amf[2]; uint64_t sqn; + int opc_is_op; } umts; struct { uint8_t ki[16]; diff --git a/src/shared/libosmocore/include/osmocom/gsm/gsm0808.h b/src/shared/libosmocore/include/osmocom/gsm/gsm0808.h index 38d88ef9..5380dd9e 100644 --- a/src/shared/libosmocore/include/osmocom/gsm/gsm0808.h +++ b/src/shared/libosmocore/include/osmocom/gsm/gsm0808.h @@ -30,7 +30,8 @@ struct msgb *gsm0808_create_clear_command(uint8_t reason); struct msgb *gsm0808_create_clear_complete(void); struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id); struct msgb *gsm0808_create_cipher_reject(uint8_t cause); -struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark, uint8_t length); +struct msgb *gsm0808_create_classmark_update(const uint8_t *cm2, uint8_t cm2_len, + const uint8_t *cm3, uint8_t cm3_len); struct msgb *gsm0808_create_sapi_reject(uint8_t link_id); struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause, uint8_t chosen_channel, uint8_t encr_alg_id, diff --git a/src/shared/libosmocore/include/osmocom/gsm/gsm48_ie.h b/src/shared/libosmocore/include/osmocom/gsm/gsm48_ie.h index f4fce25c..2e576429 100644 --- a/src/shared/libosmocore/include/osmocom/gsm/gsm48_ie.h +++ b/src/shared/libosmocore/include/osmocom/gsm/gsm48_ie.h @@ -108,7 +108,7 @@ int gsm48_encode_more(struct msgb *msg); struct gsm_sysinfo_freq { /* if the frequency included in the sysinfo */ uint8_t mask; -}; +} __attribute__ ((packed)); /* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */ int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, diff --git a/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h b/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h index ce780926..eecc27ce 100644 --- a/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h +++ b/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h @@ -213,15 +213,15 @@ struct gsm48_chan_desc { tsc:3; uint8_t hsn:6, maio_low:2; - } h1; + } __attribute__ ((packed)) h1; struct { uint8_t arfcn_high:2, spare:2, h:1, tsc:3; uint8_t arfcn_low; - } h0; - }; + } __attribute__ ((packed)) h0; + } __attribute__ ((packed)); } __attribute__ ((packed)); /* Chapter 10.5.2.20 */ diff --git a/src/shared/libosmocore/include/osmocom/gsm/tlv.h b/src/shared/libosmocore/include/osmocom/gsm/tlv.h index 7b41d2d7..d2936d6d 100644 --- a/src/shared/libosmocore/include/osmocom/gsm/tlv.h +++ b/src/shared/libosmocore/include/osmocom/gsm/tlv.h @@ -178,28 +178,32 @@ static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag, return buf; } -/*! \brief put (append) a LV field to a \ref msgb */ +/*! \brief put (append) a LV field to a \ref msgb + * \returns pointer to first byte after newly-put information */ static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val) { uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len)); return lv_put(buf, len, val); } -/*! \brief put (append) a TLV field to a \ref msgb */ +/*! \brief put (append) a TLV field to a \ref msgb + * \returns pointer to first byte after newly-put information */ static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val) { uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len)); return tlv_put(buf, tag, len, val); } -/*! \brief put (append) a TV field to a \ref msgb */ +/*! \brief put (append) a TV field to a \ref msgb + * \returns pointer to first byte after newly-put information */ static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val) { uint8_t *buf = msgb_put(msg, 2); return tv_put(buf, tag, val); } -/*! \brief put (append) a TVfixed field to a \ref msgb */ +/*! \brief put (append) a TVfixed field to a \ref msgb + * \returns pointer to first byte after newly-put information */ static inline uint8_t *msgb_tv_fixed_put(struct msgb *msg, uint8_t tag, unsigned int len, const uint8_t *val) { @@ -207,47 +211,57 @@ static inline uint8_t *msgb_tv_fixed_put(struct msgb *msg, uint8_t tag, return tv_fixed_put(buf, tag, len, val); } -/*! \brief put (append) a V field to a \ref msgb */ +/*! \brief put (append) a V field to a \ref msgb + * \returns pointer to first byte after newly-put information */ static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val) { uint8_t *buf = msgb_put(msg, 1); return v_put(buf, val); } -/*! \brief put (append) a TV16 field to a \ref msgb */ +/*! \brief put (append) a TV16 field to a \ref msgb + * \returns pointer to first byte after newly-put information */ static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val) { uint8_t *buf = msgb_put(msg, 3); return tv16_put(buf, tag, val); } -/*! \brief push (prepend) a TLV field to a \ref msgb */ +/*! \brief push (prepend) a TLV field to a \ref msgb + * \returns pointer to first byte of newly-pushed information */ static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val) { uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len)); - return tlv_put(buf, tag, len, val); + tlv_put(buf, tag, len, val); + return buf; } -/*! \brief push (prepend) a TV field to a \ref msgb */ +/*! \brief push (prepend) a TV field to a \ref msgb + * \returns pointer to first byte of newly-pushed information */ static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val) { uint8_t *buf = msgb_push(msg, 2); - return tv_put(buf, tag, val); + tv_put(buf, tag, val); + return buf; } -/*! \brief push (prepend) a TV16 field to a \ref msgb */ +/*! \brief push (prepend) a TV16 field to a \ref msgb + * \returns pointer to first byte of newly-pushed information */ static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val) { uint8_t *buf = msgb_push(msg, 3); - return tv16_put(buf, tag, val); + tv16_put(buf, tag, val); + return buf; } -/*! \brief push (prepend) a TvLV field to a \ref msgb */ +/*! \brief push (prepend) a TvLV field to a \ref msgb + * \returns pointer to first byte of newly-pushed information */ static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len, const uint8_t *val) { uint8_t *buf = msgb_push(msg, TVLV_GROSS_LEN(len)); - return tvlv_put(buf, tag, len, val); + tvlv_put(buf, tag, len, val); + return buf; } /* TLV parsing */ diff --git a/src/shared/libosmocore/include/osmocom/vty/misc.h b/src/shared/libosmocore/include/osmocom/vty/misc.h index 707f82fa..89234733 100644 --- a/src/shared/libosmocore/include/osmocom/vty/misc.h +++ b/src/shared/libosmocore/include/osmocom/vty/misc.h @@ -7,4 +7,7 @@ void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, struct rate_ctr_group *ctrg); +int osmo_vty_write_config_file(const char *filename); +int osmo_vty_save_config_file(void); + #endif diff --git a/src/shared/libosmocore/include/osmocom/vty/telnet_interface.h b/src/shared/libosmocore/include/osmocom/vty/telnet_interface.h index 2de4f192..65a1dd90 100644 --- a/src/shared/libosmocore/include/osmocom/vty/telnet_interface.h +++ b/src/shared/libosmocore/include/osmocom/vty/telnet_interface.h @@ -47,6 +47,7 @@ struct telnet_connection { }; int telnet_init(void *tall_ctx, void *priv, int port); +int telnet_init_dynif(void *tall_ctx, void *priv, const char *ip, int port); void telnet_exit(void); diff --git a/src/shared/libosmocore/src/gsm/a5.c b/src/shared/libosmocore/src/gsm/a5.c index e330c759..34f271a8 100644 --- a/src/shared/libosmocore/src/gsm/a5.c +++ b/src/shared/libosmocore/src/gsm/a5.c @@ -89,10 +89,10 @@ osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) #define A5_R3_MASK ((1<<A5_R3_LEN)-1) #define A5_R4_MASK ((1<<A5_R4_LEN)-1) -#define A5_R1_TAPS 0x072000 /* x^19 + x^5 + x^2 + x + 1 */ -#define A5_R2_TAPS 0x300000 /* x^22 + x + 1 */ -#define A5_R3_TAPS 0x700080 /* x^23 + x^15 + x^2 + x + 1 */ -#define A5_R4_TAPS 0x010800 /* x^17 + x^5 + 1 */ +#define A5_R1_TAPS 0x072000 /* x^19 + x^18 + x^17 + x^14 + 1 */ +#define A5_R2_TAPS 0x300000 /* x^22 + x^21 + 1 */ +#define A5_R3_TAPS 0x700080 /* x^23 + x^22 + x^21 + x^8 + 1 */ +#define A5_R4_TAPS 0x010800 /* x^17 + x^12 + 1 */ /*! \brief Computes parity of a 32-bit word * \param[in] x 32 bit word diff --git a/src/shared/libosmocore/src/gsm/auth_milenage.c b/src/shared/libosmocore/src/gsm/auth_milenage.c index 2a9ba334..5b2787dd 100644 --- a/src/shared/libosmocore/src/gsm/auth_milenage.c +++ b/src/shared/libosmocore/src/gsm/auth_milenage.c @@ -83,10 +83,21 @@ static int milenage_gen_vec_auts(struct osmo_auth_vector *vec, const uint8_t *_rand) { uint8_t sqn_out[6]; + uint8_t gen_opc[16]; + uint8_t *opc; int rc; - rc = milenage_auts(aud->u.umts.opc, aud->u.umts.k, - rand_auts, auts, sqn_out); + /* Check if we only know OP and compute OPC if required */ + if (aud->type == OSMO_AUTH_TYPE_UMTS && aud->u.umts.opc_is_op) { + rc = milenage_opc_gen(gen_opc, aud->u.umts.k, + aud->u.umts.opc); + if (rc < 0) + return rc; + opc = gen_opc; + } else + opc = aud->u.umts.opc; + + rc = milenage_auts(opc, aud->u.umts.k, rand_auts, auts, sqn_out); if (rc < 0) return rc; diff --git a/src/shared/libosmocore/src/gsm/gsm0808.c b/src/shared/libosmocore/src/gsm/gsm0808.c index 01221bd8..30098278 100644 --- a/src/shared/libosmocore/src/gsm/gsm0808.c +++ b/src/shared/libosmocore/src/gsm/gsm0808.c @@ -27,69 +27,52 @@ #define BSSMAP_MSG_SIZE 512 #define BSSMAP_MSG_HEADROOM 128 -static void put_data_16(uint8_t *data, const uint16_t val) -{ - memcpy(data, &val, sizeof(val)); -} - struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, uint16_t _ci) { - uint8_t *data; - uint8_t *ci; struct msgb* msg; - struct gsm48_loc_area_id *lai; + struct { + uint8_t ident; + struct gsm48_loc_area_id lai; + uint16_t ci; + } __attribute__ ((packed)) lai_ci; msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "bssmap cmpl l3"); if (!msg) return NULL; - /* create the bssmap header */ - msg->l3h = msgb_put(msg, 2); - msg->l3h[0] = 0x0; - /* create layer 3 header */ - data = msgb_put(msg, 1); - data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3; + msgb_v_put(msg, BSS_MAP_MSG_COMPLETE_LAYER_3); /* create the cell header */ - data = msgb_put(msg, 3); - data[0] = GSM0808_IE_CELL_IDENTIFIER; - data[1] = 1 + sizeof(*lai) + 2; - data[2] = CELL_IDENT_WHOLE_GLOBAL; - - lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai)); - gsm48_generate_lai(lai, cc, nc, lac); - - ci = msgb_put(msg, 2); - put_data_16(ci, htons(_ci)); + lai_ci.ident = CELL_IDENT_WHOLE_GLOBAL; + gsm48_generate_lai(&lai_ci.lai, cc, nc, lac); + lai_ci.ci = htons(_ci); + msgb_tlv_put(msg, GSM0808_IE_CELL_IDENTIFIER, sizeof(lai_ci), + (uint8_t *) &lai_ci); /* copy the layer3 data */ - data = msgb_put(msg, msgb_l3len(msg_l3) + 2); - data[0] = GSM0808_IE_LAYER_3_INFORMATION; - data[1] = msgb_l3len(msg_l3); - memcpy(&data[2], msg_l3->l3h, data[1]); + msgb_tlv_put(msg, GSM0808_IE_LAYER_3_INFORMATION, + msgb_l3len(msg_l3), msg_l3->l3h); - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; + /* push the bssmap header */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; } struct msgb *gsm0808_create_reset(void) { + uint8_t cause = GSM0808_CAUSE_EQUIPMENT_FAILURE; struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "bssmap: reset"); if (!msg) return NULL; - msg->l3h = msgb_put(msg, 6); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0x04; - msg->l3h[2] = 0x30; - msg->l3h[3] = 0x04; - msg->l3h[4] = 0x01; - msg->l3h[5] = 0x20; + msgb_v_put(msg, BSS_MAP_MSG_RESET); + msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause); + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + return msg; } @@ -97,13 +80,12 @@ struct msgb *gsm0808_create_clear_complete(void) { struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "bssmap: clear complete"); + uint8_t val = BSS_MAP_MSG_CLEAR_COMPLETE; if (!msg) return NULL; - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 1; - msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE; + msg->l3h = msg->data; + msgb_tlv_put(msg, BSSAP_MSG_BSS_MANAGEMENT, 1, &val); return msg; } @@ -118,6 +100,7 @@ struct msgb *gsm0808_create_clear_command(uint8_t reason) msg->l3h = msgb_tv_put(msg, BSSAP_MSG_BSS_MANAGEMENT, 4); msgb_v_put(msg, BSS_MAP_MSG_CLEAR_CMD); msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &reason); + return msg; } @@ -129,26 +112,20 @@ struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id) return NULL; /* send response with BSS override for A5/1... cheating */ - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE; + msgb_v_put(msg, BSS_MAP_MSG_CIPHER_MODE_COMPLETE); /* include layer3 in case we have at least two octets */ if (layer3 && msgb_l3len(layer3) > 2) { - msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2); - msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS; - msg->l4h[1] = msgb_l3len(layer3); - memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3)); + msg->l4h = msgb_tlv_put(msg, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS, + msgb_l3len(layer3), layer3->l3h); } /* and the optional BSS message */ - msg->l4h = msgb_put(msg, 2); - msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG; - msg->l4h[1] = alg_id; + msgb_tv_put(msg, GSM0808_IE_CHOSEN_ENCR_ALG, alg_id); + + /* pre-pend the header */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; return msg; } @@ -159,32 +136,29 @@ struct msgb *gsm0808_create_cipher_reject(uint8_t cause) if (!msg) return NULL; - msg->l3h = msgb_put(msg, 4); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 2; - msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT; - msg->l3h[3] = cause; + msgb_tv_put(msg, BSS_MAP_MSG_CIPHER_MODE_REJECT, cause); + + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; } -struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length) +struct msgb *gsm0808_create_classmark_update(const uint8_t *cm2, uint8_t cm2_len, + const uint8_t *cm3, uint8_t cm3_len) { struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "classmark-update"); if (!msg) return NULL; - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE; + msgb_v_put(msg, BSS_MAP_MSG_CLASSMARK_UPDATE); + msgb_tlv_put(msg, GSM0808_IE_CLASSMARK_INFORMATION_T2, cm2_len, cm2); + if (cm3) + msgb_tlv_put(msg, GSM0808_IE_CLASSMARK_INFORMATION_T3, + cm3_len, cm3); - msg->l4h = msgb_put(msg, length); - memcpy(msg->l4h, classmark_data, length); + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; return msg; } @@ -195,12 +169,11 @@ struct msgb *gsm0808_create_sapi_reject(uint8_t link_id) if (!msg) return NULL; - msg->l3h = msgb_put(msg, 5); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 3; - msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT; - msg->l3h[3] = link_id; - msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED; + msgb_v_put(msg, BSS_MAP_MSG_SAPI_N_REJECT); + msgb_v_put(msg, link_id); + msgb_v_put(msg, GSM0808_CAUSE_BSS_NOT_EQUIPPED); + + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; } @@ -209,78 +182,56 @@ struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause, uint8_t chosen_channel, uint8_t encr_alg_id, uint8_t speech_mode) { - uint8_t *data; - - struct msgb *msg = msgb_alloc(35, "bssmap: ass compl"); + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: ass compl"); if (!msg) return NULL; - msg->l3h = msgb_put(msg, 3); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE; + msgb_v_put(msg, BSS_MAP_MSG_ASSIGMENT_COMPLETE); /* write 3.2.2.22 */ - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_RR_CAUSE; - data[1] = rr_cause; + msgb_tv_put(msg, GSM0808_IE_RR_CAUSE, rr_cause); /* write cirtcuit identity code 3.2.2.2 */ /* write cell identifier 3.2.2.17 */ /* write chosen channel 3.2.2.33 when BTS picked it */ - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_CHOSEN_CHANNEL; - data[1] = chosen_channel; + msgb_tv_put(msg, GSM0808_IE_CHOSEN_CHANNEL, chosen_channel); /* write chosen encryption algorithm 3.2.2.44 */ - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_CHOSEN_ENCR_ALG; - data[1] = encr_alg_id; + msgb_tv_put(msg, GSM0808_IE_CHOSEN_ENCR_ALG, encr_alg_id); /* write circuit pool 3.2.2.45 */ /* write speech version chosen: 3.2.2.51 when BTS picked it */ - if (speech_mode != 0) { - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_SPEECH_VERSION; - data[1] = speech_mode; - } + if (speech_mode != 0) + msgb_tv_put(msg, GSM0808_IE_SPEECH_VERSION, speech_mode); /* write LSA identifier 3.2.2.15 */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; return msg; } struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause) { - uint8_t *data; struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "bssmap: ass fail"); if (!msg) return NULL; - msg->l3h = msgb_put(msg, 6); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 0xff; - msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE; - msg->l3h[3] = GSM0808_IE_CAUSE; - msg->l3h[4] = 1; - msg->l3h[5] = cause; + msgb_v_put(msg, BSS_MAP_MSG_ASSIGMENT_FAILURE); + msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause); /* RR cause 3.2.2.22 */ - if (rr_cause) { - data = msgb_put(msg, 2); - data[0] = GSM0808_IE_RR_CAUSE; - data[1] = *rr_cause; - } + if (rr_cause) + msgb_tv_put(msg, GSM0808_IE_RR_CAUSE, *rr_cause); /* Circuit pool 3.22.45 */ /* Circuit pool list 3.2.2.46 */ /* update the size */ - msg->l3h[1] = msgb_l3len(msg) - 2; + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + return msg; } @@ -293,14 +244,10 @@ struct msgb *gsm0808_create_clear_rqst(uint8_t cause) if (!msg) return NULL; - msg->l3h = msgb_put(msg, 2 + 4); - msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; - msg->l3h[1] = 4; + msgb_v_put(msg, BSS_MAP_MSG_CLEAR_RQST); + msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause); + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - msg->l3h[2] = BSS_MAP_MSG_CLEAR_RQST; - msg->l3h[3] = GSM0808_IE_CAUSE; - msg->l3h[4] = 1; - msg->l3h[5] = cause; return msg; } diff --git a/src/shared/libosmocore/src/gsm/lapd_core.c b/src/shared/libosmocore/src/gsm/lapd_core.c index b1b5a1ba..96099edb 100644 --- a/src/shared/libosmocore/src/gsm/lapd_core.c +++ b/src/shared/libosmocore/src/gsm/lapd_core.c @@ -707,7 +707,7 @@ static void lapd_acknowledge(struct lapd_msg_ctx *lctx) { struct lapd_datalink *dl = lctx->dl; uint8_t nr = lctx->n_recv; - int s = 0, rej = 0, t200_reset = 0, t200_start = 0; + int s = 0, rej = 0, t200_reset = 0; int i, h; /* supervisory frame ? */ @@ -758,7 +758,6 @@ static void lapd_acknowledge(struct lapd_msg_ctx *lctx) if (dl->tx_hist[sub_mod(dl->v_send, 1, dl->range_hist)].msg) { LOGP(DLLAPD, LOGL_INFO, "start T200, due to unacked I " "frame(s)\n"); - t200_start = 1; lapd_start_t200(dl); } } @@ -1731,7 +1730,15 @@ static int lapd_data_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) struct lapd_datalink *dl = lctx->dl; struct msgb *msg = dp->oph.msg; - LOGP(DLLAPD, LOGL_INFO, "writing message to send-queue\n"); + if (msgb_l3len(msg) == 0) { + LOGP(DLLAPD, LOGL_ERROR, + "writing an empty message is not possible.\n"); + msgb_free(msg); + return -1; + } + + LOGP(DLLAPD, LOGL_INFO, + "writing message to send-queue: l3len: %d\n", msgb_l3len(msg)); /* Write data into the send queue */ msgb_enqueue(&dl->send_queue, msg); diff --git a/src/shared/libosmocore/src/gsm/lapdm.c b/src/shared/libosmocore/src/gsm/lapdm.c index 3d2f3d83..e9ce881b 100644 --- a/src/shared/libosmocore/src/gsm/lapdm.c +++ b/src/shared/libosmocore/src/gsm/lapdm.c @@ -792,7 +792,7 @@ static int rslms_rx_rll_est_req(struct msgb *msg, struct lapdm_datalink *dl) /* Remove RLL header from msgb and set length to L3-info */ msgb_pull_l2h(msg); msg->len = length; - msg->tail = msg->data + length; + msg->tail = msg->l3h + length; /* prepare prim */ osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg); @@ -845,7 +845,7 @@ static int rslms_rx_rll_udata_req(struct msgb *msg, struct lapdm_datalink *dl) /* Remove RLL header from msgb and set length to L3-info */ msgb_pull_l2h(msg); msg->len = length; - msg->tail = msg->data + length; + msg->tail = msg->l3h + length; /* Push L1 + LAPDm header on msgb */ msg->l2h = msgb_push(msg, 4 + !ui_bts); @@ -881,7 +881,7 @@ static int rslms_rx_rll_data_req(struct msgb *msg, struct lapdm_datalink *dl) /* Remove RLL header from msgb and set length to L3-info */ msgb_pull_l2h(msg); msg->len = length; - msg->tail = msg->data + length; + msg->tail = msg->l3h + length; /* prepare prim */ osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg); @@ -938,7 +938,7 @@ static int rslms_rx_rll_res_req(struct msgb *msg, struct lapdm_datalink *dl) /* Remove RLL header from msgb and set length to L3-info */ msgb_pull_l2h(msg); msg->len = length; - msg->tail = msg->data + length; + msg->tail = msg->l3h + length; /* prepare prim */ osmo_prim_init(&dp.oph, 0, (msg_type == RSL_MT_RES_REQ) ? PRIM_DL_RES diff --git a/src/shared/libosmocore/src/gsm/milenage/milenage.c b/src/shared/libosmocore/src/gsm/milenage/milenage.c index cc4e95c5..b43f986a 100644 --- a/src/shared/libosmocore/src/gsm/milenage/milenage.c +++ b/src/shared/libosmocore/src/gsm/milenage/milenage.c @@ -327,3 +327,18 @@ int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, return 0; } + +int milenage_opc_gen(u8 *opc, const u8 *k, const u8 *op) +{ + int i; + + /* Encrypt OP using K */ + if (aes_128_encrypt_block(k, op, opc)) + return -1; + + /* XOR the resulting Ek(OP) with OP */ + for (i = 0; i < 16; i++) + opc[i] = opc[i] ^ op[i]; + + return 0; +} diff --git a/src/shared/libosmocore/src/gsm/milenage/milenage.h b/src/shared/libosmocore/src/gsm/milenage/milenage.h index d5054d6d..a91e946a 100644 --- a/src/shared/libosmocore/src/gsm/milenage/milenage.h +++ b/src/shared/libosmocore/src/gsm/milenage/milenage.h @@ -30,4 +30,6 @@ int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar); +int milenage_opc_gen(u8 *opc, const u8 *k, const u8 *op); + #endif /* MILENAGE_H */ diff --git a/src/shared/libosmocore/src/vty/command.c b/src/shared/libosmocore/src/vty/command.c index ab1eacaa..fda2e17f 100644 --- a/src/shared/libosmocore/src/vty/command.c +++ b/src/shared/libosmocore/src/vty/command.c @@ -2268,31 +2268,19 @@ gDEFUN(config_list, config_list_cmd, "list", "Print command list\n") return CMD_SUCCESS; } -/* Write current configuration into file. */ -DEFUN(config_write_file, - config_write_file_cmd, - "write file", - "Write running configuration to memory, network, or terminal\n" - "Write to configuration file\n") +static int write_config_file(const char *config_file, char **outpath) { unsigned int i; int fd; struct cmd_node *node; - char *config_file; char *config_file_tmp = NULL; char *config_file_sav = NULL; struct vty *file_vty; + struct stat st; - /* Check and see if we are operating under vtysh configuration */ - if (host.config == NULL) { - vty_out(vty, "Can't save to configuration file, using vtysh.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - /* Get filename. */ - config_file = host.config; + *outpath = NULL; + /* Check and see if we are operating under vtysh configuration */ config_file_sav = _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1, @@ -2307,11 +2295,10 @@ DEFUN(config_write_file, /* Open file to configuration write. */ fd = mkstemp(config_file_tmp); if (fd < 0) { - vty_out(vty, "Can't open configuration file %s.%s", - config_file_tmp, VTY_NEWLINE); + *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file_tmp); talloc_free(config_file_tmp); talloc_free(config_file_sav); - return CMD_WARNING; + return -1; } /* Make vty for configuration file. */ @@ -2334,38 +2321,37 @@ DEFUN(config_write_file, if (unlink(config_file_sav) != 0) if (errno != ENOENT) { - vty_out(vty, - "Can't unlink backup configuration file %s.%s", - config_file_sav, VTY_NEWLINE); + *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file_sav); talloc_free(config_file_sav); talloc_free(config_file_tmp); unlink(config_file_tmp); - return CMD_WARNING; + return -2; + } + + /* Only link the .sav file if the original file exists */ + if (stat(config_file, &st) == 0) { + if (link(config_file, config_file_sav) != 0) { + *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file_sav); + talloc_free(config_file_sav); + talloc_free(config_file_tmp); + unlink(config_file_tmp); + return -3; + } + sync(); + if (unlink(config_file) != 0) { + *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file); + talloc_free(config_file_sav); + talloc_free(config_file_tmp); + unlink(config_file_tmp); + return -4; } - if (link(config_file, config_file_sav) != 0) { - vty_out(vty, "Can't backup old configuration file %s.%s", - config_file_sav, VTY_NEWLINE); - talloc_free(config_file_sav); - talloc_free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; - } - sync(); - if (unlink(config_file) != 0) { - vty_out(vty, "Can't unlink configuration file %s.%s", - config_file, VTY_NEWLINE); - talloc_free(config_file_sav); - talloc_free(config_file_tmp); - unlink(config_file_tmp); - return CMD_WARNING; } if (link(config_file_tmp, config_file) != 0) { - vty_out(vty, "Can't save configuration file %s.%s", config_file, - VTY_NEWLINE); + *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file); talloc_free(config_file_sav); talloc_free(config_file_tmp); unlink(config_file_tmp); - return CMD_WARNING; + return -5; } unlink(config_file_tmp); sync(); @@ -2374,13 +2360,70 @@ DEFUN(config_write_file, talloc_free(config_file_tmp); if (chmod(config_file, 0666 & ~CONFIGFILE_MASK) != 0) { - vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s", - config_file, strerror(errno), errno, VTY_NEWLINE); + *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file); + return -6; + } + + return 0; +} + + +/* Write current configuration into file. */ +DEFUN(config_write_file, + config_write_file_cmd, + "write file", + "Write running configuration to memory, network, or terminal\n" + "Write to configuration file\n") +{ + char *failed_file; + int rc; + + if (host.config == NULL) { + vty_out(vty, "Can't save to configuration file, using vtysh.%s", + VTY_NEWLINE); return CMD_WARNING; } - vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE); - return CMD_SUCCESS; + rc = write_config_file(host.config, &failed_file); + switch (rc) { + case -1: + vty_out(vty, "Can't open configuration file %s.%s", + failed_file, VTY_NEWLINE); + rc = CMD_WARNING; + break; + case -2: + vty_out(vty, "Can't unlink backup configuration file %s.%s", + failed_file, VTY_NEWLINE); + rc = CMD_WARNING; + break; + case -3: + vty_out(vty, "Can't backup old configuration file %s.%s", + failed_file, VTY_NEWLINE); + rc = CMD_WARNING; + break; + case -4: + vty_out(vty, "Can't unlink configuration file %s.%s", + failed_file, VTY_NEWLINE); + rc = CMD_WARNING; + break; + case -5: + vty_out(vty, "Can't save configuration file %s.%s", failed_file, + VTY_NEWLINE); + rc = CMD_WARNING; + break; + case -6: + vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s", + failed_file, strerror(errno), errno, VTY_NEWLINE); + rc = CMD_WARNING; + break; + default: + vty_out(vty, "Configuration saved to %s%s", host.config, VTY_NEWLINE); + rc = CMD_SUCCESS; + break; + } + + talloc_free(failed_file); + return rc; } ALIAS(config_write_file, @@ -3160,6 +3203,47 @@ void install_default(enum node_type node) install_element(node, &show_running_config_cmd); } +/** + * \brief Write the current running config to a given file + * \param[in] vty the vty of the code + * \param[in] filename where to store the file + * \return 0 in case of success. + * + * If the filename already exists create a filename.sav + * version with the current code. + * + */ +int osmo_vty_write_config_file(const char *filename) +{ + char *failed_file; + int rc; + + rc = write_config_file(filename, &failed_file); + talloc_free(failed_file); + return rc; +} + +/** + * \brief Save the current state to the config file + * \return 0 in case of success. + * + * If the filename already exists create a filename.sav + * version with the current code. + * + */ +int osmo_vty_save_config_file(void) +{ + char *failed_file; + int rc; + + if (host.config == NULL) + return -7; + + rc = write_config_file(host.config, &failed_file); + talloc_free(failed_file); + return rc; +} + /* Initialize command interface. Install basic nodes and commands. */ void cmd_init(int terminal) { diff --git a/src/shared/libosmocore/src/vty/telnet_interface.c b/src/shared/libosmocore/src/vty/telnet_interface.c index 167acc18..001b016e 100644 --- a/src/shared/libosmocore/src/vty/telnet_interface.c +++ b/src/shared/libosmocore/src/vty/telnet_interface.c @@ -20,12 +20,14 @@ #include <sys/socket.h> #include <netinet/in.h> +#include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <osmocom/core/msgb.h> +#include <osmocom/core/socket.h> #include <osmocom/core/talloc.h> #include <osmocom/core/logging.h> @@ -52,53 +54,38 @@ static struct osmo_fd server_socket = { .priv_nr = 0, }; -/*! \brief Initialize telnet based VTY interface +/*! \brief Initialize telnet based VTY interface listening to 127.0.0.1 * \param[in] tall_ctx \ref talloc context * \param[in] priv private data to be passed to callback * \param[in] port UDP port number */ int telnet_init(void *tall_ctx, void *priv, int port) { - struct sockaddr_in sock_addr; - int fd, rc, on = 1; - - tall_telnet_ctx = talloc_named_const(tall_ctx, 1, - "telnet_connection"); - - /* FIXME: use new socket.c code of libosmocore */ - fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - - if (fd < 0) { - LOGP(0, LOGL_ERROR, "Telnet interface socket creation failed\n"); - return fd; - } - - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + return telnet_init_dynif(tall_ctx, priv, "127.0.0.1", port); +} - memset(&sock_addr, 0, sizeof(sock_addr)); - sock_addr.sin_family = AF_INET; - sock_addr.sin_port = htons(port); - sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +/*! \brief Initialize telnet based VTY interface + * \param[in] tall_ctx \ref talloc context + * \param[in] priv private data to be passed to callback + * \param[in] ip IP to listen to ('::1' for localhost, '::0' for all, ...) + * \param[in] port UDP port number + */ +int telnet_init_dynif(void *tall_ctx, void *priv, const char *ip, int port) +{ + int rc; - rc = bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); - if (rc < 0) { - LOGP(0, LOGL_ERROR, "Telnet interface failed to bind\n"); - close(fd); - return rc; - } + tall_telnet_ctx = talloc_named_const(tall_ctx, 1, + "telnet_connection"); - rc = listen(fd, 0); - if (rc < 0) { - LOGP(0, LOGL_ERROR, "Telnet interface failed to listen\n"); - close(fd); - return rc; - } + rc = osmo_sock_init_ofd( + &server_socket, + AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, + ip, port, OSMO_SOCK_F_BIND + ); server_socket.data = priv; - server_socket.fd = fd; - osmo_fd_register(&server_socket); - return 0; + return (rc < 0) ? -1 : 0; } extern struct host host; diff --git a/src/shared/libosmocore/tests/Makefile.am b/src/shared/libosmocore/tests/Makefile.am index 348355f2..eff1ac44 100644 --- a/src/shared/libosmocore/tests/Makefile.am +++ b/src/shared/libosmocore/tests/Makefile.am @@ -1,5 +1,5 @@ if ENABLE_TESTS -SUBDIRS = timer sms ussd smscb bits a5 conv auth lapd +SUBDIRS = timer sms ussd smscb bits a5 conv auth lapd gsm0808 if ENABLE_MSGFILE SUBDIRS += msgfile endif diff --git a/src/shared/libosmocore/tests/auth/milenage_test.c b/src/shared/libosmocore/tests/auth/milenage_test.c index da7c800a..7c996f02 100644 --- a/src/shared/libosmocore/tests/auth/milenage_test.c +++ b/src/shared/libosmocore/tests/auth/milenage_test.c @@ -37,6 +37,24 @@ static struct osmo_sub_auth_data test_aud = { }, }; +static int opc_test(const struct osmo_sub_auth_data *aud) +{ + int rc; + uint8_t opc[16]; +#if 0 + const uint8_t op[16] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }; +#else + const uint8_t op[16] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 }; +#endif + + rc = milenage_opc_gen(opc, aud->u.umts.k, op); + + printf("OP:\t%s\n", osmo_hexdump(op, sizeof(op))); + printf("OPC:\t%s\n", osmo_hexdump(opc, sizeof(opc))); + return rc; +} + int main(int argc, char **argv) { struct osmo_auth_vector _vec; @@ -73,6 +91,8 @@ int main(int argc, char **argv) printf("AUTS success: SEQ.MS = %lu\n", test_aud.u.umts.sqn); } + opc_test(&test_aud); + exit(0); } diff --git a/src/shared/libosmocore/tests/auth/milenage_test.ok b/src/shared/libosmocore/tests/auth/milenage_test.ok index 66337ca9..00ffc222 100644 --- a/src/shared/libosmocore/tests/auth/milenage_test.ok +++ b/src/shared/libosmocore/tests/auth/milenage_test.ok @@ -6,3 +6,5 @@ RES: e9 fc 88 cc c8 a3 53 81 SRES: 21 5f db 4d Kc: 6d e8 16 a7 59 a4 29 12 AUTS success: SEQ.MS = 33 +OP: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +OPC: c6 a1 3b 37 87 8f 5b 82 6f 4f 81 62 a1 c8 d8 79 diff --git a/src/shared/libosmocore/tests/gsm0808/Makefile.am b/src/shared/libosmocore/tests/gsm0808/Makefile.am new file mode 100644 index 00000000..a238e7f3 --- /dev/null +++ b/src/shared/libosmocore/tests/gsm0808/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/include +noinst_PROGRAMS = gsm0808_test +EXTRA_DIST = gsm0808_test.ok + +gsm0808_test_SOURCES = gsm0808_test.c +gsm0808_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la diff --git a/src/shared/libosmocore/tests/gsm0808/gsm0808_test.c b/src/shared/libosmocore/tests/gsm0808/gsm0808_test.c new file mode 100644 index 00000000..7e5e97b5 --- /dev/null +++ b/src/shared/libosmocore/tests/gsm0808/gsm0808_test.c @@ -0,0 +1,269 @@ +/* + * (C) 2012 by Holger Hans Peter Freyther + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <osmocom/gsm/gsm0808.h> + +#include <stdio.h> +#include <stdlib.h> + +#define VERIFY(msg, data, len) \ + if (msgb_l3len(msg) != len) { \ + printf("%s:%d Length don't match: %d vs. %d. %s\n", \ + __func__, __LINE__, msgb_l3len(msg), len, \ + osmo_hexdump(msg->l3h, msgb_l3len(msg))); \ + abort(); \ + } else if (memcmp(msg->l3h, data, len) != 0) { \ + printf("%s:%d didn't match: got: %s\n", \ + __func__, __LINE__, \ + osmo_hexdump(msg->l3h, msgb_l3len(msg))); \ + abort(); \ + } + + +static void test_create_layer3(void) +{ + static const uint8_t res[] = { + 0x00, 0x0e, 0x57, 0x05, 0x08, 0x00, 0x77, 0x62, + 0x83, 0x33, 0x66, 0x44, 0x88, 0x17, 0x01, 0x23 }; + struct msgb *msg, *in_msg; + printf("Testing creating Layer3\n"); + + in_msg = msgb_alloc_headroom(512, 128, "foo"); + in_msg->l3h = in_msg->data; + msgb_v_put(in_msg, 0x23); + + msg = gsm0808_create_layer3(in_msg, 0x1122, 0x2244, 0x3366, 0x4488); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); + msgb_free(in_msg); +} + +static void test_create_reset() +{ + static const uint8_t res[] = { 0x00, 0x04, 0x30, 0x04, 0x01, 0x20 }; + struct msgb *msg; + + printf("Testing creating Reset\n"); + msg = gsm0808_create_reset(); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); +} + +static void test_create_clear_command() +{ + static const uint8_t res[] = { 0x20, 0x04, 0x01, 0x23 }; + struct msgb *msg; + + printf("Testing creating Clear Command\n"); + msg = gsm0808_create_clear_command(0x23); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); +} + +static void test_create_clear_complete() +{ + static const uint8_t res[] = { 0x00, 0x01, 0x21 }; + struct msgb *msg; + + printf("Testing creating Clear Complete\n"); + msg = gsm0808_create_clear_complete(); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); +} + +static void test_create_cipher_complete() +{ + static const uint8_t res1[] = { + 0x00, 0x08, 0x55, 0x20, 0x03, 0x23, 0x42, 0x21, 0x2c, 0x04 }; + static const uint8_t res2[] = { 0x00, 0x03, 0x55, 0x2c, 0x04}; + struct msgb *l3, *msg; + + printf("Testing creating Cipher Complete\n"); + l3 = msgb_alloc_headroom(512, 128, "l3h"); + l3->l3h = l3->data; + msgb_v_put(l3, 0x23); + msgb_v_put(l3, 0x42); + msgb_v_put(l3, 0x21); + + /* with l3 data */ + msg = gsm0808_create_cipher_complete(l3, 4); + VERIFY(msg, res1, ARRAY_SIZE(res1)); + msgb_free(msg); + + /* with l3 data but short */ + l3->len -= 1; + l3->tail -= 1; + msg = gsm0808_create_cipher_complete(l3, 4); + VERIFY(msg, res2, ARRAY_SIZE(res2)); + msgb_free(msg); + + /* without l3 data */ + msg = gsm0808_create_cipher_complete(NULL, 4); + VERIFY(msg, res2, ARRAY_SIZE(res2)); + msgb_free(msg); + + + msgb_free(l3); +} + +static void test_create_cipher_reject() +{ + static const uint8_t res[] = { 0x00, 0x02, 0x59, 0x23 }; + struct msgb *msg; + + printf("Testing creating Cipher Reject\n"); + msg = gsm0808_create_cipher_reject(0x23); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); +} + +static void test_create_cm_u() +{ + static const uint8_t res[] = { + 0x00, 0x07, 0x54, 0x12, 0x01, 0x23, 0x13, 0x01, 0x42 }; + static const uint8_t res2o[] = { + 0x00, 0x04, 0x54, 0x12, 0x01, 0x23 }; + struct msgb *msg; + const uint8_t cm2 = 0x23; + const uint8_t cm3 = 0x42; + + printf("Testing creating CM U\n"); + msg = gsm0808_create_classmark_update(&cm2, 1, &cm3, 1); + VERIFY(msg, res, ARRAY_SIZE(res)); + + msg = gsm0808_create_classmark_update(&cm2, 1, NULL, 0); + VERIFY(msg, res2o, ARRAY_SIZE(res2o)); + + msgb_free(msg); +} + +static void test_create_sapi_reject() +{ + static const uint8_t res[] = { 0x00, 0x03, 0x25, 0x03, 0x25 }; + struct msgb *msg; + + printf("Testing creating SAPI Reject\n"); + msg = gsm0808_create_sapi_reject(3); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); +} + +static void test_create_ass_compl() +{ + static const uint8_t res1[] = { + 0x00, 0x09, 0x02, 0x15, 0x23, 0x21, 0x42, 0x2c, + 0x11, 0x40, 0x22 }; + static const uint8_t res2[] = { + 0x00, 0x07, 0x02, 0x15, 0x23, 0x21, 0x42, 0x2c, 0x11}; + struct msgb *msg; + + printf("Testing creating Assignment Complete\n"); + msg = gsm0808_create_assignment_completed(0x23, 0x42, 0x11, 0x22); + VERIFY(msg, res1, ARRAY_SIZE(res1)); + msgb_free(msg); + + msg = gsm0808_create_assignment_completed(0x23, 0x42, 0x11, 0); + VERIFY(msg, res2, ARRAY_SIZE(res2)); + msgb_free(msg); +} + +static void test_create_ass_fail() +{ + static const uint8_t res1[] = { 0x00, 0x04, 0x03, 0x04, 0x01, 0x23 }; + static const uint8_t res2[] = { + 0x00, 0x06, 0x03, 0x04, 0x01, 0x23, 0x15, 0x02}; + uint8_t rr_res = 2; + struct msgb *msg; + + printf("Testing creating Assignment Failure\n"); + msg = gsm0808_create_assignment_failure(0x23, NULL); + VERIFY(msg, res1, ARRAY_SIZE(res1)); + msgb_free(msg); + + msg = gsm0808_create_assignment_failure(0x23, &rr_res); + VERIFY(msg, res2, ARRAY_SIZE(res2)); + msgb_free(msg); +} + +static void test_create_clear_rqst() +{ + static const uint8_t res[] = { 0x00, 0x04, 0x22, 0x04, 0x01, 0x23 }; + struct msgb *msg; + + printf("Testing creating Clear Request\n"); + msg = gsm0808_create_clear_rqst(0x23); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); +} + +static void test_create_dtap() +{ + static const uint8_t res[] = { 0x01, 0x03, 0x02, 0x23, 0x42 }; + struct msgb *msg, *l3; + + printf("Testing creating DTAP\n"); + l3 = msgb_alloc_headroom(512, 128, "test"); + l3->l3h = l3->data; + msgb_v_put(l3, 0x23); + msgb_v_put(l3, 0x42); + + msg = gsm0808_create_dtap(l3, 0x3); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); + msgb_free(l3); +} + +static void test_prepend_dtap() +{ + static const uint8_t res[] = { 0x01, 0x03, 0x02, 0x23, 0x42 }; + struct msgb *in_msg; + + printf("Testing prepend DTAP\n"); + + in_msg = msgb_alloc_headroom(512, 128, "test"); + msgb_v_put(in_msg, 0x23); + msgb_v_put(in_msg, 0x42); + + gsm0808_prepend_dtap_header(in_msg, 0x3); + in_msg->l3h = in_msg->data; + VERIFY(in_msg, res, ARRAY_SIZE(res)); + msgb_free(in_msg); +} + +int main(int argc, char **argv) +{ + printf("Testing generation of GSM0808 messages\n"); + test_create_layer3(); + test_create_reset(); + test_create_clear_command(); + test_create_clear_complete(); + test_create_cipher_complete(); + test_create_cipher_reject(); + test_create_cm_u(); + test_create_sapi_reject(); + test_create_ass_compl(); + test_create_ass_fail(); + test_create_clear_rqst(); + test_create_dtap(); + test_prepend_dtap(); + + printf("Done\n"); + return EXIT_SUCCESS; +} diff --git a/src/shared/libosmocore/tests/gsm0808/gsm0808_test.ok b/src/shared/libosmocore/tests/gsm0808/gsm0808_test.ok new file mode 100644 index 00000000..eb431267 --- /dev/null +++ b/src/shared/libosmocore/tests/gsm0808/gsm0808_test.ok @@ -0,0 +1,15 @@ +Testing generation of GSM0808 messages +Testing creating Layer3 +Testing creating Reset +Testing creating Clear Command +Testing creating Clear Complete +Testing creating Cipher Complete +Testing creating Cipher Reject +Testing creating CM U +Testing creating SAPI Reject +Testing creating Assignment Complete +Testing creating Assignment Failure +Testing creating Clear Request +Testing creating DTAP +Testing prepend DTAP +Done diff --git a/src/shared/libosmocore/tests/lapd/lapd_test.c b/src/shared/libosmocore/tests/lapd/lapd_test.c index 8c6b0df2..d58bec65 100644 --- a/src/shared/libosmocore/tests/lapd/lapd_test.c +++ b/src/shared/libosmocore/tests/lapd/lapd_test.c @@ -73,8 +73,8 @@ static const uint8_t cm_padded[] = { }; static const uint8_t mm[] = { - 0x05, 0x24, 0x31, 0x03, 0x50, 0x18, 0x93, 0x08, - 0x29, 0x47, 0x80, 0x00, + 0x00, 0x0c, 0x00, 0x03, 0x01, 0x01, 0x20, 0x02, + 0x00, 0x0b, 0x00, 0x03, 0x05, 0x04, 0x0d }; static const uint8_t dummy1[] = { @@ -95,6 +95,20 @@ static struct msgb *create_mm_id_req(void) struct msgb *msg; msg = msgb_from_array(mm, sizeof(mm)); + msg->l2h = msg->data + 3; + ASSERT(msgb_l2len(msg) == 12); + msg->l3h = msg->l2h + 6; + ASSERT(msgb_l3len(msg) == 6); + + return msg; +} + +static struct msgb *create_empty_msg(void) +{ + struct msgb *msg; + + msg = msgb_from_array(NULL, 0); + ASSERT(msgb_l3len(msg) == 0); rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, 0, 0, 1); return msg; } @@ -194,9 +208,9 @@ static int ms_to_bts_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *_ctx /* ASSERT(msg->data[7] == 0x0 && msg->data[8] == 0x9c); */ /* this should be 0x0 and 0x0... but we have a bug */ } else if (state->ms_read == 1) { - printf("MS: Verifying incoming MM message.\n"); - ASSERT(msgb_l3len(msg) == ARRAY_SIZE(mm)); - ASSERT(memcmp(msg->l3h, mm, msgb_l3len(msg)) == 0); + printf("MS: Verifying incoming MM message: %d\n", msgb_l3len(msg)); + ASSERT(msgb_l3len(msg) == 3); + ASSERT(memcmp(msg->l3h, &mm[12], msgb_l3len(msg)) == 0); } else { printf("MS: Do not know to verify: %d\n", state->ms_read); } @@ -271,7 +285,7 @@ static void test_lapdm_polling() lapdm_rslms_recvmsg(create_dummy_data_req(), &ms_to_bts_channel); - /* 4. And back to the MS */ + /* 4. And back to the MS, but let's move data/l2h apart */ ASSERT(test_state.bts_read == 2) ASSERT(test_state.ms_read == 2); rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp); @@ -284,6 +298,11 @@ static void test_lapdm_polling() rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp); ASSERT(rc < 0); + /* check sending an empty L3 message fails */ + rc = lapdm_rslms_recvmsg(create_empty_msg(), &bts_to_ms_channel); + ASSERT(rc == -1); + ASSERT(test_state.ms_read == 2); + /* clean up */ lapdm_channel_exit(&bts_to_ms_channel); lapdm_channel_exit(&ms_to_bts_channel); diff --git a/src/shared/libosmocore/tests/lapd/lapd_test.ok b/src/shared/libosmocore/tests/lapd/lapd_test.ok index 058ac3d7..d67a0a80 100644 --- a/src/shared/libosmocore/tests/lapd/lapd_test.ok +++ b/src/shared/libosmocore/tests/lapd/lapd_test.ok @@ -9,8 +9,8 @@ ms_to_bts_tx_cb: BTS->MS(us) message 9 MS: Verifying incoming primitive. Sending back to MS -ms_to_bts_tx_cb: BTS->MS(us) message 21 -MS: Verifying incoming MM message. +ms_to_bts_tx_cb: BTS->MS(us) message 12 +MS: Verifying incoming MM message: 3 ms_to_bts_l1_cb: MS(us) -> BTS prim message Sending back to BTS diff --git a/src/shared/libosmocore/tests/testsuite.at b/src/shared/libosmocore/tests/testsuite.at index 6aae04d4..69624c12 100644 --- a/src/shared/libosmocore/tests/testsuite.at +++ b/src/shared/libosmocore/tests/testsuite.at @@ -65,3 +65,9 @@ AT_KEYWORDS([lapd]) cat $abs_srcdir/lapd/lapd_test.ok > expout AT_CHECK([$abs_top_builddir/tests/lapd/lapd_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([gsm0808]) +AT_KEYWORDS([gsm0808]) +cat $abs_srcdir/gsm0808/gsm0808_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/gsm0808/gsm0808_test], [], [expout], [ignore]) +AT_CLEANUP diff --git a/src/shared/libosmocore/utils/osmo-auc-gen.c b/src/shared/libosmocore/utils/osmo-auc-gen.c index 62b51289..e3502b2c 100644 --- a/src/shared/libosmocore/utils/osmo-auc-gen.c +++ b/src/shared/libosmocore/utils/osmo-auc-gen.c @@ -1,6 +1,6 @@ /* GSM/GPRS/3G authentication testing tool */ -/* (C) 2010-2011 by Harald Welte <laforge@gnumonks.org> +/* (C) 2010-2012 by Harald Welte <laforge@gnumonks.org> * * All Rights Reserved * @@ -52,17 +52,34 @@ static struct osmo_sub_auth_data test_aud = { .algo = OSMO_AUTH_ALG_NONE, }; +static void help() +{ + printf( "-2 --2g\tUse 2G (GSM) authentication\n" + "-3 --3g\tUse 3G (UMTS) authentication\n" + "-a --algorithm\tSpecify name of the algorithm\n" + "-k --key\tSpecify Ki / K\n" + "-o --opc\tSpecify OPC (only for 3G)\n" + "-O --op\tSpecify OP (only for 3G)\n" + "-a --amf\tSpecify AMF (only for 3G)\n" + "-s --sqn\tSpecify SQN (only for 3G)\n" + "-A --auts\tSpecify AUTS (only for 3G)\n" + "-r --rand\tSpecify random value\n"); +} + int main(int argc, char **argv) { struct osmo_auth_vector _vec; struct osmo_auth_vector *vec = &_vec; - uint8_t _rand[16]; + uint8_t _rand[16], _auts[16]; int rc, option_index; int rand_is_set = 0; + int auts_is_set = 0; - printf("osmo-auc-gen (C) 2011 by Harald Welte\n"); + printf("osmo-auc-gen (C) 2011-2012 by Harald Welte\n"); printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); + memset(_auts, 0, sizeof(_auts)); + while (1) { int c; unsigned long ul; @@ -72,15 +89,18 @@ int main(int argc, char **argv) { "algorithm", 1, 0, 'a' }, { "key", 1, 0, 'k' }, { "opc", 1, 0, 'o' }, + { "op", 1, 0, 'O' }, { "amf", 1, 0, 'f' }, { "sqn", 1, 0, 's' }, { "rand", 1, 0, 'r' }, + { "auts", 1, 0, 'A' }, + { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; rc = 0; - c = getopt_long(argc, argv, "23a:k:o:f:s:r:", long_options, + c = getopt_long(argc, argv, "23a:k:o:f:s:r:hO:A:", long_options, &option_index); if (c == -1) @@ -120,6 +140,24 @@ int main(int argc, char **argv) } rc = osmo_hexparse(optarg, test_aud.u.umts.opc, sizeof(test_aud.u.umts.opc)); + test_aud.u.umts.opc_is_op = 0; + break; + case 'O': + if (test_aud.type != OSMO_AUTH_TYPE_UMTS) { + fprintf(stderr, "Only UMTS has OP\n"); + exit(2); + } + rc = osmo_hexparse(optarg, test_aud.u.umts.opc, + sizeof(test_aud.u.umts.opc)); + test_aud.u.umts.opc_is_op = 1; + break; + case 'A': + if (test_aud.type != OSMO_AUTH_TYPE_UMTS) { + fprintf(stderr, "Only UMTS has AUTS\n"); + exit(2); + } + rc = osmo_hexparse(optarg, _auts, sizeof(_auts)); + auts_is_set = 1; break; case 'f': if (test_aud.type != OSMO_AUTH_TYPE_UMTS) { @@ -141,6 +179,12 @@ int main(int argc, char **argv) rc = osmo_hexparse(optarg, _rand, sizeof(_rand)); rand_is_set = 1; break; + case 'h': + help(); + exit(0); + default: + help(); + exit(1); } if (rc < 0) { @@ -158,26 +202,30 @@ int main(int argc, char **argv) *(uint32_t *)(&_rand[12]) = rand(); } + if (test_aud.type == OSMO_AUTH_TYPE_NONE || + test_aud.algo == OSMO_AUTH_ALG_NONE) { + help(); + exit(2); + } + memset(vec, 0, sizeof(*vec)); - rc = osmo_auth_gen_vec(vec, &test_aud, _rand); + if (!auts_is_set) + rc = osmo_auth_gen_vec(vec, &test_aud, _rand); + else + rc = osmo_auth_gen_vec_auts(vec, &test_aud, _auts, _rand, _rand); if (rc < 0) { - fprintf(stderr, "error generating auth vector\n"); + if (!auts_is_set) + fprintf(stderr, "error generating auth vector\n"); + else + fprintf(stderr, "AUTS from MS seems incorrect\n"); exit(1); } dump_auth_vec(vec); -#if 0 - const uint8_t auts[14] = { 0x87, 0x11, 0xa0, 0xec, 0x9e, 0x16, 0x37, 0xdf, - 0x17, 0xf8, 0x0b, 0x38, 0x4e, 0xe4 }; - rc = osmo_auth_gen_vec_auts(vec, &test_aud, auts, _rand, _rand); - if (rc < 0) { - printf("AUTS failed\n"); - } else { + if (auts_is_set) printf("AUTS success: SEQ.MS = %lu\n", test_aud.u.umts.sqn); - } -#endif - exit(0); + exit(0); } |