From 9ba500559a1609fa4bd0a7a7ea7f4d73c65d9440 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 14 Mar 2010 15:45:01 +0800 Subject: [PATCH 032/198] Create new 'gprs-sgsn' branch on top of 'gprs-conf' This branch contains the partial SGSN/GGSN implementation that was originally developed as part of the gprs branch. --- openbsc/include/openbsc/gprs_bssgp.h | 138 ++++++++++ openbsc/include/openbsc/gprs_ns.h | 61 ++++ openbsc/src/gprs_bssgp.c | 397 +++++++++++++++++++++++++++ openbsc/src/gprs_ns.c | 348 +++++++++++++++++++++++ 4 files changed, 944 insertions(+) create mode 100644 openbsc/include/openbsc/gprs_bssgp.h create mode 100644 openbsc/include/openbsc/gprs_ns.h create mode 100644 openbsc/src/gprs_bssgp.c create mode 100644 openbsc/src/gprs_ns.c diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h new file mode 100644 index 000000000..f85ac48ec --- /dev/null +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -0,0 +1,138 @@ +#ifndef _GPRS_BSSGP_H +#define _GPRS_BSSGP_H + +/* Section 11.3.26 / Table 11.27 */ +enum bssgp_pdu_type { + /* PDUs between RL and BSSGP SAPs */ + BSSGP_PDUT_DL_UNITDATA = 0x00, + BSSGP_PDUT_UL_UNITDATA = 0x01, + BSSGP_PDUT_RA_CAPABILITY = 0x02, + BSSGP_PDUT_PTM_UNITDATA = 0x03, + /* PDUs between GMM SAPs */ + BSSGP_PDUT_PAGING_PS = 0x06, + BSSGP_PDUT_PAGING_CS = 0x07, + BSSGP_PDUT_RA_CAPA_UDPATE = 0x08, + BSSGP_PDUT_RA_CAPA_UPDATE_ACK = 0x09, + BSSGP_PDUT_RADIO_STATUS = 0x0a, + BSSGP_PDUT_SUSPEND = 0x0b, + BSSGP_PDUT_SUSPEND_ACK = 0x0c, + BSSGP_PDUT_SUSPEND_NACK = 0x0d, + BSSGP_PDUT_RESUME = 0x0e, + BSSGP_PDUT_RESUME_ACK = 0x0f, + BSSGP_PDUT_RESUME_NACK = 0x10, + /* PDus between NM SAPs */ + BSSGP_PDUT_BVC_BLOCK = 0x20, + BSSGP_PDUT_BVC_BLOCK_ACK = 0x21, + BSSGP_PDUT_BVC_RESET = 0x22, + BSSGP_PDUT_BVC_RESET_ACK = 0x23, + BSSGP_PDUT_BVC_UNBLOCK = 0x24, + BSSGP_PDUT_BVC_UNBLOCK_ACK = 0x25, + BSSGP_PDUT_FLOW_CONTROL_BVC = 0x26, + BSSGP_PDUT_FLOW_CONTROL_BVC_ACK = 0x27, + BSSGP_PDUT_FLOW_CONTROL_MS = 0x28, + BSSGP_PDUT_FLOW_CONTROL_MS_ACK = 0x29, + BSSGP_PDUT_FLUSH_LL = 0x2a, + BSSGP_PDUT_FLUSH_LL_ACK = 0x2b, + BSSGP_PDUT_LLC_DISCARD = 0x2c, + BSSGP_PDUT_SGSN_INVOKE_TRACE = 0x40, + BSSGP_PDUT_STATUS = 0x41, + /* PDUs between PFM SAP's */ + BSSGP_PDUT_DOWNLOAD_BSS_PFC = 0x50, + BSSGP_PDUT_CREATE_BSS_PFC = 0x51, + BSSGP_PDUT_CREATE_BSS_PFC_ACK = 0x52, + BSSGP_PDUT_CREATE_BSS_PFC_NACK = 0x53, + BSSGP_PDUT_MODIFY_BSS_PFC = 0x54, + BSSGP_PDUT_MODIFY_BSS_PFC_ACK = 0x55, + BSSGP_PDUT_DELETE_BSS_PFC = 0x56, + BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57, +}; + +/* Section 10.2.1 and 10.2.2 */ +struct bssgp_ud_hdr { + u_int8_t pdu_type; + u_int32_t tlli; + u_int8_t qos_profile[3]; + u_int8_t data[0]; /* TLV's */ +} __attribute__((packed)); + +struct bssgp_normal_hdr { + u_int8_t pdu_type; + u_int8_t data[0]; /* TLV's */ +}; + +enum bssgp_iei_type { + BSSGP_IE_ALIGNMENT = 0x00, + BSSGP_IE_BMAX_DEFAULT_MS = 0x01, + BSSGP_IE_BSS_AREA_ID = 0x02, + BSSGP_IE_BUCKET_LEAK_RATE = 0x03, + BSSGP_IE_BVCI = 0x04, + BSSGP_IE_BVC_BUCKET_SIZE = 0x05, + BSSGP_IE_BVC_MEASUREMENT = 0x06, + BSSGP_IE_CAUSE = 0x07, + BSSGP_IE_CELL_ID = 0x08, + BSSGP_IE_CHAN_NEEDED = 0x09, + BSSGP_IE_DRX_PARAMS = 0x0a, + BSSGP_IE_EMLPP_PRIO = 0x0b, + BSSGP_IE_FLUSH_ACTION = 0x0c, + BSSGP_IE_IMSI = 0x0d, + BSSGP_IE_LLC_PDU = 0x0e, + BSSGP_IE_LLC_FRAMES_DISCARDED = 0x0f, + BSSGP_IE_LOCATION_AREA = 0x10, + BSSGP_IE_MOBILE_ID = 0x11, + BSSGP_IE_MS_BUCKET_SIZE = 0x12, + BSSGP_IE_MS_RADIO_ACCESS_CAP = 0x13, + BSSGP_IE_OMC_ID = 0x14, + BSSGP_IE_PDU_IN_ERROR = 0x15, + BSSGP_IE_PDU_LIFETIME = 0x16, + BSSGP_IE_PRIORITY = 0x17, + BSSGP_IE_QOS_PROFILE = 0x18, + BSSGP_IE_RADIO_CAUSE = 0x19, + BSSGP_IE_RA_CAP_UPD_CAUSE = 0x1a, + BSSGP_IE_ROUTEING_AREA = 0x1b, + BSSGP_IE_R_DEFAULT_MS = 0x1c, + BSSGP_IE_SUSPEND_REF_NR = 0x1d, + BSSGP_IE_TAG = 0x1e, + BSSGP_IE_TLLI = 0x1f, + BSSGP_IE_TMSI = 0x20, + BSSGP_IE_TRACE_REFERENC = 0x21, + BSSGP_IE_TRACE_TYPE = 0x22, + BSSGP_IE_TRANSACTION_ID = 0x23, + BSSGP_IE_TRIGGER_ID = 0x24, + BSSGP_IE_NUM_OCT_AFF = 0x25, + BSSGP_IE_LSA_ID_LIST = 0x26, + BSSGP_IE_LSA_INFORMATION = 0x27, + BSSGP_IE_PACKET_FLOW_ID = 0x28, + BSSGP_IE_PACKET_FLOW_TIMER = 0x29, + BSSGP_IE_AGG_BSS_QOS_PROFILE = 0x3a, + BSSGP_IE_FEATURE_BITMAP = 0x3b, + BSSGP_IE_BUCKET_FULL_RATIO = 0x3c, + BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d, +}; + +/* Section 11.3.8 / Table 11.10: Cause coding */ +enum gprs_bssgp_cause { + BSSGP_CAUSE_PROC_OVERLOAD = 0x00, + BSSGP_CAUSE_EQUIP_FAIL = 0x01, + BSSGP_CAUSE_TRASIT_NET_FAIL = 0x02, + BSSGP_CAUSE_CAPA_GREATER_0KPBS = 0x03, + BSSGP_CAUSE_UNKNOWN_MS = 0x04, + BSSGP_CAUSE_UNKNOWN_BVCI = 0x05, + BSSGP_CAUSE_CELL_TRAF_CONG = 0x06, + BSSGP_CAUSE_SGSN_CONG = 0x07, + BSSGP_CAUSE_OML_INTERV = 0x08, + BSSGP_CAUSE_BVCI_BLOCKED = 0x09, + BSSGP_CAUSE_PFC_CREATE_FAIL = 0x0a, + BSSGP_CAUSE_SEM_INCORR_PDU = 0x20, + BSSGP_CAUSE_INV_MAND_INF = 0x21, + BSSGP_CAUSE_MISSING_MAND_IE = 0x22, + BSSGP_CAUSE_MISSING_COND_IE = 0x23, + BSSGP_CAUSE_UNEXP_COND_IE = 0x24, + BSSGP_CAUSE_COND_IE_ERR = 0x25, + BSSGP_CAUSE_PDU_INCOMP_STATE = 0x26, + BSSGP_CAUSE_PROTO_ERR_UNSPEC = 0x27, + BSSGP_CAUSE_PDU_INCOMP_FEAT = 0x28, +}; + +extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci); + +#endif /* _GPRS_BSSGP_H */ diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h new file mode 100644 index 000000000..90f1adf3e --- /dev/null +++ b/openbsc/include/openbsc/gprs_ns.h @@ -0,0 +1,61 @@ +#ifndef _GPRS_NS_H +#define _GPRS_NS_H + +struct gprs_ns_hdr { + u_int8_t pdu_type; + u_int8_t data[0]; +} __attribute__((packed)); + +/* TS 08.16, Section 10.3.7, Table 14 */ +enum ns_pdu_type { + NS_PDUT_UNITDATA = 0x00, + NS_PDUT_RESET = 0x02, + NS_PDUT_RESET_ACK = 0x03, + NS_PDUT_BLOCK = 0x04, + NS_PDUT_BLOCK_ACK = 0x05, + NS_PDUT_UNBLOCK = 0x06, + NS_PDUT_UNBLOCK_ACK = 0x07, + NS_PDUT_STATUS = 0x08, + NS_PDUT_ALIVE = 0x0a, + NS_PDUT_ALIVE_ACK = 0x0b, +}; + +/* TS 08.16, Section 10.3, Table 12 */ +enum ns_ctrl_ie { + NS_IE_CAUSE = 0x00, + NS_IE_VCI = 0x01, + NS_IE_PDU = 0x02, + NS_IE_BVCI = 0x03, + NS_IE_NSEI = 0x04, +}; + +/* TS 08.16, Section 10.3.2, Table 13 */ +enum ns_cause { + NS_CAUSE_TRANSIT_FAIL = 0x00, + NS_CAUSE_OM_INTERVENTION = 0x01, + NS_CAUSE_EQUIP_FAIL = 0x02, + NS_CAUSE_NSVC_BLOCKED = 0x03, + NS_CAUSE_NSVC_UNKNOWN = 0x04, + NS_CAUSE_BVCI_UNKNOWN = 0x05, + NS_CAUSE_SEM_INCORR_PDU = 0x08, + NS_CAUSE_PDU_INCOMP_PSTATE = 0x0a, + NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b, + NS_CAUSE_INVAL_ESSENT_IE = 0x0c, + NS_CAUSE_MISSING_ESSENT_IE = 0x0d, +}; + +/* a layer 1 entity transporting NS frames */ +struct gprs_ns_link { + union { + struct { + int fd; + } ip; + }; +}; + + +int gprs_ns_rcvmsg(struct msgb *msg); + +int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, + struct msgb *msg); +#endif diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c new file mode 100644 index 000000000..de57d25df --- /dev/null +++ b/openbsc/src/gprs_bssgp.c @@ -0,0 +1,397 @@ +/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ + +/* (C) 2009 by Harald Welte + * + * 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 +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* global pointer to the gsm network data structure */ +/* FIXME: this must go! */ +extern struct gsm_network *bsc_gsmnet; + +/* Chapter 11.3.9 / Table 11.10: Cause coding */ +static const char *bssgp_cause_strings[] = { + [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload", + [BSSGP_CAUSE_EQUIP_FAIL] = "Equipment Failure", + [BSSGP_CAUSE_TRASIT_NET_FAIL] = "Transit netowkr service failure", + [BSSGP_CAUSE_CAPA_GREATER_0KPBS]= "Transmission capacity modified", + [BSSGP_CAUSE_UNKNOWN_MS] = "Unknown MS", + [BSSGP_CAUSE_UNKNOWN_BVCI] = "Unknown BVCI", + [BSSGP_CAUSE_CELL_TRAF_CONG] = "Cell traffic congestion", + [BSSGP_CAUSE_SGSN_CONG] = "SGSN congestion", + [BSSGP_CAUSE_OML_INTERV] = "O&M intervention", + [BSSGP_CAUSE_BVCI_BLOCKED] = "BVCI blocked", + [BSSGP_CAUSE_PFC_CREATE_FAIL] = "PFC create failure", + [BSSGP_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", + [BSSGP_CAUSE_INV_MAND_INF] = "Invalid mandatory information", + [BSSGP_CAUSE_MISSING_MAND_IE] = "Missing mandatory IE", + [BSSGP_CAUSE_MISSING_COND_IE] = "Missing conditional IE", + [BSSGP_CAUSE_UNEXP_COND_IE] = "Unexpected conditional IE", + [BSSGP_CAUSE_COND_IE_ERR] = "Conditional IE error", + [BSSGP_CAUSE_PDU_INCOMP_STATE] = "PDU incompatible with protocol state", + [BSSGP_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error - unspecified", + [BSSGP_CAUSE_PDU_INCOMP_FEAT] = "PDU not compatible with feature set", +}; + +static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) +{ + if (cause >= ARRAY_SIZE(bssgp_cause_strings)) + return "undefined"; + + if (bssgp_cause_strings[cause]) + return bssgp_cause_strings[cause]; + + return "undefined"; +} + +static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) +{ + return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); +} + +static inline struct msgb *bssgp_msgb_alloc(void) +{ + return msgb_alloc_headroom(4096, 128, "BSSGP"); +} + +/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ +static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t bvci, u_int16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + u_int16_t _bvci; + + bgph->pdu_type = pdu_type; + _bvci = htons(bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + + return gprs_ns_sendmsg(NULL, ns_bvci, msg); +} + +/* Chapter 10.4.5: Flow Control BVC ACK */ +static int bssgp_tx_fc_bvc_ack(u_int8_t tag, u_int16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK; + msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag); + + return gprs_ns_sendmsg(NULL, ns_bvci, msg); +} + +/* Chapter 10.4.14: Status */ +static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + + bgph->pdu_type = BSSGP_PDUT_STATUS; + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + if (bvci) { + u_int16_t _bvci = htons(*bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + } + if (orig_msg) + msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, + msgb_l3len(orig_msg), orig_msg->l3h); + + return gprs_ns_sendmsg(NULL, 0, msg); +} + +/* Uplink unit-data */ +static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) +{ + struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h; + struct gsm_bts *bts; + int data_len = msgb_l3len(msg) - sizeof(*budh); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP UL-UD\n"); + + msg->tlli = ntohl(budh->tlli); + rc = bssgp_tlv_parse(&tp, budh->data, data_len); + + /* Cell ID and LLC_PDU are the only mandatory IE */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) || + !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) + return -EIO; + + /* Determine the BTS based on the Cell ID */ + bts = gsm48_bts_by_ra_id(bsc_gsmnet, + TLVP_VAL(&tp, BSSGP_IE_CELL_ID), + TLVP_LEN(&tp, BSSGP_IE_CELL_ID)); + if (bts) + msg->trx = bts->c0; + + msg->llch = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); + + return gprs_llc_rcvmsg(msg, &tp); +} + +static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP SUSPEND\n"); + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + if (rc < 0) + return rc; + + if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + return -EIO; + + /* SEND SUSPEND_ACK or SUSPEND_NACK */ + /* FIXME */ +} + +static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP RESUME\n"); + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + if (rc < 0) + return rc; + + if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) || + !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR)) + return -EIO; + + /* SEND RESUME_ACK or RESUME_NACK */ + /* FIXME */ +} + +static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, + u_int16_t ns_bvci) +{ + + DEBUGP(DGPRS, "BSSGP FC BVC\n"); + + if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) || + !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) || + !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) || + !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) || + !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + + /* Send FLOW_CONTROL_BVC_ACK */ + return bssgp_tx_fc_bvc_ack(*TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci); +} +/* We expect msg->l3h to point to the BSSGP header */ +int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct tlv_parsed tp; + u_int8_t pdu_type = bgph->pdu_type; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + u_int16_t bvci; + int rc = 0; + + if (pdu_type != BSSGP_PDUT_UL_UNITDATA && + pdu_type != BSSGP_PDUT_DL_UNITDATA) + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_UL_UNITDATA: + /* some LLC data from the MS */ + rc = bssgp_rx_ul_ud(msg, ns_bvci); + break; + case BSSGP_PDUT_RA_CAPABILITY: + /* BSS requests RA capability or IMSI */ + DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n"); + /* FIXME: send RA_CAPA_UPDATE_ACK */ + break; + case BSSGP_PDUT_RADIO_STATUS: + DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); + /* BSS informs us of some exception */ + break; + case BSSGP_PDUT_SUSPEND: + /* MS wants to suspend */ + rc = bssgp_rx_suspend(msg, ns_bvci); + break; + case BSSGP_PDUT_RESUME: + /* MS wants to resume */ + rc = bssgp_rx_resume(msg, ns_bvci); + break; + case BSSGP_PDUT_FLUSH_LL: + /* BSS informs MS has moved to one cell to other cell */ + DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); + /* Send FLUSH_LL_ACK */ + break; + case BSSGP_PDUT_LLC_DISCARD: + /* BSS informs that some LLC PDU's have been discarded */ + DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); + break; + case BSSGP_PDUT_FLOW_CONTROL_BVC: + /* BSS informs us of available bandwidth in Gb interface */ + rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci); + break; + case BSSGP_PDUT_FLOW_CONTROL_MS: + /* BSS informs us of available bandwidth to one MS */ + DEBUGP(DGPRS, "BSSGP FC MS\n"); + /* Send FLOW_CONTROL_MS_ACK */ + break; + case BSSGP_PDUT_BVC_BLOCK: + /* BSS tells us that BVC shall be blocked */ + DEBUGP(DGPRS, "BSSGP BVC BLOCK "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, + bvci, ns_bvci); + break; + case BSSGP_PDUT_BVC_UNBLOCK: + /* BSS tells us that BVC shall be unblocked */ + DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) + goto err_mand_ie; + bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u\n", bvci); + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, + bvci, ns_bvci); + break; + case BSSGP_PDUT_BVC_RESET: + /* BSS tells us that BVC init is required */ + DEBUGP(DGPRS, "BSSGP BVC RESET "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + bvci, ns_bvci); + break; + case BSSGP_PDUT_STATUS: + /* Some exception has occurred */ + case BSSGP_PDUT_DOWNLOAD_BSS_PFC: + case BSSGP_PDUT_CREATE_BSS_PFC_ACK: + case BSSGP_PDUT_CREATE_BSS_PFC_NACK: + case BSSGP_PDUT_MODIFY_BSS_PFC: + case BSSGP_PDUT_DELETE_BSS_PFC_ACK: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n", + pdu_type); + break; + /* those only exist in the SGSN -> BSS direction */ + case BSSGP_PDUT_DL_UNITDATA: + case BSSGP_PDUT_PAGING_PS: + case BSSGP_PDUT_PAGING_CS: + case BSSGP_PDUT_RA_CAPA_UPDATE_ACK: + case BSSGP_PDUT_SUSPEND_ACK: + case BSSGP_PDUT_SUSPEND_NACK: + case BSSGP_PDUT_RESUME_ACK: + case BSSGP_PDUT_RESUME_NACK: + case BSSGP_PDUT_FLUSH_LL_ACK: + case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: + case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: + case BSSGP_PDUT_BVC_BLOCK_ACK: + case BSSGP_PDUT_BVC_UNBLOCK_ACK: + case BSSGP_PDUT_SGSN_INVOKE_TRACE: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n", + pdu_type); + rc = -EINVAL; + break; + default: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + break; + } + + return rc; +err_mand_ie: + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); +} + +int gprs_bssgp_tx_dl_ud(struct msgb *msg) +{ + struct gsm_bts *bts; + struct bssgp_ud_hdr *budh; + u_int8_t llc_pdu_tlv_hdr_len = 2; + u_int8_t *llc_pdu_tlv, *qos_profile; + u_int16_t pdu_lifetime = 1000; /* centi-seconds */ + u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; + u_int16_t msg_len = msg->len; + + if (!msg->trx) { + DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n"); + return -EINVAL; + } + + bts = msg->trx->bts; + + if (msg->len > TVLV_MAX_ONEBYTE) + llc_pdu_tlv_hdr_len += 1; + + /* prepend the tag and length of the LLC-PDU TLV */ + llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len); + llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU; + if (llc_pdu_tlv_hdr_len > 2) { + llc_pdu_tlv[1] = msg_len >> 8; + llc_pdu_tlv[2] = msg_len & 0xff; + } else { + llc_pdu_tlv[1] = msg_len & 0x3f; + llc_pdu_tlv[1] |= 0x80; + } + + /* FIXME: optional elements */ + + /* prepend the pdu lifetime */ + pdu_lifetime = htons(pdu_lifetime); + msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime); + + /* prepend the QoS profile, TLLI and pdu type */ + budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); + memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default)); + budh->tlli = htonl(msg->tlli); + budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; + + return gprs_ns_sendmsg(NULL, bts->gprs.cell.bvci, msg); +} diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c new file mode 100644 index 000000000..a686a22aa --- /dev/null +++ b/openbsc/src/gprs_ns.c @@ -0,0 +1,348 @@ +/* GPRS Networks Service (NS) messages on the Gb interface + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ + +/* (C) 2009 by Harald Welte + * + * 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. + * + */ + +/* Some introduction into NS: NS is used typically on top of frame relay, + * but in the ip.access world it is encapsulated in UDP packets. It serves + * as an intermediate shim betwen BSSGP and the underlying medium. It doesn't + * do much, apart from providing congestion notification and status indication. + * + * Terms: + * NS Network Service + * NSVC NS Virtual Connection + * NSEI NS Entity Identifier + * NSVL NS Virtual Link + * NSVLI NS Virtual Link Identifier + * BVC BSSGP Virtual Connection + * BVCI BSSGP Virtual Connection Identifier + * NSVCG NS Virtual Connection Goup + * Blocked NS-VC cannot be used for user traffic + * Alive Ability of a NS-VC to provide communication + * + * There can be multiple BSSGP virtual connections over one (group of) NSVC's. BSSGP will + * therefore identify the BSSGP virtual connection by a BVCI passed down to NS. + * NS then has to firgure out which NSVC's are responsible for this BVCI. + * Those mappings are administratively configured. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NS_ALLOC_SIZE 1024 + +static const struct tlv_definition ns_att_tlvdef = { + .def = { + [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_VCI] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_PDU] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_BVCI] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_NSEI] = { TLV_TYPE_TvLV, 0 }, + }, +}; + +#define NSE_S_BLOCKED 0x0001 +#define NSE_S_ALIVE 0x0002 + +struct gprs_nsvc { + struct llist_head list; + + u_int16_t nsei; /* end-to-end significance */ + u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ + + u_int32_t state; + + struct timer_list alive_timer; + int timer_is_tns_alive; + int alive_retries; +}; + +/* FIXME: dynamically search for the matching NSVC */ +static struct gprs_nsvc dummy_nsvc = { .state = NSE_S_BLOCKED | NSE_S_ALIVE }; + +/* Section 10.3.2, Table 13 */ +static const char *ns_cause_str[] = { + [NS_CAUSE_TRANSIT_FAIL] = "Transit network failure", + [NS_CAUSE_OM_INTERVENTION] = "O&M intervention", + [NS_CAUSE_EQUIP_FAIL] = "Equipment failure", + [NS_CAUSE_NSVC_BLOCKED] = "NS-VC blocked", + [NS_CAUSE_NSVC_UNKNOWN] = "NS-VC unknown", + [NS_CAUSE_BVCI_UNKNOWN] = "BVCI unknown", + [NS_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", + [NS_CAUSE_PDU_INCOMP_PSTATE] = "PDU not compatible with protocol state", + [NS_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error, unspecified", + [NS_CAUSE_INVAL_ESSENT_IE] = "Invalid essential IE", + [NS_CAUSE_MISSING_ESSENT_IE] = "Missing essential IE", +}; + +static const char *gprs_ns_cause_str(enum ns_cause cause) +{ + if (cause >= ARRAY_SIZE(ns_cause_str)) + return "undefined"; + + if (ns_cause_str[cause]) + return ns_cause_str[cause]; + + return "undefined"; +} + +static int gprs_ns_tx(struct msgb *msg) +{ + return ipac_gprs_send(msg); +} + +static int gprs_ns_tx_simple(struct gprs_ns_link *link, u_int8_t pdu_type) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + + nsh->pdu_type = pdu_type; + + return gprs_ns_tx(msg); +} + +#define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ +#define NS_TIMER_TEST 30, 0 /* every 10 seconds we check if the BTS is still alive */ +#define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ + +static void gprs_ns_alive_cb(void *data) +{ + struct gprs_nsvc *nsvc = data; + + if (nsvc->timer_is_tns_alive) { + /* Tns-alive case: we expired without response ! */ + nsvc->alive_retries++; + if (nsvc->alive_retries > NS_ALIVE_RETRIES) { + /* mark as dead and blocked */ + nsvc->state = NSE_S_BLOCKED; + DEBUGP(DGPRS, "Tns-alive more then %u retries, " + " blocking NS-VC\n", NS_ALIVE_RETRIES); + /* FIXME: inform higher layers */ + return; + } + } else { + /* Tns-test case: send NS-ALIVE PDU */ + gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE); + /* start Tns-alive timer */ + nsvc->timer_is_tns_alive = 1; + } + bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); +} + +/* Section 9.2.6 */ +static int gprs_ns_tx_reset_ack(u_int16_t nsvci, u_int16_t nsei) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + + if (!msg) + return -ENOMEM; + + nsvci = htons(nsvci); + nsei = htons(nsei); + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + + nsh->pdu_type = NS_PDUT_RESET_ACK; + + msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); + + return gprs_ns_tx(msg); +} + +/* Section 9.2.10: transmit side */ +int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, + struct msgb *msg) +{ + struct gprs_ns_hdr *nsh; + + nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); + if (!nsh) { + DEBUGP(DGPRS, "Not enough headroom for NS header\n"); + return -EIO; + } + + nsh->pdu_type = NS_PDUT_UNITDATA; + /* spare octet in data[0] */ + nsh->data[1] = bvci >> 8; + nsh->data[2] = bvci & 0xff; + + return gprs_ns_tx(msg); +} + +/* Section 9.2.10: receive side */ +static int gprs_ns_rx_unitdata(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; + u_int16_t bvci; + + /* spare octet in data[0] */ + bvci = nsh->data[1] << 8 | nsh->data[2]; + msg->l3h = &nsh->data[3]; + + /* call upper layer (BSSGP) */ + return gprs_bssgp_rcvmsg(msg, bvci); +} + +/* Section 9.2.7 */ +static int gprs_ns_rx_status(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = msg->l2h; + struct tlv_parsed tp; + u_int8_t cause; + int rc; + + DEBUGP(DGPRS, "NS STATUS "); + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { + DEBUGPC(DGPRS, "missing cause IE\n"); + return -EINVAL; + } + + cause = *TLVP_VAL(&tp, NS_IE_CAUSE); + DEBUGPC(DGPRS, "cause=%s\n", gprs_ns_cause_str(cause)); + + return 0; +} + +/* Section 7.3 */ +static int gprs_ns_rx_reset(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = &dummy_nsvc; + struct tlv_parsed tp; + u_int8_t *cause; + u_int16_t *nsvci, *nsei; + int rc; + + DEBUGP(DGPRS, "NS RESET "); + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || + !TLVP_PRESENT(&tp, NS_IE_VCI) || + !TLVP_PRESENT(&tp, NS_IE_NSEI)) { + /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ + DEBUGPC(DGPRS, "Missing mandatory IE\n"); + return -EINVAL; + } + + cause = (u_int8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + nsvci = (u_int16_t *) TLVP_VAL(&tp, NS_IE_VCI); + nsei = (u_int16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + + *nsvci = ntohs(*nsvci); + *nsei = ntohs(*nsei); + + DEBUGPC(DGPRS, "cause=%s, NSVCI=%u, NSEI=%u\n", + gprs_ns_cause_str(*cause), *nsvci, *nsei); + + /* mark the NS-VC as blocked and alive */ + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + nsvc->nsei = *nsei; + nsvc->nsvci = *nsvci; + + /* start the test procedure */ + nsvc->alive_timer.cb = gprs_ns_alive_cb; + nsvc->alive_timer.data = nsvc; + bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); + + return gprs_ns_tx_reset_ack(*nsvci, *nsei); +} + +/* main entry point, here incoming NS frames enter */ +int gprs_ns_rcvmsg(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = &dummy_nsvc; + int rc = 0; + + switch (nsh->pdu_type) { + case NS_PDUT_ALIVE: + /* remote end inquires whether we're still alive, + * we need to respond with ALIVE_ACK */ + rc = gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE_ACK); + break; + case NS_PDUT_ALIVE_ACK: + /* stop Tns-alive */ + bsc_del_timer(&nsvc->alive_timer); + /* start Tns-test */ + nsvc->timer_is_tns_alive = 0; + bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_TEST); + break; + case NS_PDUT_UNITDATA: + /* actual user data */ + rc = gprs_ns_rx_unitdata(msg); + break; + case NS_PDUT_STATUS: + rc = gprs_ns_rx_status(msg); + break; + case NS_PDUT_RESET: + rc = gprs_ns_rx_reset(msg); + break; + case NS_PDUT_RESET_ACK: + /* FIXME: mark remote NS-VC as blocked + active */ + break; + case NS_PDUT_UNBLOCK: + /* Section 7.2: unblocking procedure */ + DEBUGP(DGPRS, "NS UNBLOCK\n"); + nsvc->state &= ~NSE_S_BLOCKED; + rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + break; + case NS_PDUT_UNBLOCK_ACK: + /* FIXME: mark remote NS-VC as unblocked + active */ + break; + case NS_PDUT_BLOCK: + DEBUGP(DGPRS, "NS BLOCK\n"); + nsvc->state |= NSE_S_BLOCKED; + rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + break; + case NS_PDUT_BLOCK_ACK: + /* FIXME: mark remote NS-VC as blocked + active */ + break; + default: + DEBUGP(DGPRS, "Unknown NS PDU type 0x%02x\n", nsh->pdu_type); + rc = -EINVAL; + break; + } + return rc; +} + From c547848eadb3f285078a68d17240ba9280c2c117 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Mar 2010 00:01:43 +0800 Subject: [PATCH 033/198] GPRS: remove hard-coded IP address for NSIP responses from SGSN->BTS --- openbsc/include/openbsc/gprs_ns.h | 2 +- openbsc/src/gprs_ns.c | 54 ++++++++++++++++++------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 90f1adf3e..9ea4d6752 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -54,7 +54,7 @@ struct gprs_ns_link { }; -int gprs_ns_rcvmsg(struct msgb *msg); +int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr); int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, struct msgb *msg); diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index a686a22aa..6fb7d1d93 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -85,6 +85,12 @@ struct gprs_nsvc { struct timer_list alive_timer; int timer_is_tns_alive; int alive_retries; + + union { + struct { + struct sockaddr_in bts_addr; + } ip; + }; }; /* FIXME: dynamically search for the matching NSVC */ @@ -116,12 +122,12 @@ static const char *gprs_ns_cause_str(enum ns_cause cause) return "undefined"; } -static int gprs_ns_tx(struct msgb *msg) +static int gprs_ns_tx(struct msgb *msg, struct gprs_nsvc *nsvc) { - return ipac_gprs_send(msg); + return ipac_gprs_send(msg, &nsvc->ip.bts_addr); } -static int gprs_ns_tx_simple(struct gprs_ns_link *link, u_int8_t pdu_type) +static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; @@ -133,7 +139,7 @@ static int gprs_ns_tx_simple(struct gprs_ns_link *link, u_int8_t pdu_type) nsh->pdu_type = pdu_type; - return gprs_ns_tx(msg); + return gprs_ns_tx(msg, nsvc); } #define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ @@ -157,7 +163,7 @@ static void gprs_ns_alive_cb(void *data) } } else { /* Tns-test case: send NS-ALIVE PDU */ - gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE); + gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); /* start Tns-alive timer */ nsvc->timer_is_tns_alive = 1; } @@ -165,25 +171,28 @@ static void gprs_ns_alive_cb(void *data) } /* Section 9.2.6 */ -static int gprs_ns_tx_reset_ack(u_int16_t nsvci, u_int16_t nsei) +static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; + u_int16_t nsvci, nsei; if (!msg) return -ENOMEM; - nsvci = htons(nsvci); - nsei = htons(nsei); + nsvci = htons(nsvc->nsvci); + nsei = htons(nsvc->nsei); nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); nsh->pdu_type = NS_PDUT_RESET_ACK; + DEBUGP(DGPRS, "nsvci=%u, nsei=%u\n", nsvc->nsvci, nsvc->nsei); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); - return gprs_ns_tx(msg); + return gprs_ns_tx(msg, nsvc); } /* Section 9.2.10: transmit side */ @@ -191,6 +200,7 @@ int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, struct msgb *msg) { struct gprs_ns_hdr *nsh; + struct gprs_nsvc *nsvc = &dummy_nsvc; nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { @@ -203,7 +213,7 @@ int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, nsh->data[1] = bvci >> 8; nsh->data[2] = bvci & 0xff; - return gprs_ns_tx(msg); + return gprs_ns_tx(msg, nsvc); } /* Section 9.2.10: receive side */ @@ -269,37 +279,37 @@ static int gprs_ns_rx_reset(struct msgb *msg) nsvci = (u_int16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (u_int16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - *nsvci = ntohs(*nsvci); - *nsei = ntohs(*nsei); + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + nsvc->nsei = ntohs(*nsei); + nsvc->nsvci = ntohs(*nsvci); DEBUGPC(DGPRS, "cause=%s, NSVCI=%u, NSEI=%u\n", - gprs_ns_cause_str(*cause), *nsvci, *nsei); + gprs_ns_cause_str(*cause), nsvc->nsvci, nsvc->nsei); /* mark the NS-VC as blocked and alive */ - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; - nsvc->nsei = *nsei; - nsvc->nsvci = *nsvci; - /* start the test procedure */ nsvc->alive_timer.cb = gprs_ns_alive_cb; nsvc->alive_timer.data = nsvc; bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); - return gprs_ns_tx_reset_ack(*nsvci, *nsei); + return gprs_ns_tx_reset_ack(nsvc); } /* main entry point, here incoming NS frames enter */ -int gprs_ns_rcvmsg(struct msgb *msg) +int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct gprs_nsvc *nsvc = &dummy_nsvc; int rc = 0; + /* FIXME: do this properly! */ + nsvc->ip.bts_addr = *saddr; + switch (nsh->pdu_type) { case NS_PDUT_ALIVE: /* remote end inquires whether we're still alive, * we need to respond with ALIVE_ACK */ - rc = gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE_ACK); + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ @@ -325,7 +335,7 @@ int gprs_ns_rcvmsg(struct msgb *msg) /* Section 7.2: unblocking procedure */ DEBUGP(DGPRS, "NS UNBLOCK\n"); nsvc->state &= ~NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: /* FIXME: mark remote NS-VC as unblocked + active */ @@ -333,7 +343,7 @@ int gprs_ns_rcvmsg(struct msgb *msg) case NS_PDUT_BLOCK: DEBUGP(DGPRS, "NS BLOCK\n"); nsvc->state |= NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: /* FIXME: mark remote NS-VC as blocked + active */ From 510c3920c8e965d1bd36ece2a686d9e63f009d17 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 16:33:12 +0200 Subject: [PATCH 034/198] gprs: Update gprs-sgsn branch to use new msgb->cb layout The explicit 'tlli, gmmh' members of struct msgb are gone from current libosmocore and have been replaced by the more generic 'control buffer' mechanism. --- openbsc/src/gprs_bssgp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index de57d25df..b4436294d 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -144,7 +144,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) DEBUGP(DGPRS, "BSSGP UL-UD\n"); - msg->tlli = ntohl(budh->tlli); + msgb_tlli(msg) = ntohl(budh->tlli); rc = bssgp_tlv_parse(&tp, budh->data, data_len); /* Cell ID and LLC_PDU are the only mandatory IE */ @@ -159,7 +159,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) if (bts) msg->trx = bts->c0; - msg->llch = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); + msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); return gprs_llc_rcvmsg(msg, &tp); } @@ -390,7 +390,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) /* prepend the QoS profile, TLLI and pdu type */ budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default)); - budh->tlli = htonl(msg->tlli); + budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; return gprs_ns_sendmsg(NULL, bts->gprs.cell.bvci, msg); From f030b210e8c13314d361a6b721a0cbcc72935219 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 26 Apr 2010 19:18:54 +0200 Subject: [PATCH 035/198] GPRS: Modularize the NS implementation * move UDP listener code for NSIP from input/ipaccess.c and into gprs_ns.c * add PDU type, IE and CAUSE values for later IP based 3GPP TS 48.016 * support multiple NS-VCs and their lookup based on NSVC and sockaddr_in * maintain the remote_state (blocked/alive) for each NSVC * introduce the concept of GPRS_NS instances, move all global vars to instance * remove hardcoded calls to gprs_bssgp_rcvmsg() and replace it by callback WARNING: This is not finished code. While it will compile, it will not work yet, as BSSGP needs to be converted to properly indicate the NSVC to which it needs to send data. --- openbsc/include/openbsc/gprs_ns.h | 62 ++++++-- openbsc/src/gprs_ns.c | 253 +++++++++++++++++++++++++++--- 2 files changed, 284 insertions(+), 31 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 9ea4d6752..98b31f8da 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -1,6 +1,10 @@ #ifndef _GPRS_NS_H #define _GPRS_NS_H +/* GPRS Networks Service (NS) messages on the Gb interface + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) + * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ + struct gprs_ns_hdr { u_int8_t pdu_type; u_int8_t data[0]; @@ -18,6 +22,15 @@ enum ns_pdu_type { NS_PDUT_STATUS = 0x08, NS_PDUT_ALIVE = 0x0a, NS_PDUT_ALIVE_ACK = 0x0b, + /* TS 48.016 Section 10.3.7, Table 10.3.7.1 */ + SNS_PDUT_ACK = 0x0c, + SNS_PDUT_ADD = 0x0d, + SNS_PDUT_CHANGE_WEIGHT = 0x0e, + SNS_PDUT_CONFIG = 0x0f, + SNS_PDUT_CONFIG_ACK = 0x10, + SNS_PDUT_DELETE = 0x11, + SNS_PDUT_SIZE = 0x12, + SNS_PDUT_SIZE_ACK = 0x13, }; /* TS 08.16, Section 10.3, Table 12 */ @@ -27,6 +40,14 @@ enum ns_ctrl_ie { NS_IE_PDU = 0x02, NS_IE_BVCI = 0x03, NS_IE_NSEI = 0x04, + /* TS 48.016 Section 10.3, Table 10.3.1 */ + NS_IE_IPv4_LIST = 0x05, + NS_IE_IPv6_LIST = 0x06, + NS_IE_MAX_NR_NSVC = 0x07, + NS_IE_IPv4_EP_NR = 0x08, + NS_IE_IPv6_EP_NR = 0x09, + NS_IE_RESET_FLAG = 0x0a, + NS_IE_IP_ADDR = 0x0b, }; /* TS 08.16, Section 10.3.2, Table 13 */ @@ -42,20 +63,43 @@ enum ns_cause { NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b, NS_CAUSE_INVAL_ESSENT_IE = 0x0c, NS_CAUSE_MISSING_ESSENT_IE = 0x0d, + /* TS 48.016 Section 10.3.2, Table 10.3.2.1 */ + NS_CAUSE_INVAL_NR_IPv4_EP = 0x0e, + NS_CAUSE_INVAL_NR_IPv6_EP = 0x0f, + NS_CAUSE_INVAL_NR_NS_VC = 0x10, + NS_CAUSE_INVAL_WEIGH = 0x11, + NS_CAUSE_UNKN_IP_EP = 0x12, + NS_CAUSE_UNKN_IP_ADDR = 0x13, + NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, }; -/* a layer 1 entity transporting NS frames */ -struct gprs_ns_link { - union { - struct { - int fd; - } ip; - }; +struct gprs_nsvc; +struct gprs_ns_inst; + +enum gprs_ns_evt { + GPRS_NS_EVT_UNIT_DATA, }; +typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci); -int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr); +/* Create a new NS protocol instance */ +struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); -int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, +/* Destroy a NS protocol instance */ +void gprs_ns_destroy(struct gprs_ns_inst *nsi); + +/* Listen for incoming GPRS packets */ +int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); + +struct sockaddr_in; + +/* main entry point, here incoming NS frames enter */ +int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, + struct sockaddr_in *saddr); + +/* main function for higher layers (BSSGP) to send NS messages */ +int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, struct msgb *msg); + #endif diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 6fb7d1d93..c5166fa53 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -1,7 +1,7 @@ /* GPRS Networks Service (NS) messages on the Gb interface * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ -/* (C) 2009 by Harald Welte +/* (C) 2009-2010 by Harald Welte * * All Rights Reserved * @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -76,11 +77,13 @@ static const struct tlv_definition ns_att_tlvdef = { struct gprs_nsvc { struct llist_head list; + struct gprs_ns_inst *nsi; u_int16_t nsei; /* end-to-end significance */ u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ u_int32_t state; + u_int32_t remote_state; struct timer_list alive_timer; int timer_is_tns_alive; @@ -93,8 +96,67 @@ struct gprs_nsvc { }; }; -/* FIXME: dynamically search for the matching NSVC */ -static struct gprs_nsvc dummy_nsvc = { .state = NSE_S_BLOCKED | NSE_S_ALIVE }; +enum gprs_ns_ll { + GPRS_NS_LL_UDP, + GPRS_NS_LL_E1, +}; + +/* An instance of the NS protocol stack */ +struct gprs_ns_inst { + /* callback to the user for incoming UNIT DATA IND */ + gprs_ns_cb_t *cb; + + /* linked lists of all NSVC in this instance */ + struct llist_head gprs_nsvcs; + + /* which link-layer are we based on? */ + enum gprs_ns_ll ll; + + union { + /* NS-over-IP specific bits */ + struct { + struct bsc_fd fd; + } nsip; + }; +}; + +/* Lookup struct gprs_nsvc based on NSVCI */ +static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, + u_int16_t nsvci) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc->nsvci == nsvci) + return nsvc; + } + return NULL; +} + +/* Lookup struct gprs_nsvc based on remote peer socket addr */ +static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, + struct sockaddr_in *sin) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (!memcmp(&nsvc->ip.bts_addr, sin, sizeof(*sin))) + return nsvc; + } + return NULL; +} + +static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, u_int16_t nsvci) +{ + struct gprs_nsvc *nsvc; + + nsvc = talloc_zero(nsi, struct gprs_nsvc); + nsvc->nsvci = nsvci; + /* before RESET procedure: BLOCKED and DEAD */ + nsvc->state = NSE_S_BLOCKED; + nsvc->nsi = nsi; + llist_add(&nsvc->list, &nsi->gprs_nsvcs); + + return nsvc; +} /* Section 10.3.2, Table 13 */ static const char *ns_cause_str[] = { @@ -122,9 +184,23 @@ static const char *gprs_ns_cause_str(enum ns_cause cause) return "undefined"; } +static int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc); + static int gprs_ns_tx(struct msgb *msg, struct gprs_nsvc *nsvc) { - return ipac_gprs_send(msg, &nsvc->ip.bts_addr); + int ret; + + switch (nsvc->nsi->ll) { + case GPRS_NS_LL_UDP: + ret = nsip_sendmsg(msg, nsvc); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); + msgb_free(msg); + ret = -EIO; + break; + } + return ret; } static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) @@ -196,11 +272,10 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) } /* Section 9.2.10: transmit side */ -int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, +int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, struct msgb *msg) { struct gprs_ns_hdr *nsh; - struct gprs_nsvc *nsvc = &dummy_nsvc; nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { @@ -217,7 +292,7 @@ int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, } /* Section 9.2.10: receive side */ -static int gprs_ns_rx_unitdata(struct msgb *msg) +static int gprs_ns_rx_unitdata(struct msgb *msg, struct gprs_nsvc *nsvc) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; u_int16_t bvci; @@ -227,13 +302,13 @@ static int gprs_ns_rx_unitdata(struct msgb *msg) msg->l3h = &nsh->data[3]; /* call upper layer (BSSGP) */ - return gprs_bssgp_rcvmsg(msg, bvci); + return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); } /* Section 9.2.7 */ -static int gprs_ns_rx_status(struct msgb *msg) +static int gprs_ns_rx_status(struct msgb *msg, struct gprs_nsvc *nsvc) { - struct gprs_ns_hdr *nsh = msg->l2h; + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct tlv_parsed tp; u_int8_t cause; int rc; @@ -254,10 +329,9 @@ static int gprs_ns_rx_status(struct msgb *msg) } /* Section 7.3 */ -static int gprs_ns_rx_reset(struct msgb *msg) +static int gprs_ns_rx_reset(struct msgb *msg, struct gprs_nsvc *nsvc) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = &dummy_nsvc; struct tlv_parsed tp; u_int8_t *cause; u_int16_t *nsvci, *nsei; @@ -296,14 +370,24 @@ static int gprs_ns_rx_reset(struct msgb *msg) } /* main entry point, here incoming NS frames enter */ -int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) +int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, + struct sockaddr_in *saddr) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = &dummy_nsvc; + struct gprs_nsvc *nsvc; int rc = 0; - /* FIXME: do this properly! */ - nsvc->ip.bts_addr = *saddr; + /* look up the NSVC based on source address */ + nsvc = nsvc_by_rem_addr(nsi, saddr); + if (!nsvc) { + /* Only the RESET procedure creates a new NSVC */ + if (nsh->pdu_type != NS_PDUT_RESET) + return -EIO; + nsvc = nsvc_create(nsi, 0xffff); + nsvc->ip.bts_addr = *saddr; + rc = gprs_ns_rx_reset(msg, nsvc); + return rc; + } switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -320,16 +404,18 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) break; case NS_PDUT_UNITDATA: /* actual user data */ - rc = gprs_ns_rx_unitdata(msg); + rc = gprs_ns_rx_unitdata(msg, nsvc); break; case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(msg); + rc = gprs_ns_rx_status(msg, nsvc); break; case NS_PDUT_RESET: - rc = gprs_ns_rx_reset(msg); + rc = gprs_ns_rx_reset(msg, nsvc); break; case NS_PDUT_RESET_ACK: - /* FIXME: mark remote NS-VC as blocked + active */ + DEBUGP(DGPRS, "NS RESET ACK\n"); + /* mark remote NS-VC as blocked + active */ + nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ @@ -338,7 +424,9 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - /* FIXME: mark remote NS-VC as unblocked + active */ + DEBUGP(DGPRS, "NS UNBLOCK ACK\n"); + /* mark remote NS-VC as unblocked + active */ + nsvc->remote_state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: DEBUGP(DGPRS, "NS BLOCK\n"); @@ -346,7 +434,9 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: - /* FIXME: mark remote NS-VC as blocked + active */ + DEBUGP(DGPRS, "NS BLOCK ACK\n"); + /* mark remote NS-VC as blocked + active */ + nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: DEBUGP(DGPRS, "Unknown NS PDU type 0x%02x\n", nsh->pdu_type); @@ -356,3 +446,122 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) return rc; } +struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) +{ + struct gprs_ns_inst *nsi = talloc_zero(tall_bsc_ctx, struct gprs_ns_inst); + + nsi->cb = cb; + INIT_LLIST_HEAD(&nsi->gprs_nsvcs); + + return NULL; +} + +void gprs_ns_destroy(struct gprs_ns_inst *nsi) +{ + /* FIXME: clear all timers */ + + /* recursively free the NSI and all its NSVCs */ + talloc_free(nsi); +} + + +/* NS-over-IP code, according to 3GPP TS 48.016 Chapter 6.2 + * We don't support Size Procedure, Configuration Procedure, ChangeWeight Procedure */ + +/* Read a single NS-over-IP message */ +static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, + struct sockaddr_in *saddr) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Abis/IP/GPRS-NS"); + int ret = 0; + socklen_t saddr_len = sizeof(*saddr); + + if (!msg) { + *error = -ENOMEM; + return NULL; + } + + ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, + (struct sockaddr *)saddr, &saddr_len); + if (ret < 0) { + fprintf(stderr, "recv error %s\n", strerror(errno)); + msgb_free(msg); + *error = ret; + return NULL; + } else if (ret == 0) { + msgb_free(msg); + *error = ret; + return NULL; + } + + msg->l2h = msg->data; + msgb_put(msg, ret); + + return msg; +} + +static int handle_nsip_read(struct bsc_fd *bfd) +{ + int error; + struct sockaddr_in saddr; + struct gprs_ns_inst *nsi = bfd->data; + struct msgb *msg = read_nsip_msg(bfd, &error, &saddr); + + if (!msg) + return error; + + return gprs_ns_rcvmsg(nsi, msg, &saddr); +} + +static int handle_nsip_write(struct bsc_fd *bfd) +{ + /* FIXME: actually send the data here instead of nsip_sendmsg() */ + return -EIO; +} + +int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc) +{ + int rc; + struct gprs_ns_inst *nsi = nsvc->nsi; + struct sockaddr_in *daddr = &nsvc->ip.bts_addr; + + rc = sendto(nsi->nsip.fd.fd, msg->data, msg->len, 0, + (struct sockaddr *)daddr, sizeof(*daddr)); + + talloc_free(msg); + + return rc; +} + +/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */ +static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) + rc = handle_nsip_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_nsip_write(bfd); + + return rc; +} + + +/* FIXME: this is currently in input/ipaccess.c */ +extern int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, + int (*cb)(struct bsc_fd *fd, unsigned int what)); + +/* Listen for incoming GPRS packets */ +int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) +{ + int ret; + + ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, udp_port, nsip_fd_cb); + if (ret < 0) + return ret; + + nsi->ll = GPRS_NS_LL_UDP; + nsi->nsip.fd.data = nsi; + + return ret; +} From 645609ddc8e3e4fe4508af5f3fa3edd073185fef Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 16:43:39 +0200 Subject: [PATCH 036/198] gprs: Use new msgb->cb[] for storing a pointer to the NS-VC through which it was received --- openbsc/src/gprs_ns.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index c5166fa53..b57de1d72 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -292,9 +292,10 @@ int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, } /* Section 9.2.10: receive side */ -static int gprs_ns_rx_unitdata(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_rx_unitdata(struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; + struct gprs_nsvc *nsvc = msgb_nsvc(msg); u_int16_t bvci; /* spare octet in data[0] */ @@ -306,9 +307,10 @@ static int gprs_ns_rx_unitdata(struct msgb *msg, struct gprs_nsvc *nsvc) } /* Section 9.2.7 */ -static int gprs_ns_rx_status(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_rx_status(struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t cause; int rc; @@ -329,9 +331,10 @@ static int gprs_ns_rx_status(struct msgb *msg, struct gprs_nsvc *nsvc) } /* Section 7.3 */ -static int gprs_ns_rx_reset(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_rx_reset(struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t *cause; u_int16_t *nsvci, *nsei; @@ -385,9 +388,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, return -EIO; nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; - rc = gprs_ns_rx_reset(msg, nsvc); + rc = gprs_ns_rx_reset(msg); return rc; } + msgb_nsvc(msg) = nsvc; switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -404,13 +408,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNITDATA: /* actual user data */ - rc = gprs_ns_rx_unitdata(msg, nsvc); + rc = gprs_ns_rx_unitdata(msg); break; case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(msg, nsvc); + rc = gprs_ns_rx_status(msg); break; case NS_PDUT_RESET: - rc = gprs_ns_rx_reset(msg, nsvc); + rc = gprs_ns_rx_reset(msg); break; case NS_PDUT_RESET_ACK: DEBUGP(DGPRS, "NS RESET ACK\n"); From 24a655f1406f53ce54802e72f72b6bf19394672e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 19:54:29 +0200 Subject: [PATCH 037/198] gprs: remove msgb->nsvc pointer and replace it with NSEI and BVCI According to TS 08.16, the BSSGP layer needs to specify NSEI and BVCI when executing the NS UNITDATA REQUEST primitive of the underlying NS layer. Rather than passing around a pointer to the 'struct gprs_nsvc', we now have NSEI and BVCI as members of 'struct obsc_msgb_cb' and set them when BSSGP hands a message down to NS. NS then does a lookup of the 'gprs_nsvc' based on the NSEI parameter. --- openbsc/include/openbsc/gprs_ns.h | 3 +- openbsc/src/gprs_bssgp.c | 34 ++++++++++++----- openbsc/src/gprs_ns.c | 61 ++++++++++++++++++++----------- 3 files changed, 64 insertions(+), 34 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 98b31f8da..34a3e581f 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -99,7 +99,6 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct sockaddr_in *saddr); /* main function for higher layers (BSSGP) to send NS messages */ -int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, - struct msgb *msg); +int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); #endif diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index b4436294d..650d7d45d 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -37,6 +37,7 @@ /* global pointer to the gsm network data structure */ /* FIXME: this must go! */ extern struct gsm_network *bsc_gsmnet; +struct gprs_ns_inst *bssgp_nsi; /* Chapter 11.3.9 / Table 11.10: Cause coding */ static const char *bssgp_cause_strings[] = { @@ -84,31 +85,38 @@ static inline struct msgb *bssgp_msgb_alloc(void) } /* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ -static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t bvci, u_int16_t ns_bvci) +static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t nsei, + u_int16_t bvci, u_int16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); u_int16_t _bvci; + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + bgph->pdu_type = pdu_type; _bvci = htons(bvci); msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); - return gprs_ns_sendmsg(NULL, ns_bvci, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Chapter 10.4.5: Flow Control BVC ACK */ -static int bssgp_tx_fc_bvc_ack(u_int8_t tag, u_int16_t ns_bvci) +static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK; msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag); - return gprs_ns_sendmsg(NULL, ns_bvci, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Chapter 10.4.14: Status */ @@ -119,6 +127,8 @@ static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_ms (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + msgb_nsei(msg) = msgb_nsei(orig_msg); + msgb_bvci(msg) = 0; bgph->pdu_type = BSSGP_PDUT_STATUS; msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); @@ -130,7 +140,7 @@ static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_ms msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, msgb_l3len(orig_msg), orig_msg->l3h); - return gprs_ns_sendmsg(NULL, 0, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Uplink unit-data */ @@ -221,7 +231,8 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); /* Send FLOW_CONTROL_BVC_ACK */ - return bssgp_tx_fc_bvc_ack(*TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci); + return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), + ns_bvci); } /* We expect msg->l3h to point to the BSSGP header */ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) @@ -287,7 +298,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, - bvci, ns_bvci); + msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_BVC_UNBLOCK: /* BSS tells us that BVC shall be unblocked */ @@ -297,7 +308,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u\n", bvci); rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, - bvci, ns_bvci); + msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_BVC_RESET: /* BSS tells us that BVC init is required */ @@ -309,7 +320,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - bvci, ns_bvci); + msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ @@ -393,5 +404,8 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; - return gprs_ns_sendmsg(NULL, bts->gprs.cell.bvci, msg); + msgb_nsei(msg) = bts->gprs.nse.nsei; + msgb_bvci(msg) = bts->gprs.cell.bvci; + + return gprs_ns_sendmsg(bssgp_nsi, msg); } diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index b57de1d72..6c495b01e 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -1,4 +1,4 @@ -/* GPRS Networks Service (NS) messages on the Gb interface +/* GPRS Networks Service (NS) messages on the Gb interfacebvci = msgb_bvci(msg); * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ /* (C) 2009-2010 by Harald Welte @@ -132,6 +132,19 @@ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, return NULL; } +/* Lookup struct gprs_nsvc based on NSVCI */ +static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, + u_int16_t nsei) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc->nsei == nsei) + return nsvc; + } + return NULL; +} + + /* Lookup struct gprs_nsvc based on remote peer socket addr */ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, struct sockaddr_in *sin) @@ -184,15 +197,15 @@ static const char *gprs_ns_cause_str(enum ns_cause cause) return "undefined"; } -static int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc); +static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); -static int gprs_ns_tx(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) { int ret; switch (nsvc->nsi->ll) { case GPRS_NS_LL_UDP: - ret = nsip_sendmsg(msg, nsvc); + ret = nsip_sendmsg(nsvc, msg); break; default: LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); @@ -215,7 +228,7 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) nsh->pdu_type = pdu_type; - return gprs_ns_tx(msg, nsvc); + return gprs_ns_tx(nsvc, msg); } #define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ @@ -268,14 +281,21 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); - return gprs_ns_tx(msg, nsvc); + return gprs_ns_tx(nsvc, msg); } -/* Section 9.2.10: transmit side */ -int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, - struct msgb *msg) +/* Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive */ +int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) { + struct gprs_nsvc *nsvc; struct gprs_ns_hdr *nsh; + u_int16_t bvci = msgb_bvci(msg); + + nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); + if (!nsvc) { + DEBUGP(DGPRS, "Unable to resolve NSEI %u to NS-VC!\n", msgb_nsei(msg)); + return -EINVAL; + } nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { @@ -288,14 +308,13 @@ int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, nsh->data[1] = bvci >> 8; nsh->data[2] = bvci & 0xff; - return gprs_ns_tx(msg, nsvc); + return gprs_ns_tx(nsvc, msg); } /* Section 9.2.10: receive side */ -static int gprs_ns_rx_unitdata(struct msgb *msg) +static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; - struct gprs_nsvc *nsvc = msgb_nsvc(msg); u_int16_t bvci; /* spare octet in data[0] */ @@ -307,10 +326,9 @@ static int gprs_ns_rx_unitdata(struct msgb *msg) } /* Section 9.2.7 */ -static int gprs_ns_rx_status(struct msgb *msg) +static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t cause; int rc; @@ -331,10 +349,9 @@ static int gprs_ns_rx_status(struct msgb *msg) } /* Section 7.3 */ -static int gprs_ns_rx_reset(struct msgb *msg) +static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t *cause; u_int16_t *nsvci, *nsei; @@ -388,10 +405,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, return -EIO; nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; - rc = gprs_ns_rx_reset(msg); + rc = gprs_ns_rx_reset(nsvc, msg); return rc; } - msgb_nsvc(msg) = nsvc; + msgb_nsei(msg) = nsvc->nsei; switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -408,13 +425,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNITDATA: /* actual user data */ - rc = gprs_ns_rx_unitdata(msg); + rc = gprs_ns_rx_unitdata(nsvc, msg); break; case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(msg); + rc = gprs_ns_rx_status(nsvc, msg); break; case NS_PDUT_RESET: - rc = gprs_ns_rx_reset(msg); + rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: DEBUGP(DGPRS, "NS RESET ACK\n"); @@ -523,7 +540,7 @@ static int handle_nsip_write(struct bsc_fd *bfd) return -EIO; } -int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc) +int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) { int rc; struct gprs_ns_inst *nsi = nsvc->nsi; From 3771d09ec01581e50253dce4dc5ec0abba9a1e35 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 20:26:32 +0200 Subject: [PATCH 038/198] GPRS: Introduce a GPRS Gb Proxy The ida of the Gb proxy is to aggregate Gb links with a number of BSS and then present all the BSSGP-VC's together inside one NS-VC to the actual SGSN. The code is not yet expected to be complete. --- openbsc/include/openbsc/gprs_bssgp.h | 10 ++++++ openbsc/include/openbsc/gprs_ns.h | 39 ++++++++++++++++++++++- openbsc/src/gprs_bssgp.c | 7 +---- openbsc/src/gprs_ns.c | 47 +++++++++++++--------------- 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index f85ac48ec..3040e6a0e 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -133,6 +133,16 @@ enum gprs_bssgp_cause { BSSGP_CAUSE_PDU_INCOMP_FEAT = 0x28, }; +/* Our implementation */ + +#include + extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci); +/* Wrapper around TLV parser to parse BSSGP IEs */ +static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) +{ + return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); +} + #endif /* _GPRS_BSSGP_H */ diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 34a3e581f..dd10d3339 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -73,7 +73,37 @@ enum ns_cause { NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, }; -struct gprs_nsvc; + +/* Our Implementation */ +#include + +#define NSE_S_BLOCKED 0x0001 +#define NSE_S_ALIVE 0x0002 + +struct gprs_nsvc { + struct llist_head list; + struct gprs_ns_inst *nsi; + + u_int16_t nsei; /* end-to-end significance */ + u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ + + u_int32_t state; + u_int32_t remote_state; + + struct timer_list alive_timer; + int timer_is_tns_alive; + int alive_retries; + + int remote_end_is_sgsn; + + union { + struct { + struct sockaddr_in bts_addr; + } ip; + }; +}; + + struct gprs_ns_inst; enum gprs_ns_evt { @@ -101,4 +131,11 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* main function for higher layers (BSSGP) to send NS messages */ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); + +/* Listen for incoming GPRS packets */ +int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); + +/* Establish a connection (from the BSS) to the SGSN */ +struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, + struct sockaddr_in *dest, uint16_t nsvci); #endif diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 650d7d45d..a2181b124 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -74,11 +74,6 @@ static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) return "undefined"; } -static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) -{ - return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); -} - static inline struct msgb *bssgp_msgb_alloc(void) { return msgb_alloc_headroom(4096, 128, "BSSGP"); @@ -120,7 +115,7 @@ static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) } /* Chapter 10.4.14: Status */ -static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) +int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 6c495b01e..3bb0bf94d 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -72,30 +72,6 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; -#define NSE_S_BLOCKED 0x0001 -#define NSE_S_ALIVE 0x0002 - -struct gprs_nsvc { - struct llist_head list; - struct gprs_ns_inst *nsi; - - u_int16_t nsei; /* end-to-end significance */ - u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ - - u_int32_t state; - u_int32_t remote_state; - - struct timer_list alive_timer; - int timer_is_tns_alive; - int alive_retries; - - union { - struct { - struct sockaddr_in bts_addr; - } ip; - }; -}; - enum gprs_ns_ll { GPRS_NS_LL_UDP, GPRS_NS_LL_E1, @@ -474,7 +450,7 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->cb = cb; INIT_LLIST_HEAD(&nsi->gprs_nsvcs); - return NULL; + return nsi; } void gprs_ns_destroy(struct gprs_ns_inst *nsi) @@ -586,3 +562,24 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) return ret; } + +/* Establish a connection (from the BSS) to the SGSN */ +struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, + struct sockaddr_in *dest, uint16_t nsvci) +{ + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_rem_addr(nsi, dest); + if (!nsvc) { + nsvc = nsvc_create(nsi, nsvci); + nsvc->ip.bts_addr = *dest; + } + nsvc->remote_end_is_sgsn = 1; + + /* Initiate a RESET procedure */ + if (gprs_ns_tx_simple(nsvc, NS_PDUT_RESET) < 0) + return NULL; + /* FIXME: should we run a timer and re-transmit the reset request? */ + + return nsvc; +} From 1203de3993a7df15a01469492d8ea9179c763668 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 11:28:43 +0200 Subject: [PATCH 039/198] [gprs] fully integrate VTY configuration into Gb proxy The Gb-proxy is now fully configured by config file / VTY --- openbsc/include/openbsc/gprs_ns.h | 49 ++++++++++++++++++++++++------- openbsc/src/gprs_ns.c | 29 +++--------------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index dd10d3339..ca02c4b5d 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -76,10 +76,46 @@ enum ns_cause { /* Our Implementation */ #include +#include +#include +#include +#include #define NSE_S_BLOCKED 0x0001 #define NSE_S_ALIVE 0x0002 +enum gprs_ns_ll { + GPRS_NS_LL_UDP, + GPRS_NS_LL_E1, +}; + +enum gprs_ns_evt { + GPRS_NS_EVT_UNIT_DATA, +}; + +struct gprs_nsvc; +typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci); + +/* An instance of the NS protocol stack */ +struct gprs_ns_inst { + /* callback to the user for incoming UNIT DATA IND */ + gprs_ns_cb_t *cb; + + /* linked lists of all NSVC in this instance */ + struct llist_head gprs_nsvcs; + + /* which link-layer are we based on? */ + enum gprs_ns_ll ll; + + union { + /* NS-over-IP specific bits */ + struct { + struct bsc_fd fd; + } nsip; + }; +}; + struct gprs_nsvc { struct llist_head list; struct gprs_ns_inst *nsi; @@ -103,16 +139,6 @@ struct gprs_nsvc { }; }; - -struct gprs_ns_inst; - -enum gprs_ns_evt { - GPRS_NS_EVT_UNIT_DATA, -}; - -typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, u_int16_t bvci); - /* Create a new NS protocol instance */ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); @@ -137,5 +163,6 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); /* Establish a connection (from the BSS) to the SGSN */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, - struct sockaddr_in *dest, uint16_t nsvci); + struct sockaddr_in *dest, uint16_t nsei, + uint16_t nsvci); #endif diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 3bb0bf94d..18d189f5a 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -72,30 +72,6 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; -enum gprs_ns_ll { - GPRS_NS_LL_UDP, - GPRS_NS_LL_E1, -}; - -/* An instance of the NS protocol stack */ -struct gprs_ns_inst { - /* callback to the user for incoming UNIT DATA IND */ - gprs_ns_cb_t *cb; - - /* linked lists of all NSVC in this instance */ - struct llist_head gprs_nsvcs; - - /* which link-layer are we based on? */ - enum gprs_ns_ll ll; - - union { - /* NS-over-IP specific bits */ - struct { - struct bsc_fd fd; - } nsip; - }; -}; - /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, u_int16_t nsvci) @@ -565,7 +541,8 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) /* Establish a connection (from the BSS) to the SGSN */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, - struct sockaddr_in *dest, uint16_t nsvci) + struct sockaddr_in *dest, uint16_t nsei, + uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -574,6 +551,8 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc = nsvc_create(nsi, nsvci); nsvc->ip.bts_addr = *dest; } + nsvc->nsei = nsei; + nsvc->nsvci = nsvci; nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ From 3fddf3c4ef22c5f973843f250c5700814fc465c1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 16:48:27 +0200 Subject: [PATCH 040/198] [gprs] Build the SGSN stand-alone and not as part of bsc_hack Instead of continuing to add more and more functionality to the bsc_hack binary, we should have the new SGSN code run as a separate executable. After this commit we now build a 'osmo_sgsn' executable, using its own osmo_sgsn.cfg config file. However, the SGSN is not yet functional, mainly due to the fact that the BSSGP and GMM code are written with the assumption that there is a msgb->trx->bts and the according 'sturct gsm_bts' data model around - which clearly is no longer the case outside of bsc_hack. --- openbsc/src/gprs_bssgp.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index a2181b124..ab6d1a098 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -138,6 +138,25 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) return gprs_ns_sendmsg(bssgp_nsi, msg); } +/* Chapter 8.4 BVC-Reset Procedure */ +static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, + uint16_t ns_bvci) +{ + uint8_t bvci; + int rc; + + bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); + + /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS + * informs us about its RAC + Cell ID, so we can create a mapping */ + + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + msgb_nsei(msg), bvci, ns_bvci); + return 0; +} + /* Uplink unit-data */ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) { @@ -157,10 +176,12 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) return -EIO; +#if 0 //FIXME /* Determine the BTS based on the Cell ID */ bts = gsm48_bts_by_ra_id(bsc_gsmnet, TLVP_VAL(&tp, BSSGP_IE_CELL_ID), TLVP_LEN(&tp, BSSGP_IE_CELL_ID)); +#endif if (bts) msg->trx = bts->c0; @@ -229,6 +250,7 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci); } + /* We expect msg->l3h to point to the BSSGP header */ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) { @@ -311,11 +333,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, - bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - msgb_nsei(msg), bvci, ns_bvci); + rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci); break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ From 6752fa43b6cdcc2cb33d04b5e6cf3c87c609de68 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:23:16 +0200 Subject: [PATCH 041/198] [gprs] introduce BSSGP concept of BTS contextx A BTS context represents the mapping betewen (RA-ID, Cell-ID) and (BVCI, NSEI) as well as the per-BVC local state. --- openbsc/src/gprs_bssgp.c | 133 ++++++++++++++++++++++++++++++++------- 1 file changed, 110 insertions(+), 23 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index ab6d1a098..44e0a35c0 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -1,6 +1,6 @@ /* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ -/* (C) 2009 by Harald Welte +/* (C) 2009-2010 by Harald Welte * * All Rights Reserved * @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -39,6 +41,8 @@ extern struct gsm_network *bsc_gsmnet; struct gprs_ns_inst *bssgp_nsi; +void *bssgp_tall_ctx = NULL; + /* Chapter 11.3.9 / Table 11.10: Cause coding */ static const char *bssgp_cause_strings[] = { [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload", @@ -74,6 +78,68 @@ static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) return "undefined"; } +#define BVC_F_BLOCKED 0x0001 + +/* The per-BTS context that we keep on the SGSN side of the BSSGP link */ +struct bssgp_bts_ctx { + struct llist_head list; + + /* parsed RA ID and Cell ID of the remote BTS */ + struct gprs_ra_id ra_id; + uint16_t cell_id; + + /* NSEI and BVCI of underlying Gb link. Together they + * uniquely identify a link to a BTS (5.4.4) */ + uint16_t bvci; + uint16_t nsei; + + uint32_t bvc_state; + + /* we might want to add this as a shortcut later, avoiding the NSVC + * lookup for every packet, similar to a routing cache */ + //struct gprs_nsvc *nsvc; +}; +LLIST_HEAD(bts_ctxts); + +/* Find a BTS Context based on parsed RA ID and Cell ID */ +struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) +{ + struct bssgp_bts_ctx *bctx; + + llist_for_each_entry(bctx, &bts_ctxts, list) { + if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) && + bctx->cell_id == cid) + return bctx; + } + return NULL; +} + +/* Find a BTS context based on BVCI+NSEI tuple */ +struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) +{ + struct bssgp_bts_ctx *bctx; + + llist_for_each_entry(bctx, &bts_ctxts, list) { + if (bctx->nsei == nsei && bctx->bvci == bvci) + return bctx; + } + return NULL; +} + +struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) +{ + struct bssgp_bts_ctx *ctx; + + ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bts_ctx); + if (!ctx) + return NULL; + ctx->bvci = bvci; + ctx->nsei = nsei; + llist_add(&ctx->list, &bts_ctxts); + + return ctx; +} + static inline struct msgb *bssgp_msgb_alloc(void) { return msgb_alloc_headroom(4096, 128, "BSSGP"); @@ -138,22 +204,52 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) return gprs_ns_sendmsg(bssgp_nsi, msg); } +static void bssgp_parse_cell_id(struct gprs_ra_id *raid, uint16_t *cid, + const uint8_t *buf) +{ + /* 6 octets RAC */ + gsm48_parse_ra(raid, buf); + /* 2 octets CID */ + *cid = ntohs(*(uint16_t *) (buf+6)); +} + /* Chapter 8.4 BVC-Reset Procedure */ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, uint16_t ns_bvci) { - uint8_t bvci; + struct bssgp_bts_ctx *bctx; + uint16_t nsei = msgb_nsei(msg); + uint16_t bvci; int rc; bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); + /* look-up or create the BTS context for this BVC */ + bctx = btsctx_by_bvci_nsei(bvci, nsei); + if (!bctx) + bctx = btsctx_alloc(bvci, nsei); + /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS * informs us about its RAC + Cell ID, so we can create a mapping */ + if (bvci != 0 && bvci != 1) { + if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { + LOGP(DGPRS, LOGL_ERROR, "BSSGP RESET BVCI=%u " + "missing mandatory IE\n", bvci); + return -EINVAL; + } + /* actually extract RAC / CID */ + bssgp_parse_cell_id(&bctx->ra_id, &bctx->cell_id, + TLVP_VAL(tp, BSSGP_IE_CELL_ID)); + LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", + bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, + bctx->ra_id.rac, bctx->cell_id, bvci); + } + /* Acknowledge the RESET to the BTS */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - msgb_nsei(msg), bvci, ns_bvci); + nsei, bvci, ns_bvci); return 0; } @@ -161,13 +257,13 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h; - struct gsm_bts *bts; int data_len = msgb_l3len(msg) - sizeof(*budh); struct tlv_parsed tp; int rc; DEBUGP(DGPRS, "BSSGP UL-UD\n"); + /* extract TLLI and parse TLV IEs */ msgb_tlli(msg) = ntohl(budh->tlli); rc = bssgp_tlv_parse(&tp, budh->data, data_len); @@ -176,15 +272,6 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) return -EIO; -#if 0 //FIXME - /* Determine the BTS based on the Cell ID */ - bts = gsm48_bts_by_ra_id(bsc_gsmnet, - TLVP_VAL(&tp, BSSGP_IE_CELL_ID), - TLVP_LEN(&tp, BSSGP_IE_CELL_ID)); -#endif - if (bts) - msg->trx = bts->c0; - msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); return gprs_llc_rcvmsg(msg, &tp); @@ -261,6 +348,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) u_int16_t bvci; int rc = 0; + /* UNITDATA BSSGP headers have TLLI in front */ if (pdu_type != BSSGP_PDUT_UL_UNITDATA && pdu_type != BSSGP_PDUT_DL_UNITDATA) rc = bssgp_tlv_parse(&tp, bgph->data, data_len); @@ -314,6 +402,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + /* We always acknowledge the BLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); break; @@ -324,6 +413,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) goto err_mand_ie; bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u\n", bvci); + /* We always acknowledge the unBLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); break; @@ -374,9 +464,11 @@ err_mand_ie: return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); } -int gprs_bssgp_tx_dl_ud(struct msgb *msg) +/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU + * to a remote MS (identified by TLLI) at a BTS identified by its RAC and CID */ +int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_t cid) { - struct gsm_bts *bts; + struct bssgp_bts_ctx *bctx; struct bssgp_ud_hdr *budh; u_int8_t llc_pdu_tlv_hdr_len = 2; u_int8_t *llc_pdu_tlv, *qos_profile; @@ -384,12 +476,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; u_int16_t msg_len = msg->len; - if (!msg->trx) { - DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n"); - return -EINVAL; - } - - bts = msg->trx->bts; + bctx = btsctx_by_raid_cid(raid, cid); if (msg->len > TVLV_MAX_ONEBYTE) llc_pdu_tlv_hdr_len += 1; @@ -417,8 +504,8 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; - msgb_nsei(msg) = bts->gprs.nse.nsei; - msgb_bvci(msg) = bts->gprs.cell.bvci; + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = bctx->bvci; return gprs_ns_sendmsg(bssgp_nsi, msg); } From 290671d6835079a08ee2a1cdc85406f8291da517 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:34:20 +0200 Subject: [PATCH 042/198] [gprs] BSSGP: convert cause strings to value_string --- openbsc/src/gprs_bssgp.c | 59 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 44e0a35c0..4b5821343 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -43,41 +43,42 @@ struct gprs_ns_inst *bssgp_nsi; void *bssgp_tall_ctx = NULL; +/* BSSGP Protocol specific, not implementation specific */ +/* FIXME: This needs to go into libosmocore after finished */ + /* Chapter 11.3.9 / Table 11.10: Cause coding */ -static const char *bssgp_cause_strings[] = { - [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload", - [BSSGP_CAUSE_EQUIP_FAIL] = "Equipment Failure", - [BSSGP_CAUSE_TRASIT_NET_FAIL] = "Transit netowkr service failure", - [BSSGP_CAUSE_CAPA_GREATER_0KPBS]= "Transmission capacity modified", - [BSSGP_CAUSE_UNKNOWN_MS] = "Unknown MS", - [BSSGP_CAUSE_UNKNOWN_BVCI] = "Unknown BVCI", - [BSSGP_CAUSE_CELL_TRAF_CONG] = "Cell traffic congestion", - [BSSGP_CAUSE_SGSN_CONG] = "SGSN congestion", - [BSSGP_CAUSE_OML_INTERV] = "O&M intervention", - [BSSGP_CAUSE_BVCI_BLOCKED] = "BVCI blocked", - [BSSGP_CAUSE_PFC_CREATE_FAIL] = "PFC create failure", - [BSSGP_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", - [BSSGP_CAUSE_INV_MAND_INF] = "Invalid mandatory information", - [BSSGP_CAUSE_MISSING_MAND_IE] = "Missing mandatory IE", - [BSSGP_CAUSE_MISSING_COND_IE] = "Missing conditional IE", - [BSSGP_CAUSE_UNEXP_COND_IE] = "Unexpected conditional IE", - [BSSGP_CAUSE_COND_IE_ERR] = "Conditional IE error", - [BSSGP_CAUSE_PDU_INCOMP_STATE] = "PDU incompatible with protocol state", - [BSSGP_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error - unspecified", - [BSSGP_CAUSE_PDU_INCOMP_FEAT] = "PDU not compatible with feature set", +static const struct value_string bssgp_cause_strings[] = { + { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, + { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, + { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, + { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, + { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, + { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, + { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, + { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, + { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, + { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, + { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, + { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, + { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, + { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, + { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, + { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, + { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, + { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, + { 0, NULL }, }; -static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) +const char *bssgp_cause_str(enum gprs_bssgp_cause cause) { - if (cause >= ARRAY_SIZE(bssgp_cause_strings)) - return "undefined"; - - if (bssgp_cause_strings[cause]) - return bssgp_cause_strings[cause]; - - return "undefined"; + return get_value_string(bssgp_cause_strings, cause); } + +/* Our actual implementation */ + #define BVC_F_BLOCKED 0x0001 /* The per-BTS context that we keep on the SGSN side of the BSSGP link */ From 2577d415269085d71fff62aead723c7d28522645 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:37:45 +0200 Subject: [PATCH 043/198] [gprs] convert ns_cause_str to value_string --- openbsc/src/gprs_ns.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 18d189f5a..7f94b97b1 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -124,29 +124,24 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, u_int16_t nsvci) } /* Section 10.3.2, Table 13 */ -static const char *ns_cause_str[] = { - [NS_CAUSE_TRANSIT_FAIL] = "Transit network failure", - [NS_CAUSE_OM_INTERVENTION] = "O&M intervention", - [NS_CAUSE_EQUIP_FAIL] = "Equipment failure", - [NS_CAUSE_NSVC_BLOCKED] = "NS-VC blocked", - [NS_CAUSE_NSVC_UNKNOWN] = "NS-VC unknown", - [NS_CAUSE_BVCI_UNKNOWN] = "BVCI unknown", - [NS_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", - [NS_CAUSE_PDU_INCOMP_PSTATE] = "PDU not compatible with protocol state", - [NS_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error, unspecified", - [NS_CAUSE_INVAL_ESSENT_IE] = "Invalid essential IE", - [NS_CAUSE_MISSING_ESSENT_IE] = "Missing essential IE", +static const struct value_string ns_cause_str[] = { + { NS_CAUSE_TRANSIT_FAIL, "Transit network failure" }, + { NS_CAUSE_OM_INTERVENTION, "O&M intervention" }, + { NS_CAUSE_EQUIP_FAIL, "Equipment failure" }, + { NS_CAUSE_NSVC_BLOCKED, "NS-VC blocked" }, + { NS_CAUSE_NSVC_UNKNOWN, "NS-VC unknown" }, + { NS_CAUSE_BVCI_UNKNOWN, "BVCI unknown" }, + { NS_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { NS_CAUSE_PDU_INCOMP_PSTATE, "PDU not compatible with protocol state" }, + { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error }, unspecified" }, + { NS_CAUSE_INVAL_ESSENT_IE, "Invalid essential IE" }, + { NS_CAUSE_MISSING_ESSENT_IE, "Missing essential IE" }, + { 0, NULL } }; -static const char *gprs_ns_cause_str(enum ns_cause cause) +const char *gprs_ns_cause_str(enum ns_cause cause) { - if (cause >= ARRAY_SIZE(ns_cause_str)) - return "undefined"; - - if (ns_cause_str[cause]) - return ns_cause_str[cause]; - - return "undefined"; + return get_value_string(ns_cause_str, cause); } static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); From ec19c10829ff94946887f893f9fb3b617f36889a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:50:42 +0200 Subject: [PATCH 044/198] [gprs] Ensure msgb->l3h points to Layer3 (04.08) In the old code l3h = BSSGP, l4h = LLC, cb[gmmh] = 04.08 Now, this has been changed to cb[bssgph] = BSSGP, cb[llch] = LLC, l3h = 04.08 This way, GSM general 04.08 and GPRS 04.08 code can expect a GSM 04.08 header at msgb->l3h --- openbsc/src/gprs_bssgp.c | 15 +++++++++------ openbsc/src/gprs_ns.c | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 4b5821343..330d8c875 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -200,7 +200,7 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) } if (orig_msg) msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_l3len(orig_msg), orig_msg->l3h); + msgb_l3len(orig_msg), msgb_bssgph(orig_msg)); return gprs_ns_sendmsg(bssgp_nsi, msg); } @@ -257,7 +257,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, /* Uplink unit-data */ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) { - struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h; + struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*budh); struct tlv_parsed tp; int rc; @@ -280,7 +280,8 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -301,7 +302,8 @@ static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -339,10 +341,11 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, ns_bvci); } -/* We expect msg->l3h to point to the BSSGP header */ +/* We expect msgb_bssgph() to point to the BSSGP header */ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; u_int8_t pdu_type = bgph->pdu_type; int data_len = msgb_l3len(msg) - sizeof(*bgph); diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 7f94b97b1..470ccb080 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -266,7 +266,7 @@ static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; - msg->l3h = &nsh->data[3]; + msgb_bssgph(msg) = &nsh->data[3]; /* call upper layer (BSSGP) */ return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); From 30bc19a5c6b171142569a00739a52db008eb8ba6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 11:19:37 +0200 Subject: [PATCH 045/198] [gprs] SGSN: Expect all Identifiers to be stored at highest level We now expect the highest level (actual SGSN GMM code) to know all identifiers for every element in the protocol stack, i.e. TLLI, SAPI, BVCI and NSEI. The layer-inetrnal state is looked up based on those identifiers. The reason for this is to ensure only the highest level state needs to be persistent, while everything else can be regenerated dynamically (e.g. in a SGSN restart) --- openbsc/include/openbsc/gprs_bssgp.h | 2 +- openbsc/src/gprs_bssgp.c | 63 ++++++++++++++++++---------- openbsc/src/gprs_ns.c | 1 + 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index 3040e6a0e..a00481e4e 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -137,7 +137,7 @@ enum gprs_bssgp_cause { #include -extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci); +extern int gprs_bssgp_rcvmsg(struct msgb *msg); /* Wrapper around TLV parser to parse BSSGP IEs */ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 330d8c875..6bba1af8a 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -255,7 +255,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, } /* Uplink unit-data */ -static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) +static int bssgp_rx_ul_ud(struct msgb *msg) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*budh); @@ -273,12 +273,14 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) return -EIO; + /* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */ + msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); return gprs_llc_rcvmsg(msg, &tp); } -static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) +static int bssgp_rx_suspend(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -296,11 +298,11 @@ static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) return -EIO; + /* FIXME: pass the SUSPEND request to GMM */ /* SEND SUSPEND_ACK or SUSPEND_NACK */ - /* FIXME */ } -static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) +static int bssgp_rx_resume(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -319,12 +321,11 @@ static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR)) return -EIO; + /* FIXME: pass the RESUME request to GMM */ /* SEND RESUME_ACK or RESUME_NACK */ - /* FIXME */ } -static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, - u_int16_t ns_bvci) +static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) { DEBUGP(DGPRS, "BSSGP FC BVC\n"); @@ -336,22 +337,27 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + /* FIXME: actually implement flow control */ + /* Send FLOW_CONTROL_BVC_ACK */ return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), - ns_bvci); + msgb_bvci(msg)); } /* We expect msgb_bssgph() to point to the BSSGP header */ -int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) +int gprs_bssgp_rcvmsg(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; - u_int8_t pdu_type = bgph->pdu_type; + uint8_t pdu_type = bgph->pdu_type; int data_len = msgb_l3len(msg) - sizeof(*bgph); - u_int16_t bvci; + uint16_t bvci; /* PTP BVCI */ + uint16_t ns_bvci = msgb_bvci(msg); int rc = 0; + /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */ + /* UNITDATA BSSGP headers have TLLI in front */ if (pdu_type != BSSGP_PDUT_UL_UNITDATA && pdu_type != BSSGP_PDUT_DL_UNITDATA) @@ -360,7 +366,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) switch (pdu_type) { case BSSGP_PDUT_UL_UNITDATA: /* some LLC data from the MS */ - rc = bssgp_rx_ul_ud(msg, ns_bvci); + rc = bssgp_rx_ul_ud(msg); break; case BSSGP_PDUT_RA_CAPABILITY: /* BSS requests RA capability or IMSI */ @@ -370,32 +376,36 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) case BSSGP_PDUT_RADIO_STATUS: DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); /* BSS informs us of some exception */ + /* FIXME: notify GMM */ break; case BSSGP_PDUT_SUSPEND: /* MS wants to suspend */ - rc = bssgp_rx_suspend(msg, ns_bvci); + rc = bssgp_rx_suspend(msg); break; case BSSGP_PDUT_RESUME: /* MS wants to resume */ - rc = bssgp_rx_resume(msg, ns_bvci); + rc = bssgp_rx_resume(msg); break; case BSSGP_PDUT_FLUSH_LL: /* BSS informs MS has moved to one cell to other cell */ DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); + /* FIXME: notify GMM */ /* Send FLUSH_LL_ACK */ break; case BSSGP_PDUT_LLC_DISCARD: /* BSS informs that some LLC PDU's have been discarded */ DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); + /* FIXME: notify GMM */ break; case BSSGP_PDUT_FLOW_CONTROL_BVC: /* BSS informs us of available bandwidth in Gb interface */ - rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci); + rc = bssgp_rx_fc_bvc(msg, &tp); break; case BSSGP_PDUT_FLOW_CONTROL_MS: /* BSS informs us of available bandwidth to one MS */ DEBUGP(DGPRS, "BSSGP FC MS\n"); - /* Send FLOW_CONTROL_MS_ACK */ + /* FIXME: actually implement flow control */ + /* FIXME: Send FLOW_CONTROL_MS_ACK */ break; case BSSGP_PDUT_BVC_BLOCK: /* BSS tells us that BVC shall be blocked */ @@ -431,6 +441,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ + /* FIXME: notify GMM */ case BSSGP_PDUT_DOWNLOAD_BSS_PFC: case BSSGP_PDUT_CREATE_BSS_PFC_ACK: case BSSGP_PDUT_CREATE_BSS_PFC_NACK: @@ -469,8 +480,8 @@ err_mand_ie: } /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU - * to a remote MS (identified by TLLI) at a BTS identified by its RAC and CID */ -int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_t cid) + * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ +int gprs_bssgp_tx_dl_ud(struct msgb *msg) { struct bssgp_bts_ctx *bctx; struct bssgp_ud_hdr *budh; @@ -479,8 +490,19 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_ u_int16_t pdu_lifetime = 1000; /* centi-seconds */ u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; u_int16_t msg_len = msg->len; + uint16_t bvci = msgb_bvci(msg); + uint16_t nsei = msgb_nsei(msg); - bctx = btsctx_by_raid_cid(raid, cid); + /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ + if (bvci < 2) { + LOGP(DGPRS, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", + bvci); + return -EINVAL; + } + + bctx = btsctx_by_bvci_nsei(bvci, nsei); + if (!bctx) + bctx = btsctx_alloc(bvci, nsei); if (msg->len > TVLV_MAX_ONEBYTE) llc_pdu_tlv_hdr_len += 1; @@ -508,8 +530,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_ budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; - msgb_nsei(msg) = bctx->nsei; - msgb_bvci(msg) = bctx->bvci; + /* Identifiers down: BVCI, NSEI (in msgb->cb) */ return gprs_ns_sendmsg(bssgp_nsi, msg); } diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 470ccb080..1558ca146 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -267,6 +267,7 @@ static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; msgb_bssgph(msg) = &nsh->data[3]; + msgb_bvci(msg) = bvci; /* call upper layer (BSSGP) */ return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); From 8f9a3ee67bf25b62936ffbcd88936936916ad0e9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 11:26:34 +0200 Subject: [PATCH 046/198] [gprs] Use stdint.h types (uintXX_t instead of u_intXX_t) libosmocore already uses them, it's time (at least for new code) in openbsc to do the same. --- openbsc/include/openbsc/gprs_bssgp.h | 16 +++++++------ openbsc/include/openbsc/gprs_ns.h | 16 +++++++------ openbsc/src/gprs_bssgp.c | 36 ++++++++++++++-------------- openbsc/src/gprs_ns.c | 34 +++++++++++++------------- 4 files changed, 53 insertions(+), 49 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index a00481e4e..c70868af3 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -1,6 +1,8 @@ #ifndef _GPRS_BSSGP_H #define _GPRS_BSSGP_H +#include + /* Section 11.3.26 / Table 11.27 */ enum bssgp_pdu_type { /* PDUs between RL and BSSGP SAPs */ @@ -49,15 +51,15 @@ enum bssgp_pdu_type { /* Section 10.2.1 and 10.2.2 */ struct bssgp_ud_hdr { - u_int8_t pdu_type; - u_int32_t tlli; - u_int8_t qos_profile[3]; - u_int8_t data[0]; /* TLV's */ + uint8_t pdu_type; + uint32_t tlli; + uint8_t qos_profile[3]; + uint8_t data[0]; /* TLV's */ } __attribute__((packed)); struct bssgp_normal_hdr { - u_int8_t pdu_type; - u_int8_t data[0]; /* TLV's */ + uint8_t pdu_type; + uint8_t data[0]; /* TLV's */ }; enum bssgp_iei_type { @@ -140,7 +142,7 @@ enum gprs_bssgp_cause { extern int gprs_bssgp_rcvmsg(struct msgb *msg); /* Wrapper around TLV parser to parse BSSGP IEs */ -static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) +static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) { return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); } diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index ca02c4b5d..573536d11 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -1,13 +1,15 @@ #ifndef _GPRS_NS_H #define _GPRS_NS_H +#include + /* GPRS Networks Service (NS) messages on the Gb interface * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ struct gprs_ns_hdr { - u_int8_t pdu_type; - u_int8_t data[0]; + uint8_t pdu_type; + uint8_t data[0]; } __attribute__((packed)); /* TS 08.16, Section 10.3.7, Table 14 */ @@ -95,7 +97,7 @@ enum gprs_ns_evt { struct gprs_nsvc; typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, u_int16_t bvci); + struct msgb *msg, uint16_t bvci); /* An instance of the NS protocol stack */ struct gprs_ns_inst { @@ -120,11 +122,11 @@ struct gprs_nsvc { struct llist_head list; struct gprs_ns_inst *nsi; - u_int16_t nsei; /* end-to-end significance */ - u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ + uint16_t nsei; /* end-to-end significance */ + uint16_t nsvci; /* uniquely identifies NS-VC at SGSN */ - u_int32_t state; - u_int32_t remote_state; + uint32_t state; + uint32_t remote_state; struct timer_list alive_timer; int timer_is_tns_alive; diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 6bba1af8a..a3fa3ecca 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -21,7 +21,7 @@ */ #include -#include +#include #include @@ -147,26 +147,26 @@ static inline struct msgb *bssgp_msgb_alloc(void) } /* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ -static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t nsei, - u_int16_t bvci, u_int16_t ns_bvci) +static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - u_int16_t _bvci; + uint16_t _bvci; msgb_nsei(msg) = nsei; msgb_bvci(msg) = ns_bvci; bgph->pdu_type = pdu_type; _bvci = htons(bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Chapter 10.4.5: Flow Control BVC ACK */ -static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) +static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = @@ -182,7 +182,7 @@ static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) } /* Chapter 10.4.14: Status */ -int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) +int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = @@ -195,8 +195,8 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) bgph->pdu_type = BSSGP_PDUT_STATUS; msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); if (bvci) { - u_int16_t _bvci = htons(*bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + uint16_t _bvci = htons(*bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); } if (orig_msg) msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, @@ -223,7 +223,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, uint16_t bvci; int rc; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); @@ -413,7 +413,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); /* We always acknowledge the BLOCKing */ @@ -425,7 +425,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) goto err_mand_ie; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u\n", bvci); /* We always acknowledge the unBLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, @@ -485,11 +485,11 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) { struct bssgp_bts_ctx *bctx; struct bssgp_ud_hdr *budh; - u_int8_t llc_pdu_tlv_hdr_len = 2; - u_int8_t *llc_pdu_tlv, *qos_profile; - u_int16_t pdu_lifetime = 1000; /* centi-seconds */ - u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; - u_int16_t msg_len = msg->len; + uint8_t llc_pdu_tlv_hdr_len = 2; + uint8_t *llc_pdu_tlv, *qos_profile; + uint16_t pdu_lifetime = 1000; /* centi-seconds */ + uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; + uint16_t msg_len = msg->len; uint16_t bvci = msgb_bvci(msg); uint16_t nsei = msgb_nsei(msg); @@ -522,7 +522,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) /* prepend the pdu lifetime */ pdu_lifetime = htons(pdu_lifetime); - msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime); + msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (uint8_t *)&pdu_lifetime); /* prepend the QoS profile, TLLI and pdu type */ budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 1558ca146..0db06c3f0 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include @@ -74,7 +74,7 @@ static const struct tlv_definition ns_att_tlvdef = { /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, - u_int16_t nsvci) + uint16_t nsvci) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -86,7 +86,7 @@ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, - u_int16_t nsei) + uint16_t nsei) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -109,7 +109,7 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, return NULL; } -static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, u_int16_t nsvci) +static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -163,7 +163,7 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) return ret; } -static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) +static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; @@ -211,7 +211,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; - u_int16_t nsvci, nsei; + uint16_t nsvci, nsei; if (!msg) return -ENOMEM; @@ -225,8 +225,8 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) DEBUGP(DGPRS, "nsvci=%u, nsei=%u\n", nsvc->nsvci, nsvc->nsei); - msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); - msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); return gprs_ns_tx(nsvc, msg); } @@ -236,7 +236,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) { struct gprs_nsvc *nsvc; struct gprs_ns_hdr *nsh; - u_int16_t bvci = msgb_bvci(msg); + uint16_t bvci = msgb_bvci(msg); nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); if (!nsvc) { @@ -262,7 +262,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; - u_int16_t bvci; + uint16_t bvci; /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; @@ -278,7 +278,7 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct tlv_parsed tp; - u_int8_t cause; + uint8_t cause; int rc; DEBUGP(DGPRS, "NS STATUS "); @@ -301,8 +301,8 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct tlv_parsed tp; - u_int8_t *cause; - u_int16_t *nsvci, *nsei; + uint8_t *cause; + uint16_t *nsvci, *nsei; int rc; DEBUGP(DGPRS, "NS RESET "); @@ -317,9 +317,9 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) return -EINVAL; } - cause = (u_int8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); - nsvci = (u_int16_t *) TLVP_VAL(&tp, NS_IE_VCI); - nsei = (u_int16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); + nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->nsei = ntohs(*nsei); @@ -517,7 +517,7 @@ static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) /* FIXME: this is currently in input/ipaccess.c */ -extern int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, +extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port, int (*cb)(struct bsc_fd *fd, unsigned int what)); /* Listen for incoming GPRS packets */ From a2ca4ed96073328c33cc6fd8fdf626b2685463f8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 11:54:55 +0200 Subject: [PATCH 047/198] [gprs] pass BSSGP UL-UNITDATA Cell ID up into GMM layer BSSGP stores a pointer to the Cell Identifier IE in msgb->cb, which is later used by the GMM layer to identify the cell that has sent a given message. This now also means that the gsm_04_08_gprs.c code is free of any legacy references to msg->trx or struct gsm_bts. --- openbsc/include/openbsc/gprs_bssgp.h | 1 + openbsc/src/gprs_bssgp.c | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index c70868af3..c1094b351 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -140,6 +140,7 @@ enum gprs_bssgp_cause { #include extern int gprs_bssgp_rcvmsg(struct msgb *msg); +uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); /* Wrapper around TLV parser to parse BSSGP IEs */ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index a3fa3ecca..aceedb589 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -205,13 +205,12 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) return gprs_ns_sendmsg(bssgp_nsi, msg); } -static void bssgp_parse_cell_id(struct gprs_ra_id *raid, uint16_t *cid, - const uint8_t *buf) +uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) { /* 6 octets RAC */ gsm48_parse_ra(raid, buf); /* 2 octets CID */ - *cid = ntohs(*(uint16_t *) (buf+6)); + return ntohs(*(uint16_t *) (buf+6)); } /* Chapter 8.4 BVC-Reset Procedure */ @@ -241,8 +240,8 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, return -EINVAL; } /* actually extract RAC / CID */ - bssgp_parse_cell_id(&bctx->ra_id, &bctx->cell_id, - TLVP_VAL(tp, BSSGP_IE_CELL_ID)); + bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id, + TLVP_VAL(tp, BSSGP_IE_CELL_ID)); LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, bctx->ra_id.rac, bctx->cell_id, bvci); @@ -275,7 +274,9 @@ static int bssgp_rx_ul_ud(struct msgb *msg) /* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */ + /* store pointer to LLC header and CELL ID in msgb->cb */ msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); + msgb_bcid(msg) = TLVP_VAL(&tp, BSSGP_IE_CELL_ID); return gprs_llc_rcvmsg(msg, &tp); } From f76aee438e6391731a89fcba8a130a7acbe160ce Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 21:29:36 +0200 Subject: [PATCH 048/198] [gprs] correctly calculate the length of the BSSGP PDUs --- openbsc/src/gprs_bssgp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index aceedb589..554738b56 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -200,7 +200,7 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) } if (orig_msg) msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_l3len(orig_msg), msgb_bssgph(orig_msg)); + msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); return gprs_ns_sendmsg(bssgp_nsi, msg); } @@ -257,7 +257,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_ul_ud(struct msgb *msg) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); - int data_len = msgb_l3len(msg) - sizeof(*budh); + int data_len = msgb_bssgp_len(msg) - sizeof(*budh); struct tlv_parsed tp; int rc; @@ -285,7 +285,7 @@ static int bssgp_rx_suspend(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -307,7 +307,7 @@ static int bssgp_rx_resume(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -352,7 +352,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); uint16_t bvci; /* PTP BVCI */ uint16_t ns_bvci = msgb_bvci(msg); int rc = 0; From bbc9fac7b731dee4c3e60c5b6a9aadf0a3141dcf Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 18:54:12 +0200 Subject: [PATCH 049/198] [gprs] Unify log messages of the NS protocol implementation --- openbsc/src/gprs_ns.c | 50 ++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 0db06c3f0..619a82904 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -223,7 +223,8 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsh->pdu_type = NS_PDUT_RESET_ACK; - DEBUGP(DGPRS, "nsvci=%u, nsei=%u\n", nsvc->nsvci, nsvc->nsei); + DEBUGP(DGPRS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); @@ -240,13 +241,14 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); if (!nsvc) { - DEBUGP(DGPRS, "Unable to resolve NSEI %u to NS-VC!\n", msgb_nsei(msg)); + LOGP(DGPRS, LOGL_ERROR, "Unable to resolve NSEI %u " + "to NS-VC!\n", msgb_nsei(msg)); return -EINVAL; } nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { - DEBUGP(DGPRS, "Not enough headroom for NS header\n"); + LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); return -EIO; } @@ -281,7 +283,7 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t cause; int rc; - DEBUGP(DGPRS, "NS STATUS "); + DEBUGP(DGPRS, "NSEI=%u NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); @@ -305,15 +307,13 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) uint16_t *nsvci, *nsei; int rc; - DEBUGP(DGPRS, "NS RESET "); - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ - DEBUGPC(DGPRS, "Missing mandatory IE\n"); + LOGP(DGPRS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); return -EINVAL; } @@ -321,13 +321,13 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + DEBUGP(DGPRS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", + nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->nsei = ntohs(*nsei); nsvc->nsvci = ntohs(*nsvci); - DEBUGPC(DGPRS, "cause=%s, NSVCI=%u, NSEI=%u\n", - gprs_ns_cause_str(*cause), nsvc->nsvci, nsvc->nsei); - /* mark the NS-VC as blocked and alive */ /* start the test procedure */ nsvc->alive_timer.cb = gprs_ns_alive_cb; @@ -349,14 +349,18 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { /* Only the RESET procedure creates a new NSVC */ - if (nsh->pdu_type != NS_PDUT_RESET) + if (nsh->pdu_type != NS_PDUT_RESET) { + LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " + "from %s for non-existing NS-VC\n", + nsh->pdu_type, inet_ntoa(saddr->sin_addr)); return -EIO; + } + LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; - rc = gprs_ns_rx_reset(nsvc, msg); - return rc; - } - msgb_nsei(msg) = nsvc->nsei; + } else + msgb_nsei(msg) = nsvc->nsei; switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -382,33 +386,34 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - DEBUGP(DGPRS, "NS RESET ACK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ - DEBUGP(DGPRS, "NS UNBLOCK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - DEBUGP(DGPRS, "NS UNBLOCK ACK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: - DEBUGP(DGPRS, "NS BLOCK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); nsvc->state |= NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: - DEBUGP(DGPRS, "NS BLOCK ACK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: - DEBUGP(DGPRS, "Unknown NS PDU type 0x%02x\n", nsh->pdu_type); + DEBUGP(DGPRS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", + nsvc->nsei, nsh->pdu_type); rc = -EINVAL; break; } @@ -453,7 +458,8 @@ static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)saddr, &saddr_len); if (ret < 0) { - fprintf(stderr, "recv error %s\n", strerror(errno)); + LOGP(DGPRS, LOGL_ERROR, "recv error %s during NSIP recv\n", + strerror(errno)); msgb_free(msg); *error = ret; return NULL; From 80405458a0c325e11e55133065df9b767bb0edc4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 20:16:13 +0200 Subject: [PATCH 050/198] [gprs] NS: replace nsvc->timer_is_tns_alive with nsvc->timer_mode This will allow to use the timer in more than 2 modes --- openbsc/include/openbsc/gprs_ns.h | 12 ++++++++++-- openbsc/src/gprs_ns.c | 25 ++++++++++++++----------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 573536d11..407840491 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -118,6 +118,14 @@ struct gprs_ns_inst { }; }; +enum nsvc_timer_mode { + /* standard timers */ + NSVC_TIMER_TNS_TEST, + NSVC_TIMER_TNS_ALIVE, + /* custom timer */ + NSVC_TIMER_RESET, +}; + struct gprs_nsvc { struct llist_head list; struct gprs_ns_inst *nsi; @@ -128,8 +136,8 @@ struct gprs_nsvc { uint32_t state; uint32_t remote_state; - struct timer_list alive_timer; - int timer_is_tns_alive; + struct timer_list timer; + enum nsvc_timer_mode timer_mode; int alive_retries; int remote_end_is_sgsn; diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 619a82904..9c198ad9a 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -182,11 +182,12 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) #define NS_TIMER_TEST 30, 0 /* every 10 seconds we check if the BTS is still alive */ #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ -static void gprs_ns_alive_cb(void *data) +static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; - if (nsvc->timer_is_tns_alive) { + switch (nsvc->timer_mode) { + case NSVC_TIMER_TNS_ALIVE: /* Tns-alive case: we expired without response ! */ nsvc->alive_retries++; if (nsvc->alive_retries > NS_ALIVE_RETRIES) { @@ -197,13 +198,15 @@ static void gprs_ns_alive_cb(void *data) /* FIXME: inform higher layers */ return; } - } else { + break; + case NSVC_TIMER_TNS_TEST: /* Tns-test case: send NS-ALIVE PDU */ gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); /* start Tns-alive timer */ - nsvc->timer_is_tns_alive = 1; + nsvc->timer_mode = NSVC_TIMER_TNS_ALIVE; + break; } - bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); + bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); } /* Section 9.2.6 */ @@ -330,9 +333,9 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* mark the NS-VC as blocked and alive */ /* start the test procedure */ - nsvc->alive_timer.cb = gprs_ns_alive_cb; - nsvc->alive_timer.data = nsvc; - bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); + nsvc->timer.cb = gprs_ns_timer_cb; + nsvc->timer.data = nsvc; + bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); return gprs_ns_tx_reset_ack(nsvc); } @@ -370,10 +373,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ - bsc_del_timer(&nsvc->alive_timer); + bsc_del_timer(&nsvc->timer); /* start Tns-test */ - nsvc->timer_is_tns_alive = 0; - bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_TEST); + nsvc->timer_mode = NSVC_TIMER_TNS_TEST; + bsc_schedule_timer(&nsvc->timer, NS_TIMER_TEST); break; case NS_PDUT_UNITDATA: /* actual user data */ From 69a4cf27318f471a70759a80923a0dfbbe0a8e0a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 20:55:10 +0200 Subject: [PATCH 051/198] [gprs] NS: improved timer handling for RESET --- openbsc/include/openbsc/gprs_ns.h | 4 +- openbsc/src/gprs_ns.c | 93 ++++++++++++++++++++++++++----- 2 files changed, 80 insertions(+), 17 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 407840491..27c54cb13 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -122,8 +122,8 @@ enum nsvc_timer_mode { /* standard timers */ NSVC_TIMER_TNS_TEST, NSVC_TIMER_TNS_ALIVE, - /* custom timer */ - NSVC_TIMER_RESET, + NSVC_TIMER_TNS_RESET, + _NSVC_TIMER_NR, }; struct gprs_nsvc { diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 9c198ad9a..39ca8101f 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -109,6 +109,8 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, return NULL; } +static void gprs_ns_timer_cb(void *data); + static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -118,6 +120,9 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) /* before RESET procedure: BLOCKED and DEAD */ nsvc->state = NSE_S_BLOCKED; nsvc->nsi = nsi; + nsvc->timer.cb = gprs_ns_timer_cb; + nsvc->timer.data = nsvc; + llist_add(&nsvc->list, &nsi->gprs_nsvcs); return nsvc; @@ -133,7 +138,7 @@ static const struct value_string ns_cause_str[] = { { NS_CAUSE_BVCI_UNKNOWN, "BVCI unknown" }, { NS_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, { NS_CAUSE_PDU_INCOMP_PSTATE, "PDU not compatible with protocol state" }, - { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error }, unspecified" }, + { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, { NS_CAUSE_INVAL_ESSENT_IE, "Invalid essential IE" }, { NS_CAUSE_MISSING_ESSENT_IE, "Missing essential IE" }, { 0, NULL } @@ -178,10 +183,47 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) return gprs_ns_tx(nsvc, msg); } -#define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ -#define NS_TIMER_TEST 30, 0 /* every 10 seconds we check if the BTS is still alive */ +static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint8_t cause = NS_CAUSE_OM_INTERVENTION; + uint16_t nsvci = htons(nsvc->nsvci); + uint16_t nsei = htons(nsvc->nsei); + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + nsh->pdu_type = NS_PDUT_RESET; + + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei); + + return gprs_ns_tx(nsvc, msg); + +} + #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ +static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { + [NSVC_TIMER_TNS_RESET] = 60, + [NSVC_TIMER_TNS_ALIVE] = 3, + [NSVC_TIMER_TNS_TEST] = 30, +}; + +static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) +{ + nsvc->alive_retries = 0; + + if (bsc_timer_pending(&nsvc->timer)) + bsc_del_timer(&nsvc->timer); + + nsvc->timer_mode = mode; + bsc_schedule_timer(&nsvc->timer, timer_mode_tout[mode], 0); +} + static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; @@ -193,20 +235,26 @@ static void gprs_ns_timer_cb(void *data) if (nsvc->alive_retries > NS_ALIVE_RETRIES) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; - DEBUGP(DGPRS, "Tns-alive more then %u retries, " - " blocking NS-VC\n", NS_ALIVE_RETRIES); + DEBUGP(DGPRS, "NSEI=%u Tns-alive expired more then " + "%u times, blocking NS-VC\n", nsvc->nsei, + NS_ALIVE_RETRIES); /* FIXME: inform higher layers */ return; } + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_TEST: /* Tns-test case: send NS-ALIVE PDU */ gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); /* start Tns-alive timer */ - nsvc->timer_mode = NSVC_TIMER_TNS_ALIVE; + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + break; + case NSVC_TIMER_TNS_RESET: + /* Chapter 7.3: Re-send the RESET */ + gprs_ns_tx_reset(nsvc); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; } - bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); } /* Section 9.2.6 */ @@ -249,6 +297,17 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) return -EINVAL; } + if (!(nsvc->state & NSE_S_ALIVE)) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", + nsvc->nsei); + return -EBUSY; + } + if (nsvc->state & NSE_S_BLOCKED) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", + nsvc->nsei); + return -EBUSY; + } + nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); @@ -333,9 +392,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* mark the NS-VC as blocked and alive */ /* start the test procedure */ - nsvc->timer.cb = gprs_ns_timer_cb; - nsvc->timer.data = nsvc; - bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); return gprs_ns_tx_reset_ack(nsvc); } @@ -375,8 +432,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* stop Tns-alive */ bsc_del_timer(&nsvc->timer); /* start Tns-test */ - nsvc->timer_mode = NSVC_TIMER_TNS_TEST; - bsc_schedule_timer(&nsvc->timer, NS_TIMER_TEST); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); break; case NS_PDUT_UNITDATA: /* actual user data */ @@ -392,6 +448,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + if (nsvc->remote_end_is_sgsn) { + /* stop RESET timer */ + bsc_del_timer(&nsvc->timer); + } break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ @@ -561,9 +621,12 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ - if (gprs_ns_tx_simple(nsvc, NS_PDUT_RESET) < 0) - return NULL; - /* FIXME: should we run a timer and re-transmit the reset request? */ + if (gprs_ns_tx_reset(nsvc) < 0) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", + nsei); + } + /* run a timer and re-transmit the reset request? */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); return nsvc; } From 570fb83fd570660cd56c0272a0a123bc660baa38 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 21:05:24 +0200 Subject: [PATCH 052/198] [gprs] NS: Start ALIVE Procedure after receiving RESET_ACK --- openbsc/src/gprs_ns.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 39ca8101f..72558ca42 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -183,11 +183,10 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) return gprs_ns_tx(nsvc, msg); } -static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc) +static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; - uint8_t cause = NS_CAUSE_OM_INTERVENTION; uint16_t nsvci = htons(nsvc->nsvci); uint16_t nsei = htons(nsvc->nsei); @@ -251,7 +250,7 @@ static void gprs_ns_timer_cb(void *data) break; case NSVC_TIMER_TNS_RESET: /* Chapter 7.3: Re-send the RESET */ - gprs_ns_tx_reset(nsvc); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; } @@ -413,6 +412,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " "from %s for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr)); + //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", @@ -451,6 +451,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); + /* send ALIVE PDU */ + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); } break; case NS_PDUT_UNBLOCK: @@ -621,7 +624,7 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ - if (gprs_ns_tx_reset(nsvc) < 0) { + if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", nsei); } From 7fb7e6154c0a286b1d4126642218c7a2f1d0d77c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 21:11:22 +0200 Subject: [PATCH 053/198] [gprs] NS: If we are the BSS side, UNBLOCK the connection after it is ALIVE After RESET / RESET-ACK and ALIVE / ALIVE-ACK, the connection needs to be unblocked from the BSS side to the SGSN. --- openbsc/src/gprs_ns.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 72558ca42..3d9bb8963 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -433,6 +433,11 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, bsc_del_timer(&nsvc->timer); /* start Tns-test */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); + if (nsvc->remote_end_is_sgsn) { + /* FIXME: this should be one level higher */ + if (nsvc->state & NSE_S_BLOCKED) + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); + } break; case NS_PDUT_UNITDATA: /* actual user data */ @@ -454,6 +459,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* send ALIVE PDU */ rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + /* mark local state as BLOCKED + ALIVE */ + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; } break; case NS_PDUT_UNBLOCK: @@ -466,6 +473,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; + if (nsvc->remote_end_is_sgsn) + nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); From 94633f3e2b9d6ccfad93a5d518e4b83c5802c7c1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 4 May 2010 07:41:59 +0200 Subject: [PATCH 054/198] [gprs] Move all GPRS related code to src/gprs subdirectory --- openbsc/src/{ => gprs}/gprs_bssgp.c | 0 openbsc/src/{ => gprs}/gprs_ns.c | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename openbsc/src/{ => gprs}/gprs_bssgp.c (100%) rename openbsc/src/{ => gprs}/gprs_ns.c (100%) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c similarity index 100% rename from openbsc/src/gprs_bssgp.c rename to openbsc/src/gprs/gprs_bssgp.c diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c similarity index 100% rename from openbsc/src/gprs_ns.c rename to openbsc/src/gprs/gprs_ns.c From b8a6a83be64ff93993d442fcea8b10962f646c10 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 05:54:22 +0200 Subject: [PATCH 055/198] [gprs] Add new 'NS' and 'BSSGP' logging categories --- openbsc/src/gprs/gprs_bssgp.c | 44 +++++++++++++++++------------------ openbsc/src/gprs/gprs_ns.c | 44 +++++++++++++++++------------------ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 554738b56..0f658b993 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -188,7 +188,7 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); msgb_nsei(msg) = msgb_nsei(orig_msg); msgb_bvci(msg) = 0; @@ -223,7 +223,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, int rc; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); /* look-up or create the BTS context for this BVC */ @@ -235,14 +235,14 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, * informs us about its RAC + Cell ID, so we can create a mapping */ if (bvci != 0 && bvci != 1) { if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { - LOGP(DGPRS, LOGL_ERROR, "BSSGP RESET BVCI=%u " + LOGP(DBSSGP, LOGL_ERROR, "BSSGP RESET BVCI=%u " "missing mandatory IE\n", bvci); return -EINVAL; } /* actually extract RAC / CID */ bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id, TLVP_VAL(tp, BSSGP_IE_CELL_ID)); - LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", + LOGP(DBSSGP, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, bctx->ra_id.rac, bctx->cell_id, bvci); } @@ -261,7 +261,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg) struct tlv_parsed tp; int rc; - DEBUGP(DGPRS, "BSSGP UL-UD\n"); + DEBUGP(DBSSGP, "BSSGP UL-UD\n"); /* extract TLLI and parse TLV IEs */ msgb_tlli(msg) = ntohl(budh->tlli); @@ -289,7 +289,7 @@ static int bssgp_rx_suspend(struct msgb *msg) struct tlv_parsed tp; int rc; - DEBUGP(DGPRS, "BSSGP SUSPEND\n"); + DEBUGP(DBSSGP, "BSSGP SUSPEND\n"); rc = bssgp_tlv_parse(&tp, bgph->data, data_len); if (rc < 0) @@ -311,7 +311,7 @@ static int bssgp_rx_resume(struct msgb *msg) struct tlv_parsed tp; int rc; - DEBUGP(DGPRS, "BSSGP RESUME\n"); + DEBUGP(DBSSGP, "BSSGP RESUME\n"); rc = bssgp_tlv_parse(&tp, bgph->data, data_len); if (rc < 0) @@ -329,7 +329,7 @@ static int bssgp_rx_resume(struct msgb *msg) static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) { - DEBUGP(DGPRS, "BSSGP FC BVC\n"); + DEBUGP(DBSSGP, "BSSGP FC BVC\n"); if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) || !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) || @@ -371,11 +371,11 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_RA_CAPABILITY: /* BSS requests RA capability or IMSI */ - DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n"); + DEBUGP(DBSSGP, "BSSGP RA CAPABILITY UPDATE\n"); /* FIXME: send RA_CAPA_UPDATE_ACK */ break; case BSSGP_PDUT_RADIO_STATUS: - DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); + DEBUGP(DBSSGP, "BSSGP RADIO STATUS\n"); /* BSS informs us of some exception */ /* FIXME: notify GMM */ break; @@ -389,13 +389,13 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_FLUSH_LL: /* BSS informs MS has moved to one cell to other cell */ - DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); + DEBUGP(DBSSGP, "BSSGP FLUSH LL\n"); /* FIXME: notify GMM */ /* Send FLUSH_LL_ACK */ break; case BSSGP_PDUT_LLC_DISCARD: /* BSS informs that some LLC PDU's have been discarded */ - DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); + DEBUGP(DBSSGP, "BSSGP LLC DISCARDED\n"); /* FIXME: notify GMM */ break; case BSSGP_PDUT_FLOW_CONTROL_BVC: @@ -404,18 +404,18 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_FLOW_CONTROL_MS: /* BSS informs us of available bandwidth to one MS */ - DEBUGP(DGPRS, "BSSGP FC MS\n"); + DEBUGP(DBSSGP, "BSSGP FC MS\n"); /* FIXME: actually implement flow control */ /* FIXME: Send FLOW_CONTROL_MS_ACK */ break; case BSSGP_PDUT_BVC_BLOCK: /* BSS tells us that BVC shall be blocked */ - DEBUGP(DGPRS, "BSSGP BVC BLOCK "); + DEBUGP(DBSSGP, "BSSGP BVC BLOCK "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); /* We always acknowledge the BLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, @@ -423,18 +423,18 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_BVC_UNBLOCK: /* BSS tells us that BVC shall be unblocked */ - DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); + DEBUGP(DBSSGP, "BSSGP BVC UNBLOCK "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) goto err_mand_ie; bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u\n", bvci); + DEBUGPC(DBSSGP, "BVCI=%u\n", bvci); /* We always acknowledge the unBLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_BVC_RESET: /* BSS tells us that BVC init is required */ - DEBUGP(DGPRS, "BSSGP BVC RESET "); + DEBUGP(DBSSGP, "BSSGP BVC RESET "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; @@ -448,7 +448,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) case BSSGP_PDUT_CREATE_BSS_PFC_NACK: case BSSGP_PDUT_MODIFY_BSS_PFC: case BSSGP_PDUT_DELETE_BSS_PFC_ACK: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n", + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x not [yet] implemented\n", pdu_type); break; /* those only exist in the SGSN -> BSS direction */ @@ -466,12 +466,12 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) case BSSGP_PDUT_BVC_BLOCK_ACK: case BSSGP_PDUT_BVC_UNBLOCK_ACK: case BSSGP_PDUT_SGSN_INVOKE_TRACE: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n", + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x only exists in DL\n", pdu_type); rc = -EINVAL; break; default: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x unknown\n", pdu_type); break; } @@ -496,7 +496,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ if (bvci < 2) { - LOGP(DGPRS, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", + LOGP(DBSSGP, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", bvci); return -EINVAL; } diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3d9bb8963..be3d1d93a 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -160,7 +160,7 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) ret = nsip_sendmsg(nsvc, msg); break; default: - LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); + LOGP(DNS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); msgb_free(msg); ret = -EIO; break; @@ -234,7 +234,7 @@ static void gprs_ns_timer_cb(void *data) if (nsvc->alive_retries > NS_ALIVE_RETRIES) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; - DEBUGP(DGPRS, "NSEI=%u Tns-alive expired more then " + DEBUGP(DNS, "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, NS_ALIVE_RETRIES); /* FIXME: inform higher layers */ @@ -273,7 +273,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsh->pdu_type = NS_PDUT_RESET_ACK; - DEBUGP(DGPRS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", + DEBUGP(DNS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); @@ -291,25 +291,25 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); if (!nsvc) { - LOGP(DGPRS, LOGL_ERROR, "Unable to resolve NSEI %u " + LOGP(DNS, LOGL_ERROR, "Unable to resolve NSEI %u " "to NS-VC!\n", msgb_nsei(msg)); return -EINVAL; } if (!(nsvc->state & NSE_S_ALIVE)) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", + LOGP(DNS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", nsvc->nsei); return -EBUSY; } if (nsvc->state & NSE_S_BLOCKED) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", + LOGP(DNS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", nsvc->nsei); return -EBUSY; } nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { - LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); + LOGP(DNS, LOGL_ERROR, "Not enough headroom for NS header\n"); return -EIO; } @@ -344,17 +344,17 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t cause; int rc; - DEBUGP(DGPRS, "NSEI=%u NS STATUS ", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { - DEBUGPC(DGPRS, "missing cause IE\n"); + DEBUGPC(DNS, "missing cause IE\n"); return -EINVAL; } cause = *TLVP_VAL(&tp, NS_IE_CAUSE); - DEBUGPC(DGPRS, "cause=%s\n", gprs_ns_cause_str(cause)); + DEBUGPC(DNS, "cause=%s\n", gprs_ns_cause_str(cause)); return 0; } @@ -374,7 +374,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ - LOGP(DGPRS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); return -EINVAL; } @@ -382,7 +382,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - DEBUGP(DGPRS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", + DEBUGP(DNS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; @@ -409,13 +409,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (!nsvc) { /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { - LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " + LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " "from %s for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr)); //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } - LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", + LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; @@ -450,7 +450,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) { @@ -465,29 +465,29 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ - DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: - DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); nsvc->state |= NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: - DEBUGP(DGPRS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", + DEBUGP(DNS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", nsvc->nsei, nsh->pdu_type); rc = -EINVAL; break; @@ -533,7 +533,7 @@ static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)saddr, &saddr_len); if (ret < 0) { - LOGP(DGPRS, LOGL_ERROR, "recv error %s during NSIP recv\n", + LOGP(DNS, LOGL_ERROR, "recv error %s during NSIP recv\n", strerror(errno)); msgb_free(msg); *error = ret; @@ -634,7 +634,7 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, /* Initiate a RESET procedure */ if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", + LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", nsei); } /* run a timer and re-transmit the reset request? */ From 834f26d62c55a7ba837ca370e7c60d0672aaead1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 06:20:54 +0200 Subject: [PATCH 056/198] [gprs] NS: Add signals in the event of BLOCK/UNBLOCK/RESET The signals will be sent upon reception of NS-BLOCK/UNBLOCK/RESET PDUs We also export functions to generate/send BLOCK/UNBLOCK and RESET. --- openbsc/include/openbsc/gprs_ns.h | 3 ++ openbsc/src/gprs/gprs_ns.c | 77 +++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 27c54cb13..c74546a8b 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -167,6 +167,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* main function for higher layers (BSSGP) to send NS messages */ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); +int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause); +int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause); +int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc); /* Listen for incoming GPRS packets */ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index be3d1d93a..3fa2c0169 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,17 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) return nsvc; } +static void ns_dispatch_signal(struct nsvc *nsvc, unsigned int signal, + uint8_t cause) +{ + struct ns_signal_data nssd; + + nssd.nsvc = nsvc; + nssd.cause = cause; + + dispatch_signal(SS_NS, signal, &nssd); +} + /* Section 10.3.2, Table 13 */ static const struct value_string ns_cause_str[] = { { NS_CAUSE_TRANSIT_FAIL, "Transit network failure" }, @@ -183,7 +195,7 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) return gprs_ns_tx(nsvc, msg); } -static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) +int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; @@ -204,6 +216,32 @@ static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) } +int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint16_t nsvci = htons(nsvc->nsvci); + + if (!msg) + return -ENOMEM; + + /* be conservative and mark it as blocked even now! */ + nsvc->state |= NSE_S_BLOCKED; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + nsh->pdu_type = NS_PDUT_BLOCK; + + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci); + + return gprs_ns_tx(nsvc, msg); +} + +int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) +{ + return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); +} + #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { @@ -393,9 +431,41 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* start the test procedure */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + /* inform interested parties about the fact that this NSVC + * has received RESET */ + ns_dispatch_signal(nsvc, S_NS_RESET, cause); + return gprs_ns_tx_reset_ack(nsvc); } +static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct tlv_parsed tp; + uint8_t *cause; + int rc; + + DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); + + nsvc->state |= NSE_S_BLOCKED; + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || + !TLVP_PRESENT(&tp, NS_IE_VCI)) { + /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ + LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + return -EINVAL; + } + + cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); + + ns_dispatch_signal(nsvc, S_NS_BLOCK, cause); + + return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); +} + /* main entry point, here incoming NS frames enter */ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct sockaddr_in *saddr) @@ -467,6 +537,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* Section 7.2: unblocking procedure */ DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; + ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: @@ -477,9 +548,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: - DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); - nsvc->state |= NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); + rc = gprs_ns_rx_block(nsvc, msg); break; case NS_PDUT_BLOCK_ACK: DEBUGP(DNS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); From af0867882d5302f5f356aedf55524315624c5071 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:01:17 +0200 Subject: [PATCH 057/198] [gprs] gb_proxy: Send proper BSSGP STATUS msg in error case In order to reuse the existing bssgp_tx_* functions without pulling in the dependencies of gprs_bssgp.c, we have to move those functions to gprs_bssgp_util.c Furthermore, we can remove gbprox_nsi and replace it with bssgp_nsi, and we can do proper processing of BVC-RESET messages coming from the SGSN on the signalling BVC. In that case we need to send RESET messages to all the BSS. --- openbsc/include/openbsc/gprs_bssgp.h | 12 +++ openbsc/src/gprs/gprs_bssgp.c | 82 ------------------ openbsc/src/gprs/gprs_bssgp_util.c | 119 +++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 82 deletions(-) create mode 100644 openbsc/src/gprs/gprs_bssgp_util.c diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index c1094b351..d3ccb12ee 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -137,6 +137,18 @@ enum gprs_bssgp_cause { /* Our implementation */ +/* gprs_bssgp_util.c */ +extern struct gprs_ns_inst *bssgp_nsi; +struct msgb *bssgp_msgb_alloc(void); +const char *bssgp_cause_str(enum gprs_bssgp_cause cause); +/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ +int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci); +/* Chapter 10.4.14: Status */ +int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg); + +/* gprs_bssgp.c */ + #include extern int gprs_bssgp_rcvmsg(struct msgb *msg); diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 0f658b993..b2f292858 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -39,43 +39,9 @@ /* global pointer to the gsm network data structure */ /* FIXME: this must go! */ extern struct gsm_network *bsc_gsmnet; -struct gprs_ns_inst *bssgp_nsi; void *bssgp_tall_ctx = NULL; -/* BSSGP Protocol specific, not implementation specific */ -/* FIXME: This needs to go into libosmocore after finished */ - -/* Chapter 11.3.9 / Table 11.10: Cause coding */ -static const struct value_string bssgp_cause_strings[] = { - { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, - { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, - { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, - { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, - { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, - { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, - { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, - { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, - { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, - { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, - { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, - { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, - { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, - { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, - { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, - { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, - { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, - { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, - { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, - { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, - { 0, NULL }, -}; - -const char *bssgp_cause_str(enum gprs_bssgp_cause cause) -{ - return get_value_string(bssgp_cause_strings, cause); -} - /* Our actual implementation */ @@ -141,30 +107,6 @@ struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) return ctx; } -static inline struct msgb *bssgp_msgb_alloc(void) -{ - return msgb_alloc_headroom(4096, 128, "BSSGP"); -} - -/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ -static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, - uint16_t bvci, uint16_t ns_bvci) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - uint16_t _bvci; - - msgb_nsei(msg) = nsei; - msgb_bvci(msg) = ns_bvci; - - bgph->pdu_type = pdu_type; - _bvci = htons(bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} - /* Chapter 10.4.5: Flow Control BVC ACK */ static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) { @@ -181,30 +123,6 @@ static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) return gprs_ns_sendmsg(bssgp_nsi, msg); } -/* Chapter 10.4.14: Status */ -int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - - DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); - msgb_nsei(msg) = msgb_nsei(orig_msg); - msgb_bvci(msg) = 0; - - bgph->pdu_type = BSSGP_PDUT_STATUS; - msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); - if (bvci) { - uint16_t _bvci = htons(*bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - } - if (orig_msg) - msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} - uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) { /* 6 octets RAC */ diff --git a/openbsc/src/gprs/gprs_bssgp_util.c b/openbsc/src/gprs/gprs_bssgp_util.c new file mode 100644 index 000000000..d9b5175f6 --- /dev/null +++ b/openbsc/src/gprs/gprs_bssgp_util.c @@ -0,0 +1,119 @@ +/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ + +/* (C) 2009-2010 by Harald Welte + * + * 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 +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +struct gprs_ns_inst *bssgp_nsi; + +/* BSSGP Protocol specific, not implementation specific */ +/* FIXME: This needs to go into libosmocore after finished */ + +/* Chapter 11.3.9 / Table 11.10: Cause coding */ +static const struct value_string bssgp_cause_strings[] = { + { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, + { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, + { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, + { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, + { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, + { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, + { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, + { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, + { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, + { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, + { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, + { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, + { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, + { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, + { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, + { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, + { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, + { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, + { 0, NULL }, +}; + +const char *bssgp_cause_str(enum gprs_bssgp_cause cause) +{ + return get_value_string(bssgp_cause_strings, cause); +} + + +struct msgb *bssgp_msgb_alloc(void) +{ + return msgb_alloc_headroom(4096, 128, "BSSGP"); +} + +/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ +int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + bgph->pdu_type = pdu_type; + _bvci = htons(bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* Chapter 10.4.14: Status */ +int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + msgb_nsei(msg) = msgb_nsei(orig_msg); + msgb_bvci(msg) = 0; + + bgph->pdu_type = BSSGP_PDUT_STATUS; + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + if (bvci) { + uint16_t _bvci = htons(*bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + } + if (orig_msg) + msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, + msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} From fa270b9d5bd18c65efbedde9d3a73859df3c28c6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:05:12 +0200 Subject: [PATCH 058/198] [gprs] BSSGP: cosmetic cleanup --- openbsc/src/gprs/gprs_bssgp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index b2f292858..9fdfd329d 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -36,15 +36,8 @@ #include #include -/* global pointer to the gsm network data structure */ -/* FIXME: this must go! */ -extern struct gsm_network *bsc_gsmnet; - void *bssgp_tall_ctx = NULL; - -/* Our actual implementation */ - #define BVC_F_BLOCKED 0x0001 /* The per-BTS context that we keep on the SGSN side of the BSSGP link */ @@ -66,7 +59,7 @@ struct bssgp_bts_ctx { * lookup for every packet, similar to a routing cache */ //struct gprs_nsvc *nsvc; }; -LLIST_HEAD(bts_ctxts); +static LLIST_HEAD(bts_ctxts); /* Find a BTS Context based on parsed RA ID and Cell ID */ struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) @@ -93,7 +86,7 @@ struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) return NULL; } -struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) +struct bssgp_bts_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) { struct bssgp_bts_ctx *ctx; From 2fc725de723b534a8a9c031ef12429ffa6bb092f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:15:26 +0200 Subject: [PATCH 059/198] [gprs] NS: cleanup / fix compiler warnings --- openbsc/src/gprs/gprs_ns.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3fa2c0169..69c96ca37 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -129,7 +129,7 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) return nsvc; } -static void ns_dispatch_signal(struct nsvc *nsvc, unsigned int signal, +static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal, uint8_t cause) { struct ns_signal_data nssd; @@ -291,6 +291,8 @@ static void gprs_ns_timer_cb(void *data) gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; + case _NSVC_TIMER_NR: + break; } } @@ -433,7 +435,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* inform interested parties about the fact that this NSVC * has received RESET */ - ns_dispatch_signal(nsvc, S_NS_RESET, cause); + ns_dispatch_signal(nsvc, S_NS_RESET, *cause); return gprs_ns_tx_reset_ack(nsvc); } @@ -461,7 +463,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); - ns_dispatch_signal(nsvc, S_NS_BLOCK, cause); + ns_dispatch_signal(nsvc, S_NS_BLOCK, *cause); return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); } From e8b9ca297259c5ac9918710d5b89e585ef28acf3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:18:31 +0200 Subject: [PATCH 060/198] [gprs] NS: Make sure we include "Rx" in the log statement for NS RESET --- openbsc/src/gprs/gprs_ns.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 69c96ca37..bd9791afa 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -422,10 +422,14 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - DEBUGP(DNS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", + DEBUGP(DNS, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + /* FIXME: Check if we have an existing peer with this NSEI/NSVCI + * and remove it, as our BSS may just have changed its source IP + * address */ + nsvc->nsei = ntohs(*nsei); nsvc->nsvci = ntohs(*nsvci); From 9a39293ced5f44f8bad243f50b6cb8af4414d91f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:30:37 +0200 Subject: [PATCH 061/198] [gprs] gb-proxy: We might receive a NS-RESET for a NS-VC that we already know In this case, don't blindly allocate a new NS-VC but rather use the NSEI to lookup the 'struct gprs_nsvc' for it. --- openbsc/src/gprs/gprs_ns.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index bd9791afa..3d05dd0ff 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -483,6 +483,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* look up the NSVC based on source address */ nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { + struct tlv_parsed tp; + uint16_t nsei; /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " @@ -491,10 +493,25 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } - LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", - inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - nsvc = nsvc_create(nsi, 0xffff); - nsvc->ip.bts_addr = *saddr; + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, + msgb_l2len(msg), 0, 0); + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || + !TLVP_PRESENT(&tp, NS_IE_VCI) || + !TLVP_PRESENT(&tp, NS_IE_NSEI)) { + /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ + LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + return -EINVAL; + } + nsei = ntohs(*(uint16_t *)TLVP_VAL(&tp, NS_IE_NSEI)); + /* Check if we already know this NSEI, the remote end might + * simply have changed addresses, or it is a SGSN */ + nsvc = nsvc_by_nsei(nsi, nsei); + if (!nsvc) { + LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); + nsvc = nsvc_create(nsi, 0xffff); + nsvc->ip.bts_addr = *saddr; + } } else msgb_nsei(msg) = nsvc->nsei; From bba902db196e4e947b786022e9c19aa3f1ae195e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:38:36 +0200 Subject: [PATCH 062/198] [gprs] NS: include port number in log statement --- openbsc/src/gprs/gprs_ns.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3d05dd0ff..9c0c4ec91 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -488,8 +488,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " - "from %s for non-existing NS-VC\n", - nsh->pdu_type, inet_ntoa(saddr->sin_addr)); + "from %s:%u for non-existing NS-VC\n", + nsh->pdu_type, inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } From 2b7d4658fb603c910f77feceea85392ed0f31e51 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:40:45 +0200 Subject: [PATCH 063/198] [gprs] NS: update the remote peer IP addr/port on NS RESET --- openbsc/src/gprs/gprs_ns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 9c0c4ec91..745a0b57f 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -511,8 +511,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); nsvc = nsvc_create(nsi, 0xffff); - nsvc->ip.bts_addr = *saddr; } + /* Update the remote peer IP address/port */ + nsvc->ip.bts_addr = *saddr; } else msgb_nsei(msg) = nsvc->nsei; From e4ecc8c81e0333506e1ddee18ac82321d8950e81 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 00:16:57 +0200 Subject: [PATCH 064/198] [gprs] NS: elevate events from LOGL_DEBUG to LOGL_INFO --- openbsc/src/gprs/gprs_ns.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 745a0b57f..fdefa653c 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -272,10 +272,11 @@ static void gprs_ns_timer_cb(void *data) if (nsvc->alive_retries > NS_ALIVE_RETRIES) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; - DEBUGP(DNS, "NSEI=%u Tns-alive expired more then " + LOGP(DNS, LOGL_NOTICE, + "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, NS_ALIVE_RETRIES); - /* FIXME: inform higher layers */ + ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); @@ -313,7 +314,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsh->pdu_type = NS_PDUT_RESET_ACK; - DEBUGP(DNS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); @@ -384,17 +385,17 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t cause; int rc; - DEBUGP(DNS, "NSEI=%u NS STATUS ", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { - DEBUGPC(DNS, "missing cause IE\n"); + LOGPC(DNS, LOGL_INFO, "missing cause IE\n"); return -EINVAL; } cause = *TLVP_VAL(&tp, NS_IE_CAUSE); - DEBUGPC(DNS, "cause=%s\n", gprs_ns_cause_str(cause)); + LOGPC(DNS, LOGL_INFO, "cause=%s\n", gprs_ns_cause_str(cause)); return 0; } @@ -422,7 +423,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - DEBUGP(DNS, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; @@ -451,7 +452,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t *cause; int rc; - DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); nsvc->state |= NSE_S_BLOCKED; @@ -545,7 +546,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - DEBUGP(DNS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) { @@ -560,13 +561,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ - DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) @@ -576,12 +577,12 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_block(nsvc, msg); break; case NS_PDUT_BLOCK_ACK: - DEBUGP(DNS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: - DEBUGP(DNS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", + LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", nsvc->nsei, nsh->pdu_type); rc = -EINVAL; break; From c1402a68c55ea8c30b2aa9db7ae16e5df0820948 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 11:48:44 +0200 Subject: [PATCH 065/198] [gprs] NS: more state transitions, error reporting via Tx STATUS PDU --- openbsc/src/gprs/gprs_ns.c | 80 ++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index fdefa653c..9cb330058 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -216,6 +216,49 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) } +int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, + uint16_t bvci, struct msgb *orig_msg) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint16_t nsvci = htons(nsvc->nsvci); + + bvci = htons(bvci); + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + nsh->pdu_type = NS_PDUT_STATUS; + + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); + + /* Section 9.2.7.1: Static conditions for NS-VCI */ + if (cause == NS_CAUSE_NSVC_BLOCKED || + cause == NS_CAUSE_NSVC_UNKNOWN) + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); + + /* Section 9.2.7.2: Static conditions for NS PDU */ + switch (cause) { + case NS_CAUSE_SEM_INCORR_PDU: + case NS_CAUSE_PDU_INCOMP_PSTATE: + case NS_CAUSE_PROTO_ERR_UNSPEC: + case NS_CAUSE_INVAL_ESSENT_IE: + case NS_CAUSE_MISSING_ESSENT_IE: + msgb_tvlv_put(msg, NS_IE_PDU, msgb_l2len(orig_msg), + orig_msg->l2h); + break; + default: + break; + } + + /* Section 9.2.7.3: Static conditions for BVCI */ + if (cause == NS_CAUSE_BVCI_UNKNOWN) + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci); + + return gprs_ns_tx(nsvc, msg); +} + int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); @@ -290,6 +333,7 @@ static void gprs_ns_timer_cb(void *data) case NSVC_TIMER_TNS_RESET: /* Chapter 7.3: Re-send the RESET */ gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + /* Re-start Tns-reset timer */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; case _NSVC_TIMER_NR: @@ -368,6 +412,10 @@ static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; uint16_t bvci; + if (nsvc->state & NSE_S_BLOCKED) + return gprs_ns_tx_status(nsvc, NS_CAUSE_NSVC_BLOCKED, + 0, msg); + /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; msgb_bssgph(msg) = &nsh->data[3]; @@ -414,8 +462,8 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { - /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg); return -EINVAL; } @@ -426,15 +474,12 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); + /* Mark NS-VC as blocked and alive */ nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; - /* FIXME: Check if we have an existing peer with this NSEI/NSVCI - * and remove it, as our BSS may just have changed its source IP - * address */ nsvc->nsei = ntohs(*nsei); nsvc->nsvci = ntohs(*nsvci); - /* mark the NS-VC as blocked and alive */ /* start the test procedure */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); @@ -460,8 +505,8 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI)) { - /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg); return -EINVAL; } @@ -492,6 +537,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); + /* FIXME: send STATUS (but we have no NSVC!) */ //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } @@ -500,8 +546,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { - /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, + msg); return -EINVAL; } nsei = ntohs(*(uint16_t *)TLVP_VAL(&tp, NS_IE_NSEI)); @@ -532,7 +579,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsvc->remote_end_is_sgsn) { /* FIXME: this should be one level higher */ if (nsvc->state & NSE_S_BLOCKED) - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); + rc = gprs_ns_tx_unblock(nsvc); } break; case NS_PDUT_UNITDATA: @@ -547,16 +594,15 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_RESET_ACK: LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); - /* mark remote NS-VC as blocked + active */ + /* mark NS-VC as blocked + active */ + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); - /* send ALIVE PDU */ + /* Initiate TEST proc.: Send ALIVE and start timer */ rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); - /* mark local state as BLOCKED + ALIVE */ - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; } break; case NS_PDUT_UNBLOCK: @@ -568,10 +614,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNBLOCK_ACK: LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); - /* mark remote NS-VC as unblocked + active */ + /* mark NS-VC as unblocked + active */ + nsvc->state = NSE_S_ALIVE; nsvc->remote_state = NSE_S_ALIVE; - if (nsvc->remote_end_is_sgsn) - nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: rc = gprs_ns_rx_block(nsvc, msg); @@ -728,11 +773,14 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ + /* Mark NS-VC locally as blocked and dead */ + nsvc->state = NSE_S_BLOCKED; + /* Send NS-RESET PDU */ if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", nsei); } - /* run a timer and re-transmit the reset request? */ + /* Start Tns-reset */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); return nsvc; From 38407efdf88992e11c06659eb3f15d3142e1726f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 11:56:39 +0000 Subject: [PATCH 066/198] NS: don't memcmp sockaddr_in but compare ip and port individually this seems to work more portably (ppc/32bit big endian) --- openbsc/src/gprs/gprs_ns.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 9cb330058..a166956b0 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -104,7 +104,9 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - if (!memcmp(&nsvc->ip.bts_addr, sin, sizeof(*sin))) + if (nsvc->ip.bts_addr.sin_addr.s_addr == + sin->sin_addr.s_addr && + nsvc->ip.bts_addr.sin_port == sin->sin_port) return nsvc; } return NULL; @@ -764,10 +766,9 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct gprs_nsvc *nsvc; nsvc = nsvc_by_rem_addr(nsi, dest); - if (!nsvc) { + if (!nsvc) nsvc = nsvc_create(nsi, nsvci); - nsvc->ip.bts_addr = *dest; - } + nsvc->ip.bts_addr = *dest; nsvc->nsei = nsei; nsvc->nsvci = nsvci; nsvc->remote_end_is_sgsn = 1; From 6ecaa3da2b2ff5dda53840476a792e12ce99d372 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 12:01:33 +0000 Subject: [PATCH 067/198] NS: More INFO messages about what we actually transmit --- openbsc/src/gprs/gprs_ns.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index a166956b0..e93bd43fb 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -207,6 +207,9 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) if (!msg) return -ENOMEM; + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n", + nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); nsh->pdu_type = NS_PDUT_RESET; @@ -230,6 +233,9 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, if (!msg) return -ENOMEM; + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n", + nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); nsh->pdu_type = NS_PDUT_STATUS; @@ -270,6 +276,9 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) if (!msg) return -ENOMEM; + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS BLOCK (NSVCI=%u, cause=%s)\n", + nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); + /* be conservative and mark it as blocked even now! */ nsvc->state |= NSE_S_BLOCKED; @@ -284,6 +293,10 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) { + + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); + return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); } From b983c3104dd3e187a9d7a424b1f70ef6ef8f615e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 12:11:45 +0000 Subject: [PATCH 068/198] NS: Add more LOG_DEBGU messages and retransmit NS-ALIVE --- openbsc/src/gprs/gprs_ns.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index e93bd43fb..19653f6a6 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -293,13 +293,28 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) { - LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); } +int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) +{ + LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); + + return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); +} + +int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc) +{ + LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE_ACK (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); + + return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); +} + #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { @@ -337,12 +352,16 @@ static void gprs_ns_timer_cb(void *data) ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } + /* Tns-test case: send NS-ALIVE PDU */ + gprs_ns_tx_alive(nsvc); + /* start Tns-alive timer */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_TEST: /* Tns-test case: send NS-ALIVE PDU */ - gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - /* start Tns-alive timer */ + gprs_ns_tx_alive(nsvc); + /* start Tns-alive timer (transition into faster + * alive retransmissions) */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_RESET: @@ -584,7 +603,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, case NS_PDUT_ALIVE: /* remote end inquires whether we're still alive, * we need to respond with ALIVE_ACK */ - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); + rc = gprs_ns_tx_alive_ack(nsvc); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ From 7c24b9edbc784a225ed0ce8e688f2c1e8511c5da Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 12:21:52 +0000 Subject: [PATCH 069/198] NS: Debug NS timer expiry --- openbsc/src/gprs/gprs_ns.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 19653f6a6..0ef0c3fcb 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -323,10 +323,19 @@ static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { [NSVC_TIMER_TNS_TEST] = 30, }; +static const struct value_string timer_mode_strs[] = { + { NSVC_TIMER_TNS_RESET, "tns-reset" }, + { NSVC_TIMER_TNS_ALIVE, "tns-alive" }, + { NSVC_TIMER_TNS_TEST, "tns-test" }, + { 0, NULL } +}; + static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) { - nsvc->alive_retries = 0; - + DEBUGP(DNS, "NSVC=%u Starting timer in mode %s (%u seconds)\n", + nsvc->nsvci, get_value_string(timer_mode_strs, mode), + timer_mode_tout[mode]); + if (bsc_timer_pending(&nsvc->timer)) bsc_del_timer(&nsvc->timer); @@ -338,6 +347,10 @@ static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; + DEBUGP(DNS, "NSVC=%u Timer expired in mode %s (%u seconds)\n", + nsvc->nsvci, get_value_string(timer_mode_strs, nsvc->timer_mode), + timer_mode_tout[nsvc->timer_mode]); + switch (nsvc->timer_mode) { case NSVC_TIMER_TNS_ALIVE: /* Tns-alive case: we expired without response ! */ @@ -362,6 +375,7 @@ static void gprs_ns_timer_cb(void *data) gprs_ns_tx_alive(nsvc); /* start Tns-alive timer (transition into faster * alive retransmissions) */ + nsvc->alive_retries = 0; nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_RESET: From 4941b35be5b827b859a773cfe2b18542515b094d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 13:28:25 +0000 Subject: [PATCH 070/198] NS / GB Proxy: Add Signal in case Tns-Alive expires too often The Gb Proxy can then restart the RESET procedure. --- openbsc/src/gprs/gprs_ns.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 0ef0c3fcb..fd0b27a6e 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -362,6 +362,7 @@ static void gprs_ns_timer_cb(void *data) "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, NS_ALIVE_RETRIES); + ns_dispatch_signal(nsvc, S_NS_ALIVE_EXP, 0); ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } From 803647e4afbf07e42fc23f7b16bb1640fe43b249 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 13:51:08 +0000 Subject: [PATCH 071/198] NS: Send STATUS or RESET when receiving NS_ALIVE on unknown NSVC --- openbsc/src/gprs/gprs_ns.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index fd0b27a6e..13ea92dd1 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -582,13 +582,25 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, uint16_t nsei; /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { + struct gprs_nsvc fake_nsvc; LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - /* FIXME: send STATUS (but we have no NSVC!) */ - //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); - return -EIO; + /* Since we have no NSVC, we have to create a fake */ + fake_nsvc.nsvci = fake_nsvc.nsei = 0; + fake_nsvc.nsi = nsi; + fake_nsvc.ip.bts_addr = *saddr; + fake_nsvc.state = NSE_S_ALIVE; +#if 0 + return gprs_ns_tx_status(&fake_nsvc, + NS_CAUSE_PDU_INCOMP_PSTATE, 0, + msg); +#else + /* BS+ Gb implementation ignores STATUS, so we try + * our luck with a RESET incompatible with the spec */ + return gprs_ns_tx_simple(&fake_nsvc, NS_PDUT_RESET); +#endif } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); @@ -785,8 +797,6 @@ static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) return rc; } - -/* FIXME: this is currently in input/ipaccess.c */ extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port, int (*cb)(struct bsc_fd *fd, unsigned int what)); From 4e187c6dbb9c428ca45f8043f51925a2bde4b520 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 13:55:36 +0000 Subject: [PATCH 072/198] Display NSEI instead of NSVCI for all debug msgs --- openbsc/src/gprs/gprs_ns.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 13ea92dd1..8cb26a633 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -332,8 +332,8 @@ static const struct value_string timer_mode_strs[] = { static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) { - DEBUGP(DNS, "NSVC=%u Starting timer in mode %s (%u seconds)\n", - nsvc->nsvci, get_value_string(timer_mode_strs, mode), + DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n", + nsvc->nsei, get_value_string(timer_mode_strs, mode), timer_mode_tout[mode]); if (bsc_timer_pending(&nsvc->timer)) @@ -347,8 +347,8 @@ static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; - DEBUGP(DNS, "NSVC=%u Timer expired in mode %s (%u seconds)\n", - nsvc->nsvci, get_value_string(timer_mode_strs, nsvc->timer_mode), + DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n", + nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode), timer_mode_tout[nsvc->timer_mode]); switch (nsvc->timer_mode) { From f88dc001821bb98986668b9daee98d9cb5b1cdd2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 14:18:46 +0000 Subject: [PATCH 073/198] NS: Send UNBLOCK signal when we get UNBLOCK_ACK from peer --- openbsc/src/gprs/gprs_ns.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 8cb26a633..3d672fb8f 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -678,6 +678,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* mark NS-VC as unblocked + active */ nsvc->state = NSE_S_ALIVE; nsvc->remote_state = NSE_S_ALIVE; + ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); break; case NS_PDUT_BLOCK: rc = gprs_ns_rx_block(nsvc, msg); From 2bffac599f4a93a3113a7260955ac3ec1cd4b39c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 15:55:23 +0000 Subject: [PATCH 074/198] NS: Add support for persistent NS-VC configuration With persistent NS-VC configuration (configured through VTY), we can respond properly to BSS with a somewhat strange NS implementation Such as the BSplus. It enables us to respond with a proper NS-RESET (including NSVCI/NSEI) when receiving a NS-ALIVE or other PDU for a BLOCKED/DEAD NS-VC after our end of the connection is rebooted. --- openbsc/include/openbsc/gprs_ns.h | 7 +- openbsc/src/gprs/gprs_ns.c | 225 ++++++++++++++++++++++++++++-- 2 files changed, 222 insertions(+), 10 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index c74546a8b..60051d13b 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -140,7 +140,8 @@ struct gprs_nsvc { enum nsvc_timer_mode timer_mode; int alive_retries; - int remote_end_is_sgsn; + unsigned int remote_end_is_sgsn:1; + unsigned int persistent:1; union { struct { @@ -178,4 +179,8 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, uint16_t nsvci); + +/* Add NS-specific VTY stuff */ +int gprs_ns_vty_init(struct gprs_ns_inst *nsi); + #endif diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3d672fb8f..ed6421032 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -131,6 +131,14 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) return nsvc; } +static void nsvc_delete(struct gprs_nsvc *nsvc) +{ + if (bsc_timer_pending(&nsvc->timer)) + bsc_del_timer(&nsvc->timer); + llist_del(&nsvc->list); + talloc_free(nsvc); +} + static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal, uint8_t cause) { @@ -592,15 +600,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, fake_nsvc.nsi = nsi; fake_nsvc.ip.bts_addr = *saddr; fake_nsvc.state = NSE_S_ALIVE; -#if 0 return gprs_ns_tx_status(&fake_nsvc, NS_CAUSE_PDU_INCOMP_PSTATE, 0, msg); -#else - /* BS+ Gb implementation ignores STATUS, so we try - * our luck with a RESET incompatible with the spec */ - return gprs_ns_tx_simple(&fake_nsvc, NS_PDUT_RESET); -#endif } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); @@ -628,9 +630,14 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, switch (nsh->pdu_type) { case NS_PDUT_ALIVE: - /* remote end inquires whether we're still alive, - * we need to respond with ALIVE_ACK */ - rc = gprs_ns_tx_alive_ack(nsvc); + /* If we're dead and blocked and suddenly receive a + * NS-ALIVE out of the blue, we might have been re-started + * and should send a NS-RESET to make sure everything recovers + * fine. */ + if (nsvc->state == NSE_S_BLOCKED) + rc = gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE); + else + rc = gprs_ns_tx_alive_ack(nsvc); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ @@ -844,3 +851,203 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, return nsvc; } + +#include +#include + +static struct gprs_ns_inst *vty_nsi = NULL; + +static struct cmd_node ns_node = { + NS_NODE, + "%s(ns)#", + 1, +}; + +static int config_write_ns(struct vty *vty) +{ + struct gprs_nsvc *nsvc; + + vty_out(vty, "ns%s", VTY_NEWLINE); + + llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { + if (!nsvc->persistent) + continue; + vty_out(vty, " nse %u nsvci %u%s", + nsvc->nsei, nsvc->nsvci, VTY_NEWLINE); + vty_out(vty, " nse %u remote-role %s%s", + nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) { + vty_out(vty, " nse %u remote-ip %s%s", + nsvc->nsei, + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + VTY_NEWLINE); + vty_out(vty, " nse %u remote-port %u%s", + nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), + VTY_NEWLINE); + } + vty_out(vty, "%s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_ns, cfg_ns_cmd, + "ns", + "Configure the GPRS Network Service") +{ + vty->node = NS_NODE; + return CMD_SUCCESS; +} + +DEFUN(show_ns, show_ns_cmd, "show ns", + SHOW_STR "Display information about the NS protocol") +{ + struct gprs_ns_inst *nsi = vty_nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, ", %15s:%u", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port)); + vty_out(vty, "%s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + + +#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" + +DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, + "nse <0-65535> nsvci <0-65534>", + NSE_CMD_STR + "NS Virtual Connection\n" + "NS Virtual Connection ID (NSVCI)\n" + ) +{ + uint16_t nsei = atoi(argv[0]); + uint16_t nsvci = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + nsvc = nsvc_create(vty_nsi, nsvci); + nsvc->nsei = nsei; + } + nsvc->nsvci = nsvci; + /* All NSVCs that are explicitly configured by VTY are + * marked as persistent so we can write them to the config + * file at some later point */ + nsvc->persistent = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, + "nse <0-65535> remote-ip A.B.C.D", + NSE_CMD_STR + "Remote IP Address\n" + "Remote IP Address\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr); + + return CMD_SUCCESS; + +} + +DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, + "nse <0-65535> remote-port <0-65535>", + NSE_CMD_STR + "Remote UDP Port\n" + "Remote UDP Port Number\n") +{ + uint16_t nsei = atoi(argv[0]); + uint16_t port = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc->ip.bts_addr.sin_port = htons(port); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, + "nse <0-65535> remote-role (sgsn|bss)", + NSE_CMD_STR + "Remote NSE Role\n" + "Remote Peer is SGSN\n" + "Remote Peer is BSS\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[1], "sgsn")) + nsvc->remote_end_is_sgsn = 1; + else + nsvc->remote_end_is_sgsn = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_nse, cfg_no_nse_cmd, + "no nse <0-65535>", + "Delete NS Entity\n" + "Delete " NSE_CMD_STR) +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc_delete(nsvc); + + return CMD_SUCCESS; +} + +int gprs_ns_vty_init(struct gprs_ns_inst *nsi) +{ + vty_nsi = nsi; + + install_element(VIEW_NODE, &show_ns_cmd); + + install_element(CONFIG_NODE, &cfg_ns_cmd); + install_node(&ns_node, config_write_ns); + install_default(NS_NODE); + install_element(NS_NODE, &cfg_nse_nsvci_cmd); + install_element(NS_NODE, &cfg_nse_remoteip_cmd); + install_element(NS_NODE, &cfg_nse_remoteport_cmd); + install_element(NS_NODE, &cfg_nse_remoterole_cmd); + install_element(NS_NODE, &cfg_no_nse_cmd); + + return 0; +} From b2a4dbe34bdfaecd62f075479a2b4679cb591357 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 16:03:27 +0000 Subject: [PATCH 075/198] Make sure all commands of SHOW_NODE to ENABLE_NODE --- openbsc/src/gprs/gprs_ns.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index ed6421032..9f65489f7 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -1039,6 +1039,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) vty_nsi = nsi; install_element(VIEW_NODE, &show_ns_cmd); + install_element(ENABLE_NODE, &show_ns_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); From ef5324fc94b8beb958ded2e9a5d31b32bc757e6b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 16:50:52 +0000 Subject: [PATCH 076/198] use new install_element_ve() --- openbsc/src/gprs/gprs_ns.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 9f65489f7..e0ee962dd 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -1038,8 +1038,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) { vty_nsi = nsi; - install_element(VIEW_NODE, &show_ns_cmd); - install_element(ENABLE_NODE, &show_ns_cmd); + install_element_ve(&show_ns_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); From fe4ab901cc00f88e644e5640c2988f52c79f4183 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 17:19:53 +0000 Subject: [PATCH 077/198] NS: Make all timers configurable from VTY --- openbsc/include/openbsc/gprs_ns.h | 22 +++++++++- openbsc/src/gprs/gprs_ns.c | 70 +++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 60051d13b..847e8f9cc 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -75,7 +75,6 @@ enum ns_cause { NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, }; - /* Our Implementation */ #include #include @@ -83,6 +82,25 @@ enum ns_cause { #include #include +#define NS_TIMERS_COUNT 7 +#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" +#define NS_TIMERS_HELP \ + "(un)blocking Timer (Tns-block) timeout\n" \ + "(un)blocking Timer (Tns-block) number of retries\n" \ + "Reset Timer (Tns-reset) timeout\n" \ + "Reset Timer (Tns-reset) number of retries\n" \ + "Test Timer (Tns-test) timeout\n" \ + +enum ns_timeout { + NS_TOUT_TNS_BLOCK, + NS_TOUT_TNS_BLOCK_RETRIES, + NS_TOUT_TNS_RESET, + NS_TOUT_TNS_RESET_RETRIES, + NS_TOUT_TNS_TEST, + NS_TOUT_TNS_ALIVE, + NS_TOUT_TNS_ALIVE_RETRIES, +}; + #define NSE_S_BLOCKED 0x0001 #define NSE_S_ALIVE 0x0002 @@ -107,6 +125,8 @@ struct gprs_ns_inst { /* linked lists of all NSVC in this instance */ struct llist_head gprs_nsvcs; + uint16_t timeout[NS_TIMERS_COUNT]; + /* which link-layer are we based on? */ enum gprs_ns_ll ll; diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index e0ee962dd..1b9d7c6d5 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -63,6 +63,19 @@ #define NS_ALLOC_SIZE 1024 +/* FIXME: this should go to some common file as it is copied + * in vty_interface.c of the BSC */ +static const struct value_string gprs_ns_timer_strs[] = { + { 0, "tns-block" }, + { 1, "tns-block-retries" }, + { 2, "tns-reset" }, + { 3, "tns-reset-retries" }, + { 4, "tns-test" }, + { 5, "tns-alive" }, + { 6, "tns-alive-retries" }, + { 0, NULL } +}; + static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -323,12 +336,10 @@ int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc) return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); } -#define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ - -static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { - [NSVC_TIMER_TNS_RESET] = 60, - [NSVC_TIMER_TNS_ALIVE] = 3, - [NSVC_TIMER_TNS_TEST] = 30, +static const enum ns_timeout timer_mode_tout[_NSVC_TIMER_NR] = { + [NSVC_TIMER_TNS_RESET] = NS_TOUT_TNS_RESET, + [NSVC_TIMER_TNS_ALIVE] = NS_TOUT_TNS_ALIVE, + [NSVC_TIMER_TNS_TEST] = NS_TOUT_TNS_TEST, }; static const struct value_string timer_mode_strs[] = { @@ -340,36 +351,42 @@ static const struct value_string timer_mode_strs[] = { static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) { + enum ns_timeout tout = timer_mode_tout[mode]; + unsigned int seconds = nsvc->nsi->timeout[tout]; + DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, mode), - timer_mode_tout[mode]); + seconds); if (bsc_timer_pending(&nsvc->timer)) bsc_del_timer(&nsvc->timer); nsvc->timer_mode = mode; - bsc_schedule_timer(&nsvc->timer, timer_mode_tout[mode], 0); + bsc_schedule_timer(&nsvc->timer, seconds, 0); } static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; + enum ns_timeout tout = timer_mode_tout[nsvc->timer_mode]; + unsigned int seconds = nsvc->nsi->timeout[tout]; DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode), - timer_mode_tout[nsvc->timer_mode]); + seconds); switch (nsvc->timer_mode) { case NSVC_TIMER_TNS_ALIVE: /* Tns-alive case: we expired without response ! */ nsvc->alive_retries++; - if (nsvc->alive_retries > NS_ALIVE_RETRIES) { + if (nsvc->alive_retries > + nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; LOGP(DNS, LOGL_NOTICE, "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, - NS_ALIVE_RETRIES); + nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]); ns_dispatch_signal(nsvc, S_NS_ALIVE_EXP, 0); ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; @@ -710,6 +727,13 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->cb = cb; INIT_LLIST_HEAD(&nsi->gprs_nsvcs); + nsi->timeout[NS_TOUT_TNS_BLOCK] = 3; + nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES] = 3; + nsi->timeout[NS_TOUT_TNS_RESET] = 3; + nsi->timeout[NS_TOUT_TNS_RESET_RETRIES] = 3; + nsi->timeout[NS_TOUT_TNS_TEST] = 30; + nsi->timeout[NS_TOUT_TNS_ALIVE] = 3; + nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10; return nsi; } @@ -866,6 +890,7 @@ static struct cmd_node ns_node = { static int config_write_ns(struct vty *vty) { struct gprs_nsvc *nsvc; + unsigned int i; vty_out(vty, "ns%s", VTY_NEWLINE); @@ -886,9 +911,13 @@ static int config_write_ns(struct vty *vty) nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); } - vty_out(vty, "%s", VTY_NEWLINE); } + for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++) + vty_out(vty, " timer %s %u%s", + get_value_string(gprs_ns_timer_strs, i), + vty_nsi->timeout[i], VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1034,6 +1063,22 @@ DEFUN(cfg_no_nse, cfg_no_nse_cmd, return CMD_SUCCESS; } +DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, + "timer " NS_TIMERS " <0-65535>", + "Network Service Timer\n" + NS_TIMERS_HELP "Timer Value\n") +{ + int idx = get_string_value(gprs_ns_timer_strs, argv[0]); + int val = atoi(argv[1]); + + if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout)) + return CMD_WARNING; + + vty_nsi->timeout[idx] = val; + + return CMD_SUCCESS; +} + int gprs_ns_vty_init(struct gprs_ns_inst *nsi) { vty_nsi = nsi; @@ -1048,6 +1093,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(NS_NODE, &cfg_nse_remoteport_cmd); install_element(NS_NODE, &cfg_nse_remoterole_cmd); install_element(NS_NODE, &cfg_no_nse_cmd); + install_element(NS_NODE, &cfg_ns_timer_cmd); return 0; } From 91813cf2148f4152ff3f4c3e1ae37f16dd1c39ff Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 18:38:45 +0000 Subject: [PATCH 078/198] GPRS: We have to do the msgb_free() in NS not Gb Proxy As only NS-UNITDATA messages are ever passed into the Gb Proxy, we need to do the msgb_free() at a much higher point in the calling stack, i.e. inside the NS protocol layer. This means it is now the same logic as in OpenBSC itself. --- openbsc/src/gprs/gprs_ns.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 1b9d7c6d5..11637f7fa 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -793,7 +793,11 @@ static int handle_nsip_read(struct bsc_fd *bfd) if (!msg) return error; - return gprs_ns_rcvmsg(nsi, msg, &saddr); + error = gprs_ns_rcvmsg(nsi, msg, &saddr); + + msgb_free(msg); + + return error; } static int handle_nsip_write(struct bsc_fd *bfd) From 144e0295c2c92470756cb2d386c136810fcd4a91 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 11:45:07 +0200 Subject: [PATCH 079/198] [GPRS] NS: Start to use rate_ctr_group code from libosmocore Every NS-VC now has a set of counters for incoming and outgoing number of packets and bytes. We also split the VTY part of the gprs_ns.c implementation into gprs_ns_vty.c to make sure the protocol can actually be used without the VTY code being present. --- openbsc/include/openbsc/gprs_ns.h | 6 + openbsc/src/gprs/gprs_ns.c | 282 +++++------------------------- openbsc/src/gprs/gprs_ns_vty.c | 275 +++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+), 243 deletions(-) create mode 100644 openbsc/src/gprs/gprs_ns_vty.c diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 847e8f9cc..34b1b62d2 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -163,6 +163,8 @@ struct gprs_nsvc { unsigned int remote_end_is_sgsn:1; unsigned int persistent:1; + struct rate_ctr_group *ctrg; + union { struct { struct sockaddr_in bts_addr; @@ -200,6 +202,10 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, uint16_t nsvci); +struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci); +void nsvc_delete(struct gprs_nsvc *nsvc); +struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); + /* Add NS-specific VTY stuff */ int gprs_ns_vty_init(struct gprs_ns_inst *nsi); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 11637f7fa..e83aee8e6 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -63,19 +64,6 @@ #define NS_ALLOC_SIZE 1024 -/* FIXME: this should go to some common file as it is copied - * in vty_interface.c of the BSC */ -static const struct value_string gprs_ns_timer_strs[] = { - { 0, "tns-block" }, - { 1, "tns-block-retries" }, - { 2, "tns-reset" }, - { 3, "tns-reset-retries" }, - { 4, "tns-test" }, - { 5, "tns-alive" }, - { 6, "tns-alive-retries" }, - { 0, NULL } -}; - static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -86,6 +74,20 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; +static const struct rate_ctr_desc nsvc_ctr_description[] = { + { "packets.in", "Packets at NS Level ( In)" }, + { "packets.out", "Packets at NS Level (Out)" }, + { "bytes.in", "Bytes at NS Level ( In)" }, + { "bytes.out", "Bytes at NS Level (Out)" }, +}; + +static const struct rate_ctr_group_desc nsvc_ctrg_desc = { + .group_prefix_fmt = "ns.nsvc%u", + .group_description = "NSVC Peer Statistics", + .num_ctr = ARRAY_SIZE(nsvc_ctr_description), + .ctr_desc = nsvc_ctr_description, +}; + /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) @@ -99,8 +101,7 @@ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, } /* Lookup struct gprs_nsvc based on NSVCI */ -static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, - uint16_t nsei) +struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -110,7 +111,6 @@ static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, return NULL; } - /* Lookup struct gprs_nsvc based on remote peer socket addr */ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, struct sockaddr_in *sin) @@ -127,7 +127,7 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, static void gprs_ns_timer_cb(void *data); -static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) +struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -138,13 +138,14 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) nsvc->nsi = nsi; nsvc->timer.cb = gprs_ns_timer_cb; nsvc->timer.data = nsvc; + nsvc->ctrg = rate_ctr_group_alloc(nsvc, &nsvc_ctrg_desc, nsvci); llist_add(&nsvc->list, &nsi->gprs_nsvcs); return nsvc; } -static void nsvc_delete(struct gprs_nsvc *nsvc) +void nsvc_delete(struct gprs_nsvc *nsvc) { if (bsc_timer_pending(&nsvc->timer)) bsc_del_timer(&nsvc->timer); @@ -190,6 +191,10 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) { int ret; + /* Increment number of Uplink bytes */ + rate_ctr_inc(&nsvc->ctrg->ctr[1]); + rate_ctr_add(&nsvc->ctrg->ctr[3], msgb_l2len(msg)); + switch (nsvc->nsi->ll) { case GPRS_NS_LL_UDP: ret = nsip_sendmsg(nsvc, msg); @@ -211,7 +216,8 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) if (!msg) return -ENOMEM; - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = pdu_type; @@ -231,7 +237,8 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_RESET; msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); @@ -257,7 +264,8 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n", nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_STATUS; msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); @@ -303,7 +311,8 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) /* be conservative and mark it as blocked even now! */ nsvc->state |= NSE_S_BLOCKED; - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_BLOCK; msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); @@ -428,7 +437,8 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsvci = htons(nsvc->nsvci); nsei = htons(nsvc->nsei); - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_RESET_ACK; @@ -600,6 +610,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct gprs_nsvc *nsvc; int rc = 0; + DEBUGP(DNS, "gprs_ns_rcvmsg(%d)\n", msgb_l2len(msg)); + /* look up the NSVC based on source address */ nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { @@ -645,6 +657,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, } else msgb_nsei(msg) = nsvc->nsei; + /* Increment number of Incoming bytes */ + rate_ctr_inc(&nsvc->ctrg->ctr[2]); + rate_ctr_add(&nsvc->ctrg->ctr[0], msgb_l2len(msg)); + switch (nsh->pdu_type) { case NS_PDUT_ALIVE: /* If we're dead and blocked and suddenly receive a @@ -880,224 +896,4 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, return nsvc; } -#include -#include -static struct gprs_ns_inst *vty_nsi = NULL; - -static struct cmd_node ns_node = { - NS_NODE, - "%s(ns)#", - 1, -}; - -static int config_write_ns(struct vty *vty) -{ - struct gprs_nsvc *nsvc; - unsigned int i; - - vty_out(vty, "ns%s", VTY_NEWLINE); - - llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { - if (!nsvc->persistent) - continue; - vty_out(vty, " nse %u nsvci %u%s", - nsvc->nsei, nsvc->nsvci, VTY_NEWLINE); - vty_out(vty, " nse %u remote-role %s%s", - nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss", - VTY_NEWLINE); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) { - vty_out(vty, " nse %u remote-ip %s%s", - nsvc->nsei, - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - VTY_NEWLINE); - vty_out(vty, " nse %u remote-port %u%s", - nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), - VTY_NEWLINE); - } - } - - for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++) - vty_out(vty, " timer %s %u%s", - get_value_string(gprs_ns_timer_strs, i), - vty_nsi->timeout[i], VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ns, cfg_ns_cmd, - "ns", - "Configure the GPRS Network Service") -{ - vty->node = NS_NODE; - return CMD_SUCCESS; -} - -DEFUN(show_ns, show_ns_cmd, "show ns", - SHOW_STR "Display information about the NS protocol") -{ - struct gprs_ns_inst *nsi = vty_nsi; - struct gprs_nsvc *nsvc; - - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", - nsvc->nsei, nsvc->nsvci, - nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", - nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", - nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, ", %15s:%u", - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - ntohs(nsvc->ip.bts_addr.sin_port)); - vty_out(vty, "%s", VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - - -#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" - -DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, - "nse <0-65535> nsvci <0-65534>", - NSE_CMD_STR - "NS Virtual Connection\n" - "NS Virtual Connection ID (NSVCI)\n" - ) -{ - uint16_t nsei = atoi(argv[0]); - uint16_t nsvci = atoi(argv[1]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - nsvc = nsvc_create(vty_nsi, nsvci); - nsvc->nsei = nsei; - } - nsvc->nsvci = nsvci; - /* All NSVCs that are explicitly configured by VTY are - * marked as persistent so we can write them to the config - * file at some later point */ - nsvc->persistent = 1; - - return CMD_SUCCESS; -} - -DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, - "nse <0-65535> remote-ip A.B.C.D", - NSE_CMD_STR - "Remote IP Address\n" - "Remote IP Address\n") -{ - uint16_t nsei = atoi(argv[0]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr); - - return CMD_SUCCESS; - -} - -DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, - "nse <0-65535> remote-port <0-65535>", - NSE_CMD_STR - "Remote UDP Port\n" - "Remote UDP Port Number\n") -{ - uint16_t nsei = atoi(argv[0]); - uint16_t port = atoi(argv[1]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - - nsvc->ip.bts_addr.sin_port = htons(port); - - return CMD_SUCCESS; -} - -DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, - "nse <0-65535> remote-role (sgsn|bss)", - NSE_CMD_STR - "Remote NSE Role\n" - "Remote Peer is SGSN\n" - "Remote Peer is BSS\n") -{ - uint16_t nsei = atoi(argv[0]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[1], "sgsn")) - nsvc->remote_end_is_sgsn = 1; - else - nsvc->remote_end_is_sgsn = 0; - - return CMD_SUCCESS; -} - -DEFUN(cfg_no_nse, cfg_no_nse_cmd, - "no nse <0-65535>", - "Delete NS Entity\n" - "Delete " NSE_CMD_STR) -{ - uint16_t nsei = atoi(argv[0]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - - nsvc_delete(nsvc); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, - "timer " NS_TIMERS " <0-65535>", - "Network Service Timer\n" - NS_TIMERS_HELP "Timer Value\n") -{ - int idx = get_string_value(gprs_ns_timer_strs, argv[0]); - int val = atoi(argv[1]); - - if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout)) - return CMD_WARNING; - - vty_nsi->timeout[idx] = val; - - return CMD_SUCCESS; -} - -int gprs_ns_vty_init(struct gprs_ns_inst *nsi) -{ - vty_nsi = nsi; - - install_element_ve(&show_ns_cmd); - - install_element(CONFIG_NODE, &cfg_ns_cmd); - install_node(&ns_node, config_write_ns); - install_default(NS_NODE); - install_element(NS_NODE, &cfg_nse_nsvci_cmd); - install_element(NS_NODE, &cfg_nse_remoteip_cmd); - install_element(NS_NODE, &cfg_nse_remoteport_cmd); - install_element(NS_NODE, &cfg_nse_remoterole_cmd); - install_element(NS_NODE, &cfg_no_nse_cmd); - install_element(NS_NODE, &cfg_ns_timer_cmd); - - return 0; -} diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c new file mode 100644 index 000000000..6e98e44d6 --- /dev/null +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -0,0 +1,275 @@ +/* VTY interface for our GPRS Networks Service (NS) implementation */ + +/* (C) 2009-2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct gprs_ns_inst *vty_nsi = NULL; + +/* FIXME: this should go to some common file as it is copied + * in vty_interface.c of the BSC */ +static const struct value_string gprs_ns_timer_strs[] = { + { 0, "tns-block" }, + { 1, "tns-block-retries" }, + { 2, "tns-reset" }, + { 3, "tns-reset-retries" }, + { 4, "tns-test" }, + { 5, "tns-alive" }, + { 6, "tns-alive-retries" }, + { 0, NULL } +}; + +static struct cmd_node ns_node = { + NS_NODE, + "%s(ns)#", + 1, +}; + +static int config_write_ns(struct vty *vty) +{ + struct gprs_nsvc *nsvc; + unsigned int i; + + vty_out(vty, "ns%s", VTY_NEWLINE); + + llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { + if (!nsvc->persistent) + continue; + vty_out(vty, " nse %u nsvci %u%s", + nsvc->nsei, nsvc->nsvci, VTY_NEWLINE); + vty_out(vty, " nse %u remote-role %s%s", + nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) { + vty_out(vty, " nse %u remote-ip %s%s", + nsvc->nsei, + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + VTY_NEWLINE); + vty_out(vty, " nse %u remote-port %u%s", + nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), + VTY_NEWLINE); + } + } + + for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++) + vty_out(vty, " timer %s %u%s", + get_value_string(gprs_ns_timer_strs, i), + vty_nsi->timeout[i], VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ns, cfg_ns_cmd, + "ns", + "Configure the GPRS Network Service") +{ + vty->node = NS_NODE; + return CMD_SUCCESS; +} + +DEFUN(show_ns, show_ns_cmd, "show ns", + SHOW_STR "Display information about the NS protocol") +{ + struct gprs_ns_inst *nsi = vty_nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, ", %15s:%u", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port)); + vty_out(vty, "%s", VTY_NEWLINE); + vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); + } + + return CMD_SUCCESS; +} + + +#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" + +DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, + "nse <0-65535> nsvci <0-65534>", + NSE_CMD_STR + "NS Virtual Connection\n" + "NS Virtual Connection ID (NSVCI)\n" + ) +{ + uint16_t nsei = atoi(argv[0]); + uint16_t nsvci = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + nsvc = nsvc_create(vty_nsi, nsvci); + nsvc->nsei = nsei; + } + nsvc->nsvci = nsvci; + /* All NSVCs that are explicitly configured by VTY are + * marked as persistent so we can write them to the config + * file at some later point */ + nsvc->persistent = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, + "nse <0-65535> remote-ip A.B.C.D", + NSE_CMD_STR + "Remote IP Address\n" + "Remote IP Address\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr); + + return CMD_SUCCESS; + +} + +DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, + "nse <0-65535> remote-port <0-65535>", + NSE_CMD_STR + "Remote UDP Port\n" + "Remote UDP Port Number\n") +{ + uint16_t nsei = atoi(argv[0]); + uint16_t port = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc->ip.bts_addr.sin_port = htons(port); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, + "nse <0-65535> remote-role (sgsn|bss)", + NSE_CMD_STR + "Remote NSE Role\n" + "Remote Peer is SGSN\n" + "Remote Peer is BSS\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[1], "sgsn")) + nsvc->remote_end_is_sgsn = 1; + else + nsvc->remote_end_is_sgsn = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_nse, cfg_no_nse_cmd, + "no nse <0-65535>", + "Delete NS Entity\n" + "Delete " NSE_CMD_STR) +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc_delete(nsvc); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, + "timer " NS_TIMERS " <0-65535>", + "Network Service Timer\n" + NS_TIMERS_HELP "Timer Value\n") +{ + int idx = get_string_value(gprs_ns_timer_strs, argv[0]); + int val = atoi(argv[1]); + + if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout)) + return CMD_WARNING; + + vty_nsi->timeout[idx] = val; + + return CMD_SUCCESS; +} + +int gprs_ns_vty_init(struct gprs_ns_inst *nsi) +{ + vty_nsi = nsi; + + install_element_ve(&show_ns_cmd); + + install_element(CONFIG_NODE, &cfg_ns_cmd); + install_node(&ns_node, config_write_ns); + install_default(NS_NODE); + install_element(NS_NODE, &cfg_nse_nsvci_cmd); + install_element(NS_NODE, &cfg_nse_remoteip_cmd); + install_element(NS_NODE, &cfg_nse_remoteport_cmd); + install_element(NS_NODE, &cfg_nse_remoterole_cmd); + install_element(NS_NODE, &cfg_no_nse_cmd); + install_element(NS_NODE, &cfg_ns_timer_cmd); + + return 0; +} From 3953bdddb78f73e019aded81c77073c55254f466 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 11:57:44 +0200 Subject: [PATCH 080/198] [GPRS] NS: Fix wrong counter use and remove debug statement --- openbsc/src/gprs/gprs_ns.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index e83aee8e6..cdc745aa6 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -610,8 +610,6 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct gprs_nsvc *nsvc; int rc = 0; - DEBUGP(DNS, "gprs_ns_rcvmsg(%d)\n", msgb_l2len(msg)); - /* look up the NSVC based on source address */ nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { @@ -658,8 +656,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, msgb_nsei(msg) = nsvc->nsei; /* Increment number of Incoming bytes */ - rate_ctr_inc(&nsvc->ctrg->ctr[2]); - rate_ctr_add(&nsvc->ctrg->ctr[0], msgb_l2len(msg)); + rate_ctr_inc(&nsvc->ctrg->ctr[0]); + rate_ctr_add(&nsvc->ctrg->ctr[2], msgb_l2len(msg)); switch (nsh->pdu_type) { case NS_PDUT_ALIVE: From ec20ba47c7d91c0f1d528a0e8d6b5373687b9632 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:18:49 +0200 Subject: [PATCH 081/198] [GPRS] NS: properly assign msgb->l2h to count outgoing bytes correctly --- openbsc/src/gprs/gprs_ns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index cdc745aa6..8530eb176 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -476,7 +476,8 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) return -EBUSY; } - nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); + msg->l2h = msgb_push(msg, sizeof(*nsh) + 3); + nsh = (struct gprs_ns_hdr *) msg->l2h; if (!nsh) { LOGP(DNS, LOGL_ERROR, "Not enough headroom for NS header\n"); return -EIO; From af1d4cb5a812092152c50f7373e1fa877dc8d060 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:32:30 +0200 Subject: [PATCH 082/198] [GPRS] NS: Show statistics on VTY only if requested --- openbsc/src/gprs/gprs_ns_vty.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 6e98e44d6..08b0076c1 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -104,10 +104,8 @@ DEFUN(cfg_ns, cfg_ns_cmd, return CMD_SUCCESS; } -DEFUN(show_ns, show_ns_cmd, "show ns", - SHOW_STR "Display information about the NS protocol") +static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) { - struct gprs_ns_inst *nsi = vty_nsi; struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -121,12 +119,28 @@ DEFUN(show_ns, show_ns_cmd, "show ns", inet_ntoa(nsvc->ip.bts_addr.sin_addr), ntohs(nsvc->ip.bts_addr.sin_port)); vty_out(vty, "%s", VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); + if (stats) + vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); } +} +DEFUN(show_ns, show_ns_cmd, "show ns", + SHOW_STR "Display information about the NS protocol") +{ + struct gprs_ns_inst *nsi = vty_nsi; + dump_ns(vty, nsi, 0); return CMD_SUCCESS; } +DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats", + SHOW_STR + "Display information about the NS protocol\n" + "Include statistics\n") +{ + struct gprs_ns_inst *nsi = vty_nsi; + dump_ns(vty, nsi, 1); + return CMD_SUCCESS; +} #define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" @@ -260,6 +274,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) vty_nsi = nsi; install_element_ve(&show_ns_cmd); + install_element_ve(&show_ns_stats_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); From c51c23cda5e75d160220894a03d4f729817bdf27 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:55:20 +0200 Subject: [PATCH 083/198] [GPRS] NS: more rate counters for BLOCK / DEAD count --- openbsc/src/gprs/gprs_ns.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 8530eb176..554e2ec38 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -74,15 +74,26 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; +enum ns_ctr { + NS_CTR_PKTS_IN, + NS_CTR_PKTS_OUT, + NS_CTR_BYTES_IN, + NS_CTR_BYTES_OUT, + NS_CTR_BLOCKED, + NS_CTR_DEAD, +}; + static const struct rate_ctr_desc nsvc_ctr_description[] = { { "packets.in", "Packets at NS Level ( In)" }, - { "packets.out", "Packets at NS Level (Out)" }, - { "bytes.in", "Bytes at NS Level ( In)" }, - { "bytes.out", "Bytes at NS Level (Out)" }, + { "packets.out","Packets at NS Level (Out)" }, + { "bytes.in", "Bytes at NS Level ( In)" }, + { "bytes.out", "Bytes at NS Level (Out)" }, + { "blocked", "NS-VC Block count " }, + { "dead", "NS-VC gone dead count " }, }; static const struct rate_ctr_group_desc nsvc_ctrg_desc = { - .group_prefix_fmt = "ns.nsvc%u", + .group_name_prefix = "ns.nsvc", .group_description = "NSVC Peer Statistics", .num_ctr = ARRAY_SIZE(nsvc_ctr_description), .ctr_desc = nsvc_ctr_description, @@ -192,8 +203,8 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) int ret; /* Increment number of Uplink bytes */ - rate_ctr_inc(&nsvc->ctrg->ctr[1]); - rate_ctr_add(&nsvc->ctrg->ctr[3], msgb_l2len(msg)); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]); + rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_l2len(msg)); switch (nsvc->nsi->ll) { case GPRS_NS_LL_UDP: @@ -310,6 +321,7 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) /* be conservative and mark it as blocked even now! */ nsvc->state |= NSE_S_BLOCKED; + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); msg->l2h = msgb_put(msg, sizeof(*nsh)); nsh = (struct gprs_ns_hdr *) msg->l2h; @@ -392,6 +404,8 @@ static void gprs_ns_timer_cb(void *data) nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_DEAD]); LOGP(DNS, LOGL_NOTICE, "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, @@ -599,6 +613,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); ns_dispatch_signal(nsvc, S_NS_BLOCK, *cause); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); } @@ -657,8 +672,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, msgb_nsei(msg) = nsvc->nsei; /* Increment number of Incoming bytes */ - rate_ctr_inc(&nsvc->ctrg->ctr[0]); - rate_ctr_add(&nsvc->ctrg->ctr[2], msgb_l2len(msg)); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]); + DEBUGP(DNS, "BYTES_IN msgb_l2len=%d\n", msgb_l2len(msg)); + rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg)); switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -697,6 +713,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* mark NS-VC as blocked + active */ nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); if (nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); From cd2890b0c6589f1c4003df7e9e82fb17ffb2076f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 13:09:01 +0200 Subject: [PATCH 084/198] [GPRS] NS: remove debug statement about l2len --- openbsc/src/gprs/gprs_ns.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 554e2ec38..2853600df 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -673,7 +673,6 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* Increment number of Incoming bytes */ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]); - DEBUGP(DNS, "BYTES_IN msgb_l2len=%d\n", msgb_l2len(msg)); rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg)); switch (nsh->pdu_type) { From dd1c83c52d66c28583e06ba3b930883b488689ea Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 13:58:08 +0200 Subject: [PATCH 085/198] [GPRS] NS: Fix segfault when receiving message from unknown NS-VC In the previous code we used a static fake_nsvc structure in case we needed to send a message to an unknown NSVC for which we don't have a real 'struct nsvc'. However, since we now have a rate_ctr_group hanging off the nsvc, the fake structure didn't have that. So now we keep a nsi->unknown_nsvc around to be used whenever we need a nsvc but don't have a real one. The gprs_ns_vty.c code explicitly does not list that NSVC in 'show ns' --- openbsc/include/openbsc/gprs_ns.h | 3 +++ openbsc/src/gprs/gprs_ns.c | 25 +++++++++++++++++-------- openbsc/src/gprs/gprs_ns_vty.c | 2 ++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 34b1b62d2..4ccf4c7b9 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -125,6 +125,9 @@ struct gprs_ns_inst { /* linked lists of all NSVC in this instance */ struct llist_head gprs_nsvcs; + /* a NSVC object that's needed to deal with packets for unknown NSVC */ + struct gprs_nsvc *unknown_nsvc; + uint16_t timeout[NS_TIMERS_COUNT]; /* which link-layer are we based on? */ diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 2853600df..50ab8203f 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -44,6 +44,14 @@ * Those mappings are administratively configured. */ +/* This implementation has the following limitations: + * o Only one NS-VC for each NSE: No load-sharing function + * o NSVCI 65535 and 65534 are reserved for internal use + * o Only UDP is supported as of now, no frame relay support + * o The IP Sub-Network-Service (SNS) as specified in 48.016 is not implemented + * o There are no BLOCK and UNBLOCK timers (yet?) + */ + #include #include #include @@ -633,17 +641,16 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, uint16_t nsei; /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { - struct gprs_nsvc fake_nsvc; - LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " + /* Since we have no NSVC, we have to use a fake */ + nsvc = nsi->unknown_nsvc; + LOGP(DNS, LOGL_INFO, "Rejecting NS PDU type 0x%0x " "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - /* Since we have no NSVC, we have to create a fake */ - fake_nsvc.nsvci = fake_nsvc.nsei = 0; - fake_nsvc.nsi = nsi; - fake_nsvc.ip.bts_addr = *saddr; - fake_nsvc.state = NSE_S_ALIVE; - return gprs_ns_tx_status(&fake_nsvc, + nsvc->nsvci = nsvc->nsei = 0xfffe; + nsvc->ip.bts_addr = *saddr; + nsvc->state = NSE_S_ALIVE; + return gprs_ns_tx_status(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE, 0, msg); } @@ -766,6 +773,8 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->timeout[NS_TOUT_TNS_ALIVE] = 3; nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10; + nsi->unknown_nsvc = nsvc_create(nsi, 0xfffe); + return nsi; } diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 08b0076c1..8f0628afd 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -109,6 +109,8 @@ static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc == nsi->unknown_nsvc) + continue; vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", nsvc->nsei, nsvc->nsvci, nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", From 60cc6acaffe4009bf829a1d939a9d08e3287107b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 14:20:56 +0200 Subject: [PATCH 086/198] [GPRS] NS: Remove 'unknown_nsvc' from list of NS-VCs --- openbsc/src/gprs/gprs_ns.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 50ab8203f..dc12953e0 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -773,7 +773,10 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->timeout[NS_TOUT_TNS_ALIVE] = 3; nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10; + /* Create the dummy NSVC that we use for sending + * messages to non-existant/unknown NS-VC's */ nsi->unknown_nsvc = nsvc_create(nsi, 0xfffe); + llist_del(&nsi->unknown_nsvc->list); return nsi; } From 61112344e58f539be46b51ff101772f9c118ae52 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 19:25:59 +0200 Subject: [PATCH 087/198] [GPRS] BSSGP: add function declaration --- openbsc/include/openbsc/gprs_bssgp.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index d3ccb12ee..8fdef811b 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -151,7 +151,12 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg); #include -extern int gprs_bssgp_rcvmsg(struct msgb *msg); +/* BSSGP-UL-UNITDATA.ind */ +int gprs_bssgp_rcvmsg(struct msgb *msg); + +/* BSSGP-DL-UNITDATA.req */ +int gprs_bssgp_tx_dl_ud(struct msgb *msg); + uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); /* Wrapper around TLV parser to parse BSSGP IEs */ From 6b7cf2551e9804defd656a2ed488e01e6de1d548 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 19:41:31 +0200 Subject: [PATCH 088/198] [GPRS] BSSGP: Elaborate more on FIXMEs And fix mistake regarding FLUSH-LL / FLUSH-LL-ACK direction --- openbsc/src/gprs/gprs_bssgp.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 9fdfd329d..a7acaf5df 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -283,12 +283,13 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) case BSSGP_PDUT_RA_CAPABILITY: /* BSS requests RA capability or IMSI */ DEBUGP(DBSSGP, "BSSGP RA CAPABILITY UPDATE\n"); + /* FIXME: send GMM_RA_CAPABILITY_UPDATE.ind to GMM */ /* FIXME: send RA_CAPA_UPDATE_ACK */ break; case BSSGP_PDUT_RADIO_STATUS: DEBUGP(DBSSGP, "BSSGP RADIO STATUS\n"); /* BSS informs us of some exception */ - /* FIXME: notify GMM */ + /* FIXME: send GMM_RADIO_STATUS.ind to GMM */ break; case BSSGP_PDUT_SUSPEND: /* MS wants to suspend */ @@ -298,16 +299,15 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) /* MS wants to resume */ rc = bssgp_rx_resume(msg); break; - case BSSGP_PDUT_FLUSH_LL: - /* BSS informs MS has moved to one cell to other cell */ + case BSSGP_PDUT_FLUSH_LL_ACK: + /* BSS informs us it has performed LL FLUSH */ DEBUGP(DBSSGP, "BSSGP FLUSH LL\n"); - /* FIXME: notify GMM */ - /* Send FLUSH_LL_ACK */ + /* FIXME: send NM_FLUSH_LL.res to NM */ break; case BSSGP_PDUT_LLC_DISCARD: /* BSS informs that some LLC PDU's have been discarded */ DEBUGP(DBSSGP, "BSSGP LLC DISCARDED\n"); - /* FIXME: notify GMM */ + /* FIXME: send NM_LLC_DISCARDED to NM */ break; case BSSGP_PDUT_FLOW_CONTROL_BVC: /* BSS informs us of available bandwidth in Gb interface */ @@ -331,6 +331,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) /* We always acknowledge the BLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); + /* FIXME: Send NM_BVC_BLOCK.ind to NM */ break; case BSSGP_PDUT_BVC_UNBLOCK: /* BSS tells us that BVC shall be unblocked */ @@ -342,6 +343,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) /* We always acknowledge the unBLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); + /* FIXME: Send NM_BVC_UNBLOCK.ind to NM */ break; case BSSGP_PDUT_BVC_RESET: /* BSS tells us that BVC init is required */ @@ -353,7 +355,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ - /* FIXME: notify GMM */ + /* FIXME: send NM_STATUS.ind to NM */ case BSSGP_PDUT_DOWNLOAD_BSS_PFC: case BSSGP_PDUT_CREATE_BSS_PFC_ACK: case BSSGP_PDUT_CREATE_BSS_PFC_NACK: @@ -371,7 +373,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) case BSSGP_PDUT_SUSPEND_NACK: case BSSGP_PDUT_RESUME_ACK: case BSSGP_PDUT_RESUME_NACK: - case BSSGP_PDUT_FLUSH_LL_ACK: + case BSSGP_PDUT_FLUSH_LL: case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: case BSSGP_PDUT_BVC_BLOCK_ACK: From 25de8110235e10874696e0c2e9598d712ec47b48 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 21:26:28 +0200 Subject: [PATCH 089/198] [GPRS] BSSGP: Make implementation more robust We now actually are much more in line with what the specification says. We track the blocked/unblocked state, we don't accept signalling messages on PTP functional entities (and vice versa), and we don't simply create a BVC context with messages other than BVC-RESET. --- openbsc/src/gprs/gprs_bssgp.c | 337 +++++++++++++++++++++++----------- 1 file changed, 228 insertions(+), 109 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index a7acaf5df..45e3de514 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,25 @@ void *bssgp_tall_ctx = NULL; #define BVC_F_BLOCKED 0x0001 +enum bssgp_ctr { + BSSGP_CTR_BLOCKED, + BSSGP_CTR_DISCARDED, +}; + +static const struct rate_ctr_desc bssgp_ctr_description[] = { + { "blocked", "BVC Blocking count" }, + { "discarded", "BVC LLC Discarded count" }, +}; + +static const struct rate_ctr_group_desc bssgp_ctrg_desc = { + .group_name_prefix = "bssgp.bss_ctx", + .group_description = "BSSGP Peer Statistics", + .num_ctr = ARRAY_SIZE(bssgp_ctr_description), + .ctr_desc = bssgp_ctr_description, +}; + +#define BVC_S_BLOCKED 0x0001 + /* The per-BTS context that we keep on the SGSN side of the BSSGP link */ struct bssgp_bts_ctx { struct llist_head list; @@ -53,7 +73,9 @@ struct bssgp_bts_ctx { uint16_t bvci; uint16_t nsei; - uint32_t bvc_state; + uint32_t state; + + struct rate_ctr_group *ctrg; /* we might want to add this as a shortcut later, avoiding the NSVC * lookup for every packet, similar to a routing cache */ @@ -95,6 +117,9 @@ struct bssgp_bts_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) return NULL; ctx->bvci = bvci; ctx->nsei = nsei; + /* FIXME: BVCI is not unique, only BVCI+NSEI ?!? */ + ctx->ctrg = rate_ctr_group_alloc(ctx, &bssgp_ctrg_desc, bvci); + llist_add(&ctx->list, &bts_ctxts); return ctx; @@ -134,7 +159,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, int rc; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", bvci, + DEBUGPC(DBSSGP, "BVCI=%u RESET cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); /* look-up or create the BTS context for this BVC */ @@ -142,6 +167,9 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, if (!bctx) bctx = btsctx_alloc(bvci, nsei); + /* As opposed to NS-VCs, BVCs are NOT blocked after RESET */ + bctx->state &= ~BVC_S_BLOCKED; + /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS * informs us about its RAC + Cell ID, so we can create a mapping */ if (bvci != 0 && bvci != 1) { @@ -164,80 +192,109 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, return 0; } +static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) +{ + uint16_t bvci; + struct bssgp_bts_ctx *ptp_ctx; + + bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + + LOGP(DBSSGP, LOGL_INFO, "BVCI=%u BVC-BLOCK\n", bvci); + + ptp_ctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg)); + if (!ptp_ctx) + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci, msg); + + ptp_ctx->state |= BVC_S_BLOCKED; + rate_ctr_inc(&ptp_ctx->ctrg->ctr[BSSGP_CTR_BLOCKED]); + + /* FIXME: Send NM_BVC_BLOCK.ind to NM */ + + /* We always acknowledge the BLOCKing */ + return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, msgb_nsei(msg), + bvci, msgb_bvci(msg)); +}; + +static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) +{ + uint16_t bvci; + struct bssgp_bts_ctx *ptp_ctx; + + bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + + DEBUGP(DBSSGP, "BVCI=%u BVC-UNBLOCK\n", bvci); + + ptp_ctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg)); + if (!ptp_ctx) + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci, msg); + + ptp_ctx->state &= ~BVC_S_BLOCKED; + + /* FIXME: Send NM_BVC_UNBLOCK.ind to NM */ + + /* We always acknowledge the unBLOCKing */ + return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg), + bvci, msgb_bvci(msg)); +}; + /* Uplink unit-data */ -static int bssgp_rx_ul_ud(struct msgb *msg) +static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bts_ctx *ctx) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); - int data_len = msgb_bssgp_len(msg) - sizeof(*budh); - struct tlv_parsed tp; - int rc; DEBUGP(DBSSGP, "BSSGP UL-UD\n"); /* extract TLLI and parse TLV IEs */ msgb_tlli(msg) = ntohl(budh->tlli); - rc = bssgp_tlv_parse(&tp, budh->data, data_len); /* Cell ID and LLC_PDU are the only mandatory IE */ - if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) || - !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) - return -EIO; - - /* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */ + if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID) || + !TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); /* store pointer to LLC header and CELL ID in msgb->cb */ - msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); - msgb_bcid(msg) = TLVP_VAL(&tp, BSSGP_IE_CELL_ID); + msgb_llch(msg) = TLVP_VAL(tp, BSSGP_IE_LLC_PDU); + msgb_bcid(msg) = TLVP_VAL(tp, BSSGP_IE_CELL_ID); - return gprs_llc_rcvmsg(msg, &tp); + return gprs_llc_rcvmsg(msg, tp); } -static int bssgp_rx_suspend(struct msgb *msg) +static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bts_ctx *ctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - struct tlv_parsed tp; - int rc; DEBUGP(DBSSGP, "BSSGP SUSPEND\n"); - rc = bssgp_tlv_parse(&tp, bgph->data, data_len); - if (rc < 0) - return rc; - - if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || - !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) - return -EIO; + if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); /* FIXME: pass the SUSPEND request to GMM */ /* SEND SUSPEND_ACK or SUSPEND_NACK */ } -static int bssgp_rx_resume(struct msgb *msg) +static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bts_ctx *ctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - struct tlv_parsed tp; - int rc; DEBUGP(DBSSGP, "BSSGP RESUME\n"); - rc = bssgp_tlv_parse(&tp, bgph->data, data_len); - if (rc < 0) - return rc; - - if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || - !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) || - !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR)) - return -EIO; + if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA) || + !TLVP_PRESENT(tp, BSSGP_IE_SUSPEND_REF_NR)) + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); /* FIXME: pass the RESUME request to GMM */ /* SEND RESUME_ACK or RESUME_NACK */ } -static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) +static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bts_ctx *bctx) { DEBUGP(DBSSGP, "BSSGP FC BVC\n"); @@ -256,29 +313,19 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) msgb_bvci(msg)); } -/* We expect msgb_bssgph() to point to the BSSGP header */ -int gprs_bssgp_rcvmsg(struct msgb *msg) +/* Receive a BSSGP PDU from a BSS on a PTP BVCI */ +static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bts_ctx *bctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - struct tlv_parsed tp; uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - uint16_t bvci; /* PTP BVCI */ - uint16_t ns_bvci = msgb_bvci(msg); int rc = 0; - /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */ - - /* UNITDATA BSSGP headers have TLLI in front */ - if (pdu_type != BSSGP_PDUT_UL_UNITDATA && - pdu_type != BSSGP_PDUT_DL_UNITDATA) - rc = bssgp_tlv_parse(&tp, bgph->data, data_len); - switch (pdu_type) { case BSSGP_PDUT_UL_UNITDATA: /* some LLC data from the MS */ - rc = bssgp_rx_ul_ud(msg); + rc = bssgp_rx_ul_ud(msg, tp, bctx); break; case BSSGP_PDUT_RA_CAPABILITY: /* BSS requests RA capability or IMSI */ @@ -291,27 +338,9 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) /* BSS informs us of some exception */ /* FIXME: send GMM_RADIO_STATUS.ind to GMM */ break; - case BSSGP_PDUT_SUSPEND: - /* MS wants to suspend */ - rc = bssgp_rx_suspend(msg); - break; - case BSSGP_PDUT_RESUME: - /* MS wants to resume */ - rc = bssgp_rx_resume(msg); - break; - case BSSGP_PDUT_FLUSH_LL_ACK: - /* BSS informs us it has performed LL FLUSH */ - DEBUGP(DBSSGP, "BSSGP FLUSH LL\n"); - /* FIXME: send NM_FLUSH_LL.res to NM */ - break; - case BSSGP_PDUT_LLC_DISCARD: - /* BSS informs that some LLC PDU's have been discarded */ - DEBUGP(DBSSGP, "BSSGP LLC DISCARDED\n"); - /* FIXME: send NM_LLC_DISCARDED to NM */ - break; case BSSGP_PDUT_FLOW_CONTROL_BVC: /* BSS informs us of available bandwidth in Gb interface */ - rc = bssgp_rx_fc_bvc(msg, &tp); + rc = bssgp_rx_fc_bvc(msg, tp, bctx); break; case BSSGP_PDUT_FLOW_CONTROL_MS: /* BSS informs us of available bandwidth to one MS */ @@ -319,40 +348,6 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) /* FIXME: actually implement flow control */ /* FIXME: Send FLOW_CONTROL_MS_ACK */ break; - case BSSGP_PDUT_BVC_BLOCK: - /* BSS tells us that BVC shall be blocked */ - DEBUGP(DBSSGP, "BSSGP BVC BLOCK "); - if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || - !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) - goto err_mand_ie; - bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", bvci, - bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); - /* We always acknowledge the BLOCKing */ - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, - msgb_nsei(msg), bvci, ns_bvci); - /* FIXME: Send NM_BVC_BLOCK.ind to NM */ - break; - case BSSGP_PDUT_BVC_UNBLOCK: - /* BSS tells us that BVC shall be unblocked */ - DEBUGP(DBSSGP, "BSSGP BVC UNBLOCK "); - if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) - goto err_mand_ie; - bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DBSSGP, "BVCI=%u\n", bvci); - /* We always acknowledge the unBLOCKing */ - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, - msgb_nsei(msg), bvci, ns_bvci); - /* FIXME: Send NM_BVC_UNBLOCK.ind to NM */ - break; - case BSSGP_PDUT_BVC_RESET: - /* BSS tells us that BVC init is required */ - DEBUGP(DBSSGP, "BSSGP BVC RESET "); - if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || - !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) - goto err_mand_ie; - rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci); - break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ /* FIXME: send NM_STATUS.ind to NM */ @@ -363,28 +358,105 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) case BSSGP_PDUT_DELETE_BSS_PFC_ACK: DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x not [yet] implemented\n", pdu_type); + rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); break; /* those only exist in the SGSN -> BSS direction */ case BSSGP_PDUT_DL_UNITDATA: case BSSGP_PDUT_PAGING_PS: case BSSGP_PDUT_PAGING_CS: case BSSGP_PDUT_RA_CAPA_UPDATE_ACK: + case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: + case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x only exists in DL\n", + pdu_type); + bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); + rc = -EINVAL; + break; + default: + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); + break; + } + + +} + +/* Receive a BSSGP PDU from a BSS on a SIGNALLING BVCI */ +static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bts_ctx *bctx) +{ + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); + uint8_t pdu_type = bgph->pdu_type; + int rc = 0; + uint16_t ns_bvci = msgb_bvci(msg); + uint16_t bvci; + + switch (bgph->pdu_type) { + case BSSGP_PDUT_SUSPEND: + /* MS wants to suspend */ + rc = bssgp_rx_suspend(msg, tp, bctx); + break; + case BSSGP_PDUT_RESUME: + /* MS wants to resume */ + rc = bssgp_rx_resume(msg, tp, bctx); + break; + case BSSGP_PDUT_FLUSH_LL_ACK: + /* BSS informs us it has performed LL FLUSH */ + DEBUGP(DBSSGP, "BSSGP FLUSH LL\n"); + /* FIXME: send NM_FLUSH_LL.res to NM */ + break; + case BSSGP_PDUT_LLC_DISCARD: + /* BSS informs that some LLC PDU's have been discarded */ + rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_DISCARDED]); + DEBUGP(DBSSGP, "BSSGP LLC DISCARDED\n"); + /* FIXME: send NM_LLC_DISCARDED to NM */ + break; + case BSSGP_PDUT_BVC_BLOCK: + /* BSS tells us that BVC shall be blocked */ + DEBUGP(DBSSGP, "BSSGP BVC BLOCK "); + if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + rc = bssgp_rx_bvc_unblock(msg, tp); + break; + case BSSGP_PDUT_BVC_UNBLOCK: + /* BSS tells us that BVC shall be unblocked */ + if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) + goto err_mand_ie; + rc = bssgp_rx_bvc_unblock(msg, tp); + break; + case BSSGP_PDUT_BVC_RESET: + /* BSS tells us that BVC init is required */ + DEBUGP(DBSSGP, "BSSGP BVC RESET "); + if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + rc = bssgp_rx_bvc_reset(msg, tp, ns_bvci); + break; + case BSSGP_PDUT_STATUS: + /* Some exception has occurred */ + /* FIXME: send NM_STATUS.ind to NM */ + break; + /* those only exist in the SGSN -> BSS direction */ + case BSSGP_PDUT_PAGING_PS: + case BSSGP_PDUT_PAGING_CS: case BSSGP_PDUT_SUSPEND_ACK: case BSSGP_PDUT_SUSPEND_NACK: case BSSGP_PDUT_RESUME_ACK: case BSSGP_PDUT_RESUME_NACK: case BSSGP_PDUT_FLUSH_LL: - case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: - case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: case BSSGP_PDUT_BVC_BLOCK_ACK: case BSSGP_PDUT_BVC_UNBLOCK_ACK: case BSSGP_PDUT_SGSN_INVOKE_TRACE: DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x only exists in DL\n", pdu_type); + bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); rc = -EINVAL; break; default: DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); break; } @@ -393,6 +465,51 @@ err_mand_ie: return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); } +/* We expect msgb_bssgph() to point to the BSSGP header */ +int gprs_bssgp_rcvmsg(struct msgb *msg) +{ + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); + struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); + struct tlv_parsed tp; + struct bssgp_bts_ctx *bctx; + uint8_t pdu_type = bgph->pdu_type; + uint16_t ns_bvci = msgb_bvci(msg); + int data_len; + int rc = 0; + + /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */ + + /* UNITDATA BSSGP headers have TLLI in front */ + if (pdu_type != BSSGP_PDUT_UL_UNITDATA && + pdu_type != BSSGP_PDUT_DL_UNITDATA) { + data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + } else { + data_len = msgb_bssgp_len(msg) - sizeof(*budh); + rc = bssgp_tlv_parse(&tp, budh->data, data_len); + } + + /* look-up or create the BTS context for this BVC */ + bctx = btsctx_by_bvci_nsei(ns_bvci, msgb_nsei(msg)); + /* Only a RESET PDU can create a new BVC context */ + if (!bctx && pdu_type != BSSGP_PDUT_BVC_RESET) { + LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU " + "type %u for unknown BVCI\n", msgb_nsei(msg), ns_bvci, + pdu_type); + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg); + } + + if (ns_bvci == 1) + rc = gprs_bssgp_rx_sign(msg, &tp, bctx); + else if (ns_bvci == 2) + rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); + else + rc = gprs_bssgp_rx_ptp(msg, &tp, bctx); + + return rc; +} + /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ int gprs_bssgp_tx_dl_ud(struct msgb *msg) @@ -415,8 +532,10 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) } bctx = btsctx_by_bvci_nsei(bvci, nsei); - if (!bctx) + if (!bctx) { + /* FIXME: don't simply create missing context, but reject message */ bctx = btsctx_alloc(bvci, nsei); + } if (msg->len > TVLV_MAX_ONEBYTE) llc_pdu_tlv_hdr_len += 1; From 58e65c90a8fc43624d45acd173b0454796fa971d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 21:45:23 +0200 Subject: [PATCH 090/198] [GPRS] BSSGP: Refuse blocking of signalling BVC; Ignore traffic on blocked BVC --- openbsc/src/gprs/gprs_bssgp.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 45e3de514..9add00fb7 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -198,6 +198,13 @@ static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) struct bssgp_bts_ctx *ptp_ctx; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + if (bvci == 0) { + /* 8.3.2: Signalling BVC shall never be blocked */ + LOGP(DBSSGP, LOGL_ERROR, "NSEI=%u/BVCI=%u " + "received block for signalling BVC!?!\n", + msgb_nsei(msg), msgb_bvci(msg)); + return 0; + } LOGP(DBSSGP, LOGL_INFO, "BVCI=%u BVC-BLOCK\n", bvci); @@ -221,6 +228,13 @@ static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) struct bssgp_bts_ctx *ptp_ctx; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + if (bvci == 0) { + /* 8.3.2: Signalling BVC shall never be blocked */ + LOGP(DBSSGP, LOGL_ERROR, "NSEI=%u/BVCI=%u " + "received unblock for signalling BVC!?!\n", + msgb_nsei(msg), msgb_bvci(msg)); + return 0; + } DEBUGP(DBSSGP, "BVCI=%u BVC-UNBLOCK\n", bvci); @@ -322,6 +336,14 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, uint8_t pdu_type = bgph->pdu_type; int rc = 0; + /* If traffic is received on a BVC that is marked as blocked, the + * received PDU shall not be accepted and a STATUS PDU (Cause value: + * BVC Blocked) shall be sent to the peer entity on the signalling BVC */ + if (bctx->state & BVC_S_BLOCKED && pdu_type != BSSGP_PDUT_STATUS) { + uint16_t bvci = msgb_bvci(msg); + return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &bvci, msg); + } + switch (pdu_type) { case BSSGP_PDUT_UL_UNITDATA: /* some LLC data from the MS */ From 731d1fc956f6fc5cd0c08e4536c00598e391bc75 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 14 May 2010 11:53:08 +0000 Subject: [PATCH 091/198] [GPRS] gb_proxy: Initiate RESET procedure on persistent NS-VC at startup Some BSS that connect to the proxy do not continue to perform the RESET procedure after a timeout. In order to resurrect them, we simply start a RESET procedure. --- openbsc/include/openbsc/gprs_ns.h | 3 +++ openbsc/src/gprs/gprs_ns.c | 33 +++++++++++++++++-------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 4ccf4c7b9..24a797450 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -209,6 +209,9 @@ struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci); void nsvc_delete(struct gprs_nsvc *nsvc); struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); +/* Initiate a RESET procedure (including timer start, ...)*/ +int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); + /* Add NS-specific VTY stuff */ int gprs_ns_vty_init(struct gprs_ns_inst *nsi); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index dc12953e0..6a6cfe154 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -720,7 +720,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); - if (nsvc->remote_end_is_sgsn) { + if (nsvc->persistent || nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); /* Initiate TEST proc.: Send ALIVE and start timer */ @@ -894,6 +894,22 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) return ret; } +/* Initiate a RESET procedure */ +int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) +{ + /* Mark NS-VC locally as blocked and dead */ + nsvc->state = NSE_S_BLOCKED; + /* Send NS-RESET PDU */ + if (gprs_ns_tx_reset(nsvc, cause) < 0) { + LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", + nsvc->nsei); + } + /* Start Tns-reset */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); + + return nsvc; +} + /* Establish a connection (from the BSS) to the SGSN */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, @@ -909,18 +925,5 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->nsvci = nsvci; nsvc->remote_end_is_sgsn = 1; - /* Initiate a RESET procedure */ - /* Mark NS-VC locally as blocked and dead */ - nsvc->state = NSE_S_BLOCKED; - /* Send NS-RESET PDU */ - if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { - LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", - nsei); - } - /* Start Tns-reset */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); - - return nsvc; + return gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION); } - - From 804fc81d2bc563d744dc2e7ff8aef54d6f03b974 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 14 May 2010 18:59:17 +0200 Subject: [PATCH 092/198] [VTY] Remove OpenBSC specific node-exit handling from src/vty The idea is to move the VTY code into libosmocore at some point, and for that we need to eliminate OpenBSC specifics from it --- openbsc/src/gprs/gprs_ns_vty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 8f0628afd..b18e65171 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -281,6 +282,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); install_default(NS_NODE); + install_element(NS_NODE, &ournode_exit_cmd); install_element(NS_NODE, &cfg_nse_nsvci_cmd); install_element(NS_NODE, &cfg_nse_remoteip_cmd); install_element(NS_NODE, &cfg_nse_remoteport_cmd); From a52ff459ec4995f0a529ba62581f374cf95fa7e6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 14 May 2010 19:11:04 +0200 Subject: [PATCH 093/198] [VTY] Introduce "end" command that works from any level in config Using "end" you can always return to the "enable" level, and from there the "show" commands are available. So no more need for exit/exit/exit/exit/disable. --- openbsc/src/gprs/gprs_ns_vty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index b18e65171..410c35f6b 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -283,6 +283,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_node(&ns_node, config_write_ns); install_default(NS_NODE); install_element(NS_NODE, &ournode_exit_cmd); + install_element(NS_NODE, &ournode_end_cmd); install_element(NS_NODE, &cfg_nse_nsvci_cmd); install_element(NS_NODE, &cfg_nse_remoteip_cmd); install_element(NS_NODE, &cfg_nse_remoteport_cmd); From 43f3b69c4329b29bfca2d21c825bda0e54528b02 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 14 May 2010 19:36:59 +0200 Subject: [PATCH 094/198] [GPRS] NS: Add 'nsvc nsei ... (block|unblock|reset)' command to VTY --- openbsc/src/gprs/gprs_ns_vty.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 410c35f6b..b119dea8c 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -272,6 +272,37 @@ DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, return CMD_SUCCESS; } +DEFUN(nsvc_nsei, nsvc_nsei_cmd, + "nsvc nsei <0-65535> (block|unblock|reset)", + "Perform an operation on a NSVC\n" + "NS-VC Identifier (NS-VCI)\n" + "Initiate BLOCK procedure\n" + "Initiate UNBLOCK procedure\n" + "Initiate RESET procedure\n") +{ + uint16_t nsvci = atoi(argv[0]); + const char *operation = argv[1]; + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsvci); + if (!nsvc) { + vty_out(vty, "No such NSVCI (%u)%s", nsvci, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(operation, "block")) + gprs_ns_tx_block(nsvc, NS_CAUSE_OM_INTERVENTION); + else if (!strcmp(operation, "unblock")) + gprs_ns_tx_unblock(nsvc); + else if (!strcmp(operation, "reset")) + gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + else + return CMD_WARNING; + + return CMD_SUCCESS; +} + + int gprs_ns_vty_init(struct gprs_ns_inst *nsi) { vty_nsi = nsi; @@ -291,5 +322,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(NS_NODE, &cfg_no_nse_cmd); install_element(NS_NODE, &cfg_ns_timer_cmd); + install_element(ENABLE_NODE, &nsvc_nsei_cmd); + return 0; } From 90af194a9d823b4b74e4025866da92f92e98cdff Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 15 May 2010 23:02:24 +0200 Subject: [PATCH 095/198] [GPRS] NS: Always start NS-ALIVE procedure after RESET So far, we only started the ALIVE procedure on RESET-ACK if the remote end was the SGSN. This resulted in the BSS->Proxy connections only being tested for alive-status from the BSS side, but not from our side. Also: export nsvc_by_nsvci() function as a public API function. --- openbsc/include/openbsc/gprs_ns.h | 1 + openbsc/src/gprs/gprs_ns.c | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 24a797450..08519f244 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -208,6 +208,7 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci); void nsvc_delete(struct gprs_nsvc *nsvc); struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); +struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci); /* Initiate a RESET procedure (including timer start, ...)*/ int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 6a6cfe154..2315f2323 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -108,8 +108,7 @@ static const struct rate_ctr_group_desc nsvc_ctrg_desc = { }; /* Lookup struct gprs_nsvc based on NSVCI */ -static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, - uint16_t nsvci) +struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -280,7 +279,7 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, if (!msg) return -ENOMEM; - LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n", + LOGP(DNS, LOGL_NOTICE, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n", nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); msg->l2h = msgb_put(msg, sizeof(*nsh)); @@ -694,9 +693,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_tx_alive_ack(nsvc); break; case NS_PDUT_ALIVE_ACK: - /* stop Tns-alive */ - bsc_del_timer(&nsvc->timer); - /* start Tns-test */ + /* stop Tns-alive and start Tns-test */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); if (nsvc->remote_end_is_sgsn) { /* FIXME: this should be one level higher */ @@ -723,10 +720,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsvc->persistent || nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); - /* Initiate TEST proc.: Send ALIVE and start timer */ - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); } + /* Initiate TEST proc.: Send ALIVE and start timer */ + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ From 92883345c893e8c4942355778fd83903e6873791 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 15 May 2010 23:04:03 +0200 Subject: [PATCH 096/198] [GPRS] NS: Introduce command to display a single NSE --- openbsc/src/gprs/gprs_ns_vty.c | 59 +++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index b119dea8c..b4102e44d 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -105,6 +105,22 @@ DEFUN(cfg_ns, cfg_ns_cmd, return CMD_SUCCESS; } +static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats) +{ + vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, ", %15s:%u", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port)); + vty_out(vty, "%s", VTY_NEWLINE); + if (stats) + vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); +} + static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) { struct gprs_nsvc *nsvc; @@ -112,18 +128,7 @@ static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { if (nsvc == nsi->unknown_nsvc) continue; - vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", - nsvc->nsei, nsvc->nsvci, - nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", - nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", - nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, ", %15s:%u", - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - ntohs(nsvc->ip.bts_addr.sin_port)); - vty_out(vty, "%s", VTY_NEWLINE); - if (stats) - vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); + dump_nse(vty, nsvc, stats); } } @@ -145,6 +150,35 @@ DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats", return CMD_SUCCESS; } +DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]", + SHOW_STR "Display information about the NS protocol\n" + "Select one NSE by its NSE Identifier\n" + "Select one NSE by its NS-VC Identifier\n" + "The Identifier of selected type\n" + "Include Statistics\n") +{ + struct gprs_ns_inst *nsi = vty_nsi; + struct gprs_nsvc *nsvc; + uint16_t id = atoi(argv[1]); + int show_stats = 0; + + if (!strcmp(argv[0], "nsei")) + nsvc = nsvc_by_nsei(nsi, id); + else + nsvc = nsvc_by_nsvci(nsi, id); + + if (!nsvc) { + vty_out(vty, "No such NS Entity%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc >= 3) + show_stats = 1; + + dump_nse(vty, nsvc, show_stats); + return CMD_SUCCESS; +} + #define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, @@ -309,6 +343,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element_ve(&show_ns_cmd); install_element_ve(&show_ns_stats_cmd); + install_element_ve(&show_nse_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); From 24133c39585e18cb91ac6caa731a303c45cd0e2b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 15 May 2010 23:06:26 +0200 Subject: [PATCH 097/198] [GPRS] NS: VTY: Don't nsvc_delete() on 'no nse...' Rather than deleting the NSE from memory, we simply mark it as non-persistent. This makes sure that there are no invalid references (e.g. from gbprox_peer) to the gprs_nsvc structure, but at the same time ensures it will no longer be stored as part of writing the config file. --- openbsc/src/gprs/gprs_ns_vty.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index b4102e44d..a945d865f 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -179,7 +179,7 @@ DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]", return CMD_SUCCESS; } -#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" +#define NSE_CMD_STR "Persistent NS Entity\n" "NS Entity ID (NSEI)\n" DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, "nse <0-65535> nsvci <0-65534>", @@ -273,7 +273,7 @@ DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, DEFUN(cfg_no_nse, cfg_no_nse_cmd, "no nse <0-65535>", - "Delete NS Entity\n" + "Delete Persistent NS Entity\n" "Delete " NSE_CMD_STR) { uint16_t nsei = atoi(argv[0]); @@ -285,7 +285,13 @@ DEFUN(cfg_no_nse, cfg_no_nse_cmd, return CMD_WARNING; } - nsvc_delete(nsvc); + if (!nsvc->persistent) { + vty_out(vty, "NSEI %u is not a persistent NSE%s", + nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc->persistent = 0; return CMD_SUCCESS; } From 91f7f4ba96ac6ed9ee88c4d818617fe36e3066dc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 15 May 2010 23:52:02 +0200 Subject: [PATCH 098/198] [GPRS] NS: Allow filtering of log messages by NSVC / NSEI --- openbsc/src/gprs/gprs_ns.c | 23 ++++++++++++++++++++++- openbsc/src/gprs/gprs_ns_vty.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 2315f2323..ea6711202 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -209,6 +209,8 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) { int ret; + log_set_context(BSC_CTX_NSVC, nsvc); + /* Increment number of Uplink bytes */ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]); rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_l2len(msg)); @@ -231,6 +233,8 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; + log_set_context(BSC_CTX_NSVC, nsvc); + if (!msg) return -ENOMEM; @@ -249,6 +253,8 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) uint16_t nsvci = htons(nsvc->nsvci); uint16_t nsei = htons(nsvc->nsei); + log_set_context(BSC_CTX_NSVC, nsvc); + if (!msg) return -ENOMEM; @@ -274,6 +280,8 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, struct gprs_ns_hdr *nsh; uint16_t nsvci = htons(nsvc->nsvci); + log_set_context(BSC_CTX_NSVC, nsvc); + bvci = htons(bvci); if (!msg) @@ -320,6 +328,8 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) struct gprs_ns_hdr *nsh; uint16_t nsvci = htons(nsvc->nsvci); + log_set_context(BSC_CTX_NSVC, nsvc); + if (!msg) return -ENOMEM; @@ -342,6 +352,7 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) { + log_set_context(BSC_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); @@ -350,6 +361,7 @@ int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) { + log_set_context(BSC_CTX_NSVC, nsvc); LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); @@ -358,6 +370,7 @@ int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc) { + log_set_context(BSC_CTX_NSVC, nsvc); LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE_ACK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); @@ -382,6 +395,7 @@ static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) enum ns_timeout tout = timer_mode_tout[mode]; unsigned int seconds = nsvc->nsi->timeout[tout]; + log_set_context(BSC_CTX_NSVC, nsvc); DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, mode), seconds); @@ -399,6 +413,7 @@ static void gprs_ns_timer_cb(void *data) enum ns_timeout tout = timer_mode_tout[nsvc->timer_mode]; unsigned int seconds = nsvc->nsi->timeout[tout]; + log_set_context(BSC_CTX_NSVC, nsvc); DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode), seconds); @@ -452,6 +467,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) struct gprs_ns_hdr *nsh; uint16_t nsvci, nsei; + log_set_context(BSC_CTX_NSVC, nsvc); if (!msg) return -ENOMEM; @@ -485,6 +501,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) "to NS-VC!\n", msgb_nsei(msg)); return -EINVAL; } + log_set_context(BSC_CTX_NSVC, nsvc); if (!(nsvc->state & NSE_S_ALIVE)) { LOGP(DNS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", @@ -642,6 +659,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsh->pdu_type != NS_PDUT_RESET) { /* Since we have no NSVC, we have to use a fake */ nsvc = nsi->unknown_nsvc; + log_set_context(BSC_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "Rejecting NS PDU type 0x%0x " "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), @@ -668,15 +686,18 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, * simply have changed addresses, or it is a SGSN */ nsvc = nsvc_by_nsei(nsi, nsei); if (!nsvc) { + nsvc = nsvc_create(nsi, 0xffff); + log_set_context(BSC_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - nsvc = nsvc_create(nsi, 0xffff); } /* Update the remote peer IP address/port */ nsvc->ip.bts_addr = *saddr; } else msgb_nsei(msg) = nsvc->nsei; + log_set_context(BSC_CTX_NSVC, nsvc); + /* Increment number of Incoming bytes */ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]); rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg)); diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index a945d865f..c124d42cc 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -342,6 +343,38 @@ DEFUN(nsvc_nsei, nsvc_nsei_cmd, return CMD_SUCCESS; } +DEFUN(logging_fltr_nsvc, + logging_fltr_nsvc_cmd, + "logging filter nsvc (nsei|nsvci) <0-65535>", + LOGGING_STR "Filter log messages\n" + "Filter based on NS Virtual Connection\n" + "Identify NS-VC by NSEI\n" + "Identify NS-VC by NSVCI\n" + "Numeric identifier\n") +{ + struct telnet_connection *conn; + struct gprs_nsvc *nsvc; + uint16_t id = atoi(argv[1]); + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[0], "nsei")) + nsvc = nsvc_by_nsei(vty_nsi, id); + else + nsvc = nsvc_by_nsvci(vty_nsi, id); + + if (!nsvc) { + vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + log_set_nsvc_filter(conn->dbg, nsvc); + return CMD_SUCCESS; +} int gprs_ns_vty_init(struct gprs_ns_inst *nsi) { @@ -350,6 +383,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element_ve(&show_ns_cmd); install_element_ve(&show_ns_stats_cmd); install_element_ve(&show_nse_cmd); + install_element_ve(&logging_fltr_nsvc_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); From 6703bf76c0cc0d6cfe0876534abcfe3a8cb40502 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 16 May 2010 00:00:04 +0200 Subject: [PATCH 099/198] VTY: Context-sensitive help for logging related commands --- openbsc/src/gprs/gprs_ns_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index c124d42cc..c20016aa5 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -346,7 +346,7 @@ DEFUN(nsvc_nsei, nsvc_nsei_cmd, DEFUN(logging_fltr_nsvc, logging_fltr_nsvc_cmd, "logging filter nsvc (nsei|nsvci) <0-65535>", - LOGGING_STR "Filter log messages\n" + LOGGING_STR FILTER_STR "Filter based on NS Virtual Connection\n" "Identify NS-VC by NSEI\n" "Identify NS-VC by NSVCI\n" From 41337832c412f9fd584c5c798013e1f8b0870562 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 16 May 2010 00:24:26 +0200 Subject: [PATCH 100/198] [GPRS] NS: Receiving a STATUS message is a NOTICEable event --- openbsc/src/gprs/gprs_ns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index ea6711202..7b1b13871 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -556,7 +556,7 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t cause; int rc; - LOGP(DNS, LOGL_INFO, "NSEI=%u NS STATUS ", nsvc->nsei); + LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); @@ -566,7 +566,7 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) } cause = *TLVP_VAL(&tp, NS_IE_CAUSE); - LOGPC(DNS, LOGL_INFO, "cause=%s\n", gprs_ns_cause_str(cause)); + LOGPC(DNS, LOGL_NOTICE, "cause=%s\n", gprs_ns_cause_str(cause)); return 0; } From 8a521136a4c0cfc94823edd7f8d6f6d5f9efdf96 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 17 May 2010 22:59:29 +0200 Subject: [PATCH 101/198] [GPRS] BSSGP: Rename bssgp_bts_ctx to bssgp_bvc_ctx The Context really is about a BVC (BSSGP Virtual Connection). In the case we operate BSSGP on the SGSN side, this corresponds to a link to a BTS. --- openbsc/src/gprs/gprs_bssgp.c | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 9add00fb7..f6b02bada 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -61,7 +61,7 @@ static const struct rate_ctr_group_desc bssgp_ctrg_desc = { #define BVC_S_BLOCKED 0x0001 /* The per-BTS context that we keep on the SGSN side of the BSSGP link */ -struct bssgp_bts_ctx { +struct bssgp_bvc_ctx { struct llist_head list; /* parsed RA ID and Cell ID of the remote BTS */ @@ -84,9 +84,9 @@ struct bssgp_bts_ctx { static LLIST_HEAD(bts_ctxts); /* Find a BTS Context based on parsed RA ID and Cell ID */ -struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) +struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) { - struct bssgp_bts_ctx *bctx; + struct bssgp_bvc_ctx *bctx; llist_for_each_entry(bctx, &bts_ctxts, list) { if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) && @@ -97,9 +97,9 @@ struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t } /* Find a BTS context based on BVCI+NSEI tuple */ -struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) +struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) { - struct bssgp_bts_ctx *bctx; + struct bssgp_bvc_ctx *bctx; llist_for_each_entry(bctx, &bts_ctxts, list) { if (bctx->nsei == nsei && bctx->bvci == bvci) @@ -108,11 +108,11 @@ struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) return NULL; } -struct bssgp_bts_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) +struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) { - struct bssgp_bts_ctx *ctx; + struct bssgp_bvc_ctx *ctx; - ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bts_ctx); + ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bvc_ctx); if (!ctx) return NULL; ctx->bvci = bvci; @@ -153,7 +153,7 @@ uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, uint16_t ns_bvci) { - struct bssgp_bts_ctx *bctx; + struct bssgp_bvc_ctx *bctx; uint16_t nsei = msgb_nsei(msg); uint16_t bvci; int rc; @@ -195,7 +195,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) { uint16_t bvci; - struct bssgp_bts_ctx *ptp_ctx; + struct bssgp_bvc_ctx *ptp_ctx; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); if (bvci == 0) { @@ -225,7 +225,7 @@ static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) { uint16_t bvci; - struct bssgp_bts_ctx *ptp_ctx; + struct bssgp_bvc_ctx *ptp_ctx; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); if (bvci == 0) { @@ -253,7 +253,7 @@ static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) /* Uplink unit-data */ static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bts_ctx *ctx) + struct bssgp_bvc_ctx *ctx) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); @@ -275,7 +275,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, } static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bts_ctx *ctx) + struct bssgp_bvc_ctx *ctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -291,7 +291,7 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, } static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bts_ctx *ctx) + struct bssgp_bvc_ctx *ctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -308,7 +308,7 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, } static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bts_ctx *bctx) + struct bssgp_bvc_ctx *bctx) { DEBUGP(DBSSGP, "BSSGP FC BVC\n"); @@ -329,7 +329,7 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, /* Receive a BSSGP PDU from a BSS on a PTP BVCI */ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bts_ctx *bctx) + struct bssgp_bvc_ctx *bctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -405,7 +405,7 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, /* Receive a BSSGP PDU from a BSS on a SIGNALLING BVCI */ static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bts_ctx *bctx) + struct bssgp_bvc_ctx *bctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -494,7 +494,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; - struct bssgp_bts_ctx *bctx; + struct bssgp_bvc_ctx *bctx; uint8_t pdu_type = bgph->pdu_type; uint16_t ns_bvci = msgb_bvci(msg); int data_len; @@ -536,7 +536,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ int gprs_bssgp_tx_dl_ud(struct msgb *msg) { - struct bssgp_bts_ctx *bctx; + struct bssgp_bvc_ctx *bctx; struct bssgp_ud_hdr *budh; uint8_t llc_pdu_tlv_hdr_len = 2; uint8_t *llc_pdu_tlv, *qos_profile; From a78b9c270bc2082d0a3fa88d6d44b6c777a86799 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 17 May 2010 23:02:42 +0200 Subject: [PATCH 102/198] [GPRS] BSSGP: expose more internal structures / API --- openbsc/include/openbsc/gprs_bssgp.h | 29 ++++++++++++++++++++++++++ openbsc/src/gprs/gprs_bssgp.c | 31 ++++------------------------ 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index 8fdef811b..f2b94c4d7 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -149,6 +149,35 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg); /* gprs_bssgp.c */ +#define BVC_S_BLOCKED 0x0001 + +/* The per-BTS context that we keep on the SGSN side of the BSSGP link */ +struct bssgp_bvc_ctx { + struct llist_head list; + + /* parsed RA ID and Cell ID of the remote BTS */ + struct gprs_ra_id ra_id; + uint16_t cell_id; + + /* NSEI and BVCI of underlying Gb link. Together they + * uniquely identify a link to a BTS (5.4.4) */ + uint16_t bvci; + uint16_t nsei; + + uint32_t state; + + struct rate_ctr_group *ctrg; + + /* we might want to add this as a shortcut later, avoiding the NSVC + * lookup for every packet, similar to a routing cache */ + //struct gprs_nsvc *nsvc; +}; +extern struct llist_head bssgp_bvc_ctxts; +/* Find a BTS Context based on parsed RA ID and Cell ID */ +struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid); +/* Find a BTS context based on BVCI+NSEI tuple */ +struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei); + #include /* BSSGP-UL-UNITDATA.ind */ diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index f6b02bada..b9c3c7830 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -58,37 +58,14 @@ static const struct rate_ctr_group_desc bssgp_ctrg_desc = { .ctr_desc = bssgp_ctr_description, }; -#define BVC_S_BLOCKED 0x0001 - -/* The per-BTS context that we keep on the SGSN side of the BSSGP link */ -struct bssgp_bvc_ctx { - struct llist_head list; - - /* parsed RA ID and Cell ID of the remote BTS */ - struct gprs_ra_id ra_id; - uint16_t cell_id; - - /* NSEI and BVCI of underlying Gb link. Together they - * uniquely identify a link to a BTS (5.4.4) */ - uint16_t bvci; - uint16_t nsei; - - uint32_t state; - - struct rate_ctr_group *ctrg; - - /* we might want to add this as a shortcut later, avoiding the NSVC - * lookup for every packet, similar to a routing cache */ - //struct gprs_nsvc *nsvc; -}; -static LLIST_HEAD(bts_ctxts); +LLIST_HEAD(bssgp_bvc_ctxts); /* Find a BTS Context based on parsed RA ID and Cell ID */ struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) { struct bssgp_bvc_ctx *bctx; - llist_for_each_entry(bctx, &bts_ctxts, list) { + llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) { if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) && bctx->cell_id == cid) return bctx; @@ -101,7 +78,7 @@ struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) { struct bssgp_bvc_ctx *bctx; - llist_for_each_entry(bctx, &bts_ctxts, list) { + llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) { if (bctx->nsei == nsei && bctx->bvci == bvci) return bctx; } @@ -120,7 +97,7 @@ struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) /* FIXME: BVCI is not unique, only BVCI+NSEI ?!? */ ctx->ctrg = rate_ctr_group_alloc(ctx, &bssgp_ctrg_desc, bvci); - llist_add(&ctx->list, &bts_ctxts); + llist_add(&ctx->list, &bssgp_bvc_ctxts); return ctx; } From 16c8dbb65577bee5b1350ccce981bde6cd9e6281 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 17 May 2010 23:30:01 +0200 Subject: [PATCH 103/198] [GPRS] BSSGP: Introduce packet/byte counters --- openbsc/src/gprs/gprs_bssgp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index b9c3c7830..304fb5e21 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -42,11 +42,19 @@ void *bssgp_tall_ctx = NULL; #define BVC_F_BLOCKED 0x0001 enum bssgp_ctr { + BSSGP_CTR_PKTS_IN, + BSSGP_CTR_PKTS_OUT, + BSSGP_CTR_BYTES_IN, + BSSGP_CTR_BYTES_OUT, BSSGP_CTR_BLOCKED, BSSGP_CTR_DISCARDED, }; static const struct rate_ctr_desc bssgp_ctr_description[] = { + { "packets.in", "Packets at BSSGP Level ( In)" }, + { "packets.out","Packets at BSSGP Level (Out)" }, + { "bytes.in", "Bytes at BSSGP Level ( In)" }, + { "bytes.out", "Bytes at BSSGP Level (Out)" }, { "blocked", "BVC Blocking count" }, { "discarded", "BVC LLC Discarded count" }, }; @@ -499,6 +507,12 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg); } + if (bctx) { + rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_IN]); + rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_IN], + msgb_bssgp_len(msg)); + } + if (ns_bvci == 1) rc = gprs_bssgp_rx_sign(msg, &tp, bctx); else if (ns_bvci == 2) @@ -562,6 +576,9 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; + rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_OUT]); + rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_OUT], msg->len); + /* Identifiers down: BVCI, NSEI (in msgb->cb) */ return gprs_ns_sendmsg(bssgp_nsi, msg); From 4e5721d02b377fc2e85d858cb2933319eb37b6c8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 17 May 2010 23:41:43 +0200 Subject: [PATCH 104/198] [GPRS] BSSGP: Add VTY for configuration and inpection This also includes log filtering based on NSEI/BVCI tuple --- openbsc/src/gprs/gprs_bssgp.c | 4 + openbsc/src/gprs/gprs_bssgp_vty.c | 177 ++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 openbsc/src/gprs/gprs_bssgp_vty.c diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 304fb5e21..0bc243ba4 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -18,6 +18,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * TODO: + * o properly count incoming BVC-RESET packets in counter group + * o set log context as early as possible for outgoing packets */ #include @@ -508,6 +511,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) } if (bctx) { + log_set_context(BSC_CTX_BVC, bctx); rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_IN]); rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_IN], msgb_bssgp_len(msg)); diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c new file mode 100644 index 000000000..a424038d9 --- /dev/null +++ b/openbsc/src/gprs/gprs_bssgp_vty.c @@ -0,0 +1,177 @@ +/* VTY interface for our GPRS BSS Gateway Protocol (BSSGP) implementation */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* FIXME: this should go to some common file as it is copied + * in vty_interface.c of the BSC */ +static const struct value_string gprs_bssgp_timer_strs[] = { + { 0, NULL } +}; + +static struct cmd_node bssgp_node = { + BSSGP_NODE, + "%s(bssgp)#", + 1, +}; + +static int config_write_bssgp(struct vty *vty) +{ + vty_out(vty, "bssgp%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_bssgp, cfg_bssgp_cmd, + "bssgp", + "Configure the GPRS BSS Gateway Protocol") +{ + vty->node = BSSGP_NODE; + return CMD_SUCCESS; +} + +static void dump_bvc(struct vty *vty, struct bssgp_bvc_ctx *bvc, int stats) +{ + vty_out(vty, "NSEI %5u, BVCI %5u, RA-ID: %u-%u-%u-%u, CID: %u, " + "STATE: %s%s", bvc->bvci, bvc->nsei, bvc->bvci, bvc->ra_id.mcc, + bvc->ra_id.mnc, bvc->ra_id.lac, bvc->ra_id.rac, bvc->cell_id, + bvc->state & BVC_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", + VTY_NEWLINE); + if (stats) + vty_out_rate_ctr_group(vty, " ", bvc->ctrg); +} + +static void dump_bssgp(struct vty *vty, int stats) +{ + struct bssgp_bvc_ctx *bvc; + + llist_for_each_entry(bvc, &bssgp_bvc_ctxts, list) { + dump_bvc(vty, bvc, stats); + } +} + +#define BSSGP_STR "Show information about the BSSGP protocol\n" + +DEFUN(show_bssgp, show_bssgp_cmd, "show bssgp", + SHOW_STR BSSGP_STR) +{ + dump_bssgp(vty, 0); + return CMD_SUCCESS; +} + +DEFUN(show_bssgp_stats, show_bssgp_stats_cmd, "show bssgp stats", + SHOW_STR BSSGP_STR + "Include statistics\n") +{ + dump_bssgp(vty, 1); + return CMD_SUCCESS; +} + +DEFUN(show_bvc, show_bvc_cmd, "show bssgp nsei <0-65535> [stats]", + SHOW_STR BSSGP_STR + "Show all BVCSE by its NSE Identifier\n" + "The NSEI\n" "Include Statistics\n") +{ + struct bssgp_bvc_ctx *bvc; + uint16_t nsei = atoi(argv[1]); + int show_stats = 0; + + if (argc >= 2) + show_stats = 1; + + llist_for_each_entry(bvc, &bssgp_bvc_ctxts, list) { + if (bvc->nsei != nsei) + continue; + dump_bvc(vty, bvc, show_stats); + } + + return CMD_SUCCESS; +} + +DEFUN(logging_fltr_bvc, + logging_fltr_bvc_cmd, + "logging filter bvc nsei <0-65535> bvci <0-65535>", + LOGGING_STR FILTER_STR + "Filter based on BSSGP Virtual Connection\n" + "NSEI of the BVC to be filtered\n" + "Network Service Entity Identifier (NSEI)\n" + "BVCI of the BVC to be filtered\n" + "BSSGP Virtual Connection Identifier (BVCI)\n") +{ + struct telnet_connection *conn; + struct bssgp_bvc_ctx *bvc; + uint16_t nsei = atoi(argv[0]); + uint16_t bvci = atoi(argv[1]); + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bvc = btsctx_by_bvci_nsei(bvci, nsei); + if (!bvc) { + vty_out(vty, "No BVC by that identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + log_set_bvc_filter(conn->dbg, bvc); + return CMD_SUCCESS; +} + +int gprs_bssgp_vty_init(void) +{ + install_element_ve(&show_bssgp_cmd); + install_element_ve(&show_bssgp_stats_cmd); + install_element_ve(&show_bvc_cmd); + install_element_ve(&logging_fltr_bvc_cmd); + + install_element(CONFIG_NODE, &cfg_bssgp_cmd); + install_node(&bssgp_node, config_write_bssgp); + install_default(BSSGP_NODE); + install_element(BSSGP_NODE, &ournode_exit_cmd); + install_element(BSSGP_NODE, &ournode_end_cmd); + //install_element(BSSGP_NODE, &cfg_bssgp_timer_cmd); + + return 0; +} From fdc73884d09c7679aa2e63359b791db46793db68 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 18 May 2010 08:02:36 +0200 Subject: [PATCH 105/198] [GPRS] SGSN: Activate BSSGP VTY functions --- openbsc/include/openbsc/gprs_bssgp.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index f2b94c4d7..4afe811c9 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -194,4 +194,7 @@ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); } +/* gprs_bssgp_vty.c */ +int gprs_bssgp_vty_init(void); + #endif /* _GPRS_BSSGP_H */ From 61c07842f2a12dfbde27b2c60b3a3c87934601ba Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 18 May 2010 11:57:08 +0200 Subject: [PATCH 106/198] [GPRS] BSSGP: Use correct values for SIGNALLING and PTM BVCI --- openbsc/include/openbsc/gprs_bssgp.h | 4 ++++ openbsc/src/gprs/gprs_bssgp.c | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index 4afe811c9..90b945aba 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -3,6 +3,10 @@ #include +/* Section 5.4.1 */ +#define BVCI_SIGNALLING 0x0000 +#define BVCI_PTM 0x0001 + /* Section 11.3.26 / Table 11.27 */ enum bssgp_pdu_type { /* PDUs between RL and BSSGP SAPs */ diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 0bc243ba4..d5ff44d87 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -186,7 +186,7 @@ static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) struct bssgp_bvc_ctx *ptp_ctx; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - if (bvci == 0) { + if (bvci == BVCI_SIGNALLING) { /* 8.3.2: Signalling BVC shall never be blocked */ LOGP(DBSSGP, LOGL_ERROR, "NSEI=%u/BVCI=%u " "received block for signalling BVC!?!\n", @@ -216,7 +216,7 @@ static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) struct bssgp_bvc_ctx *ptp_ctx; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - if (bvci == 0) { + if (bvci == BVCI_SIGNALLING) { /* 8.3.2: Signalling BVC shall never be blocked */ LOGP(DBSSGP, LOGL_ERROR, "NSEI=%u/BVCI=%u " "received unblock for signalling BVC!?!\n", @@ -517,9 +517,9 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) msgb_bssgp_len(msg)); } - if (ns_bvci == 1) + if (ns_bvci == BVCI_SIGNALLING) rc = gprs_bssgp_rx_sign(msg, &tp, bctx); - else if (ns_bvci == 2) + else if (ns_bvci == BVCI_PTM) rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); else rc = gprs_bssgp_rx_ptp(msg, &tp, bctx); @@ -542,7 +542,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) uint16_t nsei = msgb_nsei(msg); /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ - if (bvci < 2) { + if (bvci <= BVCI_PTM ) { LOGP(DBSSGP, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", bvci); return -EINVAL; From bf03d90d98d4549d0c8989001cf12f931afd9b07 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 18 May 2010 12:00:55 +0200 Subject: [PATCH 107/198] [GPRS] BSSG: Fix Vty printing of BVC --- openbsc/src/gprs/gprs_bssgp_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c index a424038d9..8377c56e8 100644 --- a/openbsc/src/gprs/gprs_bssgp_vty.c +++ b/openbsc/src/gprs/gprs_bssgp_vty.c @@ -73,7 +73,7 @@ DEFUN(cfg_bssgp, cfg_bssgp_cmd, static void dump_bvc(struct vty *vty, struct bssgp_bvc_ctx *bvc, int stats) { vty_out(vty, "NSEI %5u, BVCI %5u, RA-ID: %u-%u-%u-%u, CID: %u, " - "STATE: %s%s", bvc->bvci, bvc->nsei, bvc->bvci, bvc->ra_id.mcc, + "STATE: %s%s", bvc->nsei, bvc->bvci, bvc->ra_id.mcc, bvc->ra_id.mnc, bvc->ra_id.lac, bvc->ra_id.rac, bvc->cell_id, bvc->state & BVC_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", VTY_NEWLINE); From e0c42d1a3b2995ed313d8b505abd0b85aea0b895 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 18 May 2010 14:32:29 +0200 Subject: [PATCH 108/198] [GPRS] SGSN: properly delete a PDP context after receiving PDP CTX DEACT REQ --- openbsc/src/gprs/gprs_ns.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 7b1b13871..6d028aba1 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -667,9 +667,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc->nsvci = nsvc->nsei = 0xfffe; nsvc->ip.bts_addr = *saddr; nsvc->state = NSE_S_ALIVE; +#if 0 + return gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE); +#else return gprs_ns_tx_status(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE, 0, msg); +#endif } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); From b3ee265b69aef02b702baa45dee0d48723261398 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 14:38:50 +0200 Subject: [PATCH 109/198] [GPRS] Add Frame Relay in GRE encapsulation for NS --- openbsc/include/openbsc/gprs_ns.h | 39 +++--- openbsc/src/gprs/gprs_ns.c | 26 ++-- openbsc/src/gprs/gprs_ns_frgre.c | 222 ++++++++++++++++++++++++++++++ openbsc/src/gprs/gprs_ns_vty.c | 82 ++++++++++- 4 files changed, 336 insertions(+), 33 deletions(-) create mode 100644 openbsc/src/gprs/gprs_ns_frgre.c diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 08519f244..319ff3d3a 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -107,6 +107,7 @@ enum ns_timeout { enum gprs_ns_ll { GPRS_NS_LL_UDP, GPRS_NS_LL_E1, + GPRS_NS_LL_FR_GRE, }; enum gprs_ns_evt { @@ -130,15 +131,14 @@ struct gprs_ns_inst { uint16_t timeout[NS_TIMERS_COUNT]; - /* which link-layer are we based on? */ - enum gprs_ns_ll ll; - - union { - /* NS-over-IP specific bits */ - struct { - struct bsc_fd fd; - } nsip; - }; + /* NS-over-IP specific bits */ + struct { + struct bsc_fd fd; + } nsip; + /* NS-over-FR-over-GRE-over-IP specific bits */ + struct { + struct bsc_fd fd; + } frgre; }; enum nsvc_timer_mode { @@ -168,10 +168,16 @@ struct gprs_nsvc { struct rate_ctr_group *ctrg; + /* which link-layer are we based on? */ + enum gprs_ns_ll ll; + union { struct { struct sockaddr_in bts_addr; } ip; + struct { + struct sockaddr_in bts_addr; + } frgre; }; }; @@ -181,15 +187,11 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); /* Destroy a NS protocol instance */ void gprs_ns_destroy(struct gprs_ns_inst *nsi); -/* Listen for incoming GPRS packets */ -int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); +/* Listen for incoming GPRS packets via NS/UDP */ +int nsip_listen(struct gprs_ns_inst *nsi, uint32_t ip, uint16_t udp_port); struct sockaddr_in; -/* main entry point, here incoming NS frames enter */ -int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, - struct sockaddr_in *saddr); - /* main function for higher layers (BSSGP) to send NS messages */ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); @@ -197,8 +199,8 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause); int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause); int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc); -/* Listen for incoming GPRS packets */ -int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); +/* Listen for incoming GPRS packets via NS/FR/GRE */ +int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi, uint32_t ip); /* Establish a connection (from the BSS) to the SGSN */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, @@ -216,4 +218,7 @@ int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); /* Add NS-specific VTY stuff */ int gprs_ns_vty_init(struct gprs_ns_inst *nsi); +#define NS_ALLOC_SIZE 1024 + + #endif diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 6d028aba1..4ef3603a3 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -70,8 +70,6 @@ #include #include -#define NS_ALLOC_SIZE 1024 - static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -204,6 +202,7 @@ const char *gprs_ns_cause_str(enum ns_cause cause) } static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); +extern int grps_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) { @@ -215,12 +214,15 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]); rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_l2len(msg)); - switch (nsvc->nsi->ll) { + switch (nsvc->ll) { case GPRS_NS_LL_UDP: ret = nsip_sendmsg(nsvc, msg); break; + case GPRS_NS_LL_FR_GRE: + ret = gprs_ns_frgre_sendmsg(nsvc, msg); + break; default: - LOGP(DNS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); + LOGP(DNS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->ll); msgb_free(msg); ret = -EIO; break; @@ -644,7 +646,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) /* main entry point, here incoming NS frames enter */ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, - struct sockaddr_in *saddr) + struct sockaddr_in *saddr, enum gprs_ns_ll ll) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct gprs_nsvc *nsvc; @@ -667,6 +669,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc->nsvci = nsvc->nsei = 0xfffe; nsvc->ip.bts_addr = *saddr; nsvc->state = NSE_S_ALIVE; + nsvc->ll = ll; #if 0 return gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE); #else @@ -691,6 +694,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc = nsvc_by_nsei(nsi, nsei); if (!nsvc) { nsvc = nsvc_create(nsi, 0xffff); + nsvc->ll = ll; log_set_context(BSC_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); @@ -858,7 +862,7 @@ static int handle_nsip_read(struct bsc_fd *bfd) if (!msg) return error; - error = gprs_ns_rcvmsg(nsi, msg, &saddr); + error = gprs_ns_rcvmsg(nsi, msg, &saddr, GPRS_NS_LL_UDP); msgb_free(msg); @@ -871,7 +875,7 @@ static int handle_nsip_write(struct bsc_fd *bfd) return -EIO; } -int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) +static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) { int rc; struct gprs_ns_inst *nsi = nsvc->nsi; @@ -898,19 +902,15 @@ static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) return rc; } -extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port, - int (*cb)(struct bsc_fd *fd, unsigned int what)); - /* Listen for incoming GPRS packets */ -int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) +int nsip_listen(struct gprs_ns_inst *nsi, uint32_t ip, uint16_t udp_port) { int ret; - ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, udp_port, nsip_fd_cb); + ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, ip, udp_port, nsip_fd_cb); if (ret < 0) return ret; - nsi->ll = GPRS_NS_LL_UDP; nsi->nsip.fd.data = nsi; return ret; diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c new file mode 100644 index 000000000..d58c1d9da --- /dev/null +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -0,0 +1,222 @@ +/* GPRS Networks Service (NS) messages on the Gb interface + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ + +/* NS-over-FR-over-GRE implementation */ + +/* (C) 2009-2010 by Harald Welte + * + * 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 +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define GRE_PTYPE_FR 0x6559 + +struct gre_hdr { + uint16_t flags; + uint16_t ptype; +} __attribute__ ((packed)); + +static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, + struct sockaddr_in *saddr) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx"); + int ret = 0; + socklen_t saddr_len = sizeof(*saddr); + struct gre_hdr *greh; + uint8_t *frh; + uint32_t dlci; + + if (!msg) { + *error = -ENOMEM; + return NULL; + } + + ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, + (struct sockaddr *)saddr, &saddr_len); + if (ret < 0) { + LOGP(DNS, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n", + strerror(errno)); + *error = ret; + return NULL; + } else if (ret == 0) { + msgb_free(msg); + *error = ret; + return NULL; + } + + msgb_put(msg, ret); + + if (msg->len < sizeof(*greh)) { + LOGP(DNS, LOGL_ERROR, "Short GRE packet: %u bytes\n", msg->len); + *error = -EIO; + goto out_err; + } + + greh = (struct gre_hdr *) msg->data; + if (greh->flags) { + LOGP(DNS, LOGL_NOTICE, "Unknown GRE flags 0x%04x\n", + ntohs(greh->flags)); + } + if (greh->ptype != htons(GRE_PTYPE_FR)) { + LOGP(DNS, LOGL_NOTICE, "Unknown GRE protocol 0x%04x != FR\n", + ntohs(greh->ptype)); + *error = -EIO; + goto out_err; + } + + if (msg->len < sizeof(*greh) + 2) { + LOGP(DNS, LOGL_ERROR, "Short FR header: %u bytes\n", msg->len); + *error = -EIO; + goto out_err; + } + + frh = msg->data + sizeof(*greh); + if (frh[0] & 0x01) { + LOGP(DNS, LOGL_NOTICE, "Unsupported single-byte FR address\n"); + *error = -EIO; + goto out_err; + } + dlci = (frh[0] & 0xfc << 2); + if ((frh[1] & 0x0f) != 0x01) { + LOGP(DNS, LOGL_NOTICE, "Unknown second FR octet 0x%02x\n", + frh[1]); + *error = -EIO; + goto out_err; + } + dlci |= frh[1] >> 4; + if (dlci > 0xffff) { + LOGP(DNS, LOGL_ERROR, "We don't support DLCI > 65535 (%u)\n", + dlci); + *error = -EINVAL; + goto out_err; + } + + msg->l2h = msg->data + sizeof(*greh) + 2; + + /* Store DLCI in NETWORK BYTEORDER in sockaddr port member */ + saddr->sin_port = htons(dlci & 0xffff); + + return msg; + +out_err: + msgb_free(msg); + return NULL; +} + +int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, + struct sockaddr_in *saddr, enum gprs_ns_ll ll); + +static int handle_nsfrgre_read(struct bsc_fd *bfd) +{ + int error; + struct sockaddr_in saddr; + struct gprs_ns_inst *nsi = bfd->data; + struct msgb *msg = read_nsfrgre_msg(bfd, &error, &saddr); + + if (!msg) + return error; + + error = gprs_ns_rcvmsg(nsi, msg, &saddr, GPRS_NS_LL_FR_GRE); + + msgb_free(msg); + + return error; +} + +static int handle_nsfrgre_write(struct bsc_fd *bfd) +{ + /* FIXME: actually send the data here instead of nsip_sendmsg() */ + return -EIO; +} + +int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + int rc; + struct gprs_ns_inst *nsi = nsvc->nsi; + struct sockaddr_in daddr; + uint16_t dlci = ntohs(nsvc->frgre.bts_addr.sin_port); + uint8_t *frh; + struct gre_hdr *greh; + + /* Build socket address for the packet destionation */ + daddr.sin_addr = nsvc->frgre.bts_addr.sin_addr; + daddr.sin_port = IPPROTO_GRE; + + /* Prepend the FR header */ + frh = msgb_push(msg, sizeof(frh)); + frh[0] = (dlci >> 2) & 0xfc; + frh[1] = (dlci & 0xf0) | 0x01; + + /* Prepend the GRE header */ + greh = (struct gre_hdr *) msgb_push(msg, sizeof(*greh)); + greh->flags = 0; + greh->ptype = GRE_PTYPE_FR; + + rc = sendto(nsi->frgre.fd.fd, msg->data, msg->len, 0, + (struct sockaddr *)&daddr, sizeof(daddr)); + + talloc_free(msg); + + return rc; +} + +static int nsfrgre_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) + rc = handle_nsfrgre_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_nsfrgre_write(bfd); + + return rc; +} + +int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi, uint32_t ip) +{ + int rc; + + /* Make sure we close any existing socket before changing it */ + if (nsi->frgre.fd.fd) + close(nsi->frgre.fd.fd); + + rc = make_sock(&nsi->frgre.fd, IPPROTO_GRE, ip, 0, nsfrgre_fd_cb); + if (rc < 0) { + LOGP(DNS, LOGL_ERROR, "Error creating GRE socket (%s)\n", + strerror(errno)); + return rc; + } + nsi->frgre.fd.data = nsi; + + return rc; +} diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index c20016aa5..7d439445a 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -79,7 +79,10 @@ static int config_write_ns(struct vty *vty) vty_out(vty, " nse %u remote-role %s%s", nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss", VTY_NEWLINE); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) { + switch (nsvc->ll) { + case GPRS_NS_LL_UDP: + vty_out(vty, " nse %u encapsulation udp%s", nsvc->nsei, + VTY_NEWLINE); vty_out(vty, " nse %u remote-ip %s%s", nsvc->nsei, inet_ntoa(nsvc->ip.bts_addr.sin_addr), @@ -87,6 +90,19 @@ static int config_write_ns(struct vty *vty) vty_out(vty, " nse %u remote-port %u%s", nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + break; + case GPRS_NS_LL_FR_GRE: + vty_out(vty, " nse %u encapsulation framerelay-gre%s", + nsvc->nsei, VTY_NEWLINE); + vty_out(vty, " nse %u remote-ip %s%s", + nsvc->nsei, + inet_ntoa(nsvc->frgre.bts_addr.sin_addr), + VTY_NEWLINE); + vty_out(vty, " nse %u fr-dlci %u%s", + nsvc->nsei, ntohs(nsvc->frgre.bts_addr.sin_port), + VTY_NEWLINE); + default: + break; } } @@ -113,8 +129,9 @@ static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats) nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, ", %15s:%u", + if (nsvc->ll == GPRS_NS_LL_UDP || nsvc->ll == GPRS_NS_LL_FR_GRE) + vty_out(vty, ", %s %15s:%u", + nsvc->ll == GPRS_NS_LL_UDP ? "UDP" : "FR-GRE", inet_ntoa(nsvc->ip.bts_addr.sin_addr), ntohs(nsvc->ip.bts_addr.sin_port)); vty_out(vty, "%s", VTY_NEWLINE); @@ -243,11 +260,68 @@ DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, return CMD_WARNING; } + if (nsvc->ll != GPRS_NS_LL_UDP) { + vty_out(vty, "Cannot set UDP Port on non-UDP NSE%s", + VTY_NEWLINE); + return CMD_WARNING; + } + nsvc->ip.bts_addr.sin_port = htons(port); return CMD_SUCCESS; } +DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd, + "nse <0-65535> fr-dlci <0-1023>", + NSE_CMD_STR + "Frame Relay DLCI\n" + "Frame Relay DLCI Number\n") +{ + uint16_t nsei = atoi(argv[0]); + uint16_t dlci = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + if (nsvc->ll != GPRS_NS_LL_FR_GRE) { + vty_out(vty, "Cannot set FR DLCI on non-FR NSE%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc->frgre.bts_addr.sin_port = htons(dlci); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_encaps, cfg_nse_encaps_cmd, + "nse <0-65535> encapsulation (udp|framerelay-gre)", + NSE_CMD_STR + "Encapsulation for NS\n" + "UDP/IP Encapsulation\n" "Frame-Relay/GRE/IP Encapsulation\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[1], "udp")) + nsvc->ll = GPRS_NS_LL_UDP; + else + nsvc->ll = GPRS_NS_LL_FR_GRE; + + return CMD_SUCCESS; +} + + DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, "nse <0-65535> remote-role (sgsn|bss)", NSE_CMD_STR @@ -393,6 +467,8 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(NS_NODE, &cfg_nse_nsvci_cmd); install_element(NS_NODE, &cfg_nse_remoteip_cmd); install_element(NS_NODE, &cfg_nse_remoteport_cmd); + install_element(NS_NODE, &cfg_nse_fr_dlci_cmd); + install_element(NS_NODE, &cfg_nse_encaps_cmd); install_element(NS_NODE, &cfg_nse_remoterole_cmd); install_element(NS_NODE, &cfg_no_nse_cmd); install_element(NS_NODE, &cfg_ns_timer_cmd); From 7fb05234a7bd8c16eba2cad3074411f86b104c20 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 15:09:09 +0200 Subject: [PATCH 110/198] [GPRS] NS: VTY: Move all local ip/port bind values into 'ns' node This removes the requirement for gb_proxy and sgsn to have duplicate vty parsing code --- openbsc/include/openbsc/gprs_ns.h | 8 ++- openbsc/src/gprs/gprs_ns.c | 5 +- openbsc/src/gprs/gprs_ns_frgre.c | 8 ++- openbsc/src/gprs/gprs_ns_vty.c | 89 +++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 319ff3d3a..1ec663160 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -134,10 +134,14 @@ struct gprs_ns_inst { /* NS-over-IP specific bits */ struct { struct bsc_fd fd; + uint32_t local_ip; + uint16_t local_port; } nsip; /* NS-over-FR-over-GRE-over-IP specific bits */ struct { struct bsc_fd fd; + uint32_t local_ip; + int enabled:1; } frgre; }; @@ -188,7 +192,7 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); void gprs_ns_destroy(struct gprs_ns_inst *nsi); /* Listen for incoming GPRS packets via NS/UDP */ -int nsip_listen(struct gprs_ns_inst *nsi, uint32_t ip, uint16_t udp_port); +int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi); struct sockaddr_in; @@ -200,7 +204,7 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause); int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc); /* Listen for incoming GPRS packets via NS/FR/GRE */ -int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi, uint32_t ip); +int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi); /* Establish a connection (from the BSS) to the SGSN */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 4ef3603a3..8b226b89e 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -903,11 +903,12 @@ static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) } /* Listen for incoming GPRS packets */ -int nsip_listen(struct gprs_ns_inst *nsi, uint32_t ip, uint16_t udp_port) +int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi) { int ret; - ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, ip, udp_port, nsip_fd_cb); + ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, nsi->nsip.local_ip, + nsi->nsip.local_port, nsip_fd_cb); if (ret < 0) return ret; diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index d58c1d9da..979442b81 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -202,7 +202,7 @@ static int nsfrgre_fd_cb(struct bsc_fd *bfd, unsigned int what) return rc; } -int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi, uint32_t ip) +int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi) { int rc; @@ -210,7 +210,11 @@ int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi, uint32_t ip) if (nsi->frgre.fd.fd) close(nsi->frgre.fd.fd); - rc = make_sock(&nsi->frgre.fd, IPPROTO_GRE, ip, 0, nsfrgre_fd_cb); + if (!nsi->frgre.enabled) + return 0; + + rc = make_sock(&nsi->frgre.fd, IPPROTO_GRE, nsi->frgre.local_ip, + 0, nsfrgre_fd_cb); if (rc < 0) { LOGP(DNS, LOGL_ERROR, "Error creating GRE socket (%s)\n", strerror(errno)); diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 7d439445a..1922b0243 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -68,6 +68,7 @@ static int config_write_ns(struct vty *vty) { struct gprs_nsvc *nsvc; unsigned int i; + struct in_addr ia; vty_out(vty, "ns%s", VTY_NEWLINE); @@ -111,6 +112,21 @@ static int config_write_ns(struct vty *vty) get_value_string(gprs_ns_timer_strs, i), vty_nsi->timeout[i], VTY_NEWLINE); + if (vty_nsi->nsip.local_ip) { + ia.s_addr = htonl(vty_nsi->nsip.local_ip); + vty_out(vty, " encapsulation udp local-ip %s%s", + inet_ntoa(ia), VTY_NEWLINE); + vty_out(vty, " encapsulation udp local-port %u%s", + vty_nsi->nsip.local_port); + } + vty_out(vty, " encapsulation framerelay-gre enabled %u%s", + vty_nsi->frgre.enabled ? 1 : 0, VTY_NEWLINE); + if (vty_nsi->frgre.enabled) { + ia.s_addr = htonl(vty_nsi->frgre.local_ip); + vty_out(vty, " encapsulation framerelay-gre local-ip %s%s", + inet_ntoa(ia), VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -142,6 +158,15 @@ static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats) static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) { struct gprs_nsvc *nsvc; + struct in_addr ia; + + ia.s_addr = htonl(vty_nsi->nsip.local_ip); + vty_out(vty, "NS-UDP-IP Encapsulation: Local IP: %s, UDP Port: %u%s", + inet_ntoa(ia), vty_nsi->nsip.local_port, VTY_NEWLINE); + + ia.s_addr = htonl(vty_nsi->frgre.local_ip); + vty_out(vty, "NS-FR-GRE-IP Encapsulation: Local IP: %s%s", + inet_ntoa(ia), VTY_NEWLINE); llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { if (nsvc == nsi->unknown_nsvc) @@ -387,6 +412,66 @@ DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, return CMD_SUCCESS; } +#define ENCAPS_STR "NS encapsulation options\n" + +DEFUN(cfg_nsip_local_ip, cfg_nsip_local_ip_cmd, + "encapsulation udp local-ip A.B.C.D", + ENCAPS_STR "NS over UDP Encapsulation\n" + "Set the IP address on which we listen for NS/UDP\n" + "IP Address\n") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + vty_nsi->nsip.local_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_local_port, cfg_nsip_local_port_cmd, + "encapsulation udp local-port <0-65535>", + ENCAPS_STR "NS over UDP Encapsulation\n" + "Set the UDP port on which we listen for NS/UDP\n" + "UDP port number\n") +{ + unsigned int port = atoi(argv[0]); + + vty_nsi->nsip.local_port = port; + + return CMD_SUCCESS; +} + +DEFUN(cfg_frgre_local_ip, cfg_frgre_local_ip_cmd, + "encapsulation framerelay-gre local-ip A.B.C.D", + ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n" + "Set the IP address on which we listen for NS/FR/GRE\n" + "IP Address\n") +{ + struct in_addr ia; + + if (!vty_nsi->frgre.enabled) { + vty_out(vty, "FR/GRE is not enabled%s", VTY_NEWLINE); + return CMD_WARNING; + } + inet_aton(argv[0], &ia); + vty_nsi->frgre.local_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd, + "encapsulation framerelay-gre enabled (1|0)", + ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n" + "Enable or disable Frame Relay over GRE\n" + "Enable\n" "Disable\n") +{ + int enabled = atoi(argv[0]); + + vty_nsi->frgre.enabled = enabled; + + return CMD_SUCCESS; +} + DEFUN(nsvc_nsei, nsvc_nsei_cmd, "nsvc nsei <0-65535> (block|unblock|reset)", "Perform an operation on a NSVC\n" @@ -472,6 +557,10 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(NS_NODE, &cfg_nse_remoterole_cmd); install_element(NS_NODE, &cfg_no_nse_cmd); install_element(NS_NODE, &cfg_ns_timer_cmd); + install_element(NS_NODE, &cfg_nsip_local_ip_cmd); + install_element(NS_NODE, &cfg_nsip_local_port_cmd); + install_element(NS_NODE, &cfg_frgre_enable_cmd); + install_element(NS_NODE, &cfg_frgre_local_ip_cmd); install_element(ENABLE_NODE, &nsvc_nsei_cmd); From ac914b87780f1d0090b1d49733b271bb4bd7ef06 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 15:37:34 +0200 Subject: [PATCH 111/198] [GPRS] NS: FR/GRE: Use AF_INET, correctly encode FR DLCI and GRE payload type --- openbsc/src/gprs/gprs_ns_frgre.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index 979442b81..7367b6a6d 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -169,18 +169,19 @@ int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) struct gre_hdr *greh; /* Build socket address for the packet destionation */ + daddr.sin_family = AF_INET; daddr.sin_addr = nsvc->frgre.bts_addr.sin_addr; daddr.sin_port = IPPROTO_GRE; /* Prepend the FR header */ - frh = msgb_push(msg, sizeof(frh)); + frh = msgb_push(msg, 2); frh[0] = (dlci >> 2) & 0xfc; - frh[1] = (dlci & 0xf0) | 0x01; + frh[1] = ((dlci & 0xf)<<4) | 0x01; /* Prepend the GRE header */ greh = (struct gre_hdr *) msgb_push(msg, sizeof(*greh)); greh->flags = 0; - greh->ptype = GRE_PTYPE_FR; + greh->ptype = htons(GRE_PTYPE_FR); rc = sendto(nsi->frgre.fd.fd, msg->data, msg->len, 0, (struct sockaddr *)&daddr, sizeof(daddr)); From ba4c666a9f50efeaabb546629de320bdeb134500 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 15:38:10 +0200 Subject: [PATCH 112/198] [GPRS] NS: Make sure we allocate NS packet with headroom for FR/GRE --- openbsc/include/openbsc/gprs_ns.h | 6 +++++- openbsc/src/gprs/gprs_ns.c | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 1ec663160..03603bc82 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -223,6 +223,10 @@ int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); int gprs_ns_vty_init(struct gprs_ns_inst *nsi); #define NS_ALLOC_SIZE 1024 - +#define NS_ALLOC_HEADROOM 20 +static inline struct msgb *gprs_ns_msgb_alloc(void) +{ + return msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "GPRS/NS"); +} #endif diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 8b226b89e..9d0766c6d 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -232,7 +232,7 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) { - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct msgb *msg = gprs_ns_msgb_alloc(); struct gprs_ns_hdr *nsh; log_set_context(BSC_CTX_NSVC, nsvc); @@ -250,7 +250,7 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) { - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct msgb *msg = gprs_ns_msgb_alloc(); struct gprs_ns_hdr *nsh; uint16_t nsvci = htons(nsvc->nsvci); uint16_t nsei = htons(nsvc->nsei); @@ -278,7 +278,7 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, uint16_t bvci, struct msgb *orig_msg) { - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct msgb *msg = gprs_ns_msgb_alloc(); struct gprs_ns_hdr *nsh; uint16_t nsvci = htons(nsvc->nsvci); @@ -326,7 +326,7 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) { - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct msgb *msg = gprs_ns_msgb_alloc(); struct gprs_ns_hdr *nsh; uint16_t nsvci = htons(nsvc->nsvci); @@ -465,7 +465,7 @@ static void gprs_ns_timer_cb(void *data) /* Section 9.2.6 */ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) { - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct msgb *msg = gprs_ns_msgb_alloc(); struct gprs_ns_hdr *nsh; uint16_t nsvci, nsei; @@ -823,7 +823,7 @@ void gprs_ns_destroy(struct gprs_ns_inst *nsi) static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, struct sockaddr_in *saddr) { - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Abis/IP/GPRS-NS"); + struct msgb *msg = gprs_ns_msgb_alloc(); int ret = 0; socklen_t saddr_len = sizeof(*saddr); From b11226d77aa17bcc00177a7fcfddf9569db544fc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 15:46:49 +0200 Subject: [PATCH 113/198] [GPRS] NS/FR/GRE rcvmsg case: msgb_free() in error case --- openbsc/src/gprs/gprs_ns_frgre.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index 7367b6a6d..359c0f711 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -67,11 +67,10 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, LOGP(DNS, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n", strerror(errno)); *error = ret; - return NULL; + goto out_err; } else if (ret == 0) { - msgb_free(msg); *error = ret; - return NULL; + goto out_err; } msgb_put(msg, ret); From 6c4136e347b2053bd2fe849dc2ca7c2e7e4ada45 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 15:53:22 +0200 Subject: [PATCH 114/198] [GPRS] NS: SOCK_RAW sockets always provide the full IPv4 header on receive --- openbsc/src/gprs/gprs_ns_frgre.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index 359c0f711..baa7e5217 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -52,6 +53,7 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx"); int ret = 0; socklen_t saddr_len = sizeof(*saddr); + struct iphdr *iph; struct gre_hdr *greh; uint8_t *frh; uint32_t dlci; @@ -75,13 +77,20 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, msgb_put(msg, ret); - if (msg->len < sizeof(*greh)) { - LOGP(DNS, LOGL_ERROR, "Short GRE packet: %u bytes\n", msg->len); + if (msg->len < sizeof(*iph) + sizeof(*greh) + 2) { + LOGP(DNS, LOGL_ERROR, "Short IP packet: %u bytes\n", msg->len); *error = -EIO; goto out_err; } - greh = (struct gre_hdr *) msg->data; + iph = (struct iphdr *) msg->data; + if (msg->len < (iph->ihl*4 + sizeof(*greh) + 2)) { + LOGP(DNS, LOGL_ERROR, "Short IP packet: %u bytes\n", msg->len); + *error = -EIO; + goto out_err; + } + + greh = (struct gre_hdr *) (msg->data + iph->ihl*4); if (greh->flags) { LOGP(DNS, LOGL_NOTICE, "Unknown GRE flags 0x%04x\n", ntohs(greh->flags)); @@ -99,7 +108,7 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, goto out_err; } - frh = msg->data + sizeof(*greh); + frh = (uint8_t *)greh + sizeof(*greh); if (frh[0] & 0x01) { LOGP(DNS, LOGL_NOTICE, "Unsupported single-byte FR address\n"); *error = -EIO; @@ -120,7 +129,7 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, goto out_err; } - msg->l2h = msg->data + sizeof(*greh) + 2; + msg->l2h = frh+2; /* Store DLCI in NETWORK BYTEORDER in sockaddr port member */ saddr->sin_port = htons(dlci & 0xffff); From 1100a9d1fa38fbd931c7acfacdf1f2fa1d26627e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 16:01:39 +0200 Subject: [PATCH 115/198] [GPRS] NS: Never respond to STATUS with STATUS to prevent loops! --- openbsc/src/gprs/gprs_ns.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 9d0766c6d..04d17b8ed 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -657,6 +657,12 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (!nsvc) { struct tlv_parsed tp; uint16_t nsei; + if (nsh->pdu_type == NS_PDUT_STATUS) { + LOGP(DNS, LOGL_INFO, "Ignoring NS STATUS from %s:%u " + "for non-existing NS-VC\n", + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); + return 0; + } /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { /* Since we have no NSVC, we have to use a fake */ From 869aaa401de430933d12e6974b49f2dbfaafa886 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 16:48:12 +0200 Subject: [PATCH 116/198] [GPRS] NS: properly parse FR DLCI on Rx --- openbsc/src/gprs/gprs_ns_frgre.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index baa7e5217..94f937455 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -56,7 +56,7 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, struct iphdr *iph; struct gre_hdr *greh; uint8_t *frh; - uint32_t dlci; + uint16_t dlci; if (!msg) { *error = -ENOMEM; @@ -114,25 +114,19 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, *error = -EIO; goto out_err; } - dlci = (frh[0] & 0xfc << 2); + dlci = ((frh[0] & 0xfc) << 2); if ((frh[1] & 0x0f) != 0x01) { LOGP(DNS, LOGL_NOTICE, "Unknown second FR octet 0x%02x\n", frh[1]); *error = -EIO; goto out_err; } - dlci |= frh[1] >> 4; - if (dlci > 0xffff) { - LOGP(DNS, LOGL_ERROR, "We don't support DLCI > 65535 (%u)\n", - dlci); - *error = -EINVAL; - goto out_err; - } + dlci |= (frh[1] >> 4); msg->l2h = frh+2; /* Store DLCI in NETWORK BYTEORDER in sockaddr port member */ - saddr->sin_port = htons(dlci & 0xffff); + saddr->sin_port = htons(dlci); return msg; From ce4ccbc434e64f0c664bb1460cfa3bd6d663375b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 17:02:57 +0200 Subject: [PATCH 117/198] [GPRS] NS: Better formatting of VTY output --- openbsc/src/gprs/gprs_ns_vty.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 1922b0243..423ac205a 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -116,12 +116,14 @@ static int config_write_ns(struct vty *vty) ia.s_addr = htonl(vty_nsi->nsip.local_ip); vty_out(vty, " encapsulation udp local-ip %s%s", inet_ntoa(ia), VTY_NEWLINE); - vty_out(vty, " encapsulation udp local-port %u%s", - vty_nsi->nsip.local_port); } + if (vty_nsi->nsip.local_port) + vty_out(vty, " encapsulation udp local-port %u%s", + vty_nsi->nsip.local_port, VTY_NEWLINE); + vty_out(vty, " encapsulation framerelay-gre enabled %u%s", vty_nsi->frgre.enabled ? 1 : 0, VTY_NEWLINE); - if (vty_nsi->frgre.enabled) { + if (vty_nsi->frgre.local_ip) { ia.s_addr = htonl(vty_nsi->frgre.local_ip); vty_out(vty, " encapsulation framerelay-gre local-ip %s%s", inet_ntoa(ia), VTY_NEWLINE); @@ -147,7 +149,7 @@ static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats) nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); if (nsvc->ll == GPRS_NS_LL_UDP || nsvc->ll == GPRS_NS_LL_FR_GRE) vty_out(vty, ", %s %15s:%u", - nsvc->ll == GPRS_NS_LL_UDP ? "UDP" : "FR-GRE", + nsvc->ll == GPRS_NS_LL_UDP ? "UDP " : "FR-GRE", inet_ntoa(nsvc->ip.bts_addr.sin_addr), ntohs(nsvc->ip.bts_addr.sin_port)); vty_out(vty, "%s", VTY_NEWLINE); @@ -161,11 +163,11 @@ static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) struct in_addr ia; ia.s_addr = htonl(vty_nsi->nsip.local_ip); - vty_out(vty, "NS-UDP-IP Encapsulation: Local IP: %s, UDP Port: %u%s", + vty_out(vty, "Encapsulation NS-UDP-IP Local IP: %s, UDP Port: %u%s", inet_ntoa(ia), vty_nsi->nsip.local_port, VTY_NEWLINE); ia.s_addr = htonl(vty_nsi->frgre.local_ip); - vty_out(vty, "NS-FR-GRE-IP Encapsulation: Local IP: %s%s", + vty_out(vty, "Encapsulation NS-FR-GRE-IP Local IP: %s%s", inet_ntoa(ia), VTY_NEWLINE); llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { From b6eded84fedc625e3fc54f11be27199240bacc50 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 23 May 2010 21:11:19 +0800 Subject: [PATCH 118/198] gprs_bssgp.c: Cast const of TLVP_VAL away. Fix a compiler warning, we cast the const away at various other parts in the code as well. We should consider removing the const from the TLV struct.. --- openbsc/src/gprs/gprs_bssgp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index d5ff44d87..0d60ac9c1 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -256,8 +256,8 @@ static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); /* store pointer to LLC header and CELL ID in msgb->cb */ - msgb_llch(msg) = TLVP_VAL(tp, BSSGP_IE_LLC_PDU); - msgb_bcid(msg) = TLVP_VAL(tp, BSSGP_IE_CELL_ID); + msgb_llch(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU); + msgb_bcid(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_CELL_ID); return gprs_llc_rcvmsg(msg, tp); } From d30cefaac153377f55c57be31463633a233bb2b6 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 23 May 2010 21:12:15 +0800 Subject: [PATCH 119/198] gprs_bssgp.c: Return something from non void methods. In one use the rc variable we are assigning to, in the others return 0 even if we have a FIXME there. --- openbsc/src/gprs/gprs_bssgp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 0d60ac9c1..fa994514f 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -276,6 +276,7 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, /* FIXME: pass the SUSPEND request to GMM */ /* SEND SUSPEND_ACK or SUSPEND_NACK */ + return 0; } static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, @@ -293,6 +294,7 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, /* FIXME: pass the RESUME request to GMM */ /* SEND RESUME_ACK or RESUME_NACK */ + return 0; } static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, @@ -388,7 +390,7 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, break; } - + return rc; } /* Receive a BSSGP PDU from a BSS on a SIGNALLING BVCI */ From 5617d99388508dbb041c1af65a175cf2244e94bd Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 23 May 2010 21:18:01 +0800 Subject: [PATCH 120/198] gprs: Fix warnings on funny casts for the return statement Change gprs_nsvc_reset to return void instead of a int as the gb_proxy.c currently ignores the reutnr value anyway. Change the caller inside gprs_ns to return the newly allocated nsvc instead of the return of gprs_nsvc_reset. --- openbsc/include/openbsc/gprs_ns.h | 2 +- openbsc/src/gprs/gprs_ns.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 03603bc82..8b5e7dc31 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -217,7 +217,7 @@ struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci); /* Initiate a RESET procedure (including timer start, ...)*/ -int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); +void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); /* Add NS-specific VTY stuff */ int gprs_ns_vty_init(struct gprs_ns_inst *nsi); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 04d17b8ed..467e43ac5 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -924,7 +924,7 @@ int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi) } /* Initiate a RESET procedure */ -int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) +void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) { /* Mark NS-VC locally as blocked and dead */ nsvc->state = NSE_S_BLOCKED; @@ -935,8 +935,6 @@ int gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) } /* Start Tns-reset */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); - - return nsvc; } /* Establish a connection (from the BSS) to the SGSN */ @@ -954,5 +952,6 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->nsvci = nsvci; nsvc->remote_end_is_sgsn = 1; - return gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + return nsvc; } From e75a34faa57f345a081f7c8b87a7eb7ae631712a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 23 May 2010 21:19:55 +0800 Subject: [PATCH 121/198] gprs_ns.c: Make make_socket known to the compiler --- openbsc/src/gprs/gprs_ns.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 467e43ac5..4846b6473 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -69,6 +69,7 @@ #include #include #include +#include static const struct tlv_definition ns_att_tlvdef = { .def = { From ee59fe4a67bdd3c5224a980c55e00ef91115664e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 23 May 2010 21:23:44 +0800 Subject: [PATCH 122/198] gprs_ns_frgre.h: Create the header and include it --- openbsc/include/openbsc/gprs_ns_frgre.h | 6 ++++++ openbsc/src/gprs/gprs_ns.c | 1 + 2 files changed, 7 insertions(+) create mode 100644 openbsc/include/openbsc/gprs_ns_frgre.h diff --git a/openbsc/include/openbsc/gprs_ns_frgre.h b/openbsc/include/openbsc/gprs_ns_frgre.h new file mode 100644 index 000000000..abcd43ffb --- /dev/null +++ b/openbsc/include/openbsc/gprs_ns_frgre.h @@ -0,0 +1,6 @@ +#ifndef _GPRS_NS_FRGRE_H +#define _GPRS_NS_FRGRE_H + +int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); + +#endif diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 4846b6473..3d115c114 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -69,6 +69,7 @@ #include #include #include +#include #include static const struct tlv_definition ns_att_tlvdef = { From b1020d5135d5547d279f63516e837dec39a3aaed Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 25 May 2010 22:17:30 +0200 Subject: [PATCH 123/198] [GPRS] NS: Always generate LOG_INFO message when we block NS-VC --- openbsc/src/gprs/gprs_ns.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3d115c114..bf563cc60 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -149,6 +149,8 @@ struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; + LOGP(DNS, LOGL_INFO, "NSVCI=%u Creating NS-VC\n", nsvci); + nsvc = talloc_zero(nsi, struct gprs_nsvc); nsvc->nsvci = nsvci; /* before RESET procedure: BLOCKED and DEAD */ @@ -928,6 +930,9 @@ int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi) /* Initiate a RESET procedure */ void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) { + LOGP(DNS, LOGL_INFO, "NSEI=%u RESET procedure based on API request\n", + nsvc->nsei); + /* Mark NS-VC locally as blocked and dead */ nsvc->state = NSE_S_BLOCKED; /* Send NS-RESET PDU */ From ac1a715f0bab8729680268a8b2eca09b7888040c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 May 2010 19:45:32 +0200 Subject: [PATCH 124/198] Migrate VTY code to libosmovty --- openbsc/src/gprs/gprs_bssgp_vty.c | 7 ++++--- openbsc/src/gprs/gprs_ns_vty.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c index 8377c56e8..9da02abb3 100644 --- a/openbsc/src/gprs/gprs_bssgp_vty.c +++ b/openbsc/src/gprs/gprs_bssgp_vty.c @@ -37,11 +37,12 @@ #include #include #include -#include #include -#include -#include +#include +#include +#include +#include /* FIXME: this should go to some common file as it is copied * in vty_interface.c of the BSC */ diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 423ac205a..81346c6ef 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -37,11 +37,12 @@ #include #include #include -#include #include -#include -#include +#include +#include +#include +#include static struct gprs_ns_inst *vty_nsi = NULL; From 26c325151a7680d41d05a5df67fc4af3eb2b98e6 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 28 May 2010 03:25:36 +0800 Subject: [PATCH 125/198] gprs: Subtract the headroom for what we can receive The buffer got allocated with headroom and we need to subtract that from the size of the buffer. --- openbsc/src/gprs/gprs_ns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index bf563cc60..adb552478 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -842,7 +842,7 @@ static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, return NULL; } - ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, + ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0, (struct sockaddr *)saddr, &saddr_len); if (ret < 0) { LOGP(DNS, LOGL_ERROR, "recv error %s during NSIP recv\n", From c9531203265d082b6984fef0a10c4982cd331cc3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 28 May 2010 09:58:27 +0200 Subject: [PATCH 126/198] [GPRS] NS: Start TEST procedure, not ALIVE procedure, on RESET/RESET_ACK According to the spec, after an incoming RESET or RESET_ACK, we shall start the TEST procedure, not the ALIVE procedure. Also, when we start the TEST procedure, we have to always send a NS_ALIVE packet at the same time (we didn't in the case of incoming RESET). Furthermore, we now only start TIMER_TNS_ALIVE from within the TIMER_TNS_RESET callback code, where we also make sure that the alive_retries counter is reset to zero. --- openbsc/src/gprs/gprs_ns.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index adb552478..08a7c2952 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -610,7 +610,8 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvc->nsvci = ntohs(*nsvci); /* start the test procedure */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); /* inform interested parties about the fact that this NSVC * has received RESET */ @@ -762,7 +763,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, } /* Initiate TEST proc.: Send ALIVE and start timer */ rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ From 3625038a118be1ce84bacec975e68e7c6b0e4f04 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 28 May 2010 10:08:14 +0200 Subject: [PATCH 127/198] [GPRS] NS: Print error message if TLV parser fails for some reason --- openbsc/src/gprs/gprs_ns.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 08a7c2952..c5cf962f6 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -565,6 +565,12 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + if (rc < 0) { + LOGPC(DNS, LOGL_NOTICE, "Error during TLV Parse\n"); + LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS STATUS: " + "Error during TLV Parse\n", nsvc->nsei); + return rc; + } if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { LOGPC(DNS, LOGL_INFO, "missing cause IE\n"); @@ -587,6 +593,11 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) int rc; rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + if (rc < 0) { + LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS RESET " + "Error during TLV Parse\n", nsvc->nsei); + return rc; + } if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || @@ -632,6 +643,11 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) nsvc->state |= NSE_S_BLOCKED; rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + if (rc < 0) { + LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS BLOCK " + "Error during TLV Parse\n", nsvc->nsei); + return rc; + } if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI)) { @@ -691,6 +707,12 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + if (rc < 0) { + LOGP(DNS, LOGL_ERROR, "Rx NS RESET Error during " + "TLV Parse\n"); + return rc; + } if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { From 188bda621a83c34c56f771da15d4a8655637f5b9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 28 May 2010 14:11:49 +0200 Subject: [PATCH 128/198] [GPRS] NS: Frame Relay DLCI for PVC from 16-1007 0 Reserved for ANSI Annex D and CCITT Annex A link management 1 - 15 Reserved 16 - 1007 Any PVC 1008 - 1018 Reserved 1019 - 1022 Reserved for LMI multicast 1023 Reserved for LMI link management --- openbsc/src/gprs/gprs_ns_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 81346c6ef..e395df7eb 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -300,7 +300,7 @@ DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, } DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd, - "nse <0-65535> fr-dlci <0-1023>", + "nse <0-65535> fr-dlci <16-1007>", NSE_CMD_STR "Frame Relay DLCI\n" "Frame Relay DLCI Number\n") From 57a9cf279731633f88614eb0b7be8c81bfe8777c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 28 May 2010 16:06:53 +0200 Subject: [PATCH 129/198] [GPRS] NS: Respond to GRE keepalive messages GRE has the strange notion of keepalive messages being encapsulated IPv4 packets adressed back to the sender. Since we actually really only care about frame relay, this is a bit strange. However, we'll do some sanity checks and send it back through our GRE socket... --- openbsc/src/gprs/gprs_ns_frgre.c | 68 +++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index 94f937455..e22b0c724 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -41,12 +41,67 @@ #include #define GRE_PTYPE_FR 0x6559 +#define GRE_PTYPE_IPv4 0x0800 +#define GRE_PTYPE_KAR 0x0000 /* keepalive response */ struct gre_hdr { uint16_t flags; uint16_t ptype; } __attribute__ ((packed)); +/* IPv4 messages inside the GRE tunnel might be GRE keepalives */ +static int handle_rx_gre_ipv4(struct bsc_fd *bfd, struct msgb *msg, + struct iphdr *iph, struct gre_hdr *greh) +{ + struct gprs_ns_inst *nsi = bfd->data; + int gre_payload_len; + struct iphdr *inner_iph; + struct gre_hdr *inner_greh; + struct sockaddr_in daddr; + struct in_addr ia; + + gre_payload_len = msg->len - (iph->ihl*4 + sizeof(*greh)); + + inner_iph = (struct iphdr *) (uint8_t *)greh + sizeof(*greh); + + if (gre_payload_len < inner_iph->ihl*4 + sizeof(*inner_greh)) { + LOGP(DNS, LOGL_ERROR, "GRE keepalive too short\n"); + return -EIO; + } + + if (inner_iph->saddr != iph->daddr || + inner_iph->daddr != iph->saddr) { + LOGP(DNS, LOGL_ERROR, + "GRE keepalive with wrong tunnel addresses\n"); + return -EIO; + } + + if (inner_iph->protocol != IPPROTO_GRE) { + LOGP(DNS, LOGL_ERROR, "GRE keepalive with wrong protocol\n"); + return -EIO; + } + + inner_greh = (struct gre_hdr *) ((uint8_t *)iph + iph->ihl*4); + if (inner_greh->ptype != htons(GRE_PTYPE_KAR)) { + LOGP(DNS, LOGL_ERROR, "GRE keepalive inner GRE type != 0\n"); + return -EIO; + } + + /* Actually send the response back */ + + daddr.sin_family = AF_INET; + daddr.sin_addr.s_addr = inner_iph->daddr; + daddr.sin_port = IPPROTO_GRE; + + ia.s_addr = iph->saddr; + LOGP(DNS, LOGL_DEBUG, "GRE keepalive from %s, responding\n", + inet_ntoa(ia)); + + return sendto(nsi->frgre.fd.fd, inner_greh, + gre_payload_len - inner_iph->ihl*4, 0, + (struct sockaddr *)&daddr, sizeof(daddr)); +} + static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, struct sockaddr_in *saddr) { @@ -95,11 +150,22 @@ static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, LOGP(DNS, LOGL_NOTICE, "Unknown GRE flags 0x%04x\n", ntohs(greh->flags)); } - if (greh->ptype != htons(GRE_PTYPE_FR)) { + + switch (ntohs(greh->ptype)) { + case GRE_PTYPE_IPv4: + /* IPv4 messages might be GRE keepalives */ + *error = handle_rx_gre_ipv4(bfd, msg, iph, greh); + goto out_err; + break; + case GRE_PTYPE_FR: + /* continue as usual */ + break; + default: LOGP(DNS, LOGL_NOTICE, "Unknown GRE protocol 0x%04x != FR\n", ntohs(greh->ptype)); *error = -EIO; goto out_err; + break; } if (msg->len < sizeof(*greh) + 2) { From f15497c1a3befd350f4e40be8d47bc62e49069fe Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 28 May 2010 16:12:57 +0200 Subject: [PATCH 130/198] [GPRS] NS: Don't hand Frame Relay LMI packets into the NS code --- openbsc/src/gprs/gprs_ns_frgre.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index e22b0c724..326bd70f8 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -206,19 +206,29 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, static int handle_nsfrgre_read(struct bsc_fd *bfd) { - int error; + int rc; struct sockaddr_in saddr; struct gprs_ns_inst *nsi = bfd->data; - struct msgb *msg = read_nsfrgre_msg(bfd, &error, &saddr); + struct msgb *msg; + uint16_t dlci; + msg = read_nsfrgre_msg(bfd, &rc, &saddr); if (!msg) - return error; + return rc; - error = gprs_ns_rcvmsg(nsi, msg, &saddr, GPRS_NS_LL_FR_GRE); + dlci = ntohs(saddr.sin_port); + if (dlci == 0 || dlci == 1023) { + LOGP(DNS, LOGL_INFO, "Received FR on LMI DLCI %u - ignoring\n", + dlci); + rc = 0; + goto out; + } + rc = gprs_ns_rcvmsg(nsi, msg, &saddr, GPRS_NS_LL_FR_GRE); +out: msgb_free(msg); - return error; + return rc; } static int handle_nsfrgre_write(struct bsc_fd *bfd) From bd33f3d0ef006f03188664159fbcd476068fe656 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 30 May 2010 17:19:38 +0200 Subject: [PATCH 131/198] [GPRS] NS: correctly pass the NS payload length to the TLV parser --- openbsc/src/gprs/gprs_ns.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index c5cf962f6..3db1d67fe 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -564,7 +564,8 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx NS STATUS ", nsvc->nsei); - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, + msgb_l2len(msg) - sizeof(*nsh), 0, 0); if (rc < 0) { LOGPC(DNS, LOGL_NOTICE, "Error during TLV Parse\n"); LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS STATUS: " @@ -592,7 +593,8 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) uint16_t *nsvci, *nsei; int rc; - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, + msgb_l2len(msg) - sizeof(*nsh), 0, 0); if (rc < 0) { LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS RESET " "Error during TLV Parse\n", nsvc->nsei); @@ -642,7 +644,8 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) nsvc->state |= NSE_S_BLOCKED; - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, + msgb_l2len(msg) - sizeof(*nsh), 0, 0); if (rc < 0) { LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS BLOCK " "Error during TLV Parse\n", nsvc->nsei); @@ -706,11 +709,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, #endif } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, - msgb_l2len(msg), 0, 0); - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + msgb_l2len(msg) - sizeof(*nsh), 0, 0); if (rc < 0) { - LOGP(DNS, LOGL_ERROR, "Rx NS RESET Error during " - "TLV Parse\n"); + LOGP(DNS, LOGL_ERROR, "Rx NS RESET Error %d during " + "TLV Parse\n", rc); return rc; } if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || From a8aa4df813be0819c1c3e02fc3b974388a4b170e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 30 May 2010 22:00:53 +0200 Subject: [PATCH 132/198] [GPRS] BSSGP: Acknowledge all SUSPEND and RESUME requests This is of course not the correct way of dealing with it, but for now it should make the Ericsson Mobile Plafrom based phones happy (they insist to do a suspend/resume cycle before pdp ctx act) --- openbsc/src/gprs/gprs_bssgp.c | 103 ++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index fa994514f..ea1f9f88c 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -129,6 +129,96 @@ static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) return gprs_ns_sendmsg(bssgp_nsi, msg); } +/* 10.3.7 SUSPEND-ACK PDU */ +int bssgp_tx_suspend_ack(uint16_t nsei, uint32_t tlli, + const struct gprs_ra_id *ra_id, uint8_t suspend_ref) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint32_t _tlli; + uint8_t ra[6]; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_SUSPEND_ACK; + + _tlli = htonl(tlli); + msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli); + gsm48_construct_ra(ra, ra_id); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); + msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* 10.3.8 SUSPEND-NACK PDU */ +int bssgp_tx_suspend_nack(uint16_t nsei, uint32_t tlli, + uint8_t *cause) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint32_t _tlli; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_SUSPEND_NACK; + + _tlli = htonl(tlli); + msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli); + if (cause) + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, cause); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* 10.3.10 RESUME-ACK PDU */ +int bssgp_tx_resume_ack(uint16_t nsei, uint32_t tlli, + const struct gprs_ra_id *ra_id) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint32_t _tlli; + uint8_t ra[6]; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_RESUME_ACK; + + _tlli = htonl(tlli); + msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli); + gsm48_construct_ra(ra, ra_id); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* 10.3.11 RESUME-NACK PDU */ +int bssgp_tx_resume_nack(uint16_t nsei, uint32_t tlli, + const struct gprs_ra_id *ra_id, uint8_t *cause) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint32_t _tlli; + uint8_t ra[6]; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_SUSPEND_NACK; + + _tlli = htonl(tlli); + msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli); + gsm48_construct_ra(ra, ra_id); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); + if (cause) + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, cause); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) { /* 6 octets RAC */ @@ -267,6 +357,8 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); + struct gprs_ra_id raid; + uint32_t tlli; DEBUGP(DBSSGP, "BSSGP SUSPEND\n"); @@ -274,8 +366,13 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); + gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); + /* FIXME: pass the SUSPEND request to GMM */ /* SEND SUSPEND_ACK or SUSPEND_NACK */ + bssgp_tx_suspend_ack(msgb_nsei(msg), tlli, &raid, 0); + return 0; } @@ -284,6 +381,8 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); + struct gprs_ra_id raid; + uint32_t tlli; DEBUGP(DBSSGP, "BSSGP RESUME\n"); @@ -292,8 +391,12 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, !TLVP_PRESENT(tp, BSSGP_IE_SUSPEND_REF_NR)) return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); + gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); + /* FIXME: pass the RESUME request to GMM */ /* SEND RESUME_ACK or RESUME_NACK */ + bssgp_tx_resume_ack(msgb_nsei(msg), tlli, &raid); return 0; } From 9681ce359d65060b7f9da14c3adb3bdaf9e48d11 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 31 May 2010 11:02:57 +0200 Subject: [PATCH 133/198] [GPRS] NS: Fix GRE keepalive response in FR-GRE encapsulation --- openbsc/src/gprs/gprs_ns_frgre.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index 326bd70f8..7436d0dcd 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -62,7 +62,7 @@ static int handle_rx_gre_ipv4(struct bsc_fd *bfd, struct msgb *msg, gre_payload_len = msg->len - (iph->ihl*4 + sizeof(*greh)); - inner_iph = (struct iphdr *) (uint8_t *)greh + sizeof(*greh); + inner_iph = (struct iphdr *) ((uint8_t *)greh + sizeof(*greh)); if (gre_payload_len < inner_iph->ihl*4 + sizeof(*inner_greh)) { LOGP(DNS, LOGL_ERROR, "GRE keepalive too short\n"); @@ -81,7 +81,7 @@ static int handle_rx_gre_ipv4(struct bsc_fd *bfd, struct msgb *msg, return -EIO; } - inner_greh = (struct gre_hdr *) ((uint8_t *)iph + iph->ihl*4); + inner_greh = (struct gre_hdr *) ((uint8_t *)inner_iph + iph->ihl*4); if (inner_greh->ptype != htons(GRE_PTYPE_KAR)) { LOGP(DNS, LOGL_ERROR, "GRE keepalive inner GRE type != 0\n"); return -EIO; From 2677ea547c178a545dfc34364c08b48232a04ea5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 31 May 2010 17:16:36 +0200 Subject: [PATCH 134/198] [GPRS] BSSGP: When we receive a BLOCK, we should not respond with UNBLOCK-ACK --- openbsc/src/gprs/gprs_bssgp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index ea1f9f88c..adf4f6e6c 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -529,11 +529,10 @@ static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, break; case BSSGP_PDUT_BVC_BLOCK: /* BSS tells us that BVC shall be blocked */ - DEBUGP(DBSSGP, "BSSGP BVC BLOCK "); if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) goto err_mand_ie; - rc = bssgp_rx_bvc_unblock(msg, tp); + rc = bssgp_rx_bvc_block(msg, tp); break; case BSSGP_PDUT_BVC_UNBLOCK: /* BSS tells us that BVC shall be unblocked */ From e9686b642843450956d25535b3f448c6d4f9828a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 31 May 2010 18:07:17 +0200 Subject: [PATCH 135/198] [GPRS] BSSGP: More verbose debug log / error reporting --- openbsc/src/gprs/gprs_bssgp.c | 120 ++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 34 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index adf4f6e6c..36abf1693 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -237,7 +237,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, int rc; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - DEBUGPC(DBSSGP, "BVCI=%u RESET cause=%s\n", bvci, + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx RESET cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); /* look-up or create the BTS context for this BVC */ @@ -252,7 +252,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, * informs us about its RAC + Cell ID, so we can create a mapping */ if (bvci != 0 && bvci != 1) { if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { - LOGP(DBSSGP, LOGL_ERROR, "BSSGP RESET BVCI=%u " + LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u RESET " "missing mandatory IE\n", bvci); return -EINVAL; } @@ -284,7 +284,7 @@ static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) return 0; } - LOGP(DBSSGP, LOGL_INFO, "BVCI=%u BVC-BLOCK\n", bvci); + LOGP(DBSSGP, LOGL_INFO, "BSSGP BVCI=%u BVC-BLOCK\n", bvci); ptp_ctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg)); if (!ptp_ctx) @@ -314,7 +314,7 @@ static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) return 0; } - DEBUGP(DBSSGP, "BVCI=%u BVC-UNBLOCK\n", bvci); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC-UNBLOCK\n", bvci); ptp_ctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg)); if (!ptp_ctx) @@ -335,15 +335,18 @@ static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); - DEBUGP(DBSSGP, "BSSGP UL-UD\n"); - /* extract TLLI and parse TLV IEs */ msgb_tlli(msg) = ntohl(budh->tlli); + DEBUGP(DBSSGP, "BSSGP TLLI=0x%08x UPLINK-UNITDATA\n", msgb_tlli(msg)); + /* Cell ID and LLC_PDU are the only mandatory IE */ if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID) || - !TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) + !TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD " + "missing mandatory IE\n", msgb_tlli(msg)); return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + } /* store pointer to LLC header and CELL ID in msgb->cb */ msgb_llch(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU); @@ -360,13 +363,18 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, struct gprs_ra_id raid; uint32_t tlli; - DEBUGP(DBSSGP, "BSSGP SUSPEND\n"); - if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || - !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) + !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx SUSPEND " + "missing mandatory IE\n", ctx->bvci); return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + } tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); + + DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%082x Rx SUSPEND\n", + ctx->bvci, tlli); + gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); /* FIXME: pass the SUSPEND request to GMM */ @@ -384,14 +392,18 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, struct gprs_ra_id raid; uint32_t tlli; - DEBUGP(DBSSGP, "BSSGP RESUME\n"); - if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA) || - !TLVP_PRESENT(tp, BSSGP_IE_SUSPEND_REF_NR)) + !TLVP_PRESENT(tp, BSSGP_IE_SUSPEND_REF_NR)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx RESUME " + "missing mandatory IE\n", ctx->bvci); return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + } tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); + + DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x RESUME\n", ctx->bvci, tlli); + gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); /* FIXME: pass the RESUME request to GMM */ @@ -400,18 +412,47 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, return 0; } + +static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bvc_ctx *ctx) +{ + uint32_t tlli; + + if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(tp, BSSGP_IE_LLC_FRAMES_DISCARDED) || + !TLVP_PRESENT(tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(tp, BSSGP_IE_NUM_OCT_AFF)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx LLC DISCARDED " + "missing mandatory IE\n", ctx->bvci); + } + + tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); + + DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=%u LLC DISCARDED\n", + ctx->bvci, tlli); + + rate_ctr_inc(&ctx->ctrg->ctr[BSSGP_CTR_DISCARDED]); + + /* FIXME: send NM_LLC_DISCARDED to NM */ + return 0; +} + static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx) { - DEBUGP(DBSSGP, "BSSGP FC BVC\n"); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx Flow Control BVC\n", + bctx->bvci); if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) || !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) || !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) || !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) || - !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) + !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx FC BVC " + "missing mandatory IE\n", bctx->bvci); return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + } /* FIXME: actually implement flow control */ @@ -444,12 +485,13 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, break; case BSSGP_PDUT_RA_CAPABILITY: /* BSS requests RA capability or IMSI */ - DEBUGP(DBSSGP, "BSSGP RA CAPABILITY UPDATE\n"); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx RA CAPABILITY UPDATE\n", + bctx->bvci); /* FIXME: send GMM_RA_CAPABILITY_UPDATE.ind to GMM */ /* FIXME: send RA_CAPA_UPDATE_ACK */ break; case BSSGP_PDUT_RADIO_STATUS: - DEBUGP(DBSSGP, "BSSGP RADIO STATUS\n"); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx RADIO STATUS\n", bctx->bvci); /* BSS informs us of some exception */ /* FIXME: send GMM_RADIO_STATUS.ind to GMM */ break; @@ -459,7 +501,8 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, break; case BSSGP_PDUT_FLOW_CONTROL_MS: /* BSS informs us of available bandwidth to one MS */ - DEBUGP(DBSSGP, "BSSGP FC MS\n"); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx Flow Control MS\n", + bctx->bvci); /* FIXME: actually implement flow control */ /* FIXME: Send FLOW_CONTROL_MS_ACK */ break; @@ -471,8 +514,8 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, case BSSGP_PDUT_CREATE_BSS_PFC_NACK: case BSSGP_PDUT_MODIFY_BSS_PFC: case BSSGP_PDUT_DELETE_BSS_PFC_ACK: - DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x not [yet] implemented\n", - pdu_type); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x not [yet] " + "implemented\n", bctx->bvci, pdu_type); rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); break; /* those only exist in the SGSN -> BSS direction */ @@ -482,13 +525,14 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, case BSSGP_PDUT_RA_CAPA_UPDATE_ACK: case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: - DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x only exists in DL\n", - pdu_type); + DEBUGP(DBSSGP, "BSSGP BVCI=%u PDU type 0x%02x only exists " + "in DL\n", bctx->bvci, pdu_type); bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); rc = -EINVAL; break; default: - DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + DEBUGP(DBSSGP, "BSSGP BVCI=%u PDU type 0x%02x unknown\n", + bctx->bvci, pdu_type); rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); break; } @@ -518,38 +562,45 @@ static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, break; case BSSGP_PDUT_FLUSH_LL_ACK: /* BSS informs us it has performed LL FLUSH */ - DEBUGP(DBSSGP, "BSSGP FLUSH LL\n"); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx FLUSH LL ACK\n", bctx->bvci); /* FIXME: send NM_FLUSH_LL.res to NM */ break; case BSSGP_PDUT_LLC_DISCARD: /* BSS informs that some LLC PDU's have been discarded */ - rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_DISCARDED]); - DEBUGP(DBSSGP, "BSSGP LLC DISCARDED\n"); - /* FIXME: send NM_LLC_DISCARDED to NM */ + rc = bssgp_rx_llc_disc(msg, tp, bctx); break; case BSSGP_PDUT_BVC_BLOCK: /* BSS tells us that BVC shall be blocked */ if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI) || - !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) + !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP Rx BVC-BLOCK " + "missing mandatory IE\n"); goto err_mand_ie; + } rc = bssgp_rx_bvc_block(msg, tp); break; case BSSGP_PDUT_BVC_UNBLOCK: /* BSS tells us that BVC shall be unblocked */ - if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) + if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP Rx BVC-UNBLOCK " + "missing mandatory IE\n"); goto err_mand_ie; + } rc = bssgp_rx_bvc_unblock(msg, tp); break; case BSSGP_PDUT_BVC_RESET: /* BSS tells us that BVC init is required */ - DEBUGP(DBSSGP, "BSSGP BVC RESET "); if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI) || - !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) + !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) { + LOGP(DBSSGP, LOGL_ERROR, "BSSGP Rx BVC-RESET " + "missing mandatory IE\n"); goto err_mand_ie; + } rc = bssgp_rx_bvc_reset(msg, tp, ns_bvci); break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bctx->bvci); /* FIXME: send NM_STATUS.ind to NM */ break; /* those only exist in the SGSN -> BSS direction */ @@ -563,13 +614,14 @@ static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, case BSSGP_PDUT_BVC_BLOCK_ACK: case BSSGP_PDUT_BVC_UNBLOCK_ACK: case BSSGP_PDUT_SGSN_INVOKE_TRACE: - DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x only exists in DL\n", - pdu_type); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x only exists " + "in DL\n", bctx->bvci, pdu_type); bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); rc = -EINVAL; break; default: - DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n", + bctx->bvci, pdu_type); rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); break; } From 179253282037ff0148bdd6e587d82e816fe352bd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 31 May 2010 20:18:35 +0200 Subject: [PATCH 136/198] [GPRS] BSSGP: Fix way too long TLLI debug line --- openbsc/src/gprs/gprs_bssgp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 36abf1693..f3ce8a9fe 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -372,7 +372,7 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); - DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%082x Rx SUSPEND\n", + DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x Rx SUSPEND\n", ctx->bvci, tlli); gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); From 2f94683320c3b34caa6b733fb17c4af1c3287838 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 31 May 2010 22:12:30 +0200 Subject: [PATCH 137/198] [GPRS] Include IMSI and DRX params in BSSGP DL-UD When we send a downlink unit-data request via BSSGP, there is a lot of information that needs to be copied from the mm context, such as the IMSI, DRX parametes, MS radio access parameters, ... This is a quite strange layering violation, since we now need to pass a pointer to the MM ctx from GMM through LLC into BSSGP :( --- openbsc/include/openbsc/gprs_bssgp.h | 3 ++- openbsc/src/gprs/gprs_bssgp.c | 36 ++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index 90b945aba..9eaf989af 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -188,7 +188,8 @@ struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei); int gprs_bssgp_rcvmsg(struct msgb *msg); /* BSSGP-DL-UNITDATA.req */ -int gprs_bssgp_tx_dl_ud(struct msgb *msg); +struct sgsn_mm_ctx; +int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx); uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index f3ce8a9fe..58ade4d21 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -39,6 +39,7 @@ #include #include #include +#include void *bssgp_tall_ctx = NULL; @@ -685,7 +686,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ -int gprs_bssgp_tx_dl_ud(struct msgb *msg) +int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) { struct bssgp_bvc_ctx *bctx; struct bssgp_ud_hdr *budh; @@ -696,6 +697,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) uint16_t msg_len = msg->len; uint16_t bvci = msgb_bvci(msg); uint16_t nsei = msgb_nsei(msg); + uint16_t drx_params; /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ if (bvci <= BVCI_PTM ) { @@ -724,7 +726,37 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) llc_pdu_tlv[1] |= 0x80; } - /* FIXME: optional elements */ + /* FIXME: optional elements: Alignment, UTRAN CCO, LSA, PFI */ + + if (mmctx) { + /* Old TLLI to help BSS map from old->new */ +#if 0 + if (mmctx->tlli_old) + msgb_tvlv_push(msg, BSSGP_IE_TLLI, 4, htonl(*tlli_old)); +#endif + + /* IMSI */ + if (strlen(mmctx->imsi)) { + uint8_t mi[10]; + int imsi_len = gsm48_generate_mid_from_imsi(mi, mmctx->imsi); + if (imsi_len > 2) + msgb_tvlv_push(msg, BSSGP_IE_IMSI, + imsi_len-2, mi+2); + } + + /* DRX parameters */ + drx_params = htons(mmctx->drx_parms); + msgb_tvlv_push(msg, BSSGP_IE_DRX_PARAMS, 2, + (uint8_t *) &drx_params); + + /* FIXME: Priority */ + + /* MS Radio Access Capability */ + if (mmctx->ms_radio_access_capa.len) + msgb_tvlv_push(msg, BSSGP_IE_MS_RADIO_ACCESS_CAP, + mmctx->ms_radio_access_capa.len, + mmctx->ms_radio_access_capa.buf); + } /* prepend the pdu lifetime */ pdu_lifetime = htons(pdu_lifetime); From 02f7325b9fb2f487d054b63e67df3615a4bac9cd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 1 Jun 2010 11:53:01 +0200 Subject: [PATCH 138/198] [GPRS] Major LLC / TLLI handling fixes * separate the LLME and LLE state in the LLC layer * introduce gprs_llgmm_assign() function for LLGMM-ASSIGN.req primitive * change QoS profile to match 'real' SGSN * Update the new TLLI when assigning a P-TMSI The result now is that the LLC layer is notified of TLLI changes, which in turn means it doesn't allocate a new LLE structure every TLLI change, which again in turn means that the UI frame sequence number does not reset to zero. As a result, MS should no longer ignore frames based on wrong UI sequence number. --- openbsc/src/gprs/gprs_bssgp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 58ade4d21..89b78662e 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -693,7 +693,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) uint8_t llc_pdu_tlv_hdr_len = 2; uint8_t *llc_pdu_tlv, *qos_profile; uint16_t pdu_lifetime = 1000; /* centi-seconds */ - uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; + uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x20 }; uint16_t msg_len = msg->len; uint16_t bvci = msgb_bvci(msg); uint16_t nsei = msgb_nsei(msg); From cfb545aebbd909b55f7889360cf8cfc3e2f7debe Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 3 Jun 2010 21:30:57 +0200 Subject: [PATCH 139/198] [GPRS] BSSGP: Fix formatting of BSSGP TX STATUS --- openbsc/src/gprs/gprs_bssgp_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp_util.c b/openbsc/src/gprs/gprs_bssgp_util.c index d9b5175f6..566ac4cf7 100644 --- a/openbsc/src/gprs/gprs_bssgp_util.c +++ b/openbsc/src/gprs/gprs_bssgp_util.c @@ -101,7 +101,8 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + DEBUGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Tx STATUS, cause=%s\n", + bvci ? *bvci : 0, bssgp_cause_str(cause)); msgb_nsei(msg) = msgb_nsei(orig_msg); msgb_bvci(msg) = 0; From 8e2e78ecc22d9fb011f6fd451a089d5d373aa49b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 8 Jun 2010 16:05:20 +0800 Subject: [PATCH 140/198] GPRS: Fix compiler warning that will also lead to a crash at runtime. --- openbsc/src/gprs/gprs_bssgp_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp_util.c b/openbsc/src/gprs/gprs_bssgp_util.c index 566ac4cf7..e760252bd 100644 --- a/openbsc/src/gprs/gprs_bssgp_util.c +++ b/openbsc/src/gprs/gprs_bssgp_util.c @@ -101,7 +101,7 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - DEBUGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Tx STATUS, cause=%s\n", + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Tx STATUS, cause=%s\n", bvci ? *bvci : 0, bssgp_cause_str(cause)); msgb_nsei(msg) = msgb_nsei(orig_msg); msgb_bvci(msg) = 0; From 313cccf733e07c38716ff7f566f91678366fa997 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 9 Jun 2010 11:22:47 +0200 Subject: [PATCH 141/198] [GPRS] SGSN: Pass BSSGP SUSPEND/RESUME up to GMM and alter MMCTX state --- openbsc/src/gprs/gprs_bssgp.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 89b78662e..c7c49d4bd 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -40,6 +40,7 @@ #include #include #include +#include void *bssgp_tall_ctx = NULL; @@ -363,6 +364,7 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct gprs_ra_id raid; uint32_t tlli; + int rc; if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { @@ -378,8 +380,11 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); - /* FIXME: pass the SUSPEND request to GMM */ - /* SEND SUSPEND_ACK or SUSPEND_NACK */ + /* Inform GMM about the SUSPEND request */ + rc = gprs_gmm_rx_suspend(&raid, tlli); + if (rc < 0) + return bssgp_tx_suspend_nack(msgb_nsei(msg), tlli, NULL); + bssgp_tx_suspend_ack(msgb_nsei(msg), tlli, &raid, 0); return 0; @@ -392,6 +397,8 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct gprs_ra_id raid; uint32_t tlli; + uint8_t suspend_ref; + int rc; if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA) || @@ -402,13 +409,18 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, } tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); + suspend_ref = *TLVP_VAL(tp, BSSGP_IE_SUSPEND_REF_NR); DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x RESUME\n", ctx->bvci, tlli); gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); - /* FIXME: pass the RESUME request to GMM */ - /* SEND RESUME_ACK or RESUME_NACK */ + /* Inform GMM about the RESUME request */ + rc = gprs_gmm_rx_resume(&raid, tlli, suspend_ref); + if (rc < 0) + return bssgp_tx_resume_nack(msgb_nsei(msg), tlli, &raid, + NULL); + bssgp_tx_resume_ack(msgb_nsei(msg), tlli, &raid); return 0; } From 68b4f037e0e2286fd2fe1f314d9bd2dc66fb646b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 9 Jun 2010 16:22:28 +0200 Subject: [PATCH 142/198] [GPRS] BSSGP/SGSN: Implement Gb-Interface Paging We now have a function that generates BSSGP PS and CS paging request. It is called from the libgtp code when we receive a GTP packet from the GGSN for a MM context that is in SUSPEND state. We then issue a PS paging request to the Cell with the BVCI where the last RA update was being performed. TODO: We still don't enqueue the GTP packet (and transmit it on paging complete), and we don't rate-limit the paging requests, i.e. every GTP packet will trigger another paging request. We probably also need some kind of logic that marks the phone as UNREGISTERED if it doesn't respond to paging requests for some time. --- openbsc/include/openbsc/gprs_bssgp.h | 27 ++++++++++++ openbsc/src/gprs/gprs_bssgp.c | 63 ++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index 9eaf989af..e432cf750 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -199,6 +199,33 @@ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); } +enum bssgp_paging_mode { + BSSGP_PAGING_PS, + BSSGP_PAGING_CS, +}; + +enum bssgp_paging_scope { + BSSGP_PAGING_BSS_AREA, /* all cells in BSS */ + BSSGP_PAGING_LOCATION_AREA, /* all cells in LA */ + BSSGP_PAGING_ROUTEING_AREA, /* all cells in RA */ + BSSGP_PAGING_BVCI, /* one cell */ +}; + +struct bssgp_paging_info { + enum bssgp_paging_mode mode; + enum bssgp_paging_scope scope; + struct gprs_ra_id raid; + uint16_t bvci; + const char *imsi; + uint32_t *ptmsi; + uint16_t drx_params; + uint8_t qos[3]; +}; + +/* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */ +int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, + struct bssgp_paging_info *pinfo); + /* gprs_bssgp_vty.c */ int gprs_bssgp_vty_init(void); diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index c7c49d4bd..f27e3a7e8 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -787,3 +787,66 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) return gprs_ns_sendmsg(bssgp_nsi, msg); } + +/* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */ +int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, + struct bssgp_paging_info *pinfo) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t drx_params = htons(pinfo->drx_params); + uint8_t mi[10]; + int imsi_len = gsm48_generate_mid_from_imsi(mi, pinfo->imsi); + uint8_t ra[6]; + + if (imsi_len < 2) + return -EINVAL; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + if (pinfo->mode == BSSGP_PAGING_PS) + bgph->pdu_type = BSSGP_PDUT_PAGING_PS; + else + bgph->pdu_type = BSSGP_PDUT_PAGING_CS; + /* IMSI */ + msgb_tvlv_put(msg, BSSGP_IE_IMSI, imsi_len-2, mi+2); + /* DRX Parameters */ + msgb_tvlv_put(msg, BSSGP_IE_DRX_PARAMS, 2, + (uint8_t *) &drx_params); + /* Scope */ + switch (pinfo->scope) { + case BSSGP_PAGING_BSS_AREA: + { + uint8_t null = 0; + msgb_tvlv_put(msg, BSSGP_IE_BSS_AREA_ID, 1, &null); + } + break; + case BSSGP_PAGING_LOCATION_AREA: + gsm48_construct_ra(ra, &pinfo->raid); + msgb_tvlv_put(msg, BSSGP_IE_LOCATION_AREA, 4, ra); + break; + case BSSGP_PAGING_ROUTEING_AREA: + gsm48_construct_ra(ra, &pinfo->raid); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); + break; + case BSSGP_PAGING_BVCI: + { + uint16_t bvci = htons(pinfo->bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *)&bvci); + } + break; + } + /* QoS profile mandatory for PS */ + if (pinfo->mode == BSSGP_PAGING_PS) + msgb_tvlv_put(msg, BSSGP_IE_QOS_PROFILE, 3, pinfo->qos); + + /* Optional (P-)TMSI */ + if (pinfo->ptmsi) { + uint32_t ptmsi = htonl(*pinfo->ptmsi); + msgb_tvlv_put(msg, BSSGP_IE_TMSI, 4, (uint8_t *) &ptmsi); + } + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} From 781b3e6905ca1ab6fde6db4b0908b82001f06caf Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 10 Jun 2010 00:20:12 +0200 Subject: [PATCH 143/198] [GPSR] SGSN: Keep traffic counters for each PDP context --- openbsc/src/gprs/gprs_bssgp_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c index 9da02abb3..dc1f65c38 100644 --- a/openbsc/src/gprs/gprs_bssgp_vty.c +++ b/openbsc/src/gprs/gprs_bssgp_vty.c @@ -110,7 +110,7 @@ DEFUN(show_bssgp_stats, show_bssgp_stats_cmd, "show bssgp stats", DEFUN(show_bvc, show_bvc_cmd, "show bssgp nsei <0-65535> [stats]", SHOW_STR BSSGP_STR - "Show all BVCSE by its NSE Identifier\n" + "Show all BVCs on one NSE\n" "The NSEI\n" "Include Statistics\n") { struct bssgp_bvc_ctx *bvc; From b00d1add7584b017470e60489f44a0c0e553e93f Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 9 Jun 2010 21:13:13 +0200 Subject: [PATCH 144/198] [gprs] bssgp: Fix LLC PDU length encoding in BSSGP. Signed-off-by: Sylvain Munaut --- openbsc/src/gprs/gprs_bssgp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index f27e3a7e8..0ec873ca5 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -734,7 +734,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) llc_pdu_tlv[1] = msg_len >> 8; llc_pdu_tlv[2] = msg_len & 0xff; } else { - llc_pdu_tlv[1] = msg_len & 0x3f; + llc_pdu_tlv[1] = msg_len & 0x7f; llc_pdu_tlv[1] |= 0x80; } From 4a90d22f5af99dbcb580251002e5096c9ee55ac6 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 14 Jun 2010 22:11:40 +0800 Subject: [PATCH 145/198] GPRS: Increase the NS msg size to 2048 According to the GPRS NS spec the maximum framesize is 1600 octets for FrameRelay, it can be bigger if configured to be so. Make it 2048 octets to have some space available... --- openbsc/include/openbsc/gprs_ns.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 8b5e7dc31..953c364b8 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -222,7 +222,7 @@ void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); /* Add NS-specific VTY stuff */ int gprs_ns_vty_init(struct gprs_ns_inst *nsi); -#define NS_ALLOC_SIZE 1024 +#define NS_ALLOC_SIZE 2048 #define NS_ALLOC_HEADROOM 20 static inline struct msgb *gprs_ns_msgb_alloc(void) { From 0e43007f78ad98435445dadda75c0fb9ecfcfc85 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 29 Jun 2010 18:34:26 +0200 Subject: [PATCH 147/198] [SGSN] BSSGP: Print TLLI as hex value like everwhere else --- openbsc/src/gprs/gprs_bssgp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 0ec873ca5..30bc0f9b4 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -441,7 +441,7 @@ static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); - DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=%u LLC DISCARDED\n", + DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=%08x LLC DISCARDED\n", ctx->bvci, tlli); rate_ctr_inc(&ctx->ctrg->ctr[BSSGP_CTR_DISCARDED]); From b73631455bc6b9304d72eb4af0d4510f28f6368e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 23 Jul 2010 21:59:29 +0200 Subject: [PATCH 150/198] [gprs] BSSGP: Fix null pointer dereference Zecke has found this using "make CC="clang --analyze" --- openbsc/src/gprs/gprs_bssgp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 30bc0f9b4..051ec92f8 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -429,7 +429,7 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *ctx) { - uint32_t tlli; + uint32_t tlli = 0; if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || !TLVP_PRESENT(tp, BSSGP_IE_LLC_FRAMES_DISCARDED) || @@ -439,7 +439,8 @@ static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, "missing mandatory IE\n", ctx->bvci); } - tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); + if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) + tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=%08x LLC DISCARDED\n", ctx->bvci, tlli); From f47df64a3b5f7389c8a184ee05b8dc0bcc9c0700 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 9 Aug 2010 21:15:40 +0800 Subject: [PATCH 152/198] [GPRS NS] Fix memory leak in gprs_ns_sendmsg() error path When gprs_ns_sendmsg() succeeds in sending the message, we free()d the msgb after transmitting it on the socket. However, if the NS-VC is blocked or some other error condition exists, we returned an error code but didn't free the msgb. This resulted in an error leak which is now being addressed. --- openbsc/src/gprs/gprs_ns.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3db1d67fe..6009a7d91 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -505,6 +505,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) if (!nsvc) { LOGP(DNS, LOGL_ERROR, "Unable to resolve NSEI %u " "to NS-VC!\n", msgb_nsei(msg)); + msgb_free(msg); return -EINVAL; } log_set_context(BSC_CTX_NSVC, nsvc); @@ -512,11 +513,13 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) if (!(nsvc->state & NSE_S_ALIVE)) { LOGP(DNS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", nsvc->nsei); + msgb_free(msg); return -EBUSY; } if (nsvc->state & NSE_S_BLOCKED) { LOGP(DNS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", nsvc->nsei); + msgb_free(msg); return -EBUSY; } @@ -524,6 +527,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) nsh = (struct gprs_ns_hdr *) msg->l2h; if (!nsh) { LOGP(DNS, LOGL_ERROR, "Not enough headroom for NS header\n"); + msgb_free(msg); return -EIO; } From d2b13fceed7c14ff68ecce35ce5e5a4381b05924 Mon Sep 17 00:00:00 2001 From: Dieter Spaar Date: Sun, 12 Dec 2010 12:45:08 +0100 Subject: [PATCH 159/198] Add mandatory routeing area IE to SUSPEND-NACK --- openbsc/src/gprs/gprs_bssgp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 051ec92f8..e94f35809 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -156,12 +156,14 @@ int bssgp_tx_suspend_ack(uint16_t nsei, uint32_t tlli, /* 10.3.8 SUSPEND-NACK PDU */ int bssgp_tx_suspend_nack(uint16_t nsei, uint32_t tlli, + const struct gprs_ra_id *ra_id, uint8_t *cause) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); uint32_t _tlli; + uint8_t ra[6]; msgb_nsei(msg) = nsei; msgb_bvci(msg) = 0; /* Signalling */ @@ -169,6 +171,8 @@ int bssgp_tx_suspend_nack(uint16_t nsei, uint32_t tlli, _tlli = htonl(tlli); msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli); + gsm48_construct_ra(ra, ra_id); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); if (cause) msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, cause); @@ -383,7 +387,7 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, /* Inform GMM about the SUSPEND request */ rc = gprs_gmm_rx_suspend(&raid, tlli); if (rc < 0) - return bssgp_tx_suspend_nack(msgb_nsei(msg), tlli, NULL); + return bssgp_tx_suspend_nack(msgb_nsei(msg), tlli, &raid, NULL); bssgp_tx_suspend_ack(msgb_nsei(msg), tlli, &raid, 0); From e4cbb3f0f2467c2c3a9ef4a66290173fce14511a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 Jan 2011 15:25:50 +0100 Subject: [PATCH 163/198] License change: We are now AGPLv3+ instead of GPLv2+ The reason for this is quite simple: We want to make sure anyone running a customized version of OpenBSC to operate a network will have to release all custom modifiations to the source code. --- openbsc/src/gprs/gprs_bssgp.c | 11 +++++------ openbsc/src/gprs/gprs_bssgp_util.c | 11 +++++------ openbsc/src/gprs/gprs_bssgp_vty.c | 11 +++++------ openbsc/src/gprs/gprs_ns.c | 11 +++++------ openbsc/src/gprs/gprs_ns_frgre.c | 11 +++++------ openbsc/src/gprs/gprs_ns_vty.c | 11 +++++------ 6 files changed, 30 insertions(+), 36 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index e94f35809..eca34b989 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -5,18 +5,17 @@ * 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 + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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. + * GNU Affero 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . * * TODO: * o properly count incoming BVC-RESET packets in counter group diff --git a/openbsc/src/gprs/gprs_bssgp_util.c b/openbsc/src/gprs/gprs_bssgp_util.c index e760252bd..f8e3b5699 100644 --- a/openbsc/src/gprs/gprs_bssgp_util.c +++ b/openbsc/src/gprs/gprs_bssgp_util.c @@ -5,18 +5,17 @@ * 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 + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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. + * GNU Affero 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . * */ diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c index dc1f65c38..6208ae3c1 100644 --- a/openbsc/src/gprs/gprs_bssgp_vty.c +++ b/openbsc/src/gprs/gprs_bssgp_vty.c @@ -5,18 +5,17 @@ * 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 + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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. + * GNU Affero 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . * */ diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 6009a7d91..5a8e35860 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -6,18 +6,17 @@ * 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 + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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. + * GNU Affero 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . * */ diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c index 7436d0dcd..106f410e6 100644 --- a/openbsc/src/gprs/gprs_ns_frgre.c +++ b/openbsc/src/gprs/gprs_ns_frgre.c @@ -8,18 +8,17 @@ * 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 + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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. + * GNU Affero 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . * */ diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index e395df7eb..42fc02560 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -5,18 +5,17 @@ * 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 + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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. + * GNU Affero 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . * */ From 43ae94efcbea535d94422d01d1a731707656ed5f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Feb 2011 21:10:05 +0100 Subject: [PATCH 165/198] LOGGING: make sure to make the 'logging filter' compatible with vty log cfg Recent libosmocore introdues a way how log targets can be configured from the VTY. This commit makes the 'log filter (imsi|nsvc|bvc)' compatible with it. --- openbsc/src/gprs/gprs_bssgp_vty.c | 11 +++++------ openbsc/src/gprs/gprs_ns_vty.c | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c index 6208ae3c1..9ebd09004 100644 --- a/openbsc/src/gprs/gprs_bssgp_vty.c +++ b/openbsc/src/gprs/gprs_bssgp_vty.c @@ -138,16 +138,13 @@ DEFUN(logging_fltr_bvc, "BVCI of the BVC to be filtered\n" "BSSGP Virtual Connection Identifier (BVCI)\n") { - struct telnet_connection *conn; + struct log_target *tgt = osmo_log_vty2tgt(vty); struct bssgp_bvc_ctx *bvc; uint16_t nsei = atoi(argv[0]); uint16_t bvci = atoi(argv[1]); - conn = (struct telnet_connection *) vty->priv; - if (!conn->dbg) { - vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + if (!tgt) return CMD_WARNING; - } bvc = btsctx_by_bvci_nsei(bvci, nsei); if (!bvc) { @@ -155,7 +152,7 @@ DEFUN(logging_fltr_bvc, return CMD_WARNING; } - log_set_bvc_filter(conn->dbg, bvc); + log_set_bvc_filter(tgt, bvc); return CMD_SUCCESS; } @@ -166,6 +163,8 @@ int gprs_bssgp_vty_init(void) install_element_ve(&show_bvc_cmd); install_element_ve(&logging_fltr_bvc_cmd); + install_element(CFG_LOG_NODE, &logging_fltr_bvc_cmd); + install_element(CONFIG_NODE, &cfg_bssgp_cmd); install_node(&bssgp_node, config_write_bssgp); install_default(BSSGP_NODE); diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 42fc02560..39277fc71 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -513,15 +513,12 @@ DEFUN(logging_fltr_nsvc, "Identify NS-VC by NSVCI\n" "Numeric identifier\n") { - struct telnet_connection *conn; + struct log_target *tgt = osmo_log_vty2tgt(vty); struct gprs_nsvc *nsvc; uint16_t id = atoi(argv[1]); - conn = (struct telnet_connection *) vty->priv; - if (!conn->dbg) { - vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + if (!tgt) return CMD_WARNING; - } if (!strcmp(argv[0], "nsei")) nsvc = nsvc_by_nsei(vty_nsi, id); @@ -533,7 +530,7 @@ DEFUN(logging_fltr_nsvc, return CMD_WARNING; } - log_set_nsvc_filter(conn->dbg, nsvc); + log_set_nsvc_filter(tgt, nsvc); return CMD_SUCCESS; } @@ -546,6 +543,8 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element_ve(&show_nse_cmd); install_element_ve(&logging_fltr_nsvc_cmd); + install_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd); + install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); install_default(NS_NODE); From 393becc8b85f271c6ed581eefb9c8c61292123b0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 3 Mar 2011 23:45:28 +0100 Subject: [PATCH 166/198] Move 'Gb' protocol stack into its own src/gb subdirectory --- openbsc/src/gb/Makefile.am | 9 +++++++++ openbsc/src/{gprs => gb}/gprs_bssgp.c | 0 openbsc/src/{gprs => gb}/gprs_bssgp_util.c | 0 openbsc/src/{gprs => gb}/gprs_bssgp_vty.c | 0 openbsc/src/{gprs => gb}/gprs_ns.c | 0 openbsc/src/{gprs => gb}/gprs_ns_frgre.c | 0 openbsc/src/{gprs => gb}/gprs_ns_vty.c | 0 7 files changed, 9 insertions(+) create mode 100644 openbsc/src/gb/Makefile.am rename openbsc/src/{gprs => gb}/gprs_bssgp.c (100%) rename openbsc/src/{gprs => gb}/gprs_bssgp_util.c (100%) rename openbsc/src/{gprs => gb}/gprs_bssgp_vty.c (100%) rename openbsc/src/{gprs => gb}/gprs_ns.c (100%) rename openbsc/src/{gprs => gb}/gprs_ns_frgre.c (100%) rename openbsc/src/{gprs => gb}/gprs_ns_vty.c (100%) diff --git a/openbsc/src/gb/Makefile.am b/openbsc/src/gb/Makefile.am new file mode 100644 index 000000000..b48b17791 --- /dev/null +++ b/openbsc/src/gb/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS) + +noinst_LIBRARIES = libgb.a + +libgb_a_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c \ + gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c +#gprs_llc.c gprs_llc_vty.c crc24.c diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gb/gprs_bssgp.c similarity index 100% rename from openbsc/src/gprs/gprs_bssgp.c rename to openbsc/src/gb/gprs_bssgp.c diff --git a/openbsc/src/gprs/gprs_bssgp_util.c b/openbsc/src/gb/gprs_bssgp_util.c similarity index 100% rename from openbsc/src/gprs/gprs_bssgp_util.c rename to openbsc/src/gb/gprs_bssgp_util.c diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gb/gprs_bssgp_vty.c similarity index 100% rename from openbsc/src/gprs/gprs_bssgp_vty.c rename to openbsc/src/gb/gprs_bssgp_vty.c diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gb/gprs_ns.c similarity index 100% rename from openbsc/src/gprs/gprs_ns.c rename to openbsc/src/gb/gprs_ns.c diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gb/gprs_ns_frgre.c similarity index 100% rename from openbsc/src/gprs/gprs_ns_frgre.c rename to openbsc/src/gb/gprs_ns_frgre.c diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gb/gprs_ns_vty.c similarity index 100% rename from openbsc/src/gprs/gprs_ns_vty.c rename to openbsc/src/gb/gprs_ns_vty.c From 85e109711d5b07ebc80ded03dd0b682407339800 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 4 Mar 2011 13:18:30 +0100 Subject: [PATCH 167/198] prefix sub-directories containing libraries with 'lib' ... and make sure tests work again after restructuring --- openbsc/src/{gb => libgb}/Makefile.am | 0 openbsc/src/{gb => libgb}/gprs_bssgp.c | 0 openbsc/src/{gb => libgb}/gprs_bssgp_util.c | 0 openbsc/src/{gb => libgb}/gprs_bssgp_vty.c | 0 openbsc/src/{gb => libgb}/gprs_ns.c | 0 openbsc/src/{gb => libgb}/gprs_ns_frgre.c | 0 openbsc/src/{gb => libgb}/gprs_ns_vty.c | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename openbsc/src/{gb => libgb}/Makefile.am (100%) rename openbsc/src/{gb => libgb}/gprs_bssgp.c (100%) rename openbsc/src/{gb => libgb}/gprs_bssgp_util.c (100%) rename openbsc/src/{gb => libgb}/gprs_bssgp_vty.c (100%) rename openbsc/src/{gb => libgb}/gprs_ns.c (100%) rename openbsc/src/{gb => libgb}/gprs_ns_frgre.c (100%) rename openbsc/src/{gb => libgb}/gprs_ns_vty.c (100%) diff --git a/openbsc/src/gb/Makefile.am b/openbsc/src/libgb/Makefile.am similarity index 100% rename from openbsc/src/gb/Makefile.am rename to openbsc/src/libgb/Makefile.am diff --git a/openbsc/src/gb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c similarity index 100% rename from openbsc/src/gb/gprs_bssgp.c rename to openbsc/src/libgb/gprs_bssgp.c diff --git a/openbsc/src/gb/gprs_bssgp_util.c b/openbsc/src/libgb/gprs_bssgp_util.c similarity index 100% rename from openbsc/src/gb/gprs_bssgp_util.c rename to openbsc/src/libgb/gprs_bssgp_util.c diff --git a/openbsc/src/gb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c similarity index 100% rename from openbsc/src/gb/gprs_bssgp_vty.c rename to openbsc/src/libgb/gprs_bssgp_vty.c diff --git a/openbsc/src/gb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c similarity index 100% rename from openbsc/src/gb/gprs_ns.c rename to openbsc/src/libgb/gprs_ns.c diff --git a/openbsc/src/gb/gprs_ns_frgre.c b/openbsc/src/libgb/gprs_ns_frgre.c similarity index 100% rename from openbsc/src/gb/gprs_ns_frgre.c rename to openbsc/src/libgb/gprs_ns_frgre.c diff --git a/openbsc/src/gb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c similarity index 100% rename from openbsc/src/gb/gprs_ns_vty.c rename to openbsc/src/libgb/gprs_ns_vty.c From ff663237b508109b7ccbc236ddfaa00b26a5f2ab Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 22 Mar 2011 16:47:59 +0100 Subject: [PATCH 168/198] src: use new library libosmogsm and new path to headers in libosmocore libosmogsm is a new library that is distributed in the libosmocore. Now, openbsc depends on it. This patch gets openbsc with this change. This patch also rewrites all include path to the new osmocom/[gsm|core] Signed-off-by: Pablo Neira Ayuso --- openbsc/include/openbsc/gprs_bssgp.h | 2 +- openbsc/include/openbsc/gprs_ns.h | 8 ++++---- openbsc/src/libgb/Makefile.am | 2 +- openbsc/src/libgb/gprs_bssgp.c | 8 ++++---- openbsc/src/libgb/gprs_bssgp_util.c | 6 +++--- openbsc/src/libgb/gprs_bssgp_vty.c | 10 +++++----- openbsc/src/libgb/gprs_ns.c | 10 +++++----- openbsc/src/libgb/gprs_ns_frgre.c | 6 +++--- openbsc/src/libgb/gprs_ns_vty.c | 10 +++++----- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index e432cf750..cef4c30e7 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -182,7 +182,7 @@ struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t /* Find a BTS context based on BVCI+NSEI tuple */ struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei); -#include +#include /* BSSGP-UL-UNITDATA.ind */ int gprs_bssgp_rcvmsg(struct msgb *msg); diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 953c364b8..0b5014988 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -77,10 +77,10 @@ enum ns_cause { /* Our Implementation */ #include -#include -#include -#include -#include +#include +#include +#include +#include #define NS_TIMERS_COUNT 7 #define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" diff --git a/openbsc/src/libgb/Makefile.am b/openbsc/src/libgb/Makefile.am index b48b17791..8ec100699 100644 --- a/openbsc/src/libgb/Makefile.am +++ b/openbsc/src/libgb/Makefile.am @@ -1,6 +1,6 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) -AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOCORE_GSM) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS) noinst_LIBRARIES = libgb.a diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index eca34b989..b74791c42 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -27,10 +27,10 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/openbsc/src/libgb/gprs_bssgp_util.c b/openbsc/src/libgb/gprs_bssgp_util.c index f8e3b5699..b5393239e 100644 --- a/openbsc/src/libgb/gprs_bssgp_util.c +++ b/openbsc/src/libgb/gprs_bssgp_util.c @@ -24,9 +24,9 @@ #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/openbsc/src/libgb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c index 9ebd09004..720c221b7 100644 --- a/openbsc/src/libgb/gprs_bssgp_vty.c +++ b/openbsc/src/libgb/gprs_bssgp_vty.c @@ -27,11 +27,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 5a8e35860..877a06545 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -59,11 +59,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/openbsc/src/libgb/gprs_ns_frgre.c b/openbsc/src/libgb/gprs_ns_frgre.c index 106f410e6..98b1ad602 100644 --- a/openbsc/src/libgb/gprs_ns_frgre.c +++ b/openbsc/src/libgb/gprs_ns_frgre.c @@ -31,9 +31,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index 39277fc71..505dc3b2b 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -27,11 +27,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include From 167281ec500cff6b0c00e47d1478359bc3f9c7d0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 28 Mar 2011 19:35:00 +0200 Subject: [PATCH 169/198] src: include new file osmocom/vty/misc.h for vty_out_rate_ctr_group() This uses the new include file for vty_out_rate_ctr_group() which available in libosmocore. --- openbsc/src/libgb/gprs_bssgp_vty.c | 1 + openbsc/src/libgb/gprs_ns_vty.c | 1 + 2 files changed, 2 insertions(+) diff --git a/openbsc/src/libgb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c index 720c221b7..a0d74ac94 100644 --- a/openbsc/src/libgb/gprs_bssgp_vty.c +++ b/openbsc/src/libgb/gprs_bssgp_vty.c @@ -42,6 +42,7 @@ #include #include #include +#include /* FIXME: this should go to some common file as it is copied * in vty_interface.c of the BSC */ diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index 505dc3b2b..14d7691dd 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -42,6 +42,7 @@ #include #include #include +#include static struct gprs_ns_inst *vty_nsi = NULL; From c0d04310f3867cf48eadefe0ce01c4fc3eead036 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 5 Apr 2011 18:33:24 +0200 Subject: [PATCH 170/198] libcommon: socket: extend make_sock() prototype This patch extends the make_sock() prototype so you can fully set the fields priv_nr and data of the bsc_fd structure. This is the first step to get rid of the internal make_sock() implementation that ipaccess-proxy uses. This patch includes a minor cleanup to pass INADDR_ANY instead of zero, if you do not want to bind the socket to one specific address. --- openbsc/src/libgb/gprs_ns.c | 2 +- openbsc/src/libgb/gprs_ns_frgre.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 877a06545..95e5a55d7 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -946,7 +946,7 @@ int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi) int ret; ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, nsi->nsip.local_ip, - nsi->nsip.local_port, nsip_fd_cb); + nsi->nsip.local_port, 0, nsip_fd_cb, NULL); if (ret < 0) return ret; diff --git a/openbsc/src/libgb/gprs_ns_frgre.c b/openbsc/src/libgb/gprs_ns_frgre.c index 98b1ad602..85019e1a4 100644 --- a/openbsc/src/libgb/gprs_ns_frgre.c +++ b/openbsc/src/libgb/gprs_ns_frgre.c @@ -292,7 +292,7 @@ int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi) return 0; rc = make_sock(&nsi->frgre.fd, IPPROTO_GRE, nsi->frgre.local_ip, - 0, nsfrgre_fd_cb); + 0, 0, nsfrgre_fd_cb, NULL); if (rc < 0) { LOGP(DNS, LOGL_ERROR, "Error creating GRE socket (%s)\n", strerror(errno)); From 2b15952a372238c8351ff24caa3f5842ddc31b7e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 6 May 2011 12:11:06 +0200 Subject: [PATCH 172/198] src: use namespace prefix osmo_timer* for timer functions Summary of changes: s/struct timer_list/struct osmo_timer_list/g s/bsc_add_timer/osmo_timer_add/g s/bsc_schedule_timer/osmo_timer_schedule/g s/bsc_del_timer/osmo_timer_del/g s/bsc_timer_pending/osmo_timer_pending/g s/bsc_nearest_timer/osmo_timers_nearest/g s/bsc_prepare_timers/osmo_timers_prepare/g s/bsc_update_timers/osmo_timers_update/g s/bsc_timer_check/osmo_timers_check/g --- openbsc/include/openbsc/gprs_ns.h | 2 +- openbsc/src/libgb/gprs_ns.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 0b5014988..f497e2368 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -163,7 +163,7 @@ struct gprs_nsvc { uint32_t state; uint32_t remote_state; - struct timer_list timer; + struct osmo_timer_list timer; enum nsvc_timer_mode timer_mode; int alive_retries; diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 95e5a55d7..1c3c1b6cd 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -166,8 +166,8 @@ struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) void nsvc_delete(struct gprs_nsvc *nsvc) { - if (bsc_timer_pending(&nsvc->timer)) - bsc_del_timer(&nsvc->timer); + if (osmo_timer_pending(&nsvc->timer)) + osmo_timer_del(&nsvc->timer); llist_del(&nsvc->list); talloc_free(nsvc); } @@ -405,11 +405,11 @@ static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) nsvc->nsei, get_value_string(timer_mode_strs, mode), seconds); - if (bsc_timer_pending(&nsvc->timer)) - bsc_del_timer(&nsvc->timer); + if (osmo_timer_pending(&nsvc->timer)) + osmo_timer_del(&nsvc->timer); nsvc->timer_mode = mode; - bsc_schedule_timer(&nsvc->timer, seconds, 0); + osmo_timer_schedule(&nsvc->timer, seconds, 0); } static void gprs_ns_timer_cb(void *data) @@ -786,7 +786,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); if (nsvc->persistent || nsvc->remote_end_is_sgsn) { /* stop RESET timer */ - bsc_del_timer(&nsvc->timer); + osmo_timer_del(&nsvc->timer); } /* Initiate TEST proc.: Send ALIVE and start timer */ rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); From bfadfb771dc8e6c24a5731c19fb561ce08ffe590 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 6 May 2011 12:11:23 +0200 Subject: [PATCH 173/198] src: use namespace prefix osmo_fd* and osmo_select* Summary of changes: s/struct bsc_fd/struct osmo_fd/g s/bsc_register_fd/osmo_fd_register/g s/bsc_unregister_fd/osmo_fd_unregister/g s/bsc_select_main/osmo_select_main/g --- openbsc/include/openbsc/gprs_ns.h | 4 ++-- openbsc/src/libgb/gprs_ns.c | 8 ++++---- openbsc/src/libgb/gprs_ns_frgre.c | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index f497e2368..8f28d4623 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -133,13 +133,13 @@ struct gprs_ns_inst { /* NS-over-IP specific bits */ struct { - struct bsc_fd fd; + struct osmo_fd fd; uint32_t local_ip; uint16_t local_port; } nsip; /* NS-over-FR-over-GRE-over-IP specific bits */ struct { - struct bsc_fd fd; + struct osmo_fd fd; uint32_t local_ip; int enabled:1; } frgre; diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 1c3c1b6cd..2e549f346 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -858,7 +858,7 @@ void gprs_ns_destroy(struct gprs_ns_inst *nsi) * We don't support Size Procedure, Configuration Procedure, ChangeWeight Procedure */ /* Read a single NS-over-IP message */ -static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, +static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error, struct sockaddr_in *saddr) { struct msgb *msg = gprs_ns_msgb_alloc(); @@ -890,7 +890,7 @@ static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, return msg; } -static int handle_nsip_read(struct bsc_fd *bfd) +static int handle_nsip_read(struct osmo_fd *bfd) { int error; struct sockaddr_in saddr; @@ -907,7 +907,7 @@ static int handle_nsip_read(struct bsc_fd *bfd) return error; } -static int handle_nsip_write(struct bsc_fd *bfd) +static int handle_nsip_write(struct osmo_fd *bfd) { /* FIXME: actually send the data here instead of nsip_sendmsg() */ return -EIO; @@ -928,7 +928,7 @@ static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) } /* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */ -static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) +static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what) { int rc = 0; diff --git a/openbsc/src/libgb/gprs_ns_frgre.c b/openbsc/src/libgb/gprs_ns_frgre.c index 85019e1a4..366257239 100644 --- a/openbsc/src/libgb/gprs_ns_frgre.c +++ b/openbsc/src/libgb/gprs_ns_frgre.c @@ -49,7 +49,7 @@ struct gre_hdr { } __attribute__ ((packed)); /* IPv4 messages inside the GRE tunnel might be GRE keepalives */ -static int handle_rx_gre_ipv4(struct bsc_fd *bfd, struct msgb *msg, +static int handle_rx_gre_ipv4(struct osmo_fd *bfd, struct msgb *msg, struct iphdr *iph, struct gre_hdr *greh) { struct gprs_ns_inst *nsi = bfd->data; @@ -101,7 +101,7 @@ static int handle_rx_gre_ipv4(struct bsc_fd *bfd, struct msgb *msg, (struct sockaddr *)&daddr, sizeof(daddr)); } -static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error, +static struct msgb *read_nsfrgre_msg(struct osmo_fd *bfd, int *error, struct sockaddr_in *saddr) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx"); @@ -203,7 +203,7 @@ out_err: int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct sockaddr_in *saddr, enum gprs_ns_ll ll); -static int handle_nsfrgre_read(struct bsc_fd *bfd) +static int handle_nsfrgre_read(struct osmo_fd *bfd) { int rc; struct sockaddr_in saddr; @@ -230,7 +230,7 @@ out: return rc; } -static int handle_nsfrgre_write(struct bsc_fd *bfd) +static int handle_nsfrgre_write(struct osmo_fd *bfd) { /* FIXME: actually send the data here instead of nsip_sendmsg() */ return -EIO; @@ -268,7 +268,7 @@ int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) return rc; } -static int nsfrgre_fd_cb(struct bsc_fd *bfd, unsigned int what) +static int nsfrgre_fd_cb(struct osmo_fd *bfd, unsigned int what) { int rc = 0; From 2b88a2a957977c625cac014f642fcf5acb27435e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 6 May 2011 12:12:31 +0200 Subject: [PATCH 174/198] src: use namespace prefix osmo_signal* Summary of changes: s/signal_cbfn/osmo_signal_cbfn/g s/register_signal_handler/osmo_signal_register_handler/g s/unregister_signal_handler/osmo_signal_unregister_handler/g s/dispatch_signal/osmo_signal_dispatch/g --- openbsc/src/libgb/gprs_ns.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 2e549f346..dab57e663 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -172,7 +172,7 @@ void nsvc_delete(struct gprs_nsvc *nsvc) talloc_free(nsvc); } -static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal, +static void ns_osmo_signal_dispatch(struct gprs_nsvc *nsvc, unsigned int signal, uint8_t cause) { struct ns_signal_data nssd; @@ -180,7 +180,7 @@ static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal, nssd.nsvc = nsvc; nssd.cause = cause; - dispatch_signal(SS_NS, signal, &nssd); + osmo_signal_dispatch(SS_NS, signal, &nssd); } /* Section 10.3.2, Table 13 */ @@ -437,8 +437,8 @@ static void gprs_ns_timer_cb(void *data) "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]); - ns_dispatch_signal(nsvc, S_NS_ALIVE_EXP, 0); - ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); + ns_osmo_signal_dispatch(nsvc, S_NS_ALIVE_EXP, 0); + ns_osmo_signal_dispatch(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } /* Tns-test case: send NS-ALIVE PDU */ @@ -631,7 +631,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* inform interested parties about the fact that this NSVC * has received RESET */ - ns_dispatch_signal(nsvc, S_NS_RESET, *cause); + ns_osmo_signal_dispatch(nsvc, S_NS_RESET, *cause); return gprs_ns_tx_reset_ack(nsvc); } @@ -665,7 +665,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); - ns_dispatch_signal(nsvc, S_NS_BLOCK, *cause); + ns_osmo_signal_dispatch(nsvc, S_NS_BLOCK, *cause); rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); @@ -796,7 +796,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* Section 7.2: unblocking procedure */ LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; - ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); + ns_osmo_signal_dispatch(nsvc, S_NS_UNBLOCK, 0); rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: @@ -804,7 +804,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* mark NS-VC as unblocked + active */ nsvc->state = NSE_S_ALIVE; nsvc->remote_state = NSE_S_ALIVE; - ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); + ns_osmo_signal_dispatch(nsvc, S_NS_UNBLOCK, 0); break; case NS_PDUT_BLOCK: rc = gprs_ns_rx_block(nsvc, msg); From d83d1b6a0354bf53073f4936e1c3072de0202232 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 16 Jul 2011 13:45:10 +0200 Subject: [PATCH 176/198] gprs_bssgp_util.c: orig_msg == NULL is not supported we need it for deriving the NSEI anyway. Detected by Smatch --- openbsc/src/libgb/gprs_bssgp_util.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openbsc/src/libgb/gprs_bssgp_util.c b/openbsc/src/libgb/gprs_bssgp_util.c index b5393239e..a1eb37e18 100644 --- a/openbsc/src/libgb/gprs_bssgp_util.c +++ b/openbsc/src/libgb/gprs_bssgp_util.c @@ -111,9 +111,8 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) uint16_t _bvci = htons(*bvci); msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); } - if (orig_msg) - msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); + msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, + msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); return gprs_ns_sendmsg(bssgp_nsi, msg); } From 086fe322342b9999815a27985c138a24be39c8d1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 19 Aug 2011 16:45:19 +0200 Subject: [PATCH 178/198] bssgp: make comments more explicit, include 'Rx' in received messages --- openbsc/src/libgb/gprs_bssgp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index b74791c42..072dff6ef 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -257,7 +257,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, * informs us about its RAC + Cell ID, so we can create a mapping */ if (bvci != 0 && bvci != 1) { if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { - LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u RESET " + LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx RESET " "missing mandatory IE\n", bvci); return -EINVAL; } @@ -289,7 +289,7 @@ static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) return 0; } - LOGP(DBSSGP, LOGL_INFO, "BSSGP BVCI=%u BVC-BLOCK\n", bvci); + LOGP(DBSSGP, LOGL_INFO, "BSSGP Rx BVCI=%u BVC-BLOCK\n", bvci); ptp_ctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg)); if (!ptp_ctx) @@ -343,7 +343,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, /* extract TLLI and parse TLV IEs */ msgb_tlli(msg) = ntohl(budh->tlli); - DEBUGP(DBSSGP, "BSSGP TLLI=0x%08x UPLINK-UNITDATA\n", msgb_tlli(msg)); + DEBUGP(DBSSGP, "BSSGP TLLI=0x%08x Rx UPLINK-UNITDATA\n", msgb_tlli(msg)); /* Cell ID and LLC_PDU are the only mandatory IE */ if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID) || @@ -414,7 +414,7 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); suspend_ref = *TLVP_VAL(tp, BSSGP_IE_SUSPEND_REF_NR); - DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x RESUME\n", ctx->bvci, tlli); + DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x Rx RESUME\n", ctx->bvci, tlli); gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); @@ -445,7 +445,7 @@ static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI)); - DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=%08x LLC DISCARDED\n", + DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=%08x Rx LLC DISCARDED\n", ctx->bvci, tlli); rate_ctr_inc(&ctx->ctrg->ctr[BSSGP_CTR_DISCARDED]); @@ -579,7 +579,7 @@ static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, break; case BSSGP_PDUT_FLUSH_LL_ACK: /* BSS informs us it has performed LL FLUSH */ - DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx FLUSH LL ACK\n", bctx->bvci); + DEBUGP(DBSSGP, "BSSGP Rx BVCI=%u FLUSH LL ACK\n", bctx->bvci); /* FIXME: send NM_FLUSH_LL.res to NM */ break; case BSSGP_PDUT_LLC_DISCARD: From 887934e28d41a5b1b542c6c6391d5a673e5aca01 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 5 Nov 2011 15:14:59 +0100 Subject: [PATCH 179/198] gb_proxy: Make sure each parameter has some sort of documentation --- openbsc/include/openbsc/gprs_ns.h | 2 ++ openbsc/src/libgb/gprs_ns_vty.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 8f28d4623..e26337a69 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -90,6 +90,8 @@ enum ns_cause { "Reset Timer (Tns-reset) timeout\n" \ "Reset Timer (Tns-reset) number of retries\n" \ "Test Timer (Tns-test) timeout\n" \ + "Alive Timer (Tns-alive) timeout\n" \ + "Alive Timer (Tns-alive) number of retries\n" enum ns_timeout { NS_TOUT_TNS_BLOCK, diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index 14d7691dd..1e485ac9d 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -478,7 +478,8 @@ DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd, DEFUN(nsvc_nsei, nsvc_nsei_cmd, "nsvc nsei <0-65535> (block|unblock|reset)", "Perform an operation on a NSVC\n" - "NS-VC Identifier (NS-VCI)\n" + "NSEI to identify NS-VC Identifier (NS-VCI)\n" + "The NSEI\n" "Initiate BLOCK procedure\n" "Initiate UNBLOCK procedure\n" "Initiate RESET procedure\n") From a9f23c8291a0d9a61152a6f9646d72ed3d40fff3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 23 Nov 2011 15:01:31 +0100 Subject: [PATCH 180/198] GPRS NS: Add some doxygen API documentation --- openbsc/include/openbsc/gprs_ns.h | 50 ++++++++----- openbsc/src/libgb/gprs_ns.c | 119 +++++++++++++++++++++++++++--- 2 files changed, 143 insertions(+), 26 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index e26337a69..f0ec26ed5 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -7,12 +7,19 @@ * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ +/*! \addtogroup libgb + * @{ + */ + +/*! \file gprs_ns.h */ + +/*! \brief Common header of GPRS NS */ struct gprs_ns_hdr { - uint8_t pdu_type; - uint8_t data[0]; + uint8_t pdu_type; /*!< NS PDU type */ + uint8_t data[0]; /*!< variable-length payload */ } __attribute__((packed)); -/* TS 08.16, Section 10.3.7, Table 14 */ +/*! \brief NS PDU Type (TS 08.16, Section 10.3.7, Table 14) */ enum ns_pdu_type { NS_PDUT_UNITDATA = 0x00, NS_PDUT_RESET = 0x02, @@ -35,7 +42,7 @@ enum ns_pdu_type { SNS_PDUT_SIZE_ACK = 0x13, }; -/* TS 08.16, Section 10.3, Table 12 */ +/*! \brief NS Control IE (TS 08.16, Section 10.3, Table 12) */ enum ns_ctrl_ie { NS_IE_CAUSE = 0x00, NS_IE_VCI = 0x01, @@ -52,7 +59,7 @@ enum ns_ctrl_ie { NS_IE_IP_ADDR = 0x0b, }; -/* TS 08.16, Section 10.3.2, Table 13 */ +/*! \brief NS Cause (TS 08.16, Section 10.3.2, Table 13) */ enum ns_cause { NS_CAUSE_TRANSIT_FAIL = 0x00, NS_CAUSE_OM_INTERVENTION = 0x01, @@ -106,40 +113,44 @@ enum ns_timeout { #define NSE_S_BLOCKED 0x0001 #define NSE_S_ALIVE 0x0002 +/*! \brief Osmocom NS link layer types */ enum gprs_ns_ll { - GPRS_NS_LL_UDP, - GPRS_NS_LL_E1, - GPRS_NS_LL_FR_GRE, + GPRS_NS_LL_UDP, /*!< NS/UDP/IP */ + GPRS_NS_LL_E1, /*!< NS/E1 */ + GPRS_NS_LL_FR_GRE, /*!< NS/FR/GRE/IP */ }; +/*! \brief Osmoco NS events */ enum gprs_ns_evt { GPRS_NS_EVT_UNIT_DATA, }; struct gprs_nsvc; +/*! \brief Osmocom GPRS callback function type */ typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, struct msgb *msg, uint16_t bvci); -/* An instance of the NS protocol stack */ +/*! \brief An instance of the NS protocol stack */ struct gprs_ns_inst { - /* callback to the user for incoming UNIT DATA IND */ + /*! \brief callback to the user for incoming UNIT DATA IND */ gprs_ns_cb_t *cb; - /* linked lists of all NSVC in this instance */ + /*! \brief linked lists of all NSVC in this instance */ struct llist_head gprs_nsvcs; - /* a NSVC object that's needed to deal with packets for unknown NSVC */ + /*! \brief a NSVC object that's needed to deal with packets for + * unknown NSVC */ struct gprs_nsvc *unknown_nsvc; uint16_t timeout[NS_TIMERS_COUNT]; - /* NS-over-IP specific bits */ + /*! \brief NS-over-IP specific bits */ struct { struct osmo_fd fd; uint32_t local_ip; uint16_t local_port; } nsip; - /* NS-over-FR-over-GRE-over-IP specific bits */ + /*! \brief NS-over-FR-over-GRE-over-IP specific bits */ struct { struct osmo_fd fd; uint32_t local_ip; @@ -155,12 +166,15 @@ enum nsvc_timer_mode { _NSVC_TIMER_NR, }; +/*! \brief Structure representing a single NS-VC */ struct gprs_nsvc { + /*! \brief list of NS-VCs within NS Instance */ struct llist_head list; + /*! \brief pointer to NS Instance */ struct gprs_ns_inst *nsi; - uint16_t nsei; /* end-to-end significance */ - uint16_t nsvci; /* uniquely identifies NS-VC at SGSN */ + uint16_t nsei; /*! \brief end-to-end significance */ + uint16_t nsvci; /*! \brief uniquely identifies NS-VC at SGSN */ uint32_t state; uint32_t remote_state; @@ -174,7 +188,7 @@ struct gprs_nsvc { struct rate_ctr_group *ctrg; - /* which link-layer are we based on? */ + /*! \brief which link-layer are we based on? */ enum gprs_ns_ll ll; union { @@ -231,4 +245,6 @@ static inline struct msgb *gprs_ns_msgb_alloc(void) return msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "GPRS/NS"); } +/*! }@ */ + #endif diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index dab57e663..a8f97e2a2 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -1,4 +1,4 @@ -/* GPRS Networks Service (NS) messages on the Gb interfacebvci = msgb_bvci(msg); +/* GPRS Networks Service (NS) messages on the Gb interface * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ /* (C) 2009-2010 by Harald Welte @@ -20,7 +20,17 @@ * */ -/* Some introduction into NS: NS is used typically on top of frame relay, +/*! \addtogroup libgb + * @{ + */ + +/*! \file gprs_ns.c */ + +/*! + * GPRS Networks Service (NS) messages on the Gb interface + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) + * + * Some introduction into NS: NS is used typically on top of frame relay, * but in the ip.access world it is encapsulated in UDP packets. It serves * as an intermediate shim betwen BSSGP and the underlying medium. It doesn't * do much, apart from providing congestion notification and status indication. @@ -106,7 +116,11 @@ static const struct rate_ctr_group_desc nsvc_ctrg_desc = { .ctr_desc = nsvc_ctr_description, }; -/* Lookup struct gprs_nsvc based on NSVCI */ +/*! \brief Lookup struct gprs_nsvc based on NSVCI + * \param[in] nsi NS instance in which to search + * \param[in] nsvci NSVCI to be searched + * \returns gprs_nsvc of respective NSVCI + */ struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -117,7 +131,11 @@ struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) return NULL; } -/* Lookup struct gprs_nsvc based on NSVCI */ +/*! \brief Lookup struct gprs_nsvc based on NSEI + * \param[in] nsi NS instance in which to search + * \param[in] nsei NSEI to be searched + * \returns gprs_nsvc of respective NSEI + */ struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei) { struct gprs_nsvc *nsvc; @@ -164,6 +182,9 @@ struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) return nsvc; } +/*! \brief Delete given NS-VC + * \param[in] nsvc gprs_nsvc to be deleted + */ void nsvc_delete(struct gprs_nsvc *nsvc) { if (osmo_timer_pending(&nsvc->timer)) @@ -199,6 +220,7 @@ static const struct value_string ns_cause_str[] = { { 0, NULL } }; +/*! \brief Obtain a human-readable string for NS cause value */ const char *gprs_ns_cause_str(enum ns_cause cause) { return get_value_string(ns_cause_str, cause); @@ -251,6 +273,10 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) return gprs_ns_tx(nsvc, msg); } +/*! \brief Transmit a NS-RESET on a given NSVC + * \param[in] nsvc NS-VC used for transmission + * \paam[in] cause Numeric NS cause value + */ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = gprs_ns_msgb_alloc(); @@ -278,6 +304,11 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) } +/*! \brief Transmit a NS-STATUS on a given NSVC + * \param[in] nsvc NS-VC to be used for transmission + * \param[in] cause Numeric NS cause value + * \param[in] bvci BVCI to be reset within NSVC + * \param[in] orig_msg message causing the STATUS */ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, uint16_t bvci, struct msgb *orig_msg) { @@ -327,6 +358,11 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, return gprs_ns_tx(nsvc, msg); } +/*! \brief Transmit a NS-BLOCK on a tiven NS-VC + * \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted + * \param[in] cause Numeric NS Cause value + * \returns 0 in case of success + */ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = gprs_ns_msgb_alloc(); @@ -355,6 +391,10 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) return gprs_ns_tx(nsvc, msg); } +/*! \brief Transmit a NS-UNBLOCK on a given NS-VC + * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted + * \returns 0 in case of success + */ int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) { log_set_context(BSC_CTX_NSVC, nsvc); @@ -364,6 +404,10 @@ int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); } +/*! \brief Transmit a NS-ALIVE on a given NS-VC + * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted + * \returns 0 in case of success + */ int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) { log_set_context(BSC_CTX_NSVC, nsvc); @@ -373,6 +417,10 @@ int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); } +/*! \brief Transmit a NS-ALIVE-ACK on a given NS-VC + * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted + * \returns 0 in case of success + */ int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc) { log_set_context(BSC_CTX_NSVC, nsvc); @@ -493,7 +541,16 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) return gprs_ns_tx(nsvc, msg); } -/* Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive */ +/*! \brief High-level function for transmitting a NS-UNITDATA messsage + * \param[in] nsi NS-instance on which we shall transmit + * \param[in] msg struct msgb to be trasnmitted + * + * This function obtains the NS-VC by the msgb_nsei(msg) and then checks + * if the NS-VC is ALIVEV and not BLOCKED. After that, it adds a NS + * header for the NS-UNITDATA message type and sends it off. + * + * Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive + */ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) { struct gprs_nsvc *nsvc; @@ -671,7 +728,16 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); } -/* main entry point, here incoming NS frames enter */ +/*! \brief Receive incoming NS message from underlying transport layer + * \param nsi NS instance to which the data belongs + * \param[in] msg message buffer containing newly-received data + * \param[in] saddr socketaddr from which data was received + * \param[in] ll link-layer type in which data was received + * \returns 0 in case of success, < 0 in case of error + * + * This is the main entry point int othe NS imlementation where frames + * from the underlying transport (normally UDP) enter. + */ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct sockaddr_in *saddr, enum gprs_ns_ll ll) { @@ -823,6 +889,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, return rc; } +/*! \brief Create a new GPRS NS instance + * \param[in] cb Call-back function for incoming BSSGP data + * \returns dynamically allocated gprs_ns_inst + */ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) { struct gprs_ns_inst *nsi = talloc_zero(tall_bsc_ctx, struct gprs_ns_inst); @@ -845,6 +915,12 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) return nsi; } +/*! \brief Destroy an entire NS instance + * \param nsi gprs_ns_inst that is to be destroyed + * + * This function SHOULD release all resources associated with the + * NS-instance but is actually not completely implemented! + */ void gprs_ns_destroy(struct gprs_ns_inst *nsi) { /* FIXME: clear all timers */ @@ -940,7 +1016,14 @@ static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what) return rc; } -/* Listen for incoming GPRS packets */ +/*! \brief Create a listening socket for GPRS NS/UDP/IP + * \param[in] nsi NS protocol instance to listen + * \returns >=0 (fd) in case of success, negative in case of error + * + * A call to this function will create a UDP socket bound to the port + * number and IP address specified in the NS protocol instance. The + * file descriptor of the socket will be stored in nsi->nsip.fd. + */ int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi) { int ret; @@ -955,7 +1038,14 @@ int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi) return ret; } -/* Initiate a RESET procedure */ +/*! \brief Initiate a RESET procedure + * \param[in] nsvc NS-VC in which to start the procedure + * \param[in] cause Numeric NS cause value + * + * This is a high-level function initiating a NS-RESET procedure. It + * will not only send a NS-RESET, but also set the state to BLOCKED and + * start the Tns-reset timer. + */ void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) { LOGP(DNS, LOGL_INFO, "NSEI=%u RESET procedure based on API request\n", @@ -972,7 +1062,16 @@ void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); } -/* Establish a connection (from the BSS) to the SGSN */ +/*! \brief Establish a NS connection (from the BSS) to the SGSN + * \param nsi NS-instance + * \param[in] dest Destination IP/Port + * \param[in] nsei NSEI of the to-be-established NS-VC + * \param[in] nsvci NSVCI of the to-be-established NS-VC + * \returns struct gprs_nsvc representing the new NS-VC + * + * This function will establish a single NS/UDP/IP connection in uplink + * (BSS to SGSN) direction. + */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, uint16_t nsvci) @@ -990,3 +1089,5 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION); return nsvc; } + +/*! }@ */ From 2861007a404cf6d8e85b299d4b2507485c461a4a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Nov 2011 21:32:07 +0100 Subject: [PATCH 181/198] GPRS: add new bssgp_create_cell_id(), opposite of bssgp_parse_cell_id() --- openbsc/src/libgb/gprs_bssgp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index 072dff6ef..f26ff163c 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -232,6 +232,18 @@ uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) return ntohs(*(uint16_t *) (buf+6)); } +int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid, + uint16_t cid) +{ + uint16_t *out_cid = (uint16_t *) (buf + 6); + /* 6 octets RAC */ + gsm48_construct_ra(buf, raid); + /* 2 octets CID */ + *out_cid = htons(cid); + + return 8; +} + /* Chapter 8.4 BVC-Reset Procedure */ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, uint16_t ns_bvci) From eb3ccf64898b5ca1d969dadb8e12680bf89c394d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Nov 2011 08:15:42 +0100 Subject: [PATCH 182/198] BSSGP: add more doxygen comments --- openbsc/include/openbsc/gprs_bssgp.h | 54 +++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index cef4c30e7..1205aa81c 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -3,11 +3,11 @@ #include -/* Section 5.4.1 */ +/*! \brief Fixed BVCI definitions (Section 5.4.1) */ #define BVCI_SIGNALLING 0x0000 #define BVCI_PTM 0x0001 -/* Section 11.3.26 / Table 11.27 */ +/*! \brief BSSGP PDU types (Section 11.3.26 / Table 11.27) */ enum bssgp_pdu_type { /* PDUs between RL and BSSGP SAPs */ BSSGP_PDUT_DL_UNITDATA = 0x00, @@ -53,19 +53,21 @@ enum bssgp_pdu_type { BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57, }; -/* Section 10.2.1 and 10.2.2 */ +/*! \brief BSSGP User-Data header (Section 10.2.1 and 10.2.2) */ struct bssgp_ud_hdr { - uint8_t pdu_type; - uint32_t tlli; - uint8_t qos_profile[3]; - uint8_t data[0]; /* TLV's */ + uint8_t pdu_type; /*!< BSSGP PDU type */ + uint32_t tlli; /*!< Temporary Link-Local Identifier */ + uint8_t qos_profile[3]; /*!< QoS profile */ + uint8_t data[0]; /* optional/conditional IEs as TLVs */ } __attribute__((packed)); +/*! \brief BSSGP normal header */ struct bssgp_normal_hdr { - uint8_t pdu_type; - uint8_t data[0]; /* TLV's */ + uint8_t pdu_type; /*!< BSSGP PDU type */ + uint8_t data[0]; /*!< optional/conditional IEs as TLVs */ }; +/*! \brief BSSGP Information Element Identifiers */ enum bssgp_iei_type { BSSGP_IE_ALIGNMENT = 0x00, BSSGP_IE_BMAX_DEFAULT_MS = 0x01, @@ -115,7 +117,7 @@ enum bssgp_iei_type { BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d, }; -/* Section 11.3.8 / Table 11.10: Cause coding */ +/*! \brief Cause coding (Section 11.3.8 / Table 11.10) */ enum gprs_bssgp_cause { BSSGP_CAUSE_PROC_OVERLOAD = 0x00, BSSGP_CAUSE_EQUIP_FAIL = 0x01, @@ -159,9 +161,8 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg); struct bssgp_bvc_ctx { struct llist_head list; - /* parsed RA ID and Cell ID of the remote BTS */ - struct gprs_ra_id ra_id; - uint16_t cell_id; + struct gprs_ra_id ra_id; /*!< parsed RA ID of the remote BTS */ + uint16_t cell_id; /*!< Cell ID of the remote BTS */ /* NSEI and BVCI of underlying Gb link. Together they * uniquely identify a link to a BTS (5.4.4) */ @@ -199,27 +200,30 @@ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); } +/*! \brief BSSGP Paging mode */ enum bssgp_paging_mode { BSSGP_PAGING_PS, BSSGP_PAGING_CS, }; +/*! \brief BSSGP Paging scope */ enum bssgp_paging_scope { - BSSGP_PAGING_BSS_AREA, /* all cells in BSS */ - BSSGP_PAGING_LOCATION_AREA, /* all cells in LA */ - BSSGP_PAGING_ROUTEING_AREA, /* all cells in RA */ - BSSGP_PAGING_BVCI, /* one cell */ + BSSGP_PAGING_BSS_AREA, /*!< all cells in BSS */ + BSSGP_PAGING_LOCATION_AREA, /*!< all cells in LA */ + BSSGP_PAGING_ROUTEING_AREA, /*!< all cells in RA */ + BSSGP_PAGING_BVCI, /*!< one cell */ }; +/*! \brief BSSGP paging information */ struct bssgp_paging_info { - enum bssgp_paging_mode mode; - enum bssgp_paging_scope scope; - struct gprs_ra_id raid; - uint16_t bvci; - const char *imsi; - uint32_t *ptmsi; - uint16_t drx_params; - uint8_t qos[3]; + enum bssgp_paging_mode mode; /*!< CS or PS paging */ + enum bssgp_paging_scope scope; /*!< bssgp_paging_scope */ + struct gprs_ra_id raid; /*!< RA Identifier */ + uint16_t bvci; /*!< BVCI */ + const char *imsi; /*!< IMSI, if any */ + uint32_t *ptmsi; /*!< P-TMSI, if any */ + uint16_t drx_params; /*!< DRX parameters */ + uint8_t qos[3]; /*!< QoS parameters */ }; /* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */ From 85fc31416b643c73f59e5af7a0e2d90813f29a50 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Nov 2011 08:58:40 +0100 Subject: [PATCH 183/198] BSSGP: Add functions required for true BSS-side BSSGP implementation The BSS-side of BSSGP requires quite a number of additional functions for sending unidirectional messages that a SGSN never sends. This is a first step into completing the BSSGP implementation and making it ready to be used from osmo-bts and other BTS-side GPRS implementations. --- openbsc/include/openbsc/gprs_bssgp.h | 16 +- openbsc/src/libgb/Makefile.am | 2 +- openbsc/src/libgb/gprs_bssgp.c | 11 - openbsc/src/libgb/gprs_bssgp_bss.c | 426 +++++++++++++++++++++++++++ 4 files changed, 442 insertions(+), 13 deletions(-) create mode 100644 openbsc/src/libgb/gprs_bssgp_bss.c diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index 1205aa81c..df93f5b2c 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -183,6 +183,18 @@ struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t /* Find a BTS context based on BVCI+NSEI tuple */ struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei); +#define BVC_F_BLOCKED 0x0001 + +enum bssgp_ctr { + BSSGP_CTR_PKTS_IN, + BSSGP_CTR_PKTS_OUT, + BSSGP_CTR_BYTES_IN, + BSSGP_CTR_BYTES_OUT, + BSSGP_CTR_BLOCKED, + BSSGP_CTR_DISCARDED, +}; + + #include /* BSSGP-UL-UNITDATA.ind */ @@ -193,6 +205,8 @@ struct sgsn_mm_ctx; int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx); uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); +int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid, + uint16_t cid); /* Wrapper around TLV parser to parse BSSGP IEs */ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) @@ -220,7 +234,7 @@ struct bssgp_paging_info { enum bssgp_paging_scope scope; /*!< bssgp_paging_scope */ struct gprs_ra_id raid; /*!< RA Identifier */ uint16_t bvci; /*!< BVCI */ - const char *imsi; /*!< IMSI, if any */ + char *imsi; /*!< IMSI, if any */ uint32_t *ptmsi; /*!< P-TMSI, if any */ uint16_t drx_params; /*!< DRX parameters */ uint8_t qos[3]; /*!< QoS parameters */ diff --git a/openbsc/src/libgb/Makefile.am b/openbsc/src/libgb/Makefile.am index 8ec100699..cb656cccf 100644 --- a/openbsc/src/libgb/Makefile.am +++ b/openbsc/src/libgb/Makefile.am @@ -5,5 +5,5 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOCORE_GSM) $(LIBOSMOVTY_LIBS) $(COVERAG noinst_LIBRARIES = libgb.a libgb_a_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c \ - gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c + gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c gprs_bssgp_bss.c #gprs_llc.c gprs_llc_vty.c crc24.c diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index f26ff163c..6722cafba 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -43,17 +43,6 @@ void *bssgp_tall_ctx = NULL; -#define BVC_F_BLOCKED 0x0001 - -enum bssgp_ctr { - BSSGP_CTR_PKTS_IN, - BSSGP_CTR_PKTS_OUT, - BSSGP_CTR_BYTES_IN, - BSSGP_CTR_BYTES_OUT, - BSSGP_CTR_BLOCKED, - BSSGP_CTR_DISCARDED, -}; - static const struct rate_ctr_desc bssgp_ctr_description[] = { { "packets.in", "Packets at BSSGP Level ( In)" }, { "packets.out","Packets at BSSGP Level (Out)" }, diff --git a/openbsc/src/libgb/gprs_bssgp_bss.c b/openbsc/src/libgb/gprs_bssgp_bss.c new file mode 100644 index 000000000..9d76c3aa0 --- /dev/null +++ b/openbsc/src/libgb/gprs_bssgp_bss.c @@ -0,0 +1,426 @@ +/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ + +/* (C) 2009-2011 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +uint8_t *bssgp_msgb_tlli_put(struct msgb *msg, uint32_t tlli) +{ + uint32_t _tlli = htonl(tlli); + return msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli); +} + +/*! \brief GMM-SUSPEND.req (Chapter 10.3.6) */ +int bssgp_tx_suspend(uint16_t nsei, uint32_t tlli, + const struct gprs_ra_id *ra_id) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint8_t ra[6]; + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=0) Tx SUSPEND (TLLI=0x%04x)\n", + tlli); + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_SUSPEND; + + bssgp_msgb_tlli_put(msg, tlli); + + gsm48_construct_ra(ra, ra_id); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/*! \brief GMM-RESUME.req (Chapter 10.3.9) */ +int bssgp_tx_resume(uint16_t nsei, uint32_t tlli, + const struct gprs_ra_id *ra_id, uint8_t suspend_ref) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint8_t ra[6]; + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=0) Tx RESUME (TLLI=0x%04x)\n", + tlli); + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_RESUME; + + bssgp_msgb_tlli_put(msg, tlli); + + gsm48_construct_ra(ra, ra_id); + msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra); + + msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/*! \brief Transmit RA-CAPABILITY-UPDATE (10.3.3) */ +int bssgp_tx_ra_capa_upd(struct bssgp_bvc_ctx *bctx, uint32_t tlli, uint8_t tag) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx RA-CAPA-UPD (TLLI=0x%04x)\n", + bctx->bvci, tlli); + + /* set NSEI and BVCI in msgb cb */ + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = bctx->bvci; + + bgph->pdu_type = BSSGP_PDUT_RA_CAPA_UDPATE; + bssgp_msgb_tlli_put(msg, tlli); + + msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* first common part of RADIO-STATUS */ +static struct msgb *common_tx_radio_status(struct bssgp_bvc_ctx *bctx) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx RADIO-STATUS ", + bctx->bvci); + + /* set NSEI and BVCI in msgb cb */ + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = bctx->bvci; + + bgph->pdu_type = BSSGP_PDUT_RADIO_STATUS; + + return msg; +} + +/* second common part of RADIO-STATUS */ +static int common_tx_radio_status2(struct msgb *msg, uint8_t cause) +{ + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + LOGPC(DBSSGP, LOGL_NOTICE, "CAUSE=%u\n", cause); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/*! \brief Transmit RADIO-STATUS for TLLI (10.3.5) */ +int bssgp_tx_radio_status_tlli(struct bssgp_bvc_ctx *bctx, uint8_t cause, + uint32_t tlli) +{ + struct msgb *msg = common_tx_radio_status(bctx); + + if (!msg) + return -ENOMEM; + bssgp_msgb_tlli_put(msg, tlli); + LOGPC(DBSSGP, LOGL_NOTICE, "TLLI=0x%08x ", tlli); + + return common_tx_radio_status2(msg, cause); +} + +/*! \brief Transmit RADIO-STATUS for TMSI (10.3.5) */ +int bssgp_tx_radio_status_tmsi(struct bssgp_bvc_ctx *bctx, uint8_t cause, + uint32_t tmsi) +{ + struct msgb *msg = common_tx_radio_status(bctx); + uint32_t _tmsi = htonl(tmsi); + + if (!msg) + return -ENOMEM; + msgb_tvlv_put(msg, BSSGP_IE_TMSI, 4, (uint8_t *)&_tmsi); + LOGPC(DBSSGP, LOGL_NOTICE, "TMSI=0x%08x ", tmsi); + + return common_tx_radio_status2(msg, cause); +} + +/*! \brief Transmit RADIO-STATUS for IMSI (10.3.5) */ +int bssgp_tx_radio_status_imsi(struct bssgp_bvc_ctx *bctx, uint8_t cause, + const char *imsi) +{ + struct msgb *msg = common_tx_radio_status(bctx); + uint8_t mi[10]; + int imsi_len = gsm48_generate_mid_from_imsi(mi, imsi); + + if (!msg) + return -ENOMEM; + + /* strip the MI type and length values (2 bytes) */ + if (imsi_len > 2) + msgb_tvlv_put(msg, BSSGP_IE_IMSI, imsi_len-2, mi+2); + LOGPC(DBSSGP, LOGL_NOTICE, "IMSI=%s ", imsi); + + return common_tx_radio_status2(msg, cause); +} + +/*! \brief Transmit FLUSH-LL-ACK (Chapter 10.4.2) */ +int bssgp_tx_flush_ll_ack(struct bssgp_bvc_ctx *bctx, uint32_t tlli, + uint8_t action, uint16_t bvci_new, + uint32_t num_octets) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci_new = htons(bvci_new); + uint32_t _oct_aff = htonl(num_octets & 0xFFFFFF); + + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_FLUSH_LL_ACK; + + bssgp_msgb_tlli_put(msg, tlli); + msgb_tvlv_put(msg, BSSGP_IE_FLUSH_ACTION, 1, &action); + if (action == 1) /* transferred */ + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci_new); + msgb_tvlv_put(msg, BSSGP_IE_NUM_OCT_AFF, 3, (uint8_t *) &_oct_aff); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/*! \brief Transmit LLC-DISCARDED (Chapter 10.4.3) */ +int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli, + uint8_t num_frames, uint32_t num_octets) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci = htons(bctx->bvci); + uint32_t _oct_aff = htonl(num_octets & 0xFFFFFF); + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx LLC-DISCARDED " + "TLLI=0x%04x, FRAMES=%u, OCTETS=%u\n", bctx->bvci, tlli, + num_frames, num_octets); + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_LLC_DISCARD; + + bssgp_msgb_tlli_put(msg, tlli); + + msgb_tvlv_put(msg, BSSGP_IE_LLC_FRAMES_DISCARDED, 1, &num_frames); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + msgb_tvlv_put(msg, BSSGP_IE_NUM_OCT_AFF, 3, (uint8_t *) &_oct_aff); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/*! \brief Transmit a BVC-BLOCK message (Chapter 10.4.8) */ +int bssgp_tx_bvc_block(struct bssgp_bvc_ctx *bctx, uint8_t cause) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci = htons(bctx->bvci); + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx BVC-BLOCK " + "CAUSE=%u\n", bctx->bvci, cause); + + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_BVC_BLOCK; + + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/*! \brief Transmit a BVC-UNBLOCK message (Chapter 10.4.10) */ +int bssgp_tx_bvc_unblock(struct bssgp_bvc_ctx *bctx) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci = htons(bctx->bvci); + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx BVC-BLOCK\n", bctx->bvci); + + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_BVC_UNBLOCK; + + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/*! \brief Transmit a BVC-RESET message (Chapter 10.4.12) */ +int bssgp_tx_bvc_reset(struct bssgp_bvc_ctx *bctx, uint16_t bvci, uint8_t cause) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci = htons(bvci); + + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx BVC-RESET " + "CAUSE=%u\n", bvci, cause); + + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = 0; /* Signalling */ + bgph->pdu_type = BSSGP_PDUT_BVC_RESET; + + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + if (bvci != BVCI_PTM) { + uint8_t bssgp_cid[8]; + bssgp_create_cell_id(bssgp_cid, &bctx->ra_id, bctx->cell_id); + msgb_tvlv_put(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid); + } + /* Optional: Feature Bitmap */ + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + + +/*! \brief RL-UL-UNITDATA.req (Chapter 10.2.2) */ +int bssgp_tx_ul_ud(struct bssgp_bvc_ctx *bctx, uint32_t tlli, + const uint8_t *qos_profile, struct msgb *llc_pdu) +{ + struct msgb *msg = llc_pdu; + uint8_t bssgp_cid[8]; + struct bssgp_ud_hdr *budh; + + /* FIXME: First push alignment octets, if rqd */ + + /* FIXME: Optional LSA Identifier List, PFI */ + + /* Cell Identifier */ + bssgp_create_cell_id(bssgp_cid, &bctx->ra_id, bctx->cell_id); + msgb_tvlv_push(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid); + + /* User Data Header */ + budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); + budh->tlli = htonl(tlli); + memcpy(budh->qos_profile, qos_profile, 3); + budh->pdu_type = BSSGP_PDUT_UL_UNITDATA; + + /* set NSEI and BVCI in msgb cb */ + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = bctx->bvci; + + rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_OUT]); + rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_OUT], msg->len); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* Parse a single GMM-PAGING.req to a given NSEI/NS-BVCI */ +int gprs_bssgp_rx_paging(struct bssgp_paging_info *pinfo, + struct msgb *msg) +{ + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); + struct tlv_parsed tp; + uint8_t ra[6]; + int rc, data_len; + + memset(ra, 0, sizeof(ra)); + + data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + if (rc < 0) + goto err_mand_ie; + + switch (bgph->pdu_type) { + case BSSGP_PDUT_PAGING_PS: + pinfo->mode = BSSGP_PAGING_PS; + break; + case BSSGP_PDUT_PAGING_CS: + pinfo->mode = BSSGP_PAGING_CS; + break; + default: + return -EINVAL; + } + + /* IMSI */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_IMSI)) + goto err_mand_ie; + if (!pinfo->imsi) + pinfo->imsi = talloc_zero_size(pinfo, 16); + gsm48_mi_to_string(pinfo->imsi, sizeof(pinfo->imsi), + TLVP_VAL(&tp, BSSGP_IE_IMSI), + TLVP_LEN(&tp, BSSGP_IE_IMSI)); + + /* DRX Parameters */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_DRX_PARAMS)) + goto err_mand_ie; + pinfo->drx_params = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_DRX_PARAMS)); + + /* Scope */ + if (TLVP_PRESENT(&tp, BSSGP_IE_BSS_AREA_ID)) { + pinfo->scope = BSSGP_PAGING_BSS_AREA; + } else if (TLVP_PRESENT(&tp, BSSGP_IE_LOCATION_AREA)) { + pinfo->scope = BSSGP_PAGING_LOCATION_AREA; + memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_LOCATION_AREA), + TLVP_LEN(&tp, BSSGP_IE_LOCATION_AREA)); + gsm48_parse_ra(&pinfo->raid, ra); + } else if (TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) { + pinfo->scope = BSSGP_PAGING_ROUTEING_AREA; + memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), + TLVP_LEN(&tp, BSSGP_IE_ROUTEING_AREA)); + gsm48_parse_ra(&pinfo->raid, ra); + } else if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { + pinfo->scope = BSSGP_PAGING_BVCI; + pinfo->bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + } else + return -EINVAL; + + /* QoS profile mandatory for PS */ + if (pinfo->mode == BSSGP_PAGING_PS) { + if (!TLVP_PRESENT(&tp, BSSGP_IE_QOS_PROFILE)) + goto err_cond_ie; + if (TLVP_LEN(&tp, BSSGP_IE_QOS_PROFILE) < 3) + goto err; + + memcpy(&pinfo->qos, TLVP_VAL(&tp, BSSGP_IE_QOS_PROFILE), + 3); + } + + /* Optional (P-)TMSI */ + if (TLVP_PRESENT(&tp, BSSGP_IE_TMSI) && + TLVP_LEN(&tp, BSSGP_IE_TMSI) >= 4) + if (!pinfo->ptmsi) + pinfo->ptmsi = talloc_zero_size(pinfo, sizeof(uint32_t)); + *(pinfo->ptmsi) = ntohl(*(uint32_t *) + TLVP_VAL(&tp, BSSGP_IE_TMSI)); + + return 0; + +err_mand_ie: +err_cond_ie: +err: + /* FIXME */ + return 0; +} From 322f60aeb6e018eb3d981400e544e9c22ed3b3ba Mon Sep 17 00:00:00 2001 From: Alexander Huemer Date: Sun, 20 Nov 2011 21:53:15 +0100 Subject: [PATCH 184/198] fix two mistakes in AM_LDFLAGS --- openbsc/src/libgb/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/libgb/Makefile.am b/openbsc/src/libgb/Makefile.am index cb656cccf..eebd76c72 100644 --- a/openbsc/src/libgb/Makefile.am +++ b/openbsc/src/libgb/Makefile.am @@ -1,6 +1,6 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) -AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOCORE_GSM) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS) noinst_LIBRARIES = libgb.a From 58e6d96d68bbf13bd3986173c2b4c55e6b5d6529 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 15 Jan 2012 17:52:02 +0100 Subject: [PATCH 185/198] abis: gsm_data_shared.h includes libosmo-abis header, add abis to cflags gsm_data_shared.h includes e1_input.h of libosmo-abis, add the LIBOSMOABIS_CFLAGS to Makefile.am, remove AM_LDFLAGS at the same time as we only build .a archives. --- openbsc/src/libgb/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/libgb/Makefile.am b/openbsc/src/libgb/Makefile.am index eebd76c72..fc1847f6f 100644 --- a/openbsc/src/libgb/Makefile.am +++ b/openbsc/src/libgb/Makefile.am @@ -1,6 +1,6 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) -AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS) +AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \ + $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) noinst_LIBRARIES = libgb.a From 52746469ff3d9aee14ba9fe2cffb22ce306a65ad Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 1 Mar 2012 20:30:32 +0100 Subject: [PATCH 186/198] misc: Use msgb_free for freeing the messages --- openbsc/src/libgb/gprs_ns.c | 2 +- openbsc/src/libgb/gprs_ns_frgre.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index a8f97e2a2..39ccd2851 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -998,7 +998,7 @@ static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) rc = sendto(nsi->nsip.fd.fd, msg->data, msg->len, 0, (struct sockaddr *)daddr, sizeof(*daddr)); - talloc_free(msg); + msgb_free(msg); return rc; } diff --git a/openbsc/src/libgb/gprs_ns_frgre.c b/openbsc/src/libgb/gprs_ns_frgre.c index 366257239..27c5c57b7 100644 --- a/openbsc/src/libgb/gprs_ns_frgre.c +++ b/openbsc/src/libgb/gprs_ns_frgre.c @@ -263,7 +263,7 @@ int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) rc = sendto(nsi->frgre.fd.fd, msg->data, msg->len, 0, (struct sockaddr *)&daddr, sizeof(daddr)); - talloc_free(msg); + msgb_free(msg); return rc; } From 1e57eb611238a5e46bbfdc6fdca2ba60fca1d701 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 2 Mar 2012 14:14:33 +0100 Subject: [PATCH 187/198] misc: Deal with smatch warnings about the bitfields Use unsigned ints for the bitfield. --- openbsc/include/openbsc/gprs_ns.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index f0ec26ed5..7045d84d1 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -154,7 +154,7 @@ struct gprs_ns_inst { struct { struct osmo_fd fd; uint32_t local_ip; - int enabled:1; + unsigned int enabled:1; } frgre; }; From 73952e3ab4629076c67fd64351d3d0649d75a426 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 16 Jun 2012 14:59:56 +0800 Subject: [PATCH 188/198] split libgb into a separate library for outside use This also removes the dependency to osmo_sock() inside libcommon and replaces it with osmo_sock_* from libosmocore --- openbsc/include/osmocom/gprs/Makefile.am | 3 +++ .../{openbsc => osmocom/gprs}/gprs_bssgp.h | 2 ++ .../{openbsc => osmocom/gprs}/gprs_ns.h | 0 .../{openbsc => osmocom/gprs}/gprs_ns_frgre.h | 0 openbsc/src/libgb/gprs_bssgp.c | 8 +++---- openbsc/src/libgb/gprs_bssgp_bss.c | 4 ++-- openbsc/src/libgb/gprs_bssgp_util.c | 4 ++-- openbsc/src/libgb/gprs_bssgp_vty.c | 13 ++++++------ openbsc/src/libgb/gprs_ns.c | 21 ++++++++++++------- openbsc/src/libgb/gprs_ns_frgre.c | 14 +++++++++---- openbsc/src/libgb/gprs_ns_vty.c | 13 ++++++------ 11 files changed, 50 insertions(+), 32 deletions(-) create mode 100644 openbsc/include/osmocom/gprs/Makefile.am rename openbsc/include/{openbsc => osmocom/gprs}/gprs_bssgp.h (99%) rename openbsc/include/{openbsc => osmocom/gprs}/gprs_ns.h (100%) rename openbsc/include/{openbsc => osmocom/gprs}/gprs_ns_frgre.h (100%) diff --git a/openbsc/include/osmocom/gprs/Makefile.am b/openbsc/include/osmocom/gprs/Makefile.am new file mode 100644 index 000000000..fe5714ea8 --- /dev/null +++ b/openbsc/include/osmocom/gprs/Makefile.am @@ -0,0 +1,3 @@ +libgb_HEADERS = gprs_bssgp.h gprs_ns.h gprs_ns_frgre.h + +libgbdir = $(includedir)/osmocom/gprs diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h similarity index 99% rename from openbsc/include/openbsc/gprs_bssgp.h rename to openbsc/include/osmocom/gprs/gprs_bssgp.h index df93f5b2c..bfc7d331d 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h @@ -143,6 +143,8 @@ enum gprs_bssgp_cause { /* Our implementation */ +#include + /* gprs_bssgp_util.c */ extern struct gprs_ns_inst *bssgp_nsi; struct msgb *bssgp_msgb_alloc(void); diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/osmocom/gprs/gprs_ns.h similarity index 100% rename from openbsc/include/openbsc/gprs_ns.h rename to openbsc/include/osmocom/gprs/gprs_ns.h diff --git a/openbsc/include/openbsc/gprs_ns_frgre.h b/openbsc/include/osmocom/gprs/gprs_ns_frgre.h similarity index 100% rename from openbsc/include/openbsc/gprs_ns_frgre.h rename to openbsc/include/osmocom/gprs/gprs_ns_frgre.h diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index 6722cafba..e93b3de9a 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -35,10 +35,10 @@ #include #include #include -#include -#include -#include -#include + +#include +#include + #include void *bssgp_tall_ctx = NULL; diff --git a/openbsc/src/libgb/gprs_bssgp_bss.c b/openbsc/src/libgb/gprs_bssgp_bss.c index 9d76c3aa0..a53423ca1 100644 --- a/openbsc/src/libgb/gprs_bssgp_bss.c +++ b/openbsc/src/libgb/gprs_bssgp_bss.c @@ -28,11 +28,11 @@ #include #include #include +#include +#include #include #include -#include -#include uint8_t *bssgp_msgb_tlli_put(struct msgb *msg, uint32_t tlli) { diff --git a/openbsc/src/libgb/gprs_bssgp_util.c b/openbsc/src/libgb/gprs_bssgp_util.c index a1eb37e18..c794a590e 100644 --- a/openbsc/src/libgb/gprs_bssgp_util.c +++ b/openbsc/src/libgb/gprs_bssgp_util.c @@ -27,11 +27,11 @@ #include #include #include +#include +#include #include #include -#include -#include struct gprs_ns_inst *bssgp_nsi; diff --git a/openbsc/src/libgb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c index a0d74ac94..256e8af7f 100644 --- a/openbsc/src/libgb/gprs_bssgp_vty.c +++ b/openbsc/src/libgb/gprs_bssgp_vty.c @@ -26,17 +26,13 @@ #include -#include #include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -44,6 +40,11 @@ #include #include +#include +#include +#include + + /* FIXME: this should go to some common file as it is copied * in vty_interface.c of the BSC */ static const struct value_string gprs_bssgp_timer_strs[] = { diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 39ccd2851..c1efa4318 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -68,18 +68,18 @@ #include -#include #include #include #include #include #include +#include +#include +#include +#include + #include #include -#include -#include -#include -#include static const struct tlv_definition ns_att_tlvdef = { .def = { @@ -1026,14 +1026,19 @@ static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what) */ int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi) { + struct in_addr in; int ret; - ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, nsi->nsip.local_ip, - nsi->nsip.local_port, 0, nsip_fd_cb, NULL); + in.s_addr = htonl(nsi->nsip.local_ip); + + nsi->nsip.fd.cb = nsip_fd_cb; + nsi->nsip.fd.data = nsi; + ret = osmo_sock_init_ofd(&nsi->nsip.fd, AF_INET, SOCK_DGRAM, + IPPROTO_UDP, inet_ntoa(in), + nsi->nsip.local_port, OSMO_SOCK_F_BIND); if (ret < 0) return ret; - nsi->nsip.fd.data = nsi; return ret; } diff --git a/openbsc/src/libgb/gprs_ns_frgre.c b/openbsc/src/libgb/gprs_ns_frgre.c index 27c5c57b7..9be9f2a8f 100644 --- a/openbsc/src/libgb/gprs_ns_frgre.c +++ b/openbsc/src/libgb/gprs_ns_frgre.c @@ -34,10 +34,10 @@ #include #include #include +#include +#include -#include #include -#include #define GRE_PTYPE_FR 0x6559 #define GRE_PTYPE_IPv4 0x0800 @@ -282,8 +282,11 @@ static int nsfrgre_fd_cb(struct osmo_fd *bfd, unsigned int what) int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi) { + struct in_addr in; int rc; + in.s_addr = htonl(nsi->frgre.local_ip); + /* Make sure we close any existing socket before changing it */ if (nsi->frgre.fd.fd) close(nsi->frgre.fd.fd); @@ -291,8 +294,11 @@ int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi) if (!nsi->frgre.enabled) return 0; - rc = make_sock(&nsi->frgre.fd, IPPROTO_GRE, nsi->frgre.local_ip, - 0, 0, nsfrgre_fd_cb, NULL); + nsi->frgre.fd.cb = nsfrgre_fd_cb; + nsi->frgre.fd.data = nsi; + rc = osmo_sock_init_ofd(&nsi->frgre.fd, AF_INET, SOCK_RAW, + IPPROTO_GRE, inet_ntoa(in), 0, + OSMO_SOCK_F_BIND); if (rc < 0) { LOGP(DNS, LOGL_ERROR, "Error creating GRE socket (%s)\n", strerror(errno)); diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index 1e485ac9d..f1ab28731 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -26,17 +26,13 @@ #include -#include #include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -44,6 +40,11 @@ #include #include +#include +#include +#include +#include + static struct gprs_ns_inst *vty_nsi = NULL; /* FIXME: this should go to some common file as it is copied From 605ac5d1e760fad061513e555b005ff5753f3ff1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 16 Jun 2012 16:09:52 +0800 Subject: [PATCH 189/198] libgb: move GPRS specific msgb CB definitions to separate header --- openbsc/include/osmocom/gprs/Makefile.am | 2 +- openbsc/include/osmocom/gprs/gprs_bssgp.h | 1 + openbsc/include/osmocom/gprs/gprs_msgb.h | 30 +++++++++++++++++++++++ openbsc/include/osmocom/gprs/gprs_ns.h | 1 + openbsc/src/libgb/gprs_bssgp.c | 3 +-- openbsc/src/libgb/gprs_bssgp_bss.c | 3 +-- openbsc/src/libgb/gprs_bssgp_util.c | 3 +-- openbsc/src/libgb/gprs_ns.c | 2 +- 8 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 openbsc/include/osmocom/gprs/gprs_msgb.h diff --git a/openbsc/include/osmocom/gprs/Makefile.am b/openbsc/include/osmocom/gprs/Makefile.am index fe5714ea8..66b414f32 100644 --- a/openbsc/include/osmocom/gprs/Makefile.am +++ b/openbsc/include/osmocom/gprs/Makefile.am @@ -1,3 +1,3 @@ -libgb_HEADERS = gprs_bssgp.h gprs_ns.h gprs_ns_frgre.h +libgb_HEADERS = gprs_bssgp.h gprs_ns.h gprs_ns_frgre.h gprs_msgb.h libgbdir = $(includedir)/osmocom/gprs diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h index bfc7d331d..9970a513d 100644 --- a/openbsc/include/osmocom/gprs/gprs_bssgp.h +++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h @@ -198,6 +198,7 @@ enum bssgp_ctr { #include +#include /* BSSGP-UL-UNITDATA.ind */ int gprs_bssgp_rcvmsg(struct msgb *msg); diff --git a/openbsc/include/osmocom/gprs/gprs_msgb.h b/openbsc/include/osmocom/gprs/gprs_msgb.h new file mode 100644 index 000000000..eddd888f5 --- /dev/null +++ b/openbsc/include/osmocom/gprs/gprs_msgb.h @@ -0,0 +1,30 @@ +#ifndef _LIBGB_MSGB_H +#define _LIBGB_MSGB_H + +#include +/* the data structure stored in msgb->cb for libgb apps */ +struct libgb_msgb_cb { + unsigned char *bssgph; + unsigned char *llch; + + /* Cell Identifier */ + unsigned char *bssgp_cell_id; + + /* Identifiers of a BTS, equal to 'struct bssgp_bts_ctx' */ + uint16_t nsei; + uint16_t bvci; + + /* Identifier of a MS (inside BTS), equal to 'struct sgsn_mm_ctx' */ + uint32_t tlli; +} __attribute__((packed)); +#define LIBGB_MSGB_CB(__msgb) ((struct libgb_msgb_cb *)&((__msgb)->cb[0])) +#define msgb_tlli(__x) LIBGB_MSGB_CB(__x)->tlli +#define msgb_nsei(__x) LIBGB_MSGB_CB(__x)->nsei +#define msgb_bvci(__x) LIBGB_MSGB_CB(__x)->bvci +#define msgb_gmmh(__x) (__x)->l3h +#define msgb_bssgph(__x) LIBGB_MSGB_CB(__x)->bssgph +#define msgb_bssgp_len(__x) ((__x)->tail - (uint8_t *)msgb_bssgph(__x)) +#define msgb_bcid(__x) LIBGB_MSGB_CB(__x)->bssgp_cell_id +#define msgb_llch(__x) LIBGB_MSGB_CB(__x)->llch + +#endif diff --git a/openbsc/include/osmocom/gprs/gprs_ns.h b/openbsc/include/osmocom/gprs/gprs_ns.h index 7045d84d1..cfc2e9050 100644 --- a/openbsc/include/osmocom/gprs/gprs_ns.h +++ b/openbsc/include/osmocom/gprs/gprs_ns.h @@ -88,6 +88,7 @@ enum ns_cause { #include #include #include +#include #define NS_TIMERS_COUNT 7 #define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index e93b3de9a..7615299a9 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -1,6 +1,6 @@ /* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ -/* (C) 2009-2010 by Harald Welte +/* (C) 2009-2012 by Harald Welte * * All Rights Reserved * @@ -33,7 +33,6 @@ #include #include -#include #include #include diff --git a/openbsc/src/libgb/gprs_bssgp_bss.c b/openbsc/src/libgb/gprs_bssgp_bss.c index a53423ca1..a681b9dab 100644 --- a/openbsc/src/libgb/gprs_bssgp_bss.c +++ b/openbsc/src/libgb/gprs_bssgp_bss.c @@ -1,6 +1,6 @@ /* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ -/* (C) 2009-2011 by Harald Welte +/* (C) 2009-2012 by Harald Welte * * All Rights Reserved * @@ -32,7 +32,6 @@ #include #include -#include uint8_t *bssgp_msgb_tlli_put(struct msgb *msg, uint32_t tlli) { diff --git a/openbsc/src/libgb/gprs_bssgp_util.c b/openbsc/src/libgb/gprs_bssgp_util.c index c794a590e..6ab97a79c 100644 --- a/openbsc/src/libgb/gprs_bssgp_util.c +++ b/openbsc/src/libgb/gprs_bssgp_util.c @@ -1,6 +1,6 @@ /* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ -/* (C) 2009-2010 by Harald Welte +/* (C) 2009-2012 by Harald Welte * * All Rights Reserved * @@ -31,7 +31,6 @@ #include #include -#include struct gprs_ns_inst *bssgp_nsi; diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index c1efa4318..8bed1b7bb 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -1,7 +1,7 @@ /* GPRS Networks Service (NS) messages on the Gb interface * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ -/* (C) 2009-2010 by Harald Welte +/* (C) 2009-2012 by Harald Welte * * All Rights Reserved * From 4fcdd76073edd55fb84e4579777eca006836662c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 16 Jun 2012 16:40:42 +0800 Subject: [PATCH 190/198] libgb: Use library SS_L_NS instead lf local SS_NS which removes some further dependencies of libgb to openbsc internal code and data. --- openbsc/include/osmocom/gprs/gprs_ns.h | 14 +++++++++++++- openbsc/src/libgb/gprs_bssgp.c | 1 - openbsc/src/libgb/gprs_ns.c | 8 ++++---- openbsc/src/libgb/gprs_ns_vty.c | 1 - 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/openbsc/include/osmocom/gprs/gprs_ns.h b/openbsc/include/osmocom/gprs/gprs_ns.h index cfc2e9050..ab4bd4e67 100644 --- a/openbsc/include/osmocom/gprs/gprs_ns.h +++ b/openbsc/include/osmocom/gprs/gprs_ns.h @@ -203,7 +203,7 @@ struct gprs_nsvc { }; /* Create a new NS protocol instance */ -struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); +struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb, void *ctx); /* Destroy a NS protocol instance */ void gprs_ns_destroy(struct gprs_ns_inst *nsi); @@ -246,6 +246,18 @@ static inline struct msgb *gprs_ns_msgb_alloc(void) return msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "GPRS/NS"); } +enum signal_ns { + S_NS_RESET, + S_NS_BLOCK, + S_NS_UNBLOCK, + S_NS_ALIVE_EXP, /* Tns-alive expired more than N times */ +}; + +struct ns_signal_data { + struct gprs_nsvc *nsvc; + uint8_t cause; +}; + /*! }@ */ #endif diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index 7615299a9..33cca3dfc 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -33,7 +33,6 @@ #include #include -#include #include #include diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 8bed1b7bb..617c50d69 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -74,12 +74,12 @@ #include #include #include +#include #include #include #include #include -#include static const struct tlv_definition ns_att_tlvdef = { .def = { @@ -201,7 +201,7 @@ static void ns_osmo_signal_dispatch(struct gprs_nsvc *nsvc, unsigned int signal, nssd.nsvc = nsvc; nssd.cause = cause; - osmo_signal_dispatch(SS_NS, signal, &nssd); + osmo_signal_dispatch(SS_L_NS, signal, &nssd); } /* Section 10.3.2, Table 13 */ @@ -893,9 +893,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, * \param[in] cb Call-back function for incoming BSSGP data * \returns dynamically allocated gprs_ns_inst */ -struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) +struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb, void *ctx) { - struct gprs_ns_inst *nsi = talloc_zero(tall_bsc_ctx, struct gprs_ns_inst); + struct gprs_ns_inst *nsi = talloc_zero(ctx, struct gprs_ns_inst); nsi->cb = cb; INIT_LLIST_HEAD(&nsi->gprs_nsvcs); diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index f1ab28731..a33e754b5 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -42,7 +42,6 @@ #include #include -#include #include static struct gprs_ns_inst *vty_nsi = NULL; From 4f5883bc6ef83e692625de05e1d7297a0772d4c7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 16 Jun 2012 16:54:06 +0800 Subject: [PATCH 191/198] libgb: remove dependencies to openbsc/vty.h and openbsc/gsm_data.h Rather than using openbsc internal data/functions, we now use only internal and libosmocore-provided ones. --- openbsc/src/libgb/Makefile.am | 4 +- openbsc/src/libgb/common_vty.c | 63 ++++++++++++++++++++++++++++++ openbsc/src/libgb/common_vty.h | 5 +++ openbsc/src/libgb/gprs_bssgp_vty.c | 15 ++++--- openbsc/src/libgb/gprs_ns_vty.c | 38 +++++++++--------- 5 files changed, 96 insertions(+), 29 deletions(-) create mode 100644 openbsc/src/libgb/common_vty.c create mode 100644 openbsc/src/libgb/common_vty.h diff --git a/openbsc/src/libgb/Makefile.am b/openbsc/src/libgb/Makefile.am index fc1847f6f..eafbc3437 100644 --- a/openbsc/src/libgb/Makefile.am +++ b/openbsc/src/libgb/Makefile.am @@ -5,5 +5,5 @@ AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \ noinst_LIBRARIES = libgb.a libgb_a_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c \ - gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c gprs_bssgp_bss.c -#gprs_llc.c gprs_llc_vty.c crc24.c + gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c \ + gprs_bssgp_bss.c common_vty.c diff --git a/openbsc/src/libgb/common_vty.c b/openbsc/src/libgb/common_vty.c new file mode 100644 index 000000000..269df8cd4 --- /dev/null +++ b/openbsc/src/libgb/common_vty.c @@ -0,0 +1,63 @@ +/* OpenBSC VTY common helpers */ +/* (C) 2009-2012 by Harald Welte + * (C) 2009-2010 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 Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include + +#include +#include +#include +#include + +/* Down vty node level. */ +gDEFUN(libgb_exit, + libgb_exit_cmd, "exit", "Exit current mode and down to previous mode\n") +{ + switch (vty->node) { + case L_NS_NODE: + case L_BSSGP_NODE: + vty->node = CONFIG_NODE; + vty->index = NULL; + break; + default: + break; + } + return CMD_SUCCESS; +} + +/* End of configuration. */ +gDEFUN(libgb_end, + libgb_end_cmd, "end", "End current mode and change to enable mode.") +{ + switch (vty->node) { + case L_NS_NODE: + case L_BSSGP_NODE: + vty_config_unlock(vty); + vty->node = ENABLE_NODE; + vty->index = NULL; + vty->index_sub = NULL; + break; + default: + break; + } + return CMD_SUCCESS; +} diff --git a/openbsc/src/libgb/common_vty.h b/openbsc/src/libgb/common_vty.h new file mode 100644 index 000000000..a2782663d --- /dev/null +++ b/openbsc/src/libgb/common_vty.h @@ -0,0 +1,5 @@ +#include + +extern struct cmd_element libgb_exit_cmd; +extern struct cmd_element libgb_end_cmd; + diff --git a/openbsc/src/libgb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c index 256e8af7f..37919e669 100644 --- a/openbsc/src/libgb/gprs_bssgp_vty.c +++ b/openbsc/src/libgb/gprs_bssgp_vty.c @@ -40,10 +40,9 @@ #include #include -#include -#include #include +#include "common_vty.h" /* FIXME: this should go to some common file as it is copied * in vty_interface.c of the BSC */ @@ -52,7 +51,7 @@ static const struct value_string gprs_bssgp_timer_strs[] = { }; static struct cmd_node bssgp_node = { - BSSGP_NODE, + L_BSSGP_NODE, "%s(bssgp)#", 1, }; @@ -68,7 +67,7 @@ DEFUN(cfg_bssgp, cfg_bssgp_cmd, "bssgp", "Configure the GPRS BSS Gateway Protocol") { - vty->node = BSSGP_NODE; + vty->node = L_BSSGP_NODE; return CMD_SUCCESS; } @@ -169,10 +168,10 @@ int gprs_bssgp_vty_init(void) install_element(CONFIG_NODE, &cfg_bssgp_cmd); install_node(&bssgp_node, config_write_bssgp); - install_default(BSSGP_NODE); - install_element(BSSGP_NODE, &ournode_exit_cmd); - install_element(BSSGP_NODE, &ournode_end_cmd); - //install_element(BSSGP_NODE, &cfg_bssgp_timer_cmd); + install_default(L_BSSGP_NODE); + install_element(L_BSSGP_NODE, &libgb_exit_cmd); + install_element(L_BSSGP_NODE, &libgb_end_cmd); + //install_element(L_BSSGP_NODE, &cfg_bssgp_timer_cmd); return 0; } diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index a33e754b5..0ae314197 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -40,9 +40,9 @@ #include #include -#include #include -#include + +#include "common_vty.h" static struct gprs_ns_inst *vty_nsi = NULL; @@ -60,7 +60,7 @@ static const struct value_string gprs_ns_timer_strs[] = { }; static struct cmd_node ns_node = { - NS_NODE, + L_NS_NODE, "%s(ns)#", 1, }; @@ -137,7 +137,7 @@ DEFUN(cfg_ns, cfg_ns_cmd, "ns", "Configure the GPRS Network Service") { - vty->node = NS_NODE; + vty->node = L_NS_NODE; return CMD_SUCCESS; } @@ -549,21 +549,21 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); - install_default(NS_NODE); - install_element(NS_NODE, &ournode_exit_cmd); - install_element(NS_NODE, &ournode_end_cmd); - install_element(NS_NODE, &cfg_nse_nsvci_cmd); - install_element(NS_NODE, &cfg_nse_remoteip_cmd); - install_element(NS_NODE, &cfg_nse_remoteport_cmd); - install_element(NS_NODE, &cfg_nse_fr_dlci_cmd); - install_element(NS_NODE, &cfg_nse_encaps_cmd); - install_element(NS_NODE, &cfg_nse_remoterole_cmd); - install_element(NS_NODE, &cfg_no_nse_cmd); - install_element(NS_NODE, &cfg_ns_timer_cmd); - install_element(NS_NODE, &cfg_nsip_local_ip_cmd); - install_element(NS_NODE, &cfg_nsip_local_port_cmd); - install_element(NS_NODE, &cfg_frgre_enable_cmd); - install_element(NS_NODE, &cfg_frgre_local_ip_cmd); + install_default(L_NS_NODE); + install_element(L_NS_NODE, &libgb_exit_cmd); + install_element(L_NS_NODE, &libgb_end_cmd); + install_element(L_NS_NODE, &cfg_nse_nsvci_cmd); + install_element(L_NS_NODE, &cfg_nse_remoteip_cmd); + install_element(L_NS_NODE, &cfg_nse_remoteport_cmd); + install_element(L_NS_NODE, &cfg_nse_fr_dlci_cmd); + install_element(L_NS_NODE, &cfg_nse_encaps_cmd); + install_element(L_NS_NODE, &cfg_nse_remoterole_cmd); + install_element(L_NS_NODE, &cfg_no_nse_cmd); + install_element(L_NS_NODE, &cfg_ns_timer_cmd); + install_element(L_NS_NODE, &cfg_nsip_local_ip_cmd); + install_element(L_NS_NODE, &cfg_nsip_local_port_cmd); + install_element(L_NS_NODE, &cfg_frgre_enable_cmd); + install_element(L_NS_NODE, &cfg_frgre_local_ip_cmd); install_element(ENABLE_NODE, &nsvc_nsei_cmd); From cca4963c581f26353b6fb1187446df70b399cf29 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 16 Jun 2012 17:45:59 +0800 Subject: [PATCH 192/198] libgb: Remove dependency to openbsc/debug.h --- openbsc/include/osmocom/gprs/gprs_bssgp.h | 1 + openbsc/include/osmocom/gprs/gprs_msgb.h | 4 ++ openbsc/include/osmocom/gprs/gprs_ns.h | 2 + openbsc/src/libgb/common_vty.c | 2 + openbsc/src/libgb/common_vty.h | 3 ++ openbsc/src/libgb/gprs_bssgp.c | 11 +++-- openbsc/src/libgb/gprs_bssgp_bss.c | 2 +- openbsc/src/libgb/gprs_bssgp_util.c | 2 +- openbsc/src/libgb/gprs_bssgp_vty.c | 2 - openbsc/src/libgb/gprs_ns.c | 37 ++++++++------- openbsc/src/libgb/gprs_ns_frgre.c | 2 +- openbsc/src/libgb/gprs_ns_vty.c | 2 - openbsc/src/libgb/libosmo-gb.map | 56 +++++++++++++++++++++++ 13 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 openbsc/src/libgb/libosmo-gb.map diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h index 9970a513d..25c902c17 100644 --- a/openbsc/include/osmocom/gprs/gprs_bssgp.h +++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h @@ -249,5 +249,6 @@ int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, /* gprs_bssgp_vty.c */ int gprs_bssgp_vty_init(void); +void gprs_bssgp_set_log_ss(int ss); #endif /* _GPRS_BSSGP_H */ diff --git a/openbsc/include/osmocom/gprs/gprs_msgb.h b/openbsc/include/osmocom/gprs/gprs_msgb.h index eddd888f5..3567bb7f3 100644 --- a/openbsc/include/osmocom/gprs/gprs_msgb.h +++ b/openbsc/include/osmocom/gprs/gprs_msgb.h @@ -27,4 +27,8 @@ struct libgb_msgb_cb { #define msgb_bcid(__x) LIBGB_MSGB_CB(__x)->bssgp_cell_id #define msgb_llch(__x) LIBGB_MSGB_CB(__x)->llch +/* logging contexts */ +#define GPRS_CTX_NSVC 0 +#define GPRS_CTX_BVC 1 + #endif diff --git a/openbsc/include/osmocom/gprs/gprs_ns.h b/openbsc/include/osmocom/gprs/gprs_ns.h index ab4bd4e67..a77515d25 100644 --- a/openbsc/include/osmocom/gprs/gprs_ns.h +++ b/openbsc/include/osmocom/gprs/gprs_ns.h @@ -258,6 +258,8 @@ struct ns_signal_data { uint8_t cause; }; +void gprs_ns_set_log_ss(int ss); + /*! }@ */ #endif diff --git a/openbsc/src/libgb/common_vty.c b/openbsc/src/libgb/common_vty.c index 269df8cd4..a16e9957c 100644 --- a/openbsc/src/libgb/common_vty.c +++ b/openbsc/src/libgb/common_vty.c @@ -61,3 +61,5 @@ gDEFUN(libgb_end, } return CMD_SUCCESS; } + +int DNS, DBSSGP; diff --git a/openbsc/src/libgb/common_vty.h b/openbsc/src/libgb/common_vty.h index a2782663d..8c6b9ab16 100644 --- a/openbsc/src/libgb/common_vty.h +++ b/openbsc/src/libgb/common_vty.h @@ -1,4 +1,7 @@ #include +#include + +extern int DNS, DBSSGP; extern struct cmd_element libgb_exit_cmd; extern struct cmd_element libgb_end_cmd; diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index 33cca3dfc..a64973645 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -32,13 +32,13 @@ #include #include -#include - #include #include #include +#include "common_vty.h" + void *bssgp_tall_ctx = NULL; static const struct rate_ctr_desc bssgp_ctr_description[] = { @@ -683,7 +683,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) } if (bctx) { - log_set_context(BSC_CTX_BVC, bctx); + log_set_context(GPRS_CTX_BVC, bctx); rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_IN]); rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_IN], msgb_bssgp_len(msg)); @@ -853,3 +853,8 @@ int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, return gprs_ns_sendmsg(bssgp_nsi, msg); } + +void gprs_bssgp_set_log_ss(int ss) +{ + DBSSGP = ss; +} diff --git a/openbsc/src/libgb/gprs_bssgp_bss.c b/openbsc/src/libgb/gprs_bssgp_bss.c index a681b9dab..4ca11ffd7 100644 --- a/openbsc/src/libgb/gprs_bssgp_bss.c +++ b/openbsc/src/libgb/gprs_bssgp_bss.c @@ -31,7 +31,7 @@ #include #include -#include +#include "common_vty.h" uint8_t *bssgp_msgb_tlli_put(struct msgb *msg, uint32_t tlli) { diff --git a/openbsc/src/libgb/gprs_bssgp_util.c b/openbsc/src/libgb/gprs_bssgp_util.c index 6ab97a79c..ae4647ef2 100644 --- a/openbsc/src/libgb/gprs_bssgp_util.c +++ b/openbsc/src/libgb/gprs_bssgp_util.c @@ -30,7 +30,7 @@ #include #include -#include +#include "common_vty.h" struct gprs_ns_inst *bssgp_nsi; diff --git a/openbsc/src/libgb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c index 37919e669..ff1b8f5c8 100644 --- a/openbsc/src/libgb/gprs_bssgp_vty.c +++ b/openbsc/src/libgb/gprs_bssgp_vty.c @@ -40,8 +40,6 @@ #include #include -#include - #include "common_vty.h" /* FIXME: this should go to some common file as it is copied diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 617c50d69..04a7f1067 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -79,7 +79,7 @@ #include #include -#include +#include "common_vty.h" static const struct tlv_definition ns_att_tlvdef = { .def = { @@ -233,7 +233,7 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) { int ret; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); /* Increment number of Uplink bytes */ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]); @@ -260,7 +260,7 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) struct msgb *msg = gprs_ns_msgb_alloc(); struct gprs_ns_hdr *nsh; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); if (!msg) return -ENOMEM; @@ -284,7 +284,7 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) uint16_t nsvci = htons(nsvc->nsvci); uint16_t nsei = htons(nsvc->nsei); - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); if (!msg) return -ENOMEM; @@ -316,7 +316,7 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, struct gprs_ns_hdr *nsh; uint16_t nsvci = htons(nsvc->nsvci); - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); bvci = htons(bvci); @@ -369,7 +369,7 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) struct gprs_ns_hdr *nsh; uint16_t nsvci = htons(nsvc->nsvci); - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); if (!msg) return -ENOMEM; @@ -397,7 +397,7 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) */ int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) { - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); @@ -410,7 +410,7 @@ int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) */ int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) { - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); @@ -423,7 +423,7 @@ int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) */ int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc) { - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE_ACK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); @@ -448,7 +448,7 @@ static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) enum ns_timeout tout = timer_mode_tout[mode]; unsigned int seconds = nsvc->nsi->timeout[tout]; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, mode), seconds); @@ -466,7 +466,7 @@ static void gprs_ns_timer_cb(void *data) enum ns_timeout tout = timer_mode_tout[nsvc->timer_mode]; unsigned int seconds = nsvc->nsi->timeout[tout]; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode), seconds); @@ -520,7 +520,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) struct gprs_ns_hdr *nsh; uint16_t nsvci, nsei; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); if (!msg) return -ENOMEM; @@ -564,7 +564,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) msgb_free(msg); return -EINVAL; } - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); if (!(nsvc->state & NSE_S_ALIVE)) { LOGP(DNS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", @@ -760,7 +760,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsh->pdu_type != NS_PDUT_RESET) { /* Since we have no NSVC, we have to use a fake */ nsvc = nsi->unknown_nsvc; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "Rejecting NS PDU type 0x%0x " "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), @@ -799,7 +799,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (!nsvc) { nsvc = nsvc_create(nsi, 0xffff); nsvc->ll = ll; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); } @@ -808,7 +808,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, } else msgb_nsei(msg) = nsvc->nsei; - log_set_context(BSC_CTX_NSVC, nsvc); + log_set_context(GPRS_CTX_NSVC, nsvc); /* Increment number of Incoming bytes */ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]); @@ -1095,4 +1095,9 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, return nsvc; } +void gprs_ns_set_log_ss(int ss) +{ + DNS = ss; +} + /*! }@ */ diff --git a/openbsc/src/libgb/gprs_ns_frgre.c b/openbsc/src/libgb/gprs_ns_frgre.c index 9be9f2a8f..be5f0f6c7 100644 --- a/openbsc/src/libgb/gprs_ns_frgre.c +++ b/openbsc/src/libgb/gprs_ns_frgre.c @@ -37,7 +37,7 @@ #include #include -#include +#include "common_vty.h" #define GRE_PTYPE_FR 0x6559 #define GRE_PTYPE_IPv4 0x0800 diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index 0ae314197..2f0b70ad4 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -40,8 +40,6 @@ #include #include -#include - #include "common_vty.h" static struct gprs_ns_inst *vty_nsi = NULL; diff --git a/openbsc/src/libgb/libosmo-gb.map b/openbsc/src/libgb/libosmo-gb.map new file mode 100644 index 000000000..ab3c4eaf1 --- /dev/null +++ b/openbsc/src/libgb/libosmo-gb.map @@ -0,0 +1,56 @@ +LIBOSMOGB_1.0 { +global: +bssgp_cause_str; +bssgp_create_cell_id; +bssgp_msgb_alloc; +bssgp_msgb_tlli_put; +bssgp_parse_cell_id; +bssgp_tx_bvc_block; +bssgp_tx_bvc_reset; +bssgp_tx_bvc_unblock; +bssgp_tx_flush_ll_ack; +bssgp_tx_llc_discarded; +bssgp_tx_ra_capa_upd; +bssgp_tx_radio_status_imsi; +bssgp_tx_radio_status_tlli; +bssgp_tx_radio_status_tmsi; +bssgp_tx_resume; +bssgp_tx_resume_ack; +bssgp_tx_resume_nack; +bssgp_tx_simple_bvci; +bssgp_tx_status; +bssgp_tx_suspend; +bssgp_tx_suspend_ack; +bssgp_tx_suspend_nack; +bssgp_tx_ul_ud; + +gprs_bssgp_rcvmsg +gprs_bssgp_rx_paging +gprs_bssgp_set_log_ss +gprs_bssgp_tx_dl_ud +gprs_bssgp_tx_paging +gprs_bssgp_vty_init + +gprs_ns_cause_str; +gprs_ns_destroy; +gprs_ns_frgre_listen; +gprs_ns_frgre_sendmsg; +gprs_ns_instantiate; +gprs_ns_nsip_listen; +gprs_ns_rcvmsg; +gprs_ns_sendmsg; +gprs_ns_set_log_ss; +gprs_ns_tx_alive; +gprs_ns_tx_alive_ack; +gprs_ns_tx_block; +gprs_ns_tx_reset; +gprs_ns_tx_status; +gprs_ns_tx_unblock; +gprs_ns_vty_init; + +gprs_nsvc_reset; + +nsip_connect; + +local: *; +}; From 8ef54d112c2c17a5303fac035825640987cbd40a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 17 Jun 2012 09:31:16 +0800 Subject: [PATCH 193/198] libgb: remove dependency of BSSGP to include sgsn/gmm internal structs --- openbsc/include/osmocom/gprs/gprs_bssgp.h | 17 ++++++++-- openbsc/src/libgb/gprs_bssgp.c | 41 ++++++++++------------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h index 25c902c17..4fcdfb565 100644 --- a/openbsc/include/osmocom/gprs/gprs_bssgp.h +++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h @@ -204,8 +204,21 @@ enum bssgp_ctr { int gprs_bssgp_rcvmsg(struct msgb *msg); /* BSSGP-DL-UNITDATA.req */ -struct sgsn_mm_ctx; -int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx); +struct bssgp_lv { + uint16_t len; + uint8_t *v; +}; +/* parameters for BSSGP downlink userdata transmission */ +struct bssgp_dl_ud_par { + uint32_t *tlli; + char *imsi; + uint16_t drx_parms; + /* FIXME: priority */ + struct bssgp_lv ms_ra_cap; + uint8_t qos_profile[3]; +}; +int gprs_bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, + struct bssgp_dl_ud_par *dup); uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid, diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index a64973645..ca99dd527 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -35,8 +35,6 @@ #include #include -#include - #include "common_vty.h" void *bssgp_tall_ctx = NULL; @@ -699,19 +697,17 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) return rc; } -/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU - * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ -int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) +int gprs_bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, + struct bssgp_dl_ud_par *dup) { struct bssgp_bvc_ctx *bctx; struct bssgp_ud_hdr *budh; uint8_t llc_pdu_tlv_hdr_len = 2; - uint8_t *llc_pdu_tlv, *qos_profile; - uint16_t pdu_lifetime = 1000; /* centi-seconds */ - uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x20 }; + uint8_t *llc_pdu_tlv; uint16_t msg_len = msg->len; uint16_t bvci = msgb_bvci(msg); uint16_t nsei = msgb_nsei(msg); + uint16_t _pdu_lifetime = htons(pdu_lifetime); /* centi-seconds */ uint16_t drx_params; /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ @@ -743,43 +739,42 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) /* FIXME: optional elements: Alignment, UTRAN CCO, LSA, PFI */ - if (mmctx) { + if (dup) { /* Old TLLI to help BSS map from old->new */ -#if 0 - if (mmctx->tlli_old) - msgb_tvlv_push(msg, BSSGP_IE_TLLI, 4, htonl(*tlli_old)); -#endif + if (dup->tlli) { + uint32_t tlli = htonl(*dup->tlli); + msgb_tvlv_push(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &tlli); + } /* IMSI */ - if (strlen(mmctx->imsi)) { + if (strlen(dup->imsi)) { uint8_t mi[10]; - int imsi_len = gsm48_generate_mid_from_imsi(mi, mmctx->imsi); + int imsi_len = gsm48_generate_mid_from_imsi(mi, dup->imsi); if (imsi_len > 2) msgb_tvlv_push(msg, BSSGP_IE_IMSI, - imsi_len-2, mi+2); + imsi_len-2, mi+2); } /* DRX parameters */ - drx_params = htons(mmctx->drx_parms); + drx_params = htons(dup->drx_parms); msgb_tvlv_push(msg, BSSGP_IE_DRX_PARAMS, 2, (uint8_t *) &drx_params); /* FIXME: Priority */ /* MS Radio Access Capability */ - if (mmctx->ms_radio_access_capa.len) + if (dup->ms_ra_cap.len) msgb_tvlv_push(msg, BSSGP_IE_MS_RADIO_ACCESS_CAP, - mmctx->ms_radio_access_capa.len, - mmctx->ms_radio_access_capa.buf); + dup->ms_ra_cap.len, dup->ms_ra_cap.v); + } /* prepend the pdu lifetime */ - pdu_lifetime = htons(pdu_lifetime); - msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (uint8_t *)&pdu_lifetime); + msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (uint8_t *)&_pdu_lifetime); /* prepend the QoS profile, TLLI and pdu type */ budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); - memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default)); + memcpy(budh->qos_profile, dup->qos_profile, sizeof(budh->qos_profile)); budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; From 15a36434e9d51e57514b2b9357a41293b063e970 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 17 Jun 2012 12:16:31 +0800 Subject: [PATCH 194/198] libgb: don't call directly into GMM / LLC layer Instead of direct function calls to individual functions, we now generate primitives (osmo_prim) and send them to one application-provided function "bssgp_prim_cb()" --- openbsc/include/osmocom/gprs/gprs_bssgp.h | 37 +++++++++++ openbsc/src/libgb/gprs_bssgp.c | 78 +++++++++++++++++++++-- 2 files changed, 108 insertions(+), 7 deletions(-) diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h index 4fcdfb565..e060fc033 100644 --- a/openbsc/include/osmocom/gprs/gprs_bssgp.h +++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h @@ -144,6 +144,7 @@ enum gprs_bssgp_cause { /* Our implementation */ #include +#include /* gprs_bssgp_util.c */ extern struct gprs_ns_inst *bssgp_nsi; @@ -155,6 +156,40 @@ int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, /* Chapter 10.4.14: Status */ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg); +enum bssgp_prim { + PRIM_BSSGP_DL_UD, + PRIM_BSSGP_UL_UD, + PRIM_BSSGP_PTM_UD, + + PRIM_BSSGP_GMM_SUSPEND, + PRIM_BSSGP_GMM_RESUME, + PRIM_BSSGP_GMM_PAGING, + + PRIM_NM_FLUSH_LL, + PRIM_NM_LLC_DISCARDED, + PRIM_NM_BVC_RESET, + PRIM_NM_BVC_BLOCK, + PRIM_NM_BVC_UNBLOCK, +}; + +struct osmo_bssgp_prim { + struct osmo_prim_hdr oph; + + /* common fields */ + uint16_t nsei; + uint16_t bvci; + uint32_t tlli; + struct tlv_parsed *tp; + struct gprs_ra_id *ra_id; + + /* specific fields */ + union { + struct { + uint8_t *suspend_ref; + } resume; + } u; +}; + /* gprs_bssgp.c */ #define BVC_S_BLOCKED 0x0001 @@ -264,4 +299,6 @@ int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, int gprs_bssgp_vty_init(void); void gprs_bssgp_set_log_ss(int ss); +int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx); + #endif /* _GPRS_BSSGP_H */ diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index ca99dd527..47750483e 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -233,6 +233,7 @@ int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid, static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, uint16_t ns_bvci) { + struct osmo_bssgp_prim nmp; struct bssgp_bvc_ctx *bctx; uint16_t nsei = msgb_nsei(msg); uint16_t bvci; @@ -266,6 +267,16 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, bctx->ra_id.rac, bctx->cell_id, bvci); } + /* Send NM_BVC_RESET.ind to NM */ + memset(&nmp, 0, sizeof(nmp)); + nmp.nsei = nsei; + nmp.bvci = bvci; + nmp.tp = tp; + nmp.ra_id = &bctx->ra_id; + osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_BVC_RESET, + PRIM_OP_INDICATION, msg); + bssgp_prim_cb(&nmp.oph, NULL); + /* Acknowledge the RESET to the BTS */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsei, bvci, ns_bvci); @@ -274,6 +285,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) { + struct osmo_bssgp_prim nmp; uint16_t bvci; struct bssgp_bvc_ctx *ptp_ctx; @@ -295,7 +307,14 @@ static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) ptp_ctx->state |= BVC_S_BLOCKED; rate_ctr_inc(&ptp_ctx->ctrg->ctr[BSSGP_CTR_BLOCKED]); - /* FIXME: Send NM_BVC_BLOCK.ind to NM */ + /* Send NM_BVC_BLOCK.ind to NM */ + memset(&nmp, 0, sizeof(nmp)); + nmp.nsei = msgb_nsei(msg); + nmp.bvci = bvci; + nmp.tp = tp; + osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_BVC_BLOCK, + PRIM_OP_INDICATION, msg); + bssgp_prim_cb(&nmp.oph, NULL); /* We always acknowledge the BLOCKing */ return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, msgb_nsei(msg), @@ -304,6 +323,7 @@ static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp) static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) { + struct osmo_bssgp_prim nmp; uint16_t bvci; struct bssgp_bvc_ctx *ptp_ctx; @@ -324,7 +344,14 @@ static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) ptp_ctx->state &= ~BVC_S_BLOCKED; - /* FIXME: Send NM_BVC_UNBLOCK.ind to NM */ + /* Send NM_BVC_UNBLOCK.ind to NM */ + memset(&nmp, 0, sizeof(nmp)); + nmp.nsei = msgb_nsei(msg); + nmp.bvci = bvci; + nmp.tp = tp; + osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_BVC_UNBLOCK, + PRIM_OP_INDICATION, msg); + bssgp_prim_cb(&nmp.oph, NULL); /* We always acknowledge the unBLOCKing */ return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg), @@ -335,6 +362,7 @@ static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp) static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *ctx) { + struct osmo_bssgp_prim gbp; struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); /* extract TLLI and parse TLV IEs */ @@ -354,12 +382,21 @@ static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp, msgb_llch(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU); msgb_bcid(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_CELL_ID); - return gprs_llc_rcvmsg(msg, tp); + /* Send BSSGP_UL_UD.ind to NM */ + memset(&gbp, 0, sizeof(gbp)); + gbp.nsei = ctx->nsei; + gbp.bvci = ctx->bvci; + gbp.tlli = msgb_tlli(msg); + gbp.tp = tp; + osmo_prim_init(&gbp.oph, SAP_BSSGP_LL, PRIM_BSSGP_UL_UD, + PRIM_OP_INDICATION, msg); + return bssgp_prim_cb(&gbp.oph, NULL); } static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *ctx) { + struct osmo_bssgp_prim gbp; struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct gprs_ra_id raid; @@ -381,7 +418,15 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); /* Inform GMM about the SUSPEND request */ - rc = gprs_gmm_rx_suspend(&raid, tlli); + memset(&gbp, 0, sizeof(gbp)); + gbp.nsei = msgb_nsei(msg); + gbp.bvci = ctx->bvci; + gbp.tlli = tlli; + gbp.ra_id = &raid; + osmo_prim_init(&gbp.oph, SAP_BSSGP_GMM, PRIM_BSSGP_GMM_SUSPEND, + PRIM_OP_REQUEST, msg); + + rc = bssgp_prim_cb(&gbp.oph, NULL); if (rc < 0) return bssgp_tx_suspend_nack(msgb_nsei(msg), tlli, &raid, NULL); @@ -393,6 +438,7 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *ctx) { + struct osmo_bssgp_prim gbp; struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct gprs_ra_id raid; @@ -416,7 +462,16 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); /* Inform GMM about the RESUME request */ - rc = gprs_gmm_rx_resume(&raid, tlli, suspend_ref); + memset(&gbp, 0, sizeof(gbp)); + gbp.nsei = msgb_nsei(msg); + gbp.bvci = ctx->bvci; + gbp.tlli = tlli; + gbp.ra_id = &raid; + gbp.u.resume.suspend_ref = suspend_ref; + osmo_prim_init(&gbp.oph, SAP_BSSGP_GMM, PRIM_BSSGP_GMM_RESUME, + PRIM_OP_REQUEST, msg); + + rc = bssgp_prim_cb(&gbp.oph, NULL); if (rc < 0) return bssgp_tx_resume_nack(msgb_nsei(msg), tlli, &raid, NULL); @@ -429,6 +484,7 @@ static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *ctx) { + struct osmo_bssgp_prim nmp; uint32_t tlli = 0; if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) || @@ -447,8 +503,16 @@ static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp, rate_ctr_inc(&ctx->ctrg->ctr[BSSGP_CTR_DISCARDED]); - /* FIXME: send NM_LLC_DISCARDED to NM */ - return 0; + /* send NM_LLC_DISCARDED to NM */ + memset(&nmp, 0, sizeof(nmp)); + nmp.nsei = msgb_nsei(msg); + nmp.bvci = ctx->bvci; + nmp.tlli = tlli; + nmp.tp = tp; + osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_LLC_DISCARDED, + PRIM_OP_INDICATION, msg); + + return bssgp_prim_cb(&nmp.oph, NULL); } static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, From f543036719ccbb2431563d6af968502f9097db98 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 17 Jun 2012 12:25:53 +0800 Subject: [PATCH 195/198] libgb: prefix all NS related functions with gprs_ --- openbsc/include/osmocom/gprs/gprs_ns.h | 19 +++++++------ openbsc/src/libgb/common_vty.c | 24 ++++++++++++++++ openbsc/src/libgb/common_vty.h | 6 ++++ openbsc/src/libgb/gprs_bssgp_vty.c | 12 ++++++++ openbsc/src/libgb/gprs_ns.c | 20 +++++++------- openbsc/src/libgb/gprs_ns_vty.c | 38 +++++++++++++++++--------- openbsc/src/libgb/libosmo-gb.map | 6 +++- 7 files changed, 92 insertions(+), 33 deletions(-) diff --git a/openbsc/include/osmocom/gprs/gprs_ns.h b/openbsc/include/osmocom/gprs/gprs_ns.h index a77515d25..206873b6f 100644 --- a/openbsc/include/osmocom/gprs/gprs_ns.h +++ b/openbsc/include/osmocom/gprs/gprs_ns.h @@ -211,6 +211,12 @@ void gprs_ns_destroy(struct gprs_ns_inst *nsi); /* Listen for incoming GPRS packets via NS/UDP */ int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi); +/* Establish a connection (from the BSS) to the SGSN */ +struct gprs_nsvc *gprs_ns_nsip_connect(struct gprs_ns_inst *nsi, + struct sockaddr_in *dest, + uint16_t nsei, uint16_t nsvci); + + struct sockaddr_in; /* main function for higher layers (BSSGP) to send NS messages */ @@ -223,15 +229,10 @@ int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc); /* Listen for incoming GPRS packets via NS/FR/GRE */ int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi); -/* Establish a connection (from the BSS) to the SGSN */ -struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, - struct sockaddr_in *dest, uint16_t nsei, - uint16_t nsvci); - -struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci); -void nsvc_delete(struct gprs_nsvc *nsvc); -struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); -struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci); +struct gprs_nsvc *gprs_nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci); +void gprs_nsvc_delete(struct gprs_nsvc *nsvc); +struct gprs_nsvc *gprs_nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); +struct gprs_nsvc *gprs_nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci); /* Initiate a RESET procedure (including timer start, ...)*/ void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); diff --git a/openbsc/src/libgb/common_vty.c b/openbsc/src/libgb/common_vty.c index a16e9957c..408dddf75 100644 --- a/openbsc/src/libgb/common_vty.c +++ b/openbsc/src/libgb/common_vty.c @@ -28,6 +28,10 @@ #include #include +#include + +#include "common_vty.h" + /* Down vty node level. */ gDEFUN(libgb_exit, libgb_exit_cmd, "exit", "Exit current mode and down to previous mode\n") @@ -62,4 +66,24 @@ gDEFUN(libgb_end, return CMD_SUCCESS; } +int gprs_log_filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + const struct gprs_nsvc *nsvc = ctx->ctx[GPRS_CTX_NSVC]; + const struct gprs_nsvc *bvc = ctx->ctx[GPRS_CTX_BVC]; + + /* Filter on the NS Virtual Connection */ + if ((tar->filter_map & (1 << FLT_NSVC)) != 0 + && nsvc && (nsvc == tar->filter_data[FLT_NSVC])) + return 1; + + /* Filter on the NS Virtual Connection */ + if ((tar->filter_map & (1 << FLT_BVC)) != 0 + && bvc && (bvc == tar->filter_data[FLT_BVC])) + return 1; + + return 0; +} + + int DNS, DBSSGP; diff --git a/openbsc/src/libgb/common_vty.h b/openbsc/src/libgb/common_vty.h index 8c6b9ab16..d8d00407b 100644 --- a/openbsc/src/libgb/common_vty.h +++ b/openbsc/src/libgb/common_vty.h @@ -3,6 +3,12 @@ extern int DNS, DBSSGP; +enum log_filter { + _FLT_ALL = LOG_FILTER_ALL, /* libosmocore */ + FLT_NSVC = 1, + FLT_BVC = 2, +}; + extern struct cmd_element libgb_exit_cmd; extern struct cmd_element libgb_end_cmd; diff --git a/openbsc/src/libgb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c index ff1b8f5c8..49a90c375 100644 --- a/openbsc/src/libgb/gprs_bssgp_vty.c +++ b/openbsc/src/libgb/gprs_bssgp_vty.c @@ -48,6 +48,18 @@ static const struct value_string gprs_bssgp_timer_strs[] = { { 0, NULL } }; +static void log_set_bvc_filter(struct log_target *target, + struct bssgp_bvc_ctx *bctx) +{ + if (bctx) { + target->filter_map |= (1 << FLT_BVC); + target->filter_data[FLT_BVC] = bctx; + } else if (target->filter_data[FLT_NSVC]) { + target->filter_map = ~(1 << FLT_BVC); + target->filter_data[FLT_BVC] = NULL; + } +} + static struct cmd_node bssgp_node = { L_BSSGP_NODE, "%s(bssgp)#", diff --git a/openbsc/src/libgb/gprs_ns.c b/openbsc/src/libgb/gprs_ns.c index 04a7f1067..cdee83382 100644 --- a/openbsc/src/libgb/gprs_ns.c +++ b/openbsc/src/libgb/gprs_ns.c @@ -121,7 +121,7 @@ static const struct rate_ctr_group_desc nsvc_ctrg_desc = { * \param[in] nsvci NSVCI to be searched * \returns gprs_nsvc of respective NSVCI */ -struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) +struct gprs_nsvc *gprs_nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -136,7 +136,7 @@ struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) * \param[in] nsei NSEI to be searched * \returns gprs_nsvc of respective NSEI */ -struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei) +struct gprs_nsvc *gprs_nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -162,7 +162,7 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, static void gprs_ns_timer_cb(void *data); -struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) +struct gprs_nsvc *gprs_nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -185,7 +185,7 @@ struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) /*! \brief Delete given NS-VC * \param[in] nsvc gprs_nsvc to be deleted */ -void nsvc_delete(struct gprs_nsvc *nsvc) +void gprs_nsvc_delete(struct gprs_nsvc *nsvc) { if (osmo_timer_pending(&nsvc->timer)) osmo_timer_del(&nsvc->timer); @@ -557,7 +557,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) struct gprs_ns_hdr *nsh; uint16_t bvci = msgb_bvci(msg); - nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); + nsvc = gprs_nsvc_by_nsei(nsi, msgb_nsei(msg)); if (!nsvc) { LOGP(DNS, LOGL_ERROR, "Unable to resolve NSEI %u " "to NS-VC!\n", msgb_nsei(msg)); @@ -795,9 +795,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsei = ntohs(*(uint16_t *)TLVP_VAL(&tp, NS_IE_NSEI)); /* Check if we already know this NSEI, the remote end might * simply have changed addresses, or it is a SGSN */ - nsvc = nsvc_by_nsei(nsi, nsei); + nsvc = gprs_nsvc_by_nsei(nsi, nsei); if (!nsvc) { - nsvc = nsvc_create(nsi, 0xffff); + nsvc = gprs_nsvc_create(nsi, 0xffff); nsvc->ll = ll; log_set_context(GPRS_CTX_NSVC, nsvc); LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", @@ -909,7 +909,7 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb, void *ctx) /* Create the dummy NSVC that we use for sending * messages to non-existant/unknown NS-VC's */ - nsi->unknown_nsvc = nsvc_create(nsi, 0xfffe); + nsi->unknown_nsvc = gprs_nsvc_create(nsi, 0xfffe); llist_del(&nsi->unknown_nsvc->list); return nsi; @@ -1077,7 +1077,7 @@ void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause) * This function will establish a single NS/UDP/IP connection in uplink * (BSS to SGSN) direction. */ -struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, +struct gprs_nsvc *gprs_ns_nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, uint16_t nsvci) { @@ -1085,7 +1085,7 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc = nsvc_by_rem_addr(nsi, dest); if (!nsvc) - nsvc = nsvc_create(nsi, nsvci); + nsvc = gprs_nsvc_create(nsi, nsvci); nsvc->ip.bts_addr = *dest; nsvc->nsei = nsei; nsvc->nsvci = nsvci; diff --git a/openbsc/src/libgb/gprs_ns_vty.c b/openbsc/src/libgb/gprs_ns_vty.c index 2f0b70ad4..fac431cb4 100644 --- a/openbsc/src/libgb/gprs_ns_vty.c +++ b/openbsc/src/libgb/gprs_ns_vty.c @@ -57,6 +57,18 @@ static const struct value_string gprs_ns_timer_strs[] = { { 0, NULL } }; +static void log_set_nsvc_filter(struct log_target *target, + struct gprs_nsvc *nsvc) +{ + if (nsvc) { + target->filter_map |= (1 << FLT_NSVC); + target->filter_data[FLT_NSVC] = nsvc; + } else if (target->filter_data[FLT_NSVC]) { + target->filter_map = ~(1 << FLT_NSVC); + target->filter_data[FLT_NSVC] = NULL; + } +} + static struct cmd_node ns_node = { L_NS_NODE, "%s(ns)#", @@ -207,9 +219,9 @@ DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]", int show_stats = 0; if (!strcmp(argv[0], "nsei")) - nsvc = nsvc_by_nsei(nsi, id); + nsvc = gprs_nsvc_by_nsei(nsi, id); else - nsvc = nsvc_by_nsvci(nsi, id); + nsvc = gprs_nsvc_by_nsvci(nsi, id); if (!nsvc) { vty_out(vty, "No such NS Entity%s", VTY_NEWLINE); @@ -236,9 +248,9 @@ DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, uint16_t nsvci = atoi(argv[1]); struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei); if (!nsvc) { - nsvc = nsvc_create(vty_nsi, nsvci); + nsvc = gprs_nsvc_create(vty_nsi, nsvci); nsvc->nsei = nsei; } nsvc->nsvci = nsvci; @@ -259,7 +271,7 @@ DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei); if (!nsvc) { vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); return CMD_WARNING; @@ -280,7 +292,7 @@ DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, uint16_t port = atoi(argv[1]); struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei); if (!nsvc) { vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); return CMD_WARNING; @@ -307,7 +319,7 @@ DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd, uint16_t dlci = atoi(argv[1]); struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei); if (!nsvc) { vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); return CMD_WARNING; @@ -333,7 +345,7 @@ DEFUN(cfg_nse_encaps, cfg_nse_encaps_cmd, uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei); if (!nsvc) { vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); return CMD_WARNING; @@ -358,7 +370,7 @@ DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei); if (!nsvc) { vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); return CMD_WARNING; @@ -380,7 +392,7 @@ DEFUN(cfg_no_nse, cfg_no_nse_cmd, uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsei); if (!nsvc) { vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); return CMD_WARNING; @@ -486,7 +498,7 @@ DEFUN(nsvc_nsei, nsvc_nsei_cmd, const char *operation = argv[1]; struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsvci); + nsvc = gprs_nsvc_by_nsei(vty_nsi, nsvci); if (!nsvc) { vty_out(vty, "No such NSVCI (%u)%s", nsvci, VTY_NEWLINE); return CMD_WARNING; @@ -521,9 +533,9 @@ DEFUN(logging_fltr_nsvc, return CMD_WARNING; if (!strcmp(argv[0], "nsei")) - nsvc = nsvc_by_nsei(vty_nsi, id); + nsvc = gprs_nsvc_by_nsei(vty_nsi, id); else - nsvc = nsvc_by_nsvci(vty_nsi, id); + nsvc = gprs_nsvc_by_nsvci(vty_nsi, id); if (!nsvc) { vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE); diff --git a/openbsc/src/libgb/libosmo-gb.map b/openbsc/src/libgb/libosmo-gb.map index ab3c4eaf1..60f85b261 100644 --- a/openbsc/src/libgb/libosmo-gb.map +++ b/openbsc/src/libgb/libosmo-gb.map @@ -37,6 +37,7 @@ gprs_ns_frgre_listen; gprs_ns_frgre_sendmsg; gprs_ns_instantiate; gprs_ns_nsip_listen; +gprs_ns_nsip_connect; gprs_ns_rcvmsg; gprs_ns_sendmsg; gprs_ns_set_log_ss; @@ -48,9 +49,12 @@ gprs_ns_tx_status; gprs_ns_tx_unblock; gprs_ns_vty_init; +gprs_nsvc_create; +gprs_nsvc_delete; gprs_nsvc_reset; +gprs_nsvc_by_nsvci; +gprs_nsvc_by_nsei; -nsip_connect; local: *; }; From 8eda90d9506ca4c34a3476415eb70d51043fcdf1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 17 Jun 2012 12:58:46 +0800 Subject: [PATCH 196/198] libgb/gprs: don't use log_info from libcommon anymore --- openbsc/include/osmocom/gprs/gprs_msgb.h | 3 +++ openbsc/src/libgb/common_vty.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/include/osmocom/gprs/gprs_msgb.h b/openbsc/include/osmocom/gprs/gprs_msgb.h index 3567bb7f3..f4c855478 100644 --- a/openbsc/include/osmocom/gprs/gprs_msgb.h +++ b/openbsc/include/osmocom/gprs/gprs_msgb.h @@ -31,4 +31,7 @@ struct libgb_msgb_cb { #define GPRS_CTX_NSVC 0 #define GPRS_CTX_BVC 1 +#include +int gprs_log_filter_fn(const struct log_context *ctx, + struct log_target *tar); #endif diff --git a/openbsc/src/libgb/common_vty.c b/openbsc/src/libgb/common_vty.c index 408dddf75..0bd0b6c37 100644 --- a/openbsc/src/libgb/common_vty.c +++ b/openbsc/src/libgb/common_vty.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -70,7 +71,7 @@ int gprs_log_filter_fn(const struct log_context *ctx, struct log_target *tar) { const struct gprs_nsvc *nsvc = ctx->ctx[GPRS_CTX_NSVC]; - const struct gprs_nsvc *bvc = ctx->ctx[GPRS_CTX_BVC]; + const struct gprs_bvc *bvc = ctx->ctx[GPRS_CTX_BVC]; /* Filter on the NS Virtual Connection */ if ((tar->filter_map & (1 << FLT_NSVC)) != 0 From de4599cc350747609f1b66d84885b34cf76ae253 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 17 Jun 2012 13:04:02 +0800 Subject: [PATCH 197/198] libgb: make sure all BSSGP functions have bssgp_ prefix We change the minority of functions employing the gprs_bssgp_ prefix to match with the majority without gprs_ in front. --- openbsc/include/osmocom/gprs/gprs_bssgp.h | 14 ++++++------- openbsc/src/libgb/gprs_bssgp.c | 24 +++++++++++------------ openbsc/src/libgb/gprs_bssgp_bss.c | 4 ++-- openbsc/src/libgb/gprs_bssgp_vty.c | 2 +- openbsc/src/libgb/libosmo-gb.map | 13 ++++++------ 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h index e060fc033..66c2290f8 100644 --- a/openbsc/include/osmocom/gprs/gprs_bssgp.h +++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h @@ -236,7 +236,7 @@ enum bssgp_ctr { #include /* BSSGP-UL-UNITDATA.ind */ -int gprs_bssgp_rcvmsg(struct msgb *msg); +int bssgp_rcvmsg(struct msgb *msg); /* BSSGP-DL-UNITDATA.req */ struct bssgp_lv { @@ -252,8 +252,8 @@ struct bssgp_dl_ud_par { struct bssgp_lv ms_ra_cap; uint8_t qos_profile[3]; }; -int gprs_bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, - struct bssgp_dl_ud_par *dup); +int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, + struct bssgp_dl_ud_par *dup); uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid, @@ -292,12 +292,12 @@ struct bssgp_paging_info { }; /* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */ -int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, - struct bssgp_paging_info *pinfo); +int bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, + struct bssgp_paging_info *pinfo); /* gprs_bssgp_vty.c */ -int gprs_bssgp_vty_init(void); -void gprs_bssgp_set_log_ss(int ss); +int bssgp_vty_init(void); +void bssgp_set_log_ss(int ss); int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx); diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c index 47750483e..4b8c73028 100644 --- a/openbsc/src/libgb/gprs_bssgp.c +++ b/openbsc/src/libgb/gprs_bssgp.c @@ -540,8 +540,8 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, } /* Receive a BSSGP PDU from a BSS on a PTP BVCI */ -static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bvc_ctx *bctx) +static int bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bvc_ctx *bctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -619,8 +619,8 @@ static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, } /* Receive a BSSGP PDU from a BSS on a SIGNALLING BVCI */ -static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, - struct bssgp_bvc_ctx *bctx) +static int bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp, + struct bssgp_bvc_ctx *bctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -710,7 +710,7 @@ err_mand_ie: } /* We expect msgb_bssgph() to point to the BSSGP header */ -int gprs_bssgp_rcvmsg(struct msgb *msg) +int bssgp_rcvmsg(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -752,17 +752,17 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) } if (ns_bvci == BVCI_SIGNALLING) - rc = gprs_bssgp_rx_sign(msg, &tp, bctx); + rc = bssgp_rx_sign(msg, &tp, bctx); else if (ns_bvci == BVCI_PTM) rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); else - rc = gprs_bssgp_rx_ptp(msg, &tp, bctx); + rc = bssgp_rx_ptp(msg, &tp, bctx); return rc; } -int gprs_bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, - struct bssgp_dl_ud_par *dup) +int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, + struct bssgp_dl_ud_par *dup) { struct bssgp_bvc_ctx *bctx; struct bssgp_ud_hdr *budh; @@ -851,8 +851,8 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, } /* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */ -int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, - struct bssgp_paging_info *pinfo) +int bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, + struct bssgp_paging_info *pinfo) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = @@ -913,7 +913,7 @@ int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci, return gprs_ns_sendmsg(bssgp_nsi, msg); } -void gprs_bssgp_set_log_ss(int ss) +void bssgp_set_log_ss(int ss) { DBSSGP = ss; } diff --git a/openbsc/src/libgb/gprs_bssgp_bss.c b/openbsc/src/libgb/gprs_bssgp_bss.c index 4ca11ffd7..c058850d8 100644 --- a/openbsc/src/libgb/gprs_bssgp_bss.c +++ b/openbsc/src/libgb/gprs_bssgp_bss.c @@ -336,8 +336,8 @@ int bssgp_tx_ul_ud(struct bssgp_bvc_ctx *bctx, uint32_t tlli, } /* Parse a single GMM-PAGING.req to a given NSEI/NS-BVCI */ -int gprs_bssgp_rx_paging(struct bssgp_paging_info *pinfo, - struct msgb *msg) +int bssgp_rx_paging(struct bssgp_paging_info *pinfo, + struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); diff --git a/openbsc/src/libgb/gprs_bssgp_vty.c b/openbsc/src/libgb/gprs_bssgp_vty.c index 49a90c375..aa1f10656 100644 --- a/openbsc/src/libgb/gprs_bssgp_vty.c +++ b/openbsc/src/libgb/gprs_bssgp_vty.c @@ -167,7 +167,7 @@ DEFUN(logging_fltr_bvc, return CMD_SUCCESS; } -int gprs_bssgp_vty_init(void) +int bssgp_vty_init(void) { install_element_ve(&show_bssgp_cmd); install_element_ve(&show_bssgp_stats_cmd); diff --git a/openbsc/src/libgb/libosmo-gb.map b/openbsc/src/libgb/libosmo-gb.map index 60f85b261..83a830261 100644 --- a/openbsc/src/libgb/libosmo-gb.map +++ b/openbsc/src/libgb/libosmo-gb.map @@ -23,13 +23,12 @@ bssgp_tx_suspend; bssgp_tx_suspend_ack; bssgp_tx_suspend_nack; bssgp_tx_ul_ud; - -gprs_bssgp_rcvmsg -gprs_bssgp_rx_paging -gprs_bssgp_set_log_ss -gprs_bssgp_tx_dl_ud -gprs_bssgp_tx_paging -gprs_bssgp_vty_init +bssgp_rcvmsg +bssgp_rx_paging +bssgp_set_log_ss +bssgp_tx_dl_ud +bssgp_tx_paging +bssgp_vty_init gprs_ns_cause_str; gprs_ns_destroy; From 8648e49a1c10ec2f6d1560aa3f6c70b059eb52c7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 17 Jun 2012 13:12:51 +0800 Subject: [PATCH 198/198] libgb: separate header files related to spec and implementation like in libosmogsm, we separate between header files that are just reflecting information in the respective specs, and header files that related to our specific implementation. --- openbsc/include/osmocom/gprs/Makefile.am | 2 + openbsc/include/osmocom/gprs/gprs_bssgp.h | 142 +---------------- openbsc/include/osmocom/gprs/gprs_ns.h | 81 +--------- .../include/osmocom/gprs/protocol/Makefile.am | 3 + .../include/osmocom/gprs/protocol/gsm_08_16.h | 85 +++++++++++ .../include/osmocom/gprs/protocol/gsm_08_18.h | 144 ++++++++++++++++++ 6 files changed, 238 insertions(+), 219 deletions(-) create mode 100644 openbsc/include/osmocom/gprs/protocol/Makefile.am create mode 100644 openbsc/include/osmocom/gprs/protocol/gsm_08_16.h create mode 100644 openbsc/include/osmocom/gprs/protocol/gsm_08_18.h diff --git a/openbsc/include/osmocom/gprs/Makefile.am b/openbsc/include/osmocom/gprs/Makefile.am index 66b414f32..d39592c1b 100644 --- a/openbsc/include/osmocom/gprs/Makefile.am +++ b/openbsc/include/osmocom/gprs/Makefile.am @@ -1,3 +1,5 @@ libgb_HEADERS = gprs_bssgp.h gprs_ns.h gprs_ns_frgre.h gprs_msgb.h libgbdir = $(includedir)/osmocom/gprs + +SUBDIRS = protocol diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h index 66c2290f8..949dbdc89 100644 --- a/openbsc/include/osmocom/gprs/gprs_bssgp.h +++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h @@ -3,149 +3,11 @@ #include -/*! \brief Fixed BVCI definitions (Section 5.4.1) */ -#define BVCI_SIGNALLING 0x0000 -#define BVCI_PTM 0x0001 - -/*! \brief BSSGP PDU types (Section 11.3.26 / Table 11.27) */ -enum bssgp_pdu_type { - /* PDUs between RL and BSSGP SAPs */ - BSSGP_PDUT_DL_UNITDATA = 0x00, - BSSGP_PDUT_UL_UNITDATA = 0x01, - BSSGP_PDUT_RA_CAPABILITY = 0x02, - BSSGP_PDUT_PTM_UNITDATA = 0x03, - /* PDUs between GMM SAPs */ - BSSGP_PDUT_PAGING_PS = 0x06, - BSSGP_PDUT_PAGING_CS = 0x07, - BSSGP_PDUT_RA_CAPA_UDPATE = 0x08, - BSSGP_PDUT_RA_CAPA_UPDATE_ACK = 0x09, - BSSGP_PDUT_RADIO_STATUS = 0x0a, - BSSGP_PDUT_SUSPEND = 0x0b, - BSSGP_PDUT_SUSPEND_ACK = 0x0c, - BSSGP_PDUT_SUSPEND_NACK = 0x0d, - BSSGP_PDUT_RESUME = 0x0e, - BSSGP_PDUT_RESUME_ACK = 0x0f, - BSSGP_PDUT_RESUME_NACK = 0x10, - /* PDus between NM SAPs */ - BSSGP_PDUT_BVC_BLOCK = 0x20, - BSSGP_PDUT_BVC_BLOCK_ACK = 0x21, - BSSGP_PDUT_BVC_RESET = 0x22, - BSSGP_PDUT_BVC_RESET_ACK = 0x23, - BSSGP_PDUT_BVC_UNBLOCK = 0x24, - BSSGP_PDUT_BVC_UNBLOCK_ACK = 0x25, - BSSGP_PDUT_FLOW_CONTROL_BVC = 0x26, - BSSGP_PDUT_FLOW_CONTROL_BVC_ACK = 0x27, - BSSGP_PDUT_FLOW_CONTROL_MS = 0x28, - BSSGP_PDUT_FLOW_CONTROL_MS_ACK = 0x29, - BSSGP_PDUT_FLUSH_LL = 0x2a, - BSSGP_PDUT_FLUSH_LL_ACK = 0x2b, - BSSGP_PDUT_LLC_DISCARD = 0x2c, - BSSGP_PDUT_SGSN_INVOKE_TRACE = 0x40, - BSSGP_PDUT_STATUS = 0x41, - /* PDUs between PFM SAP's */ - BSSGP_PDUT_DOWNLOAD_BSS_PFC = 0x50, - BSSGP_PDUT_CREATE_BSS_PFC = 0x51, - BSSGP_PDUT_CREATE_BSS_PFC_ACK = 0x52, - BSSGP_PDUT_CREATE_BSS_PFC_NACK = 0x53, - BSSGP_PDUT_MODIFY_BSS_PFC = 0x54, - BSSGP_PDUT_MODIFY_BSS_PFC_ACK = 0x55, - BSSGP_PDUT_DELETE_BSS_PFC = 0x56, - BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57, -}; - -/*! \brief BSSGP User-Data header (Section 10.2.1 and 10.2.2) */ -struct bssgp_ud_hdr { - uint8_t pdu_type; /*!< BSSGP PDU type */ - uint32_t tlli; /*!< Temporary Link-Local Identifier */ - uint8_t qos_profile[3]; /*!< QoS profile */ - uint8_t data[0]; /* optional/conditional IEs as TLVs */ -} __attribute__((packed)); - -/*! \brief BSSGP normal header */ -struct bssgp_normal_hdr { - uint8_t pdu_type; /*!< BSSGP PDU type */ - uint8_t data[0]; /*!< optional/conditional IEs as TLVs */ -}; - -/*! \brief BSSGP Information Element Identifiers */ -enum bssgp_iei_type { - BSSGP_IE_ALIGNMENT = 0x00, - BSSGP_IE_BMAX_DEFAULT_MS = 0x01, - BSSGP_IE_BSS_AREA_ID = 0x02, - BSSGP_IE_BUCKET_LEAK_RATE = 0x03, - BSSGP_IE_BVCI = 0x04, - BSSGP_IE_BVC_BUCKET_SIZE = 0x05, - BSSGP_IE_BVC_MEASUREMENT = 0x06, - BSSGP_IE_CAUSE = 0x07, - BSSGP_IE_CELL_ID = 0x08, - BSSGP_IE_CHAN_NEEDED = 0x09, - BSSGP_IE_DRX_PARAMS = 0x0a, - BSSGP_IE_EMLPP_PRIO = 0x0b, - BSSGP_IE_FLUSH_ACTION = 0x0c, - BSSGP_IE_IMSI = 0x0d, - BSSGP_IE_LLC_PDU = 0x0e, - BSSGP_IE_LLC_FRAMES_DISCARDED = 0x0f, - BSSGP_IE_LOCATION_AREA = 0x10, - BSSGP_IE_MOBILE_ID = 0x11, - BSSGP_IE_MS_BUCKET_SIZE = 0x12, - BSSGP_IE_MS_RADIO_ACCESS_CAP = 0x13, - BSSGP_IE_OMC_ID = 0x14, - BSSGP_IE_PDU_IN_ERROR = 0x15, - BSSGP_IE_PDU_LIFETIME = 0x16, - BSSGP_IE_PRIORITY = 0x17, - BSSGP_IE_QOS_PROFILE = 0x18, - BSSGP_IE_RADIO_CAUSE = 0x19, - BSSGP_IE_RA_CAP_UPD_CAUSE = 0x1a, - BSSGP_IE_ROUTEING_AREA = 0x1b, - BSSGP_IE_R_DEFAULT_MS = 0x1c, - BSSGP_IE_SUSPEND_REF_NR = 0x1d, - BSSGP_IE_TAG = 0x1e, - BSSGP_IE_TLLI = 0x1f, - BSSGP_IE_TMSI = 0x20, - BSSGP_IE_TRACE_REFERENC = 0x21, - BSSGP_IE_TRACE_TYPE = 0x22, - BSSGP_IE_TRANSACTION_ID = 0x23, - BSSGP_IE_TRIGGER_ID = 0x24, - BSSGP_IE_NUM_OCT_AFF = 0x25, - BSSGP_IE_LSA_ID_LIST = 0x26, - BSSGP_IE_LSA_INFORMATION = 0x27, - BSSGP_IE_PACKET_FLOW_ID = 0x28, - BSSGP_IE_PACKET_FLOW_TIMER = 0x29, - BSSGP_IE_AGG_BSS_QOS_PROFILE = 0x3a, - BSSGP_IE_FEATURE_BITMAP = 0x3b, - BSSGP_IE_BUCKET_FULL_RATIO = 0x3c, - BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d, -}; - -/*! \brief Cause coding (Section 11.3.8 / Table 11.10) */ -enum gprs_bssgp_cause { - BSSGP_CAUSE_PROC_OVERLOAD = 0x00, - BSSGP_CAUSE_EQUIP_FAIL = 0x01, - BSSGP_CAUSE_TRASIT_NET_FAIL = 0x02, - BSSGP_CAUSE_CAPA_GREATER_0KPBS = 0x03, - BSSGP_CAUSE_UNKNOWN_MS = 0x04, - BSSGP_CAUSE_UNKNOWN_BVCI = 0x05, - BSSGP_CAUSE_CELL_TRAF_CONG = 0x06, - BSSGP_CAUSE_SGSN_CONG = 0x07, - BSSGP_CAUSE_OML_INTERV = 0x08, - BSSGP_CAUSE_BVCI_BLOCKED = 0x09, - BSSGP_CAUSE_PFC_CREATE_FAIL = 0x0a, - BSSGP_CAUSE_SEM_INCORR_PDU = 0x20, - BSSGP_CAUSE_INV_MAND_INF = 0x21, - BSSGP_CAUSE_MISSING_MAND_IE = 0x22, - BSSGP_CAUSE_MISSING_COND_IE = 0x23, - BSSGP_CAUSE_UNEXP_COND_IE = 0x24, - BSSGP_CAUSE_COND_IE_ERR = 0x25, - BSSGP_CAUSE_PDU_INCOMP_STATE = 0x26, - BSSGP_CAUSE_PROTO_ERR_UNSPEC = 0x27, - BSSGP_CAUSE_PDU_INCOMP_FEAT = 0x28, -}; - -/* Our implementation */ - #include #include +#include + /* gprs_bssgp_util.c */ extern struct gprs_ns_inst *bssgp_nsi; struct msgb *bssgp_msgb_alloc(void); diff --git a/openbsc/include/osmocom/gprs/gprs_ns.h b/openbsc/include/osmocom/gprs/gprs_ns.h index 206873b6f..a7f32b25a 100644 --- a/openbsc/include/osmocom/gprs/gprs_ns.h +++ b/openbsc/include/osmocom/gprs/gprs_ns.h @@ -3,85 +3,6 @@ #include -/* GPRS Networks Service (NS) messages on the Gb interface - * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) - * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ - -/*! \addtogroup libgb - * @{ - */ - -/*! \file gprs_ns.h */ - -/*! \brief Common header of GPRS NS */ -struct gprs_ns_hdr { - uint8_t pdu_type; /*!< NS PDU type */ - uint8_t data[0]; /*!< variable-length payload */ -} __attribute__((packed)); - -/*! \brief NS PDU Type (TS 08.16, Section 10.3.7, Table 14) */ -enum ns_pdu_type { - NS_PDUT_UNITDATA = 0x00, - NS_PDUT_RESET = 0x02, - NS_PDUT_RESET_ACK = 0x03, - NS_PDUT_BLOCK = 0x04, - NS_PDUT_BLOCK_ACK = 0x05, - NS_PDUT_UNBLOCK = 0x06, - NS_PDUT_UNBLOCK_ACK = 0x07, - NS_PDUT_STATUS = 0x08, - NS_PDUT_ALIVE = 0x0a, - NS_PDUT_ALIVE_ACK = 0x0b, - /* TS 48.016 Section 10.3.7, Table 10.3.7.1 */ - SNS_PDUT_ACK = 0x0c, - SNS_PDUT_ADD = 0x0d, - SNS_PDUT_CHANGE_WEIGHT = 0x0e, - SNS_PDUT_CONFIG = 0x0f, - SNS_PDUT_CONFIG_ACK = 0x10, - SNS_PDUT_DELETE = 0x11, - SNS_PDUT_SIZE = 0x12, - SNS_PDUT_SIZE_ACK = 0x13, -}; - -/*! \brief NS Control IE (TS 08.16, Section 10.3, Table 12) */ -enum ns_ctrl_ie { - NS_IE_CAUSE = 0x00, - NS_IE_VCI = 0x01, - NS_IE_PDU = 0x02, - NS_IE_BVCI = 0x03, - NS_IE_NSEI = 0x04, - /* TS 48.016 Section 10.3, Table 10.3.1 */ - NS_IE_IPv4_LIST = 0x05, - NS_IE_IPv6_LIST = 0x06, - NS_IE_MAX_NR_NSVC = 0x07, - NS_IE_IPv4_EP_NR = 0x08, - NS_IE_IPv6_EP_NR = 0x09, - NS_IE_RESET_FLAG = 0x0a, - NS_IE_IP_ADDR = 0x0b, -}; - -/*! \brief NS Cause (TS 08.16, Section 10.3.2, Table 13) */ -enum ns_cause { - NS_CAUSE_TRANSIT_FAIL = 0x00, - NS_CAUSE_OM_INTERVENTION = 0x01, - NS_CAUSE_EQUIP_FAIL = 0x02, - NS_CAUSE_NSVC_BLOCKED = 0x03, - NS_CAUSE_NSVC_UNKNOWN = 0x04, - NS_CAUSE_BVCI_UNKNOWN = 0x05, - NS_CAUSE_SEM_INCORR_PDU = 0x08, - NS_CAUSE_PDU_INCOMP_PSTATE = 0x0a, - NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b, - NS_CAUSE_INVAL_ESSENT_IE = 0x0c, - NS_CAUSE_MISSING_ESSENT_IE = 0x0d, - /* TS 48.016 Section 10.3.2, Table 10.3.2.1 */ - NS_CAUSE_INVAL_NR_IPv4_EP = 0x0e, - NS_CAUSE_INVAL_NR_IPv6_EP = 0x0f, - NS_CAUSE_INVAL_NR_NS_VC = 0x10, - NS_CAUSE_INVAL_WEIGH = 0x11, - NS_CAUSE_UNKN_IP_EP = 0x12, - NS_CAUSE_UNKN_IP_ADDR = 0x13, - NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, -}; - /* Our Implementation */ #include #include @@ -90,6 +11,8 @@ enum ns_cause { #include #include +#include + #define NS_TIMERS_COUNT 7 #define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" #define NS_TIMERS_HELP \ diff --git a/openbsc/include/osmocom/gprs/protocol/Makefile.am b/openbsc/include/osmocom/gprs/protocol/Makefile.am new file mode 100644 index 000000000..8255a9529 --- /dev/null +++ b/openbsc/include/osmocom/gprs/protocol/Makefile.am @@ -0,0 +1,3 @@ +libgbp_HEADERS = gsm_08_16.h gsm_08_18.h + +libgbpdir = $(includedir)/osmocom/gprs/protocol diff --git a/openbsc/include/osmocom/gprs/protocol/gsm_08_16.h b/openbsc/include/osmocom/gprs/protocol/gsm_08_16.h new file mode 100644 index 000000000..4c3eda327 --- /dev/null +++ b/openbsc/include/osmocom/gprs/protocol/gsm_08_16.h @@ -0,0 +1,85 @@ +#ifndef _OSMO_08_16_H +#define _OSMO_08_16_H + +/* GPRS Networks Service (NS) messages on the Gb interface + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) + * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ + +#include + +/*! \addtogroup libgb + * @{ + */ + +/*! \file gprs_ns.h */ + +/*! \brief Common header of GPRS NS */ +struct gprs_ns_hdr { + uint8_t pdu_type; /*!< NS PDU type */ + uint8_t data[0]; /*!< variable-length payload */ +} __attribute__((packed)); + +/*! \brief NS PDU Type (TS 08.16, Section 10.3.7, Table 14) */ +enum ns_pdu_type { + NS_PDUT_UNITDATA = 0x00, + NS_PDUT_RESET = 0x02, + NS_PDUT_RESET_ACK = 0x03, + NS_PDUT_BLOCK = 0x04, + NS_PDUT_BLOCK_ACK = 0x05, + NS_PDUT_UNBLOCK = 0x06, + NS_PDUT_UNBLOCK_ACK = 0x07, + NS_PDUT_STATUS = 0x08, + NS_PDUT_ALIVE = 0x0a, + NS_PDUT_ALIVE_ACK = 0x0b, + /* TS 48.016 Section 10.3.7, Table 10.3.7.1 */ + SNS_PDUT_ACK = 0x0c, + SNS_PDUT_ADD = 0x0d, + SNS_PDUT_CHANGE_WEIGHT = 0x0e, + SNS_PDUT_CONFIG = 0x0f, + SNS_PDUT_CONFIG_ACK = 0x10, + SNS_PDUT_DELETE = 0x11, + SNS_PDUT_SIZE = 0x12, + SNS_PDUT_SIZE_ACK = 0x13, +}; + +/*! \brief NS Control IE (TS 08.16, Section 10.3, Table 12) */ +enum ns_ctrl_ie { + NS_IE_CAUSE = 0x00, + NS_IE_VCI = 0x01, + NS_IE_PDU = 0x02, + NS_IE_BVCI = 0x03, + NS_IE_NSEI = 0x04, + /* TS 48.016 Section 10.3, Table 10.3.1 */ + NS_IE_IPv4_LIST = 0x05, + NS_IE_IPv6_LIST = 0x06, + NS_IE_MAX_NR_NSVC = 0x07, + NS_IE_IPv4_EP_NR = 0x08, + NS_IE_IPv6_EP_NR = 0x09, + NS_IE_RESET_FLAG = 0x0a, + NS_IE_IP_ADDR = 0x0b, +}; + +/*! \brief NS Cause (TS 08.16, Section 10.3.2, Table 13) */ +enum ns_cause { + NS_CAUSE_TRANSIT_FAIL = 0x00, + NS_CAUSE_OM_INTERVENTION = 0x01, + NS_CAUSE_EQUIP_FAIL = 0x02, + NS_CAUSE_NSVC_BLOCKED = 0x03, + NS_CAUSE_NSVC_UNKNOWN = 0x04, + NS_CAUSE_BVCI_UNKNOWN = 0x05, + NS_CAUSE_SEM_INCORR_PDU = 0x08, + NS_CAUSE_PDU_INCOMP_PSTATE = 0x0a, + NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b, + NS_CAUSE_INVAL_ESSENT_IE = 0x0c, + NS_CAUSE_MISSING_ESSENT_IE = 0x0d, + /* TS 48.016 Section 10.3.2, Table 10.3.2.1 */ + NS_CAUSE_INVAL_NR_IPv4_EP = 0x0e, + NS_CAUSE_INVAL_NR_IPv6_EP = 0x0f, + NS_CAUSE_INVAL_NR_NS_VC = 0x10, + NS_CAUSE_INVAL_WEIGH = 0x11, + NS_CAUSE_UNKN_IP_EP = 0x12, + NS_CAUSE_UNKN_IP_ADDR = 0x13, + NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, +}; + +#endif diff --git a/openbsc/include/osmocom/gprs/protocol/gsm_08_18.h b/openbsc/include/osmocom/gprs/protocol/gsm_08_18.h new file mode 100644 index 000000000..3a351eaaf --- /dev/null +++ b/openbsc/include/osmocom/gprs/protocol/gsm_08_18.h @@ -0,0 +1,144 @@ +#ifndef _OSMO_08_18_H +#define _OSMO_08_18_H + +#include + +/*! \brief Fixed BVCI definitions (Section 5.4.1) */ +#define BVCI_SIGNALLING 0x0000 +#define BVCI_PTM 0x0001 + +/*! \brief BSSGP PDU types (Section 11.3.26 / Table 11.27) */ +enum bssgp_pdu_type { + /* PDUs between RL and BSSGP SAPs */ + BSSGP_PDUT_DL_UNITDATA = 0x00, + BSSGP_PDUT_UL_UNITDATA = 0x01, + BSSGP_PDUT_RA_CAPABILITY = 0x02, + BSSGP_PDUT_PTM_UNITDATA = 0x03, + /* PDUs between GMM SAPs */ + BSSGP_PDUT_PAGING_PS = 0x06, + BSSGP_PDUT_PAGING_CS = 0x07, + BSSGP_PDUT_RA_CAPA_UDPATE = 0x08, + BSSGP_PDUT_RA_CAPA_UPDATE_ACK = 0x09, + BSSGP_PDUT_RADIO_STATUS = 0x0a, + BSSGP_PDUT_SUSPEND = 0x0b, + BSSGP_PDUT_SUSPEND_ACK = 0x0c, + BSSGP_PDUT_SUSPEND_NACK = 0x0d, + BSSGP_PDUT_RESUME = 0x0e, + BSSGP_PDUT_RESUME_ACK = 0x0f, + BSSGP_PDUT_RESUME_NACK = 0x10, + /* PDus between NM SAPs */ + BSSGP_PDUT_BVC_BLOCK = 0x20, + BSSGP_PDUT_BVC_BLOCK_ACK = 0x21, + BSSGP_PDUT_BVC_RESET = 0x22, + BSSGP_PDUT_BVC_RESET_ACK = 0x23, + BSSGP_PDUT_BVC_UNBLOCK = 0x24, + BSSGP_PDUT_BVC_UNBLOCK_ACK = 0x25, + BSSGP_PDUT_FLOW_CONTROL_BVC = 0x26, + BSSGP_PDUT_FLOW_CONTROL_BVC_ACK = 0x27, + BSSGP_PDUT_FLOW_CONTROL_MS = 0x28, + BSSGP_PDUT_FLOW_CONTROL_MS_ACK = 0x29, + BSSGP_PDUT_FLUSH_LL = 0x2a, + BSSGP_PDUT_FLUSH_LL_ACK = 0x2b, + BSSGP_PDUT_LLC_DISCARD = 0x2c, + BSSGP_PDUT_SGSN_INVOKE_TRACE = 0x40, + BSSGP_PDUT_STATUS = 0x41, + /* PDUs between PFM SAP's */ + BSSGP_PDUT_DOWNLOAD_BSS_PFC = 0x50, + BSSGP_PDUT_CREATE_BSS_PFC = 0x51, + BSSGP_PDUT_CREATE_BSS_PFC_ACK = 0x52, + BSSGP_PDUT_CREATE_BSS_PFC_NACK = 0x53, + BSSGP_PDUT_MODIFY_BSS_PFC = 0x54, + BSSGP_PDUT_MODIFY_BSS_PFC_ACK = 0x55, + BSSGP_PDUT_DELETE_BSS_PFC = 0x56, + BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57, +}; + +/*! \brief BSSGP User-Data header (Section 10.2.1 and 10.2.2) */ +struct bssgp_ud_hdr { + uint8_t pdu_type; /*!< BSSGP PDU type */ + uint32_t tlli; /*!< Temporary Link-Local Identifier */ + uint8_t qos_profile[3]; /*!< QoS profile */ + uint8_t data[0]; /* optional/conditional IEs as TLVs */ +} __attribute__((packed)); + +/*! \brief BSSGP normal header */ +struct bssgp_normal_hdr { + uint8_t pdu_type; /*!< BSSGP PDU type */ + uint8_t data[0]; /*!< optional/conditional IEs as TLVs */ +}; + +/*! \brief BSSGP Information Element Identifiers */ +enum bssgp_iei_type { + BSSGP_IE_ALIGNMENT = 0x00, + BSSGP_IE_BMAX_DEFAULT_MS = 0x01, + BSSGP_IE_BSS_AREA_ID = 0x02, + BSSGP_IE_BUCKET_LEAK_RATE = 0x03, + BSSGP_IE_BVCI = 0x04, + BSSGP_IE_BVC_BUCKET_SIZE = 0x05, + BSSGP_IE_BVC_MEASUREMENT = 0x06, + BSSGP_IE_CAUSE = 0x07, + BSSGP_IE_CELL_ID = 0x08, + BSSGP_IE_CHAN_NEEDED = 0x09, + BSSGP_IE_DRX_PARAMS = 0x0a, + BSSGP_IE_EMLPP_PRIO = 0x0b, + BSSGP_IE_FLUSH_ACTION = 0x0c, + BSSGP_IE_IMSI = 0x0d, + BSSGP_IE_LLC_PDU = 0x0e, + BSSGP_IE_LLC_FRAMES_DISCARDED = 0x0f, + BSSGP_IE_LOCATION_AREA = 0x10, + BSSGP_IE_MOBILE_ID = 0x11, + BSSGP_IE_MS_BUCKET_SIZE = 0x12, + BSSGP_IE_MS_RADIO_ACCESS_CAP = 0x13, + BSSGP_IE_OMC_ID = 0x14, + BSSGP_IE_PDU_IN_ERROR = 0x15, + BSSGP_IE_PDU_LIFETIME = 0x16, + BSSGP_IE_PRIORITY = 0x17, + BSSGP_IE_QOS_PROFILE = 0x18, + BSSGP_IE_RADIO_CAUSE = 0x19, + BSSGP_IE_RA_CAP_UPD_CAUSE = 0x1a, + BSSGP_IE_ROUTEING_AREA = 0x1b, + BSSGP_IE_R_DEFAULT_MS = 0x1c, + BSSGP_IE_SUSPEND_REF_NR = 0x1d, + BSSGP_IE_TAG = 0x1e, + BSSGP_IE_TLLI = 0x1f, + BSSGP_IE_TMSI = 0x20, + BSSGP_IE_TRACE_REFERENC = 0x21, + BSSGP_IE_TRACE_TYPE = 0x22, + BSSGP_IE_TRANSACTION_ID = 0x23, + BSSGP_IE_TRIGGER_ID = 0x24, + BSSGP_IE_NUM_OCT_AFF = 0x25, + BSSGP_IE_LSA_ID_LIST = 0x26, + BSSGP_IE_LSA_INFORMATION = 0x27, + BSSGP_IE_PACKET_FLOW_ID = 0x28, + BSSGP_IE_PACKET_FLOW_TIMER = 0x29, + BSSGP_IE_AGG_BSS_QOS_PROFILE = 0x3a, + BSSGP_IE_FEATURE_BITMAP = 0x3b, + BSSGP_IE_BUCKET_FULL_RATIO = 0x3c, + BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d, +}; + +/*! \brief Cause coding (Section 11.3.8 / Table 11.10) */ +enum gprs_bssgp_cause { + BSSGP_CAUSE_PROC_OVERLOAD = 0x00, + BSSGP_CAUSE_EQUIP_FAIL = 0x01, + BSSGP_CAUSE_TRASIT_NET_FAIL = 0x02, + BSSGP_CAUSE_CAPA_GREATER_0KPBS = 0x03, + BSSGP_CAUSE_UNKNOWN_MS = 0x04, + BSSGP_CAUSE_UNKNOWN_BVCI = 0x05, + BSSGP_CAUSE_CELL_TRAF_CONG = 0x06, + BSSGP_CAUSE_SGSN_CONG = 0x07, + BSSGP_CAUSE_OML_INTERV = 0x08, + BSSGP_CAUSE_BVCI_BLOCKED = 0x09, + BSSGP_CAUSE_PFC_CREATE_FAIL = 0x0a, + BSSGP_CAUSE_SEM_INCORR_PDU = 0x20, + BSSGP_CAUSE_INV_MAND_INF = 0x21, + BSSGP_CAUSE_MISSING_MAND_IE = 0x22, + BSSGP_CAUSE_MISSING_COND_IE = 0x23, + BSSGP_CAUSE_UNEXP_COND_IE = 0x24, + BSSGP_CAUSE_COND_IE_ERR = 0x25, + BSSGP_CAUSE_PDU_INCOMP_STATE = 0x26, + BSSGP_CAUSE_PROTO_ERR_UNSPEC = 0x27, + BSSGP_CAUSE_PDU_INCOMP_FEAT = 0x28, +}; + +#endif