diff options
Diffstat (limited to 'openbsc')
-rw-r--r-- | openbsc/include/openbsc/gprs_bssgp.h | 12 | ||||
-rw-r--r-- | openbsc/src/gprs/Makefile.am | 5 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy.c | 110 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy_main.c | 13 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_bssgp.c | 82 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_bssgp_util.c | 119 |
6 files changed, 210 insertions, 131 deletions
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 <osmocore/tlv.h> extern int gprs_bssgp_rcvmsg(struct msgb *msg); diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2b4292398..7cb7ba66a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -6,10 +6,11 @@ sbin_PROGRAMS = osmo-gbproxy osmo-sgsn noinst_LIBRARIES = libsgsn.a libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \ - crc24.c gprs_sgsn.c + crc24.c gprs_sgsn.c gprs_bssgp_util.c osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gprs_ns.c $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c + gprs_ns.c gprs_bssgp_util.c \ + $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c osmo_gbproxy_LDADD = $(top_builddir)/src/libvty.a osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 3c639437a..ff80e92d4 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -55,8 +55,6 @@ struct gbprox_peer { /* Linked list of all Gb peers (except SGSN) */ static LLIST_HEAD(gbprox_bts_peers); -extern struct gprs_ns_inst *gbprox_nsi; - /* Find the gbprox_peer by its BVCI */ static struct gbprox_peer *peer_by_bvci(uint16_t bvci) { @@ -127,30 +125,6 @@ static void strip_ns_hdr(struct msgb *msg) msgb_pull(msg, strip_len); } -/* FIXME: this is copy+paste from gprs_bssgp.c */ -static inline struct msgb *bssgp_msgb_alloc(void) -{ - return msgb_alloc_headroom(4096, 128, "BSSGP"); -} -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(gbprox_nsi, msg); -} - - /* feed a message down the NS-VC associated with the specified peer */ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) { @@ -162,7 +136,7 @@ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) strip_ns_hdr(msg); - return gprs_ns_sendmsg(gbprox_nsi, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* feed a message down the NS-VC associated with the specified peer */ @@ -177,7 +151,7 @@ static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, strip_ns_hdr(msg); - return gprs_ns_sendmsg(gbprox_nsi, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Send a message to a peer identified by ptp_bvci but using ns_bvci @@ -274,9 +248,13 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ return gbprox_relay2sgsn(msg, ns_bvci); err_no_peer: + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) cannot find peer based on RAC\n", + nsvc->nsei); + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg); err_mand_ie: - /* FIXME: do something */ - ; + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) missing mandatory RA IE\n", + nsvc->nsei); + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); } /* Receive paging request from SGSN, we need to relay to proper BSS */ @@ -298,6 +276,42 @@ static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, return -EINVAL; } +/* Receive an incoming BVC-RESET message from the SGSN */ +static int rx_reset_from_sgsn(struct msgb *msg, struct tlv_parsed *tp, + struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + uint16_t ptp_bvci; + + if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, + NULL, msg); + } + ptp_bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + + if (ptp_bvci >= 2) { + /* A reset for a PTP BVC was received, forward it to its + * respective peer */ + peer = peer_by_bvci(ptp_bvci); + if (!peer) { + LOGP(DGPRS, LOGL_ERROR, "Cannot find BSS for BVCI %u\n", + ptp_bvci); + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, + NULL, msg); + } + return gbprox_relay2peer(msg, peer, ns_bvci); + } + + /* A reset for the Signalling entity has been received + * from the SGSN. As the signalling BVCI is shared + * among all the BSS's that we multiplex, it needs to + * be relayed */ + llist_for_each_entry(peer, &gbprox_bts_peers, list) + gbprox_relay2peer(msg, peer, ns_bvci); + + return 0; +} + /* Receive an incoming signalling message from the SGSN-side NS-VC */ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) @@ -313,6 +327,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, if (ns_bvci != 0) { LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI %u is not " "signalling\n", nsvc->nsei, ns_bvci); + /* FIXME: Send proper error message */ return -EINVAL; } @@ -322,16 +337,18 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, pdu_type == BSSGP_PDUT_DL_UNITDATA) { LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) UNITDATA not allowed in " "signalling\n", nsvc->nsei); - return -EINVAL; + return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); } rc = bssgp_tlv_parse(&tp, bgph->data, data_len); switch (pdu_type) { + case BSSGP_PDUT_BVC_RESET: + rc = rx_reset_from_sgsn(msg, &tp, nsvc, ns_bvci); + break; case BSSGP_PDUT_FLUSH_LL: case BSSGP_PDUT_BVC_BLOCK_ACK: case BSSGP_PDUT_BVC_UNBLOCK_ACK: - case BSSGP_PDUT_BVC_RESET: case BSSGP_PDUT_BVC_RESET_ACK: /* simple case: BVCI IE is mandatory */ if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) @@ -345,9 +362,22 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci); break; case BSSGP_PDUT_STATUS: - /* FIXME: Some exception has occurred */ + /* Some exception has occurred */ LOGP(DGPRS, LOGL_NOTICE, - "NSEI=%u(SGSN) STATUS not implemented yet\n", nsvc->nsei); + "NSEI=%u(SGSN) STATUS ", nsvc->nsei); + if (!TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) { + LOGPC(DGPRS, LOGL_NOTICE, "\n"); + goto err_mand_ie; + } + LOGPC(DGPRS, LOGL_NOTICE, + "cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE), + bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { + uint16_t *bvci = TLVP_VAL(&tp, BSSGP_IE_BVCI); + LOGPC(DGPRS, LOGL_NOTICE, + "BVCI=%u\n", ntohs(*bvci)); + } else + LOGPC(DGPRS, LOGL_NOTICE, "\n"); break; /* those only exist in the SGSN -> BSS direction */ case BSSGP_PDUT_SUSPEND_ACK: @@ -365,9 +395,11 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, case BSSGP_PDUT_SGSN_INVOKE_TRACE: LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) INVOKE TRACE not supported\n", nsvc->nsei); + rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); break; default: DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); break; } @@ -375,13 +407,11 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, err_mand_ie: LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) missing mandatory IE\n", nsvc->nsei); - /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ - //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); - return; + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); err_no_peer: - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n"); - /* FIXME */ - return; + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n", + nsvc->nsei); + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg); } /* Main input function for Gb proxy */ diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index 72f1417bc..1a5d7bd8d 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -39,6 +39,7 @@ #include <openbsc/signal.h> #include <openbsc/debug.h> #include <openbsc/gprs_ns.h> +#include <openbsc/gprs_bssgp.h> #include <openbsc/telnet_interface.h> #include <openbsc/vty.h> #include <openbsc/gb_proxy.h> @@ -53,8 +54,6 @@ void subscr_put() { abort(); } void *tall_bsc_ctx; -struct gprs_ns_inst *gbprox_nsi; - const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; const char *openbsc_copyright = "Copyright (C) 2010 Harald Welte and On-Waves\n" @@ -112,20 +111,20 @@ int main(int argc, char **argv) exit(2); } - gbprox_nsi = gprs_ns_instantiate(&proxy_ns_cb); - if (!gbprox_nsi) { + bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb); + if (!bssgp_nsi) { LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); exit(1); } - gbcfg.nsi = gbprox_nsi; + gbcfg.nsi = bssgp_nsi; register_signal_handler(SS_NS, &gbprox_signal, NULL); - nsip_listen(gbprox_nsi, gbcfg.nsip_listen_port); + nsip_listen(bssgp_nsi, gbcfg.nsip_listen_port); /* 'establish' the outgoing connection to the SGSN */ sin.sin_family = AF_INET; sin.sin_port = htons(gbcfg.nsip_sgsn_port); sin.sin_addr.s_addr = htonl(gbcfg.nsip_sgsn_ip); - nsip_connect(gbprox_nsi, &sin, gbcfg.nsip_sgsn_nsei, + nsip_connect(bssgp_nsi, &sin, gbcfg.nsip_sgsn_nsei, gbcfg.nsip_sgsn_nsvci); while (1) { 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 <laforge@gnumonks.org> + * + * 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 <errno.h> +#include <stdint.h> + +#include <netinet/in.h> + +#include <osmocore/msgb.h> +#include <osmocore/tlv.h> +#include <osmocore/talloc.h> + +#include <openbsc/debug.h> +#include <openbsc/gsm_data.h> +#include <openbsc/gprs_bssgp.h> +#include <openbsc/gprs_ns.h> + +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); +} |