From f67945f0047d62ca546afbd74def30adfc9e2f89 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Oct 2009 07:08:11 +0200 Subject: [PATCH 001/365] [mgcp] Add a simple mgcp gateway used for the BSC The python script is a simple call-agent driving the client. Currently it is sending a AuditEndpoint message and is printing the result. The bsc_mgcp.c is a standalone process that will implement a MGCP Gateway for the MSC. On call handling the Call-Agent will ask the Gateway to "CreateConnection" and then this gateway needs to communicate with OpenBSC. Currently CreateConnection,ModifiyConnection,DeleteConnection and Endpoint auditing is implemented. [mgcp] Send RSIP on start and on first receive of any message Ignore the first request and send a RSIP. We do that because we might tunnel UDP through some other things and have no direct way to connect to the call-agent. Also the transaction is not checked and we ignore the response from the call-agent, actually we print the '200 ' or any other value as unhandled... [mgcp] Print the MGCP command next to the response code This allows to see which commands were sent by the server mgcp: Terminate it with a new line [mgcp] Make number of endpoints static... For now this is fixed to the number of endpoints as of the GSM specification... [mgcp] The endpoint names seem to be base 16... use strtoul to parse Use strtoul to parse the base 16 number from the mgw string. [mgcp] Log the endpoints as hex numbers... [mgcp] Only send the RSIP on the first incoming message.. Remove call_agent option (also remove the number from the getopt call). [mgcp] Start couting at 1 for the mgcp [mgcp] Slight attempt to improve the grammar of the strings [mgcp] Share validation routines between DLCX and MDCX [mgcp] Remove help for dead config options [mgcp] Specify a different IN addr in the SDP records In case of NAT traversal be able to listen on a given interface (like 127.0.0.1) but claim to receive data at the beginning of the tunnel. [mgcp] Fix the static copy of the SDP file WIP verify out factoring broken.. [mgcp] Introduce VTY to the mgcp for config file parsing... Parse the MGCP config file via the VTY framework. [mgcp] Handle SDP parameters through VTY.. Currently the payload type, name and rate can be specified in the config file. [mgcp] Add an option to bind all rtp ports early This can be useful for testing and in deployment to make sure no runtime resource limit can be hit. [mgcp] Add some API doc comment [mgcp] Convert the packets of the example server to ascii This will allow to easily patch the call id... to run the server in a loop and make it work with the mediagateway [mgcp] Assign CI_UNUSED... to be more obvious... [mgcp] Use DEBUG and not DEBUGPC and specially not printf Improve the logging a bit in the mgcp [mgcp] Change the fake server to change the call id This assume the call-agent will just increment the id as well.... this is true for our implementation [mgcp] Generate the transaction id dynamically.. This way wireshark will be more happy about it... [mgcp] Recognize responses from the network.. This is just recognizing the response code and then is doing nothing with it. Also change the script to generate response messages... [mgcp] Improve debug messages for CRCX/MDCX.. Log on which ports the media gateway is listening and where the other (server) gateway is located --- openbsc/contrib/mgcp_server.py | 54 ++ openbsc/include/openbsc/mgcp.h | 48 ++ openbsc/include/vty/command.h | 1 + openbsc/src/Makefile.am | 6 +- openbsc/src/bsc_mgcp.c | 1117 ++++++++++++++++++++++++++++++++ openbsc/src/mgcp.cfg | 17 + 6 files changed, 1242 insertions(+), 1 deletion(-) create mode 100755 openbsc/contrib/mgcp_server.py create mode 100644 openbsc/include/openbsc/mgcp.h create mode 100644 openbsc/src/bsc_mgcp.c create mode 100644 openbsc/src/mgcp.cfg diff --git a/openbsc/contrib/mgcp_server.py b/openbsc/contrib/mgcp_server.py new file mode 100755 index 000000000..cf3ef3845 --- /dev/null +++ b/openbsc/contrib/mgcp_server.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# Simple server for mgcp... send audit, receive response.. + +import socket, time + +MGCP_GATEWAY_PORT = 2427 +MGCP_CALLAGENT_PORT = 2727 + +rsip_resp = """200 321321332\r\n""" +audit_packet = """AUEP %d 13@mgw MGCP 1.0\r\n""" +crcx_packet = """CRCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n""" +dlcx_packet = """DLCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\n""" +mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 4400 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n""" + +def hexdump(src, length=8): + """Recipe is from http://code.activestate.com/recipes/142812/""" + result = [] + digits = 4 if isinstance(src, unicode) else 2 + for i in xrange(0, len(src), length): + s = src[i:i+length] + hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s]) + text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s]) + result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) ) + return b'\n'.join(result) + +server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +server_socket.bind(("127.0.0.1", MGCP_CALLAGENT_PORT)) +server_socket.setblocking(0) + + +def send_receive(packet): + server_socket.sendto(packet, ("127.0.0.1", MGCP_GATEWAY_PORT)) + try: + data, addr = server_socket.recvfrom(4096) + print hexdump(data), addr + except socket.error: + pass + +def generate_tid(): + import random + return random.randint(0, 65123) + + + +i = 1 +while True: + send_receive(rsip_resp) + send_receive(audit_packet) + send_receive(crcx_packet % generate_tid() ) + send_receive(mdcx_packet % (generate_tid(), i)) + send_receive(dlcx_packet % (generate_tid(), i)) + i = i + 1 + + time.sleep(3) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h new file mode 100644 index 000000000..fa6224c12 --- /dev/null +++ b/openbsc/include/openbsc/mgcp.h @@ -0,0 +1,48 @@ +/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ + +/* + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by on-waves.com + * 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. + * + */ + +unsigned int rtp_base_port = 4000; + +/** + * Calculate the RTP audio port for the given multiplex + * and the direction. This allows a semi static endpoint + * to port calculation removing the need for the BSC + * and the MediaGateway to communicate. + * + * Port usage explained: + * base + (multiplex * 2) + 0 == local port to wait for network packets + * base + (multiplex * 2) + 1 == local port for rtcp + * + * The above port will receive packets from the BTS that need + * to be patched and forwarded to the network. + * The above port will receive packets from the network that + * need to be patched and forwarded to the BTS. + * + * We assume to have a static BTS IP address so we can differentiate + * network and BTS. + * + */ +int rtp_calculate_port(int multiplex, int base) +{ + return base + (multiplex * 2); +} diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 9daa2d62d..10a60add5 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -106,6 +106,7 @@ enum node_type { TRX_NODE, TS_NODE, SUBSCR_NODE, + MGCP_NODE, }; /* Node which has some commands and prompt string and configuration diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 79120081d..7651132b6 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -1,7 +1,8 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync +sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync \ + isdnsync bsc_mgcp noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h @@ -32,3 +33,6 @@ ipaccess_config_SOURCES = ipaccess-config.c ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) isdnsync_SOURCES = isdnsync.c + +bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c +bsc_mgcp_LDADD = libvty.a diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c new file mode 100644 index 000000000..8b59b31cb --- /dev/null +++ b/openbsc/src/bsc_mgcp.c @@ -0,0 +1,1117 @@ +/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ + +/* + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by on-waves.com + * 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 + +/* this is here for the vty... it will never be called */ +void subscr_put() { abort(); } +void vty_event() { } + +#define _GNU_SOURCE +#include + +#warning "Make use of the rtp proxy code" + +static int source_port = 2427; +static const char *local_ip = NULL; +static const char *source_addr = "0.0.0.0"; +static struct bsc_fd bfd; +static const unsigned int number_endpoints = 32 + 1; +static const char *bts_ip = NULL; +static struct in_addr bts_in; +static int first_request = 1; +static const char *audio_name = "GSM-EFR/8000"; +static int audio_payload = 97; +static int early_bind = 0; + +static char *config_file = "mgcp.cfg"; + +/* used by msgb and mgcp */ +void *tall_bsc_ctx = NULL; + +enum mgcp_connection_mode { + MGCP_CONN_NONE = 0, + MGCP_CONN_RECV_ONLY = 1, + MGCP_CONN_SEND_ONLY = 2, + MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, +}; + +#define CI_UNUSED 0 +static unsigned int last_call_id = 0; + +struct mgcp_endpoint { + int ci; + char *callid; + char *local_options; + int conn_mode; + + /* the local rtp port */ + int rtp_port; + + /* + * RTP mangling: + * - we get RTP and RTCP to us and need to forward to the BTS + * - we get RTP and RTCP from the BTS and forward to the network + */ + struct bsc_fd local_rtp; + struct bsc_fd local_rtcp; + + struct in_addr remote; + + /* in network byte order */ + int rtp, rtcp; + int bts_rtp, bts_rtcp; +}; + +static struct mgcp_endpoint *endpoints = NULL; +#define ENDPOINT_NUMBER(endp) abs(endp - endpoints) + +/** + * Macro for tokenizing MGCP messages and SDP in one go. + * + */ +#define MSG_TOKENIZE_START \ + line_start = 0; \ + for (i = 0; i < msgb_l3len(msg); ++i) { \ + /* we have a line end */ \ + if (msg->l3h[i] == '\n') { \ + /* skip the first line */ \ + if (line_start == 0) { \ + line_start = i + 1; \ + continue; \ + } \ + \ + /* check if we have a proper param */ \ + if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \ + } else if (i - line_start > 2 \ + && islower(msg->l3h[line_start]) \ + && msg->l3h[line_start + 1] == '=') { \ + } else if (i - line_start < 3 \ + || msg->l3h[line_start + 1] != ':' \ + || msg->l3h[line_start + 2] != ' ') \ + goto error; \ + \ + msg->l3h[i] = '\0'; \ + if (msg->l3h[i-1] == '\r') \ + msg->l3h[i-1] = '\0'; + +#define MSG_TOKENIZE_END \ + line_start = i + 1; \ + } \ + } + + +struct mgcp_msg_ptr { + unsigned int start; + unsigned int length; +}; + +struct mgcp_request { + char *name; + void (*handle_request) (struct msgb *msg, struct sockaddr_in *source); + char *debug_name; +}; + +#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \ + { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME }, + +static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source); +static void handle_create_con(struct msgb *msg, struct sockaddr_in *source); +static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source); +static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source); + +static int generate_call_id() +{ + int i; + + /* use the call id */ + ++last_call_id; + + /* handle wrap around */ + if (last_call_id == CI_UNUSED) + ++last_call_id; + + /* callstack can only be of size number_of_endpoints */ + /* verify that the call id is free, e.g. in case of overrun */ + for (i = 1; i < number_endpoints; ++i) + if (endpoints[i].ci == last_call_id) + return generate_call_id(); + + return last_call_id; +} + +/* FIXIME/TODO: need to have a list of pending transactions and check that */ +static unsigned int generate_transaction_id() +{ + return abs(rand()); +} + +static int _send(int fd, struct in_addr *addr, int port, char *buf, int len) +{ + struct sockaddr_in out; + out.sin_family = AF_INET; + out.sin_port = port; + memcpy(&out.sin_addr, addr, sizeof(*addr)); + + return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out)); +} + +/* + * There is data coming. We will have to figure out if it + * came from the BTS or the MediaGateway of the MSC. On top + * of that we need to figure out if it was RTP or RTCP. + * + * Currently we do not communicate with the BSC so we have + * no idea where the BTS is listening for RTP and need to + * do the classic routing trick. Wait for the first packet + * from the BTS and then go ahead. + */ +static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) +{ + char buf[4096]; + struct sockaddr_in addr; + socklen_t slen = sizeof(addr); + struct mgcp_endpoint *endp; + int rc, is_remote; + + endp = (struct mgcp_endpoint *) fd->data; + + rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, + (struct sockaddr *) &addr, &slen); + if (rc < 0) { + DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n", + ENDPOINT_NUMBER(endp)); + return -1; + } + + /* + * Figure out where to forward it to. This code assumes that we + * have received the Connection Modify and know who is a legitimate + * partner. According to the spec we could attempt to forward even + * after the Create Connection but we will not as we are not really + * able to tell if this is legitimate. + */ + #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." + is_remote = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0; + if (is_remote) { + if (endp->rtp == addr.sin_port) { + return _send(fd->fd, &bts_in, endp->bts_rtp, buf, rc); + } else if (endp->rtcp == addr.sin_port) { + return _send(fd->fd, &bts_in, endp->bts_rtcp, buf, rc); + } else { + DEBUGP(DMGCP, "Unknown remote port. Not able to forward on 0x%x port: %d\n", + ENDPOINT_NUMBER(endp), ntohs(addr.sin_port)); + } + + return -1; + } + + /* We have no idea who called us, maybe it is the BTS. */ + if (endp->bts_rtp == 0) { + /* it was the BTS... */ + if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { + if (fd == &endp->local_rtp) { + endp->bts_rtp = addr.sin_port; + endp->bts_rtcp = htons(ntohs(addr.sin_port) + 1); + } else { + endp->bts_rtp = htons(ntohs(addr.sin_port) - 1); + endp->bts_rtcp = addr.sin_port; + } + + DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d\n", + ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp)); + } + } + + if (endp->bts_rtp == 0 || endp->conn_mode == MGCP_CONN_RECV_ONLY) { + DEBUGP(DMGCP, "Not forwarding data from possible BTS conn: %d on 0x%x\n", + endp->conn_mode, ENDPOINT_NUMBER(endp)); + return -1; + } + + if (fd == &endp->local_rtp) { + return _send(fd->fd, &endp->remote, endp->rtp, buf, rc); + } else { + return _send(fd->fd, &endp->remote, endp->rtcp, buf, rc); + } +} + +static int create_bind(struct bsc_fd *fd, int port) +{ + struct sockaddr_in addr; + int on = 1; + + fd->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd->fd < 0) + return -1; + + setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_aton(source_addr, &addr.sin_addr); + + if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + return -1; + + return 0; +} + +static int bind_rtp(struct mgcp_endpoint *endp) +{ + /* set to zero until we get the info */ + memset(&endp->remote, 0, sizeof(endp->remote)); + endp->bts_rtp = endp->bts_rtcp = 0; + endp->rtp = endp->rtcp = 0; + + if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { + DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", + endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup0; + } + + if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) { + DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n", + endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup1; + } + + endp->local_rtp.cb = rtp_data_cb; + endp->local_rtp.data = endp; + endp->local_rtp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtp) != 0) { + DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n", + endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup2; + } + + endp->local_rtcp.cb = rtp_data_cb; + endp->local_rtcp.data = endp; + endp->local_rtcp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtcp) != 0) { + DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n", + endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup3; + } + + return 0; + +cleanup3: + bsc_unregister_fd(&endp->local_rtp); +cleanup2: + close(endp->local_rtcp.fd); + endp->local_rtcp.fd = -1; +cleanup1: + close(endp->local_rtp.fd); + endp->local_rtp.fd = -1; +cleanup0: + return -1; +} + +/* + * array of function pointers for handling various + * messages. In the future this might be binary sorted + * for performance reasons. + */ +static const struct mgcp_request mgcp_requests [] = { + MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint") + MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection") + MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection") + MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection") +}; + +static void send_response_with_data(int code, const char *msg, const char *trans, + const char *data, struct sockaddr_in *source) +{ + char buf[4096]; + int len; + + if (data) { + len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data); + } else { + len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans); + } + DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg); + + sendto(bfd.fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source)); +} + +static void send_response(int code, const char *msg, const char *trans, struct sockaddr_in *source) +{ + send_response_with_data(code, msg, trans, NULL, source); +} + +static void send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source) +{ + const char *addr = local_ip; + char sdp_record[4096]; + + if (!addr) + addr = source_addr; + + snprintf(sdp_record, sizeof(sdp_record) - 1, + "I: %d\n\n" + "v=0\r\n" + "c=IN IP4 %s\r\n" + "m=audio %d RTP/AVP %d\r\n" + "a=rtpmap:%d %s\r\n", + endp->ci, addr, endp->rtp_port, + audio_payload, audio_payload, audio_name); + return send_response_with_data(200, msg, trans_id, sdp_record, source); +} + +/* send a static record */ +static void send_rsip(struct sockaddr_in *source) +{ + char reset[4096]; + int len, rc; + + len = snprintf(reset, sizeof(reset) - 1, + "RSIP %u *@mgw MGCP 1.0\n" + "RM: restart\n", generate_transaction_id()); + rc = sendto(bfd.fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source)); + if (rc < 0) { + DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc); + } +} + +/* + * handle incoming messages: + * - this can be a command (four letters, space, transaction id) + * - or a response (three numbers, space, transaction id) + */ +static void handle_message(struct msgb *msg, struct sockaddr_in *source) +{ + int code; + + if (msg->len < 4) { + DEBUGP(DMGCP, "mgs too short: %d\n", msg->len); + return; + } + + /* attempt to treat it as a response */ + if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) { + DEBUGP(DMGCP, "Response: Code: %d\n", code); + } else { + int i, handled = 0; + msg->l3h = &msg->l2h[4]; + for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) + if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) { + handled = 1; + mgcp_requests[i].handle_request(msg, source); + } + if (!handled) { + DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]); + } + } +} + +/* string tokenizer for the poor */ +static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length) +{ + int i, found = 0; + + int whitespace = 1; + for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) { + /* if we have a space we found an end */ + if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { + if (!whitespace) { + ++found; + whitespace = 1; + ptrs->length = i - ptrs->start - 1; + ++ptrs; + --ptrs_length; + } else { + /* skip any number of whitespace */ + } + + /* line end... stop */ + if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') + break; + } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { + /* line end, be done */ + break; + } else if (whitespace) { + whitespace = 0; + ptrs->start = i; + } + } + + if (ptrs_length == 0) + return -1; + return found; +} + +static struct mgcp_endpoint *find_endpoint(const char *mgcp) +{ + char *endptr = NULL; + unsigned int gw = INT_MAX; + + gw = strtoul(mgcp, &endptr, 16); + if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) { + DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp); + return NULL; + } + + return &endpoints[gw]; +} + +static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, + const char **transaction_id, struct mgcp_endpoint **endp) +{ + int found; + + if (size < 3) { + DEBUGP(DMGCP, "Not enough space in ptr\n"); + return -1; + } + + found = find_msg_pointers(msg, ptr, size); + + if (found < 3) { + DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found); + return -1; + } + + /* + * replace the space with \0. the main method gurantess that + * we still have + 1 for null termination + */ + msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0'; + msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0'; + msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0'; + msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0'; + + if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0 + || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) { + DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n", + (const char *)&msg->l3h[ptr[3].start], + (const char *)&msg->l3h[ptr[2].start]); + return -1; + } + + *transaction_id = (const char *)&msg->l3h[ptr[0].start]; + *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]); + return *endp == NULL; +} + +static int verify_call_id(const struct mgcp_endpoint *endp, + const char *callid) +{ + if (strcmp(endp->callid, callid) != 0) { + DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n", + ENDPOINT_NUMBER(endp), endp->callid, callid); + return -1; + } + + return 0; +} + +static int verify_ci(const struct mgcp_endpoint *endp, + const char *ci) +{ + if (atoi(ci) != endp->ci) { + DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n", + ENDPOINT_NUMBER(endp), endp->ci, ci); + return -1; + } + + return 0; +} + +static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, response; + const char *trans_id; + struct mgcp_endpoint *endp; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + response = 500; + else + response = 200; + + return send_response(response, "AUEP", trans_id, source); +} + +static int parse_conn_mode(const char* msg, int *conn_mode) +{ + int ret = 0; + if (strcmp(msg, "recvonly") == 0) + *conn_mode = MGCP_CONN_RECV_ONLY; + else if (strcmp(msg, "sendrecv") == 0) + *conn_mode = MGCP_CONN_RECV_SEND; + else { + DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg); + ret = -1; + } + + return ret; +} + +static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(500, "CRCX", trans_id, source); + + if (endp->ci != CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(500, "CRCX", trans_id, source); + } + + /* parse CallID C: and LocalParameters L: */ + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'L': + endp->local_options = talloc_strdup(endpoints, + (const char *)&msg->l3h[line_start + 3]); + break; + case 'C': + endp->callid = talloc_strdup(endpoints, + (const char *)&msg->l3h[line_start + 3]); + break; + case 'M': + if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], + &endp->conn_mode) != 0) { + error_code = 517; + goto error2; + } + break; + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + + /* bind to the port now */ + endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); + if (!early_bind && bind_rtp(endp) != 0) + goto error2; + + /* assign a local call identifier or fail */ + endp->ci = generate_call_id(); + if (endp->ci == CI_UNUSED) + goto error2; + + DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n", + ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); + return send_with_sdp(endp, "CRCX", trans_id, source); +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i); + return send_response(error_code, "CRCX", trans_id, source); + +error2: + DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(error_code, "CRCX", trans_id, source); +} + +static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(error_code, "MDCX", trans_id, source); + + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(error_code, "MDCX", trans_id, source); + } + + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'C': { + if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'I': { + if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'L': + /* skip */ + break; + case 'M': + if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], + &endp->conn_mode) != 0) { + error_code = 517; + goto error3; + } + break; + case '\0': + /* SDP file begins */ + break; + case 'a': + case 'o': + case 's': + case 't': + case 'v': + /* skip these SDP attributes */ + break; + case 'm': { + int port; + const char *param = (const char *)&msg->l3h[line_start]; + + if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { + endp->rtp = htons(port); + endp->rtcp = htons(port + 1); + } + break; + } + case 'c': { + char ipv4[16]; + const char *param = (const char *)&msg->l3h[line_start]; + + if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) { + inet_aton(ipv4, &endp->remote); + } + break; + } + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + /* modify */ + DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", + ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->rtp); + return send_with_sdp(endp, "MDCX", trans_id, source); + +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); + return send_response(error_code, "MDCX", trans_id, source); + +error3: + return send_response(error_code, "MDCX", trans_id, source); +} + +static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(error_code, "DLCX", trans_id, source); + + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(error_code, "DLCX", trans_id, source); + } + + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'C': { + if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'I': { + if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + + /* free the connection */ + DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); + endp->ci= CI_UNUSED; + talloc_free(endp->callid); + talloc_free(endp->local_options); + + if (!early_bind) { + bsc_unregister_fd(&endp->local_rtp); + bsc_unregister_fd(&endp->local_rtcp); + } + + return send_response(250, "DLCX", trans_id, source); + +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i); + return send_response(error_code, "DLCX", trans_id, source); + +error3: + return send_response(error_code, "DLCX", trans_id, source); +} + +static void print_help() +{ + printf("Some useful help...\n"); + printf(" -h --help is printing this text.\n"); + printf(" -c --config-file filename The config file to use.\n"); +} + +static void handle_options(int argc, char** argv) +{ + while (1) { + int option_index = 0, c; + static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"config-file", 1, 0, 'c'}, + {0, 0, 0, 0}, + }; + + c = getopt_long(argc, argv, "hc:", long_options, &option_index); + + if (c == -1) + break; + + switch(c) { + case 'h': + print_help(); + exit(0); + break; + case 'c': + config_file = talloc_strdup(tall_bsc_ctx, optarg); + break; + default: + /* ignore */ + break; + }; + } +} + +static int read_call_agent(struct bsc_fd *fd, unsigned int what) +{ + struct sockaddr_in addr; + socklen_t slen = sizeof(addr); + struct msgb *msg; + + msg = (struct msgb *) fd->data; + + /* read one less so we can use it as a \0 */ + int rc = recvfrom(bfd.fd, msg->data, msg->data_len - 1, 0, + (struct sockaddr *) &addr, &slen); + if (rc < 0) { + perror("Gateway failed to read"); + return -1; + } else if (slen > sizeof(addr)) { + fprintf(stderr, "Gateway received message from outerspace: %d %d\n", + slen, sizeof(addr)); + return -1; + } + + if (first_request) { + first_request = 0; + send_rsip(&addr); + return 0; + } + + /* handle message now */ + msg->l2h = msgb_put(msg, rc); + handle_message(msg, &addr); + msgb_reset(msg); + return 0; +} + +/* + * vty code for mgcp below + */ +struct cmd_node mgcp_node = { + MGCP_NODE, + "%s(mgcp)#", + 1, +}; + +static int config_write_mgcp(struct vty *vty) +{ + vty_out(vty, "mgcp%s", VTY_NEWLINE); + if (local_ip) + vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); + vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); + vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); + vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); + vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp, + cfg_mgcp_cmd, + "mgcp", + "Configure the MGCP") +{ + vty->node = MGCP_NODE; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_local_ip, + cfg_mgcp_local_ip_cmd, + "local ip IP", + "Set the IP to be used in SDP records") +{ + local_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bts_ip, + cfg_mgcp_bts_ip_cmd, + "bts ip IP", + "Set the IP of the BTS for RTP forwarding") +{ + bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + inet_aton(bts_ip, &bts_in); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_ip, + cfg_mgcp_bind_ip_cmd, + "bind ip IP", + "Bind the MGCP to this local addr") +{ + source_addr = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_port, + cfg_mgcp_bind_port_cmd, + "bind port <0-65534>", + "Bind the MGCP to this port") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + source_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_early, + cfg_mgcp_bind_early_cmd, + "bind early (0|1)", + "Bind all RTP ports early") +{ + unsigned int bind = atoi(argv[0]); + if (bind != 0 && bind != 1) { + vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + early_bind = bind == 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_rtp_base_port, + cfg_mgcp_rtp_base_port_cmd, + "rtp base <0-65534>", + "Base port to use") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + rtp_base_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_number, + cfg_mgcp_sdp_payload_number_cmd, + "sdp audio payload number <1-255>", + "Set the audio codec to use") +{ + unsigned int payload = atoi(argv[0]); + if (payload > 255) { + vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + audio_payload = payload; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_name, + cfg_mgcp_sdp_payload_name_cmd, + "sdp audio payload name NAME", + "Set the audio name to use") +{ + audio_name = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +static void mgcp_vty_init() +{ + cmd_init(1); + vty_init(); + + install_element(CONFIG_NODE, &cfg_mgcp_cmd); + install_node(&mgcp_node, config_write_mgcp); + install_default(MGCP_NODE); + install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); +} + +int main(int argc, char** argv) +{ + struct sockaddr_in addr; + int on = 1, i, rc; + + tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent"); + handle_options(argc, argv); + + mgcp_vty_init(); + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + + if (!bts_ip) { + fprintf(stderr, "Need to specify the BTS ip address for RTP handling.\n"); + return -1; + } + + endpoints = _talloc_zero_array(tall_bsc_ctx, + sizeof(struct mgcp_endpoint), + number_endpoints, "endpoints"); + if (!endpoints) { + fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints); + return -1; + } + + /* Initialize all endpoints */ + for (i = 0; i < number_endpoints; ++i) { + endpoints[i].local_rtp.fd = -1; + endpoints[i].local_rtcp.fd = -1; + endpoints[i].ci = CI_UNUSED; + } + + /* initialize the socket */ + bfd.when = BSC_FD_READ; + bfd.cb = read_call_agent; + bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); + if (bfd.fd < 0) { + perror("Gateway failed to listen"); + return -1; + } + + setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(source_port); + inet_aton(source_addr, &addr.sin_addr); + + if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("Gateway failed to bind"); + return -1; + } + + bfd.data = msgb_alloc(4096, "mgcp-msg"); + if (!bfd.data) { + fprintf(stderr, "Gateway memory error.\n"); + return -1; + } + + + if (bsc_register_fd(&bfd) != 0) { + DEBUGP(DMGCP, "Failed to register the fd\n"); + return -1; + } + + /* initialisation */ + srand(time(NULL)); + + /* early bind */ + if (early_bind) { + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); + if (bind_rtp(endp) != 0) + return -1; + } + } + + /* main loop */ + while (1) { + bsc_select_main(0); + } + + + return 0; +} diff --git a/openbsc/src/mgcp.cfg b/openbsc/src/mgcp.cfg new file mode 100644 index 000000000..c4da05162 --- /dev/null +++ b/openbsc/src/mgcp.cfg @@ -0,0 +1,17 @@ +! +! MGCP configuration hand edited +! ! +password foo +! +line vty + no login +! +mgcp + local ip 172.23.23.23 + bts ip 192.168.100.100 + bind ip 0.0.0.0 + bind port 2427 + bind early 1 + rtp base 4000 + sdp audio payload number 97 + sdp audio payload name GSM-EFR/8000 From 138b7ecd5e695f2d00d6fe49756bd1d85e6a5a96 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 18 Nov 2009 18:32:31 +0100 Subject: [PATCH 002/365] [mgcp] Add option to route audio back to both ends This is a simple echo functionality in the MGCP... it will send the audio back to the network|bts.. --- openbsc/src/bsc_mgcp.c | 59 ++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 8b59b31cb..c7db3bf3d 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -61,6 +61,7 @@ static struct in_addr bts_in; static int first_request = 1; static const char *audio_name = "GSM-EFR/8000"; static int audio_payload = 97; +static int audio_loop = 0; static int early_bind = 0; static char *config_file = "mgcp.cfg"; @@ -75,6 +76,16 @@ enum mgcp_connection_mode { MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, }; +enum { + DEST_NETWORK = 0, + DEST_BTS = 1, +}; + +enum { + PROTO_RTP, + PROTO_RTCP, +}; + #define CI_UNUSED 0 static unsigned int last_call_id = 0; @@ -211,7 +222,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) struct sockaddr_in addr; socklen_t slen = sizeof(addr); struct mgcp_endpoint *endp; - int rc, is_remote; + int rc, dest, proto; endp = (struct mgcp_endpoint *) fd->data; @@ -231,22 +242,12 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) * able to tell if this is legitimate. */ #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." - is_remote = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0; - if (is_remote) { - if (endp->rtp == addr.sin_port) { - return _send(fd->fd, &bts_in, endp->bts_rtp, buf, rc); - } else if (endp->rtcp == addr.sin_port) { - return _send(fd->fd, &bts_in, endp->bts_rtcp, buf, rc); - } else { - DEBUGP(DMGCP, "Unknown remote port. Not able to forward on 0x%x port: %d\n", - ENDPOINT_NUMBER(endp), ntohs(addr.sin_port)); - } - - return -1; - } + dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 + ? DEST_BTS : DEST_NETWORK; + proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; /* We have no idea who called us, maybe it is the BTS. */ - if (endp->bts_rtp == 0) { + if (dest == DEST_NETWORK && endp->bts_rtp == 0) { /* it was the BTS... */ if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { if (fd == &endp->local_rtp) { @@ -262,16 +263,18 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) } } - if (endp->bts_rtp == 0 || endp->conn_mode == MGCP_CONN_RECV_ONLY) { - DEBUGP(DMGCP, "Not forwarding data from possible BTS conn: %d on 0x%x\n", - endp->conn_mode, ENDPOINT_NUMBER(endp)); - return -1; - } + /* dispatch */ + if (audio_loop) + dest = !dest; - if (fd == &endp->local_rtp) { - return _send(fd->fd, &endp->remote, endp->rtp, buf, rc); + if (dest == DEST_NETWORK) { + return _send(fd->fd, &endp->remote, + proto == PROTO_RTP ? endp->rtp : endp->rtcp, + buf, rc); } else { - return _send(fd->fd, &endp->remote, endp->rtcp, buf, rc); + return _send(fd->fd, &bts_in, + proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, + buf, rc); } } @@ -1007,6 +1010,15 @@ DEFUN(cfg_mgcp_sdp_payload_name, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_loop, + cfg_mgcp_loop_cmd, + "loop (0|1)", + "Loop the audio") +{ + audio_loop = atoi(argv[0]); + return CMD_SUCCESS; +} + static void mgcp_vty_init() { cmd_init(1); @@ -1023,6 +1035,7 @@ static void mgcp_vty_init() install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); + install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); } int main(int argc, char** argv) From 1cf9cf3eebdd0fce1d81feae3bb12f7f03932b0b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 11:45:43 +0100 Subject: [PATCH 003/365] [mgcp] MGCP... update config file to use AMR --- openbsc/src/mgcp.cfg | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openbsc/src/mgcp.cfg b/openbsc/src/mgcp.cfg index c4da05162..d9950ab95 100644 --- a/openbsc/src/mgcp.cfg +++ b/openbsc/src/mgcp.cfg @@ -7,11 +7,12 @@ line vty no login ! mgcp - local ip 172.23.23.23 - bts ip 192.168.100.100 - bind ip 0.0.0.0 +! local ip 213.167.134.14 + bts ip 172.16.252.43 + bind ip 213.167.134.141 bind port 2427 bind early 1 rtp base 4000 - sdp audio payload number 97 - sdp audio payload name GSM-EFR/8000 + sdp audio payload number 98 + sdp audio payload name AMR/8000 + loop 1 From 338fa562c0a8be518182d62e22de89a3e429fdb4 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 15:03:39 +0100 Subject: [PATCH 004/365] [mgcp] Add telnet interface for mgcp. --- openbsc/src/Makefile.am | 2 +- openbsc/src/bsc_mgcp.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 7651132b6..d28c80354 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -34,5 +34,5 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c -bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c +bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index c7db3bf3d..df9564140 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -38,13 +38,13 @@ #include #include #include +#include #include #include /* this is here for the vty... it will never be called */ void subscr_put() { abort(); } -void vty_event() { } #define _GNU_SOURCE #include @@ -1019,7 +1019,7 @@ DEFUN(cfg_mgcp_loop, return CMD_SUCCESS; } -static void mgcp_vty_init() +int bsc_vty_init(struct gsm_network *dummy) { cmd_init(1); vty_init(); @@ -1036,17 +1036,19 @@ static void mgcp_vty_init() install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); + return 0; } int main(int argc, char** argv) { + struct gsm_network dummy_network; struct sockaddr_in addr; int on = 1, i, rc; tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent"); handle_options(argc, argv); - mgcp_vty_init(); + telnet_init(&dummy_network, 4243); rc = vty_read_config_file(config_file); if (rc < 0) { fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); From 5fddf475d522e73462472dadc9068aad698907ab Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 15:08:02 +0100 Subject: [PATCH 005/365] [mgcp] Fix writing the configuration file --- openbsc/src/bsc_mgcp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index df9564140..4820465f7 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -899,7 +899,11 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); + vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE); vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE); + vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE); + vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); + vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); return CMD_SUCCESS; } From 17e791666d527f83ad80b346ad58ecc39a913054 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 15:20:48 +0100 Subject: [PATCH 006/365] [mgcp] Add a show command for the mgcp... --- openbsc/src/bsc_mgcp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 4820465f7..4ebf6c84e 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -908,6 +908,23 @@ static int config_write_mgcp(struct vty *vty) return CMD_SUCCESS; } +DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", + SHOW_STR "Display information about the MGCP Media Gateway") +{ + int i; + + vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE); + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", + i, endp->ci, + ntohs(endp->rtp), ntohs(endp->rtcp), + ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + DEFUN(cfg_mgcp, cfg_mgcp_cmd, "mgcp", @@ -1028,6 +1045,9 @@ int bsc_vty_init(struct gsm_network *dummy) cmd_init(1); vty_init(); + install_element(VIEW_NODE, &show_mgcp_cmd); + + install_element(CONFIG_NODE, &cfg_mgcp_cmd); install_node(&mgcp_node, config_write_mgcp); install_default(MGCP_NODE); From 48ecad48c7e79d3cc233d337db6950c9e5acbc16 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:04:10 +0100 Subject: [PATCH 007/365] [mgcp] Do not forward or find the BTS if the endpoint is unused Forget where the bts and network is located on DLCX and CRCX otherwise we would have forwarded BTS data to the wrong endpoint and would have not tried to discover the BTS again. In the case of early bind we might get data from the BTS before the CRCX and after DLCX... just ignore it then --- openbsc/src/bsc_mgcp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 4ebf6c84e..bb27d5634 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -234,6 +234,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) return -1; } + /* do not forward aynthing... maybe there is a packet from the bts */ + if (endp->ci == CI_UNUSED) + return -1; + /* * Figure out where to forward it to. This code assumes that we * have received the Connection Modify and know who is a legitimate @@ -635,6 +639,8 @@ static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) } MSG_TOKENIZE_END + /* initialize */ + endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; /* bind to the port now */ endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); @@ -800,6 +806,8 @@ static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source) bsc_unregister_fd(&endp->local_rtcp); } + endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + return send_response(250, "DLCX", trans_id, source); error: From 39e94ebbd2d70c47e1491e598a2f44b7670d45b2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:25:14 +0100 Subject: [PATCH 008/365] [mgcp] The initialisation is done inside CRCX, remove here --- openbsc/src/bsc_mgcp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index bb27d5634..d0af8c61e 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -307,8 +307,6 @@ static int bind_rtp(struct mgcp_endpoint *endp) { /* set to zero until we get the info */ memset(&endp->remote, 0, sizeof(endp->remote)); - endp->bts_rtp = endp->bts_rtcp = 0; - endp->rtp = endp->rtcp = 0; if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", From 8ea4b5688a65e2e3cd8cd2529e40721f435dd18a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:25:53 +0100 Subject: [PATCH 009/365] [mgcp] The nanoBTS is not binding a RTCP port Do not guess the RTCP port as it might be the RTP port of another connection. --- openbsc/src/bsc_mgcp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index d0af8c61e..d4007a0ec 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -256,14 +256,12 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { if (fd == &endp->local_rtp) { endp->bts_rtp = addr.sin_port; - endp->bts_rtcp = htons(ntohs(addr.sin_port) + 1); } else { - endp->bts_rtp = htons(ntohs(addr.sin_port) - 1); endp->bts_rtcp = addr.sin_port; } - DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d\n", - ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp)); + DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", + ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); } } From 4ec389e58f139fda2a540789f54ac38185dd1584 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 20 Nov 2009 11:10:31 +0100 Subject: [PATCH 010/365] [mgcp] Make the number of endpoints configurable... Allow to configure the number of endpoints at start. Currently this will not be changed at runtime but one needs to save the config and restart the system. --- openbsc/src/bsc_mgcp.c | 14 +++++++++++++- openbsc/src/mgcp.cfg | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index d4007a0ec..6d5e6b154 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -55,7 +55,7 @@ static int source_port = 2427; static const char *local_ip = NULL; static const char *source_addr = "0.0.0.0"; static struct bsc_fd bfd; -static const unsigned int number_endpoints = 32 + 1; +static unsigned int number_endpoints = 0; static const char *bts_ip = NULL; static struct in_addr bts_in; static int first_request = 1; @@ -908,6 +908,7 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE); vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); + vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); return CMD_SUCCESS; } @@ -1044,6 +1045,16 @@ DEFUN(cfg_mgcp_loop, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_number_endp, + cfg_mgcp_number_endp_cmd, + "number endpoints <0-65534>", + "The number of endpoints to allocate. This is not dynamic.") +{ + /* + 1 as we start counting at one */ + number_endpoints = atoi(argv[0]) + 1; + return CMD_SUCCESS; +} + int bsc_vty_init(struct gsm_network *dummy) { cmd_init(1); @@ -1064,6 +1075,7 @@ int bsc_vty_init(struct gsm_network *dummy) install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); + install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); return 0; } diff --git a/openbsc/src/mgcp.cfg b/openbsc/src/mgcp.cfg index d9950ab95..678f54637 100644 --- a/openbsc/src/mgcp.cfg +++ b/openbsc/src/mgcp.cfg @@ -15,4 +15,5 @@ mgcp rtp base 4000 sdp audio payload number 98 sdp audio payload name AMR/8000 + number endpoints 31 loop 1 From adb8bcea5f0a5f34b5742df124b2a9de1cba602a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 19 Aug 2009 06:31:59 +0200 Subject: [PATCH 011/365] [contrib] Add a utility to convert an IE page to an enum This script is parsing the values, converting the bits into a number and replacing the text... This should help to go from spec to code more quickly... next thing would be this for the structs used... --- openbsc/contrib/convert_to_enum.py | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100755 openbsc/contrib/convert_to_enum.py diff --git a/openbsc/contrib/convert_to_enum.py b/openbsc/contrib/convert_to_enum.py new file mode 100755 index 000000000..bcd6f2cee --- /dev/null +++ b/openbsc/contrib/convert_to_enum.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# +# Convert ETSI documents to an enum +# + +import re, sys + +def convert(string): + string = string.strip().replace(" ", "").rjust(8, "0") + var = 0 + offset = 7 + for char in string: + assert offset >= 0 + var = var | (int(char) << offset) + offset = offset - 1 + + return var + +def string(name): + name = name.replace(" ", "_") + name = name.replace('"', "") + name = name.replace('/', '_') + name = name.replace('(', '_') + name = name.replace(')', '_') + return "%s_%s" % (sys.argv[2], name.upper()) + +file = open(sys.argv[1]) + + +for line in file: + m = re.match(r"[ \t]*(?P[01 ]+)[ ]+(?P[a-zA-Z /0-9()]+)", line[:-1]) + + if m: + print "\t%s\t\t= %d," % (string(m.groupdict()["name"]), convert(m.groupdict()["value"])) + else: + print line[:-1] From 7466351026f09364aa9b92ae921e564519bb115e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 20 Nov 2009 17:57:58 +0100 Subject: [PATCH 012/365] [misc] Fix the make distcheck Mention the two new header files, do not list isdnsync twice --- openbsc/include/openbsc/Makefile.am | 3 ++- openbsc/src/Makefile.am | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 461f5a89e..8bb64eb91 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -3,4 +3,5 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ timer.h misdn.h chan_alloc.h telnet_interface.h paging.h \ subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ - bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h + bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ + silent_call.h mgcp.h diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index d28c80354..9c8fa7b4d 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync \ +sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ isdnsync bsc_mgcp noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h From a8816dd9c76627ea2f99f7405e4f44b008f1401a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 19:41:06 +0100 Subject: [PATCH 013/365] [talloc] Provide a copy of strnlen on OSX The implementation is taken from a blogspot and I don't think it is copyrightable... --- openbsc/src/talloc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openbsc/src/talloc.c b/openbsc/src/talloc.c index bd5e1b0e0..d8213238e 100644 --- a/openbsc/src/talloc.c +++ b/openbsc/src/talloc.c @@ -105,6 +105,15 @@ #endif #endif +#ifdef __APPLE__ +/* taken from http://insanecoding.blogspot.com/2007/03/methods-for-safe-string-handling.html */ +size_t strnlen(const char *s, size_t n) +{ + const char *p = (const char *)memchr(s, 0, n); + return(p ? p-s : n); +} +#endif + /* this null_context is only used if talloc_enable_leak_report() or talloc_enable_leak_report_full() is called, otherwise it remains NULL From d61654cf544e5aa1bec50724589bb76d31471709 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 20:20:43 +0100 Subject: [PATCH 014/365] [chan] Alloc SDCCH for certain reserved types Follow notes: 2.) Allocate a SDCCH for type "LMU" 2a.)Allocate a SDCCH for the three reserved types 2b.)Pick LCHAN type none to "ignore" the request --- openbsc/include/openbsc/gsm_04_08.h | 3 +++ openbsc/src/gsm_04_08_utils.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 40a76549e..b7c8a2662 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -656,6 +656,9 @@ enum chreq_type { CHREQ_T_PAG_R_ANY_NECI1, CHREQ_T_PAG_R_TCH_F, CHREQ_T_PAG_R_TCH_FH, + CHREQ_T_LMU, + CHREQ_T_RESERVED_SDCCH, + CHREQ_T_RESERVED_IGNORE, }; /* Chapter 11.3 */ diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index b2fbdc2c3..ad038fba6 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -258,6 +258,11 @@ static const struct chreq chreq_type_neci1[] = { { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI1 }, { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, + { 0x67, 0xff, CHREQ_T_LMU }, + { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH }, + { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH }, + { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH }, + { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE }, }; /* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */ @@ -270,6 +275,11 @@ static const struct chreq chreq_type_neci0[] = { { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI0 }, { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, + { 0x67, 0xff, CHREQ_T_LMU }, + { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH }, + { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH }, + { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH }, + { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE }, }; static const enum gsm_chan_t ctype_by_chreq[] = { @@ -286,6 +296,9 @@ static const enum gsm_chan_t ctype_by_chreq[] = { [CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH, [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F, [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F, + [CHREQ_T_LMU] = GSM_LCHAN_SDCCH, + [CHREQ_T_RESERVED_SDCCH] = GSM_LCHAN_SDCCH, + [CHREQ_T_RESERVED_IGNORE] = GSM_LCHAN_UNKNOWN, }; static const enum gsm_chreq_reason_t reason_by_chreq[] = { @@ -302,6 +315,9 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = { [CHREQ_T_PAG_R_ANY_NECI0] = GSM_CHREQ_REASON_PAG, [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG, [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG, + [CHREQ_T_LMU] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_RESERVED_SDCCH] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_RESERVED_IGNORE] = GSM_CHREQ_REASON_OTHER, }; enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) From c4d88ad9718a6cd4bd4bdfd57251bdd325d4db2f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 21:18:38 +0100 Subject: [PATCH 015/365] [network] Make T3101 configurable and use it in abis_rsl --- openbsc/include/openbsc/gsm_data.h | 3 +++ openbsc/src/abis_rsl.c | 2 +- openbsc/src/openbsc.cfg.1-1 | 1 + openbsc/src/openbsc.cfg.1-2 | 1 + openbsc/src/openbsc.cfg.2-2 | 1 + openbsc/src/openbsc.cfg.nanobts | 1 + openbsc/src/vty_interface.c | 23 +++++++++++++++++++++++ 7 files changed, 31 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 0ac8674fd..0c400fdde 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -422,6 +422,9 @@ struct gsm_network { unsigned int num_bts; struct llist_head bts_list; + + /* timer values */ + int T3101; }; #define SMS_HDR_SIZE 128 diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 0dee79b17..692536c50 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1186,7 +1186,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */ lchan->T3101.cb = t3101_expired; lchan->T3101.data = lchan; - bsc_schedule_timer(&lchan->T3101, 10, 0); + bsc_schedule_timer(&lchan->T3101, bts->network->T3101, 0); /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */ ret = rsl_imm_assign_cmd(bts, sizeof(ia), (u_int8_t *) &ia); diff --git a/openbsc/src/openbsc.cfg.1-1 b/openbsc/src/openbsc.cfg.1-1 index a8331ddbd..bad6df72d 100644 --- a/openbsc/src/openbsc.cfg.1-1 +++ b/openbsc/src/openbsc.cfg.1-1 @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.1-2 b/openbsc/src/openbsc.cfg.1-2 index 10aa7b48b..b4c956d16 100644 --- a/openbsc/src/openbsc.cfg.1-2 +++ b/openbsc/src/openbsc.cfg.1-2 @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.2-2 b/openbsc/src/openbsc.cfg.2-2 index 0dd9d9b5d..e123a448b 100644 --- a/openbsc/src/openbsc.cfg.2-2 +++ b/openbsc/src/openbsc.cfg.2-2 @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts index a12794ffd..7f9846803 100644 --- a/openbsc/src/openbsc.cfg.nanobts +++ b/openbsc/src/openbsc.cfg.nanobts @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type nanobts ip.access unit_id 1801 0 diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 5712ca1c7..e6513513b 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -275,6 +275,7 @@ static int config_write_net(struct vty *vty) vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); + vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); return CMD_SUCCESS; } @@ -801,6 +802,27 @@ DEFUN(cfg_net_neci, return CMD_SUCCESS; } +#define DECLARE_TIMER(number) \ + DEFUN(cfg_net_T##number, \ + cfg_net_T##number##_cmd, \ + "timer t" #number " <0-65535>", \ + "Set the T" #number " value.") \ +{ \ + int value = atoi(argv[0]); \ + \ + if (value < 0 || value > 65535) { \ + vty_out(vty, "Timer value %s out of range.%s", \ + argv[0], VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ + \ + gsmnet->T##number = value; \ + return CMD_SUCCESS; \ +} + +DECLARE_TIMER(3101) + + /* per-BTS configuration */ DEFUN(cfg_bts, cfg_bts_cmd, @@ -1241,6 +1263,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); + install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd); install_node(&bts_node, config_write_bts); From 23975e718fd456ff8be7effbb915903f1bc173be Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 21:42:26 +0100 Subject: [PATCH 016/365] [network] Add config option for the remaining network timers There are all set to 0 and not used within the code yet but should be used in the future. --- openbsc/include/openbsc/gsm_data.h | 10 ++++++++++ openbsc/src/vty_interface.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 0c400fdde..18e115c1e 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -425,6 +425,16 @@ struct gsm_network { /* timer values */ int T3101; + int T3103; + int T3105; + int T3107; + int T3109; + int T3111; + int T3113; + int T3115; + int T3117; + int T3119; + int T3141; }; #define SMS_HDR_SIZE 128 diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index e6513513b..f8bba2c44 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -276,6 +276,16 @@ static int config_write_net(struct vty *vty) vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); + vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); + vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); + vty_out(vty, " timer t3107 %u%s", gsmnet->T3107, VTY_NEWLINE); + vty_out(vty, " timer t3109 %u%s", gsmnet->T3109, VTY_NEWLINE); + vty_out(vty, " timer t3111 %u%s", gsmnet->T3111, VTY_NEWLINE); + vty_out(vty, " timer t3113 %u%s", gsmnet->T3113, VTY_NEWLINE); + vty_out(vty, " timer t3115 %u%s", gsmnet->T3115, VTY_NEWLINE); + vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE); + vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE); + vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE); return CMD_SUCCESS; } @@ -821,6 +831,16 @@ DEFUN(cfg_net_neci, } DECLARE_TIMER(3101) +DECLARE_TIMER(3103) +DECLARE_TIMER(3105) +DECLARE_TIMER(3107) +DECLARE_TIMER(3109) +DECLARE_TIMER(3111) +DECLARE_TIMER(3113) +DECLARE_TIMER(3115) +DECLARE_TIMER(3117) +DECLARE_TIMER(3119) +DECLARE_TIMER(3141) /* per-BTS configuration */ @@ -1264,6 +1284,16 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); + install_element(GSMNET_NODE, &cfg_net_T3103_cmd); + install_element(GSMNET_NODE, &cfg_net_T3105_cmd); + install_element(GSMNET_NODE, &cfg_net_T3107_cmd); + install_element(GSMNET_NODE, &cfg_net_T3109_cmd); + install_element(GSMNET_NODE, &cfg_net_T3111_cmd); + install_element(GSMNET_NODE, &cfg_net_T3113_cmd); + install_element(GSMNET_NODE, &cfg_net_T3115_cmd); + install_element(GSMNET_NODE, &cfg_net_T3117_cmd); + install_element(GSMNET_NODE, &cfg_net_T3119_cmd); + install_element(GSMNET_NODE, &cfg_net_T3141_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd); install_node(&bts_node, config_write_bts); From 4642d4917f0ced8ddf47d7f58a7d9e2ae2d23d24 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 21:48:53 +0100 Subject: [PATCH 017/365] [network] Make use of T3113 for paging Add it to the configuration files and make use of it in the the paging.c. --- openbsc/include/openbsc/gsm_data.h | 1 - openbsc/src/openbsc.cfg.1-1 | 1 + openbsc/src/openbsc.cfg.1-2 | 1 + openbsc/src/openbsc.cfg.2-2 | 1 + openbsc/src/openbsc.cfg.nanobts | 1 + openbsc/src/paging.c | 2 +- 6 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 18e115c1e..86a872b86 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -286,7 +286,6 @@ struct gsm_paging_request { gsm_cbfn *cbfn; void *cbfn_param; }; -#define T3113_VALUE 60, 0 /* * This keeps track of the paging status of one BTS. It diff --git a/openbsc/src/openbsc.cfg.1-1 b/openbsc/src/openbsc.cfg.1-1 index bad6df72d..d312843b0 100644 --- a/openbsc/src/openbsc.cfg.1-1 +++ b/openbsc/src/openbsc.cfg.1-1 @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.1-2 b/openbsc/src/openbsc.cfg.1-2 index b4c956d16..84d50c75c 100644 --- a/openbsc/src/openbsc.cfg.1-2 +++ b/openbsc/src/openbsc.cfg.1-2 @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.2-2 b/openbsc/src/openbsc.cfg.2-2 index e123a448b..c1468a647 100644 --- a/openbsc/src/openbsc.cfg.2-2 +++ b/openbsc/src/openbsc.cfg.2-2 @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts index 7f9846803..a1ceaec79 100644 --- a/openbsc/src/openbsc.cfg.nanobts +++ b/openbsc/src/openbsc.cfg.nanobts @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type nanobts ip.access unit_id 1801 0 diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 69902e8b1..fe6ea52d1 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -239,7 +239,7 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr, req->cbfn_param = data; req->T3113.cb = paging_T3113_expired; req->T3113.data = req; - bsc_schedule_timer(&req->T3113, T3113_VALUE); + bsc_schedule_timer(&req->T3113, bts->network->T3113, 0); llist_add_tail(&req->entry, &bts_entry->pending_requests); if (!bsc_timer_pending(&bts_entry->work_timer)) From fdd0ddf7e9eb6a8a7de8021678287b3d1677a070 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 22 Nov 2009 18:01:42 +0100 Subject: [PATCH 018/365] [sms] Fix compile warning by including gsm_data.h In file included from sms_test.c:27: ../../include/openbsc/gsm_utils.h:33: warning: `enum gsm_band' declared inside parameter list ../../include/openbsc/gsm_utils.h:33: warning: its scope is only this definition or declaration, which is probably not what you want ../../include/openbsc/gsm_utils.h:34: warning: `enum gsm_band' declared inside parameter list --- openbsc/tests/sms/sms_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/tests/sms/sms_test.c b/openbsc/tests/sms/sms_test.c index fa0963644..2ce2cc6c4 100644 --- a/openbsc/tests/sms/sms_test.c +++ b/openbsc/tests/sms/sms_test.c @@ -24,6 +24,7 @@ #include #include #include +#include #include int main(int argc, char** argv) From 1ce10f3854ae110f6eb73383f44de3191934804b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 19:18:29 +0100 Subject: [PATCH 019/365] [bsc_init] Activate the RC and the RSL link from the Software Activated Callback On cold start the RSL link will not be brought up. Wait for the Software to be Activated before starting the RSL link. This is working reliable on the BTS I have tested with. This is a partial revert of 8406ec2437fcc28906b2085e305d79ae73accc2a and was discussed on the mailinglist. --- openbsc/src/bsc_init.c | 49 +++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index d11cde578..66d560601 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -391,38 +391,11 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, break; case NM_OC_RADIO_CARRIER: trx = obj; - if (new_state->operational == 1 && - new_state->availability == NM_AVSTATE_OFF_LINE) { - /* Patch ARFCN into radio attribute */ - nanobts_attr_radio[5] &= 0xf0; - nanobts_attr_radio[5] |= trx->arfcn >> 8; - nanobts_attr_radio[6] = trx->arfcn & 0xff; - abis_nm_set_radio_attr(trx, nanobts_attr_radio, - sizeof(nanobts_attr_radio)); - abis_nm_chg_adm_state(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, - trx->nr, 0xff); - } if (new_state->operational == 1 && new_state->availability == NM_AVSTATE_OK) abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, trx->nr, 0xff); break; - case NM_OC_BASEB_TRANSC: - trx = container_of(obj, struct gsm_bts_trx, bb_transc); - if (new_state->operational == 1 && - new_state->availability == NM_AVSTATE_DEPENDENCY) { - abis_nm_chg_adm_state(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - abis_nm_opstart(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, 0xff); - /* TRX software is active, tell it to initiate RSL Link */ - abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); - } - break; default: break; } @@ -438,6 +411,28 @@ static int sw_activ_rep(struct msgb *mb) switch (foh->obj_class) { + case NM_OC_BASEB_TRANSC: + abis_nm_chg_adm_state(trx->bts, foh->obj_class, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + abis_nm_opstart(trx->bts, foh->obj_class, + trx->bts->bts_nr, trx->nr, 0xff); + /* TRX software is active, tell it to initiate RSL Link */ + abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); + break; + case NM_OC_RADIO_CARRIER: + /* Patch ARFCN into radio attribute */ + nanobts_attr_radio[5] &= 0xf0; + nanobts_attr_radio[5] |= trx->arfcn >> 8; + nanobts_attr_radio[6] = trx->arfcn & 0xff; + abis_nm_set_radio_attr(trx, nanobts_attr_radio, + sizeof(nanobts_attr_radio)); + abis_nm_chg_adm_state(trx->bts, foh->obj_class, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + abis_nm_opstart(trx->bts, foh->obj_class, trx->bts->bts_nr, + trx->nr, 0xff); + break; } return 0; } From 2d501ea26a219176b1c556449e45ebd90d4accfb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 11 Nov 2009 11:54:24 +0100 Subject: [PATCH 020/365] [vty] Add option to disable RF on a given TRX. - Make sure that on runtime the Radio Carrier can be locked and unlocked. The vty code calls into the Abis NM to lock/unlock the channel and the state is stored there. - Make sure that on start the Radio Carries remains offline and we are not starting it. On start the radio carrier is either locked or unlocked. This means the RSL will not connect until the RF is unlocked. It will connect then. To see RSL bringup failures one needs to parse the RSL nack message. - When the TRX is locked on startup the RSL link will only be established after it will be unlocked. --- openbsc/include/openbsc/gsm_data.h | 5 +++++ openbsc/src/abis_nm.c | 13 +++++++++++++ openbsc/src/bsc_init.c | 16 ++++++++++++++-- openbsc/src/gsm_data.c | 1 + openbsc/src/vty_interface.c | 12 ++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 86a872b86..638b03506 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -257,6 +257,9 @@ struct gsm_bts_trx { } bs11; }; struct gsm_bts_trx_ts ts[TRX_NR_TS]; + + /* NM state */ + int rf_locked; }; enum gsm_bts_type { @@ -518,4 +521,6 @@ static inline int is_siemens_bts(struct gsm_bts *bts) enum gsm_auth_policy gsm_auth_policy_parse(const char *arg); const char *gsm_auth_policy_name(enum gsm_auth_policy policy); +void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); + #endif diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 4d4cec0a3..b1fe97ddf 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2699,6 +2699,19 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, attr, attr_len); } +void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked) +{ + int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; + + trx->rf_locked = locked; + if (!trx->bts || !trx->bts->oml_link) + return; + + abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER, + trx->bts->bts_nr, trx->nr, 0xff, + new_state); +} + static const char *ipacc_testres_names[] = { [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS", [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT", diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 66d560601..153e024e4 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -420,7 +420,18 @@ static int sw_activ_rep(struct msgb *mb) /* TRX software is active, tell it to initiate RSL Link */ abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); break; - case NM_OC_RADIO_CARRIER: + case NM_OC_RADIO_CARRIER: { + /* + * Locking the radio carrier will make it go + * offline again and we would come here. The + * framework should determine that there was + * no change and avoid recursion. + * + * This code is here to make sure that on start + * a TRX remains locked. + */ + int rc_state = trx->rf_locked ? + NM_STATE_LOCKED : NM_STATE_UNLOCKED; /* Patch ARFCN into radio attribute */ nanobts_attr_radio[5] &= 0xf0; nanobts_attr_radio[5] |= trx->arfcn >> 8; @@ -429,10 +440,11 @@ static int sw_activ_rep(struct msgb *mb) sizeof(nanobts_attr_radio)); abis_nm_chg_adm_state(trx->bts, foh->obj_class, trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); + rc_state); abis_nm_opstart(trx->bts, foh->obj_class, trx->bts->bts_nr, trx->nr, 0xff); break; + } } return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 69a9096ca..8212346ec 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -27,6 +27,7 @@ #include #include +#include void *tall_bsc_ctx; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index f8bba2c44..066dfd5a9 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1200,6 +1200,17 @@ DEFUN(cfg_trx_rsl_e1_tei, return CMD_SUCCESS; } +DEFUN(cfg_trx_rf_locked, + cfg_trx_rf_locked_cmd, + "rf_locked (0|1)", + "Turn off RF of the TRX.\n") +{ + int locked = atoi(argv[0]); + struct gsm_bts_trx *trx = vty->index; + + gsm_trx_lock_rf(trx, locked); + return CMD_SUCCESS; +} /* per TS configuration */ DEFUN(cfg_ts, @@ -1321,6 +1332,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(TRX_NODE, &cfg_trx_max_power_red_cmd); install_element(TRX_NODE, &cfg_trx_rsl_e1_cmd); install_element(TRX_NODE, &cfg_trx_rsl_e1_tei_cmd); + install_element(TRX_NODE, &cfg_trx_rf_locked_cmd); install_element(TRX_NODE, &cfg_ts_cmd); install_node(&ts_node, dummy_config_write); From f326267fb7c146a73d93a50e670ea95a2c47f0c1 Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Thu, 26 Nov 2009 12:28:41 +0100 Subject: [PATCH 021/365] [SMS] Implement TP-VPF-ENHANCED While doing so, we also restructure/reorganize the vailidity period parsing in general. --- openbsc/src/gsm_04_11.c | 249 +++++++++++++++++++++++++--------------- 1 file changed, 156 insertions(+), 93 deletions(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 75ddf9dd9..8e3c64974 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -198,48 +198,172 @@ static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans, return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA); } -static time_t gsm340_scts(u_int8_t *scts); +/* Turn int into semi-octet representation: 98 => 0x89 */ +static u_int8_t bcdify(u_int8_t value) +{ + u_int8_t ret; -static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) + ret = value / 10; + ret |= (value % 10) << 4; + + return ret; +} + +/* Turn semi-octet representation into int: 0x89 => 98 */ +static u_int8_t unbcdify(u_int8_t value) +{ + u_int8_t ret; + + if ((value & 0x0F) > 9 || (value >> 4) > 9) + DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); + + ret = (value&0x0F)*10; + if (ret > 90) + ret += value>>4; + + return ret; +} + +/* Generate 03.40 TP-SCTS */ +static void gsm340_gen_scts(u_int8_t *scts, time_t time) +{ + struct tm *tm = localtime(&time); + + *scts++ = bcdify(tm->tm_year % 100); + *scts++ = bcdify(tm->tm_mon + 1); + *scts++ = bcdify(tm->tm_mday); + *scts++ = bcdify(tm->tm_hour); + *scts++ = bcdify(tm->tm_min); + *scts++ = bcdify(tm->tm_sec); + *scts++ = bcdify(tm->tm_gmtoff/(60*15)); +} + +/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ +static time_t gsm340_scts(u_int8_t *scts) +{ + struct tm tm; + + u_int8_t yr = unbcdify(*scts++); + + if (yr <= 80) + tm.tm_year = 100 + yr; + else + tm.tm_year = yr; + tm.tm_mon = unbcdify(*scts++) - 1; + tm.tm_mday = unbcdify(*scts++); + tm.tm_hour = unbcdify(*scts++); + tm.tm_min = unbcdify(*scts++); + tm.tm_sec = unbcdify(*scts++); + /* according to gsm 03.40 time zone is + "expressed in quarters of an hour" */ + tm.tm_gmtoff = unbcdify(*scts++) * 15*60; + + return mktime(&tm); +} + +/* Return the default validity period in minutes */ +static unsigned long gsm340_vp_default(void) +{ + unsigned long minutes; + /* Default validity: two days */ + minutes = 24 * 60 * 2; + return minutes; +} + +/* Decode validity period format 'relative' */ +static unsigned long gsm340_vp_relative(u_int8_t *sms_vp) +{ + /* Chapter 9.2.3.12.1 */ + u_int8_t vp; + unsigned long minutes; + + vp = *(sms_vp); + if (vp <= 143) + minutes = vp + 1 * 5; + else if (vp <= 167) + minutes = 12*60 + (vp-143) * 30; + else if (vp <= 196) + minutes = vp-166 * 60 * 24; + else + minutes = vp-192 * 60 * 24 * 7; + return minutes; +} + +/* Decode validity period format 'absolute' */ +static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp) +{ + /* Chapter 9.2.3.12.2 */ + time_t expires, now; + unsigned long minutes; + + expires = gsm340_scts(sms_vp); + now = mktime(gmtime(NULL)); + if (expires <= now) + minutes = 0; + else + minutes = (expires-now)/60; + return minutes; +} + +/* Decode validity period format 'relative in integer representation' */ +static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp) { u_int8_t vp; unsigned long minutes; - time_t expires; - time_t now; + vp = *(sms_vp); + if (vp == 0) { + DEBUGP(DSMS, "reserved relative_integer validity period\n"); + return gsm340_vp_default(); + } + minutes = vp/60; + return minutes; +} + +/* Decode validity period format 'relative in semi-octet representation' */ +static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp) +{ + unsigned long minutes; + minutes = unbcdify(*sms_vp++)*60; /* hours */ + minutes += unbcdify(*sms_vp++); /* minutes */ + minutes += unbcdify(*sms_vp++)/60; /* seconds */ + return minutes; +} + +/* decode validity period. return minutes */ +static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) +{ + u_int8_t fi; /* functionality indicator */ switch (sms_vpf) { case GSM340_TP_VPF_RELATIVE: - /* Chapter 9.2.3.12.1 */ - vp = *(sms_vp); - if (vp <= 143) - minutes = vp + 1 * 5; - else if (vp <= 167) - minutes = 12*60 + (vp-143) * 30; - else if (vp <= 196) - minutes = vp-166 * 60 * 24; - else - minutes = vp-192 * 60 * 24 * 7; - break; + return gsm340_vp_relative(sms_vp); case GSM340_TP_VPF_ABSOLUTE: - /* Chapter 9.2.3.12.2 */ - expires = gsm340_scts(sms_vp); - now = mktime(gmtime(NULL)); - if (expires <= now) - minutes = 0; - else - minutes = (expires-now)/60; - break; + return gsm340_vp_absolute(sms_vp); case GSM340_TP_VPF_ENHANCED: /* Chapter 9.2.3.12.3 */ - /* FIXME: implementation */ - DEBUGP(DSMS, "VPI enhanced not implemented yet\n"); - break; + fi = *sms_vp++; + /* ignore additional fi */ + if (fi & (1<<7)) sms_vp++; + /* read validity period format */ + switch (fi & 0b111) { + case 0b000: + return gsm340_vp_default(); /* no vpf specified */ + case 0b001: + return gsm340_vp_relative(sms_vp); + case 0b010: + return gsm340_vp_relative_integer(sms_vp); + case 0b011: + return gsm340_vp_relative_semioctet(sms_vp); + default: + /* The GSM spec says that the SC should reject any + unsupported and/or undefined values. FIXME */ + DEBUGP(DSMS, "Reserved enhanced validity period format\n"); + return gsm340_vp_default(); + } case GSM340_TP_VPF_NONE: - /* Default validity: two days */ - minutes = 24 * 60 * 2; - break; + default: + return gsm340_vp_default(); } - return minutes; } /* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */ @@ -307,69 +431,6 @@ static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len, return len_in_bytes; } -/* Turn int into semi-octet representation: 98 => 0x89 */ -static u_int8_t bcdify(u_int8_t value) -{ - u_int8_t ret; - - ret = value / 10; - ret |= (value % 10) << 4; - - return ret; -} - -/* Turn semi-octet representation into int: 0x89 => 98 */ -static u_int8_t unbcdify(u_int8_t value) -{ - u_int8_t ret; - - if ((value & 0x0F) > 9 || (value >> 4) > 9) - DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); - - ret = (value&0x0F)*10; - if (ret > 90) - ret += value>>4; - - return ret; -} - -/* Generate 03.40 TP-SCTS */ -static void gsm340_gen_scts(u_int8_t *scts, time_t time) -{ - struct tm *tm = localtime(&time); - - *scts++ = bcdify(tm->tm_year % 100); - *scts++ = bcdify(tm->tm_mon + 1); - *scts++ = bcdify(tm->tm_mday); - *scts++ = bcdify(tm->tm_hour); - *scts++ = bcdify(tm->tm_min); - *scts++ = bcdify(tm->tm_sec); - *scts++ = bcdify(tm->tm_gmtoff/(60*15)); -} - -/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ -static time_t gsm340_scts(u_int8_t *scts) -{ - struct tm tm; - - u_int8_t yr = unbcdify(*scts++); - - if (yr <= 80) - tm.tm_year = 100 + yr; - else - tm.tm_year = yr; - tm.tm_mon = unbcdify(*scts++) - 1; - tm.tm_mday = unbcdify(*scts++); - tm.tm_hour = unbcdify(*scts++); - tm.tm_min = unbcdify(*scts++); - tm.tm_sec = unbcdify(*scts++); - /* according to gsm 03.40 time zone is - "expressed in quarters of an hour" */ - tm.tm_gmtoff = unbcdify(*scts++) * 15*60; - - return mktime(&tm); -} - /* generate a msgb containing a TPDU derived from struct gsm_sms, * returns total size of TPDU */ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms) @@ -499,6 +560,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) case GSM340_TP_VPF_ABSOLUTE: case GSM340_TP_VPF_ENHANCED: sms_vp = smsp; + /* the additional functionality indicator... */ + if (*smsp & (1<<7)) smsp++; smsp += 7; break; case GSM340_TP_VPF_NONE: From ad3c844b2d1364c8e02bdbaec643716e237e0b38 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 26 Nov 2009 23:47:21 +0100 Subject: [PATCH 022/365] [wireshark] patch to correctly decode SYSTEM INFORMATION on BCCH FILLING --- wireshark/rsl-system_info.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 wireshark/rsl-system_info.patch diff --git a/wireshark/rsl-system_info.patch b/wireshark/rsl-system_info.patch new file mode 100644 index 000000000..2945c6540 --- /dev/null +++ b/wireshark/rsl-system_info.patch @@ -0,0 +1,13 @@ +Index: wireshark/epan/dissectors/packet-rsl.c +=================================================================== +--- wireshark.orig/epan/dissectors/packet-rsl.c ++++ wireshark/epan/dissectors/packet-rsl.c +@@ -2291,7 +2291,7 @@ + + proto_tree_add_text(ie_tree, tvb,offset,length,"Layer 3 message"); + next_tvb = tvb_new_subset(tvb, offset, length, length); +- /* call_dissector(gsm_a_dtap_handle, next_tvb, pinfo, top_tree);*/ ++ call_dissector(gsm_a_ccch_handle, next_tvb, pinfo, top_tree); + + offset = offset + length; + From 1a79d364401dfad2a71f1e61ff13a3861e3da46e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 27 Nov 2009 08:55:16 +0100 Subject: [PATCH 023/365] RSL: catch inconsistent parameters ofr channel_mode_from_lchan() --- openbsc/src/abis_rsl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 692536c50..219b01aa0 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -488,6 +488,11 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, /* set TCH Speech/Data */ cm->spd_ind = lchan->rsl_cmode; + if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && + lchan->tch_mode != GSM48_CMODE_SIGN) + DEBUGP(DRSL, "unsupported: rsl_mode == signalling, " + "but tch_mode != signalling\n"); + switch (lchan->type) { case GSM_LCHAN_SDCCH: cm->chan_rt = RSL_CMOD_CRT_SDCCH; From a5312fdd2b444b363c36fa7b6e78a1bbe03c9e20 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 17:41:22 +0100 Subject: [PATCH 024/365] add notes about proposed handover algorithm --- openbsc/doc/handover.txt | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 openbsc/doc/handover.txt diff --git a/openbsc/doc/handover.txt b/openbsc/doc/handover.txt new file mode 100644 index 000000000..524d38625 --- /dev/null +++ b/openbsc/doc/handover.txt @@ -0,0 +1,77 @@ +Ideas about a handover algorithm +====================================================================== + +This is mostly based on the results presented in Chapter 8 of "Performance +Enhancements in a Frequency Hopping GSM Network" by Thomas Toftegaard Nielsen +and Joeroen Wigard. + + +=== Reasons for performing handover === + +Section 2.1.1: Handover used in their CAPACITY simulation: + +1) Interference Handover + +Average RXLEV is satisfactory high, but average RXQUAL too low indicates +interference to the channel. Handover should be made. + +2) Bad Quality + +Averaged RXQUAL is lower than a threshold + +3) Low Level / Signal Strength + +Average RXLEV is lower than a threshold + +4) Distance Handover + +MS is too far away from a cell (measured by TA) + +5) Power budget / Better Cell + +RX Level of neighbor cell is at least "HO Margin dB" dB better than the +current serving cell. + +=== Ideal parameters for HO algorithm === + +Chapter 8, Section 2.2, Table 24: + +Window RXLEV averaging: 10 SACCH frames (no weighting) +Window RXQUAL averaging: 1 SACCH frame (no averaging) +Level Threashold: 1 of the last 1 AV-RXLEV values < -110dBm +Quality Threshold: 3 of the last 4 AV-RXQUAL values >= 5 +Interference Threshold: 1 of the last AV-RXLEV > -85 dBm & + 3 of the last 4 AV-RXQUAL values >= 5 +Power Budget: Level of neighbor cell > 3 dB better +Power Budget Interval: Every 6 SACCH frames (6 seconds ?!?) +Distance Handover: Disabled +Evaluation rule 1: RXLEV of the candidate cell a tleast -104 dBm +Evaluation rule 2: Level of candidate cell > 3dB better own cell +Timer Successful HO: 5 SACCH frames +Timer Unsuccessful HO: 1 SACCH frame + +In a non-frequency hopping case, RXQUAL threshold can be decreased to +RXLEV >= 4 + +When frequency hopping is enabled, the following additional parameters +should be introduced: + +* No intra-cell handover +* Use a HO Margin of 2dB + +=== Handover Channel Reservation === + +In loaded network, each cell should reserve some channels for handovers, +rather than using all of them for new call establishment. This reduces the +need to drop calls due to failing handovers, at the expense of failing new call +attempts. + +=== Dynamic HO Margin === + +The handover margin (hysteresis) should depend on the RXQUAL. Optimal results +were achieved with the following settings: +* RXQUAL <= 4: 9 dB +* RXQUAL == 5: 6 dB +* RXQUAL >= 6: 1 dB + + From 3c7dc6ed50e8baa05a8aea26c72319530e747317 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 19:07:28 +0100 Subject: [PATCH 025/365] New complete measurement result/report handling This patch extends struct gsm_meas_rep into a complete structure containing all information from both uplink and downlink measurement results/reports. This is a first step to provide this complete measurement data as a C structure into a to-be-implemented handover decision algorithm. --- openbsc/include/openbsc/gsm_04_08.h | 28 +------ openbsc/include/openbsc/meas_rep.h | 50 +++++++++++++ openbsc/src/abis_rsl.c | 112 +++++++++++++++++++++------- openbsc/src/gsm_04_08.c | 60 +++++++-------- 4 files changed, 165 insertions(+), 85 deletions(-) create mode 100644 openbsc/include/openbsc/meas_rep.h diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index b7c8a2662..cd85dff8f 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -1,6 +1,8 @@ #ifndef _GSM_04_08_H #define _GSM_04_08_H +#include + /* GSM TS 04.08 definitions */ struct gsm_lchan; @@ -618,30 +620,6 @@ enum gsm48_reject_value { GSM48_REJECT_MSC_TMP_NOT_REACHABLE = 16, }; - -/* extracted from a L3 measurement report IE */ -struct gsm_meas_rep_cell { - u_int8_t rxlev; - u_int8_t bcch_freq; /* fixme: translate to ARFCN */ - u_int8_t bsic; -}; - -struct gsm_meas_rep { - unsigned int flags; - u_int8_t rxlev_full; - u_int8_t rxqual_full; - u_int8_t rxlev_sub; - u_int8_t rxqual_sub; - int num_cell; - struct gsm_meas_rep_cell cell[6]; -}; -#define MEAS_REP_F_DTX 0x01 -#define MEAS_REP_F_VALID 0x02 -#define MEAS_REP_F_BA1 0x04 - -void gsm48_parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data, - int len); - enum chreq_type { CHREQ_T_EMERG_CALL, CHREQ_T_CALL_REEST_TCH_F, @@ -782,5 +760,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr); int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode); int gsm48_rx_rr_modif_ack(struct msgb *msg); +int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg); + #endif diff --git a/openbsc/include/openbsc/meas_rep.h b/openbsc/include/openbsc/meas_rep.h new file mode 100644 index 000000000..0c2bdabde --- /dev/null +++ b/openbsc/include/openbsc/meas_rep.h @@ -0,0 +1,50 @@ +#ifndef _MEAS_REP_H +#define _MEAS_REP_H + +/* extracted from a L3 measurement report IE */ +struct gsm_meas_rep_cell { + u_int8_t rxlev; + u_int8_t bcch_freq; /* FIXME: translate to ARFCN */ + u_int8_t bsic; +}; + +/* RX Level and RX Quality */ +struct gsm_rx_lev_qual { + u_int8_t rx_lev; + u_int8_t rx_qual; +}; + +/* unidirectional measumrement report */ +struct gsm_meas_rep_unidir { + struct gsm_rx_lev_qual full; + struct gsm_rx_lev_qual sub; +}; + +#define MEAS_REP_F_UL_DTX 0x01 +#define MEAS_REP_F_DL_VALID 0x02 +#define MEAS_REP_F_BA1 0x04 +#define MEAS_REP_F_DL_DTX 0x08 +#define MEAS_REP_F_MS_TO 0x10 +#define MEAS_REP_F_MS_L1 0x20 +#define MEAS_REP_F_FPC 0x40 + +/* parsed uplink and downlink measurement result */ +struct gsm_meas_rep { + u_int8_t nr; + unsigned int flags; + + struct gsm_meas_rep_unidir ul; + struct gsm_meas_rep_unidir dl; + + u_int8_t bs_power; + u_int8_t ms_timing_offset; + struct { + int8_t pwr; /* MS power in dBm */ + u_int8_t ta; /* MS timing advance */ + } ms_l1; + + int num_cell; + struct gsm_meas_rep_cell cell[6]; +}; + +#endif /* _MEAS_REP_H */ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 219b01aa0..743dc5f2b 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -38,6 +38,7 @@ #include #include #include +#include #define RSL_ALLOC_SIZE 1024 #define RSL_ALLOC_HEADROOM 128 @@ -949,47 +950,102 @@ static int rsl_rx_conn_fail(struct msgb *msg) return rsl_rf_chan_release(msg->lchan); } +static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru, + const char *prefix) +{ + DEBUGPC(DMEAS, "RXL-FULL-%s=%d RXL-SUB-%s=%d ", + prefix, mru->full.rx_lev, prefix, mru->sub.rx_lev); + DEBUGPC(DMEAS, "RXQ-FULL-%s=%d RXQ-SUB-%s=%d ", + prefix, mru->full.rx_qual, prefix, mru->sub.rx_qual); +} + +static void print_meas_rep(struct gsm_meas_rep *mr) +{ + DEBUGP(DMEAS, "MEASUREMENT RESULT NR=%d ", mr->nr); + + if (mr->flags & MEAS_REP_F_DL_DTX) + DEBUGPC(DMEAS, "DTXd "); + + print_meas_rep_uni(&mr->ul, "ul"); + DEBUGPC(DMEAS, "BS_POWER=%d ", mr->bs_power); + if (mr->flags & MEAS_REP_F_MS_TO) + DEBUGPC(DMEAS, "MS_TO=%d ", mr->ms_timing_offset); + + if (mr->flags & MEAS_REP_F_MS_L1) { + DEBUGPC(DMEAS, "L1_MS_PWR=%ddBm ", mr->ms_l1.pwr); + DEBUGPC(DMEAS, "L1_FPC=%u ", + mr->flags & MEAS_REP_F_FPC ? 1 : 0); + DEBUGPC(DMEAS, "L1_TA=%u ", mr->ms_l1.ta); + } + + if (mr->flags & MEAS_REP_F_UL_DTX) + DEBUGPC(DMEAS, "DTXu "); + if (mr->flags & MEAS_REP_F_BA1) + DEBUGPC(DMEAS, "BA1 "); + if (!(mr->flags & MEAS_REP_F_DL_VALID)) + DEBUGPC(DMEAS, "NOT VALID "); + else + print_meas_rep_uni(&mr->dl, "dl"); + + DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell); +} + static int rsl_rx_meas_res(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; + struct gsm_meas_rep mr; + u_int8_t len; + const u_int8_t *val; + int rc; + + memset(&mr, 0, sizeof(mr)); - DEBUGPC(DMEAS, "MEASUREMENT RESULT "); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - if (TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR)) - DEBUGPC(DMEAS, "NR=%d ", *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR)); - if (TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS)) { - u_int8_t len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); - const u_int8_t *val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); - if (len >= 3) { - if (val[0] & 0x40) - DEBUGPC(DMEAS, "DTXd "); - DEBUGPC(DMEAS, "RXL-FULL-up=%d RXL-SUB-up=%d ", - val[0] & 0x3f, val[1] & 0x3f); - DEBUGPC(DMEAS, "RXQ-FULL-up=%d RXQ-SUB-up=%d ", - val[2]>>3 & 0x7, val[2] & 0x7); - } + if (!TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR) || + !TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS) || + !TLVP_PRESENT(&tp, RSL_IE_BS_POWER)) + return -EIO; + + /* Mandatory Parts */ + mr.nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); + + len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); + val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); + if (len >= 3) { + if (val[0] & 0x40) + mr.flags |= MEAS_REP_F_DL_DTX; + mr.ul.full.rx_lev = val[0] & 0x3f; + mr.ul.sub.rx_lev = val[1] & 0x3f; + mr.ul.full.rx_qual = val[2]>>3 & 0x7; + mr.ul.sub.rx_qual = val[2] & 0x7; } - if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER)) - DEBUGPC(DMEAS, "BS_POWER=%d ", *TLVP_VAL(&tp, RSL_IE_BS_POWER)); + + mr.bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); + + /* Optional Parts */ if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET)) - DEBUGPC(DMEAS, "MS_TO=%d ", - *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET)); + mr.ms_timing_offset = + *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET); + if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) { - const u_int8_t *val = TLVP_VAL(&tp, RSL_IE_L1_INFO); - u_int8_t pwr_lvl = val[0] >> 3; - DEBUGPC(DMEAS, "L1_MS_PWR=%ddBm ", - ms_pwr_dbm(msg->trx->bts->band, pwr_lvl)); - DEBUGPC(DMEAS, "L1_FPC=%u ", val[0] & 0x04 ? 1 : 0); - DEBUGPC(DMEAS, "L1_TA=%u ", val[1]); + val = TLVP_VAL(&tp, RSL_IE_L1_INFO); + mr.flags |= MEAS_REP_F_MS_L1; + mr.ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); + if (val[0] & 0x04) + mr.flags |= MEAS_REP_F_FPC; + mr.ms_l1.ta = val[1]; } if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { - DEBUGPC(DMEAS, "L3\n"); msg->l3h = (u_int8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); - return gsm0408_rcvmsg(msg, 0); - } else - DEBUGPC(DMEAS, "\n"); + rc = gsm48_parse_meas_rep(&mr, msg); + if (rc < 0) + return rc; + } + + /* FIXME: do something with the actual result*/ + print_meas_rep(&mr); return 0; } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 1f8235411..c9e543378 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -166,25 +166,30 @@ static const char *rr_cause_name(u_int8_t cause) return strbuf; } -static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data, - int len) +int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) { - memset(rep, 0, sizeof(*rep)); + struct gsm48_hdr *gh = msgb_l3(msg); + unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); + u_int8_t *data = gh->data; + + if (gh->msg_type != GSM48_MT_RR_MEAS_REP) + return -EINVAL; if (data[0] & 0x80) rep->flags |= MEAS_REP_F_BA1; if (data[0] & 0x40) - rep->flags |= MEAS_REP_F_DTX; + rep->flags |= MEAS_REP_F_UL_DTX; if ((data[1] & 0x40) == 0x00) - rep->flags |= MEAS_REP_F_VALID; + rep->flags |= MEAS_REP_F_DL_VALID; + + rep->dl.full.rx_lev = data[0] & 0x3f; + rep->dl.sub.rx_lev = data[1] & 0x3f; + rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; + rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; - rep->rxlev_full = data[0] & 0x3f; - rep->rxlev_sub = data[1] & 0x3f; - rep->rxqual_full = (data[3] >> 4) & 0x7; - rep->rxqual_sub = (data[3] >> 1) & 0x7; rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2); if (rep->num_cell < 1) - return; + return 0; /* an encoding nightmare in perfection */ @@ -192,35 +197,37 @@ static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data, rep->cell[0].bcch_freq = data[5] >> 2; rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5); if (rep->num_cell < 2) - return; + return 0; rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7); rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f; rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4); if (rep->num_cell < 3) - return; + return 0; rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6); rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f; rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3); if (rep->num_cell < 4) - return; + return 0; rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5); rep->cell[3].bcch_freq = data[11] & 0x1f; rep->cell[3].bsic = data[12] >> 2; if (rep->num_cell < 5) - return; + return 0; rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4); rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7); rep->cell[4].bsic = (data[14] >> 1) & 0x3f; if (rep->num_cell < 6) - return; + return 0; rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3); rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6); rep->cell[5].bsic = data[16] & 0x3f; + + return 0; } int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi); @@ -1528,26 +1535,13 @@ static int gsm48_rx_rr_status(struct msgb *msg) static int gsm48_rx_rr_meas_rep(struct msgb *msg) { - struct gsm48_hdr *gh = msgb_l3(msg); - unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); static struct gsm_meas_rep meas_rep; - DEBUGP(DMEAS, "MEASUREMENT REPORT "); - parse_meas_rep(&meas_rep, gh->data, payload_len); - if (meas_rep.flags & MEAS_REP_F_DTX) - DEBUGPC(DMEAS, "DTX "); - if (meas_rep.flags & MEAS_REP_F_BA1) - DEBUGPC(DMEAS, "BA1 "); - if (!(meas_rep.flags & MEAS_REP_F_VALID)) - DEBUGPC(DMEAS, "NOT VALID "); - else - DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ", - meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub, - meas_rep.rxqual_sub); - - DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell); - - /* FIXME: put the results somwhere */ + /* This shouldn't actually end up here, as RSL treats + * L3 Info of 08.58 MEASUREMENT REPORT different by calling + * directly into gsm48_parse_meas_rep */ + DEBUGP(DMEAS, "DIRECT GSM48 MEASUREMENT REPORT ?!? "); + gsm48_parse_meas_rep(&meas_rep, msg); return 0; } From ccd5a8892ded0832bd378fb33a24412b92920963 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 20:02:20 +0100 Subject: [PATCH 026/365] print debug statement in case of HANDOVER COMPLETE or HANDOVER FAILED --- openbsc/src/gsm_04_08.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index c9e543378..eeeb739f1 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1596,6 +1596,14 @@ static int gsm0408_rcv_rr(struct msgb *msg) DEBUGP(DRR, "CIPHERING MODE COMPLETE\n"); /* FIXME: check for MI (if any) */ break; + case GSM48_MT_RR_HANDO_COMPL: + DEBUGP(DRR, "HANDOVER COMPLETE\n"); + /* FIXME: release old channel */ + break; + case GSM48_MT_RR_HANDO_FAIL: + DEBUGP(DRR, "HANDOVER FAILED\n"); + /* FIXME: release allocated new channel */ + break; default: fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n", gh->msg_type); From 8c83af65c1902811d8e9823153af09cc59f4d9f6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 20:02:53 +0100 Subject: [PATCH 027/365] [handover] Implement 04.08 HANDOVER COMMAND This is needed by a yet-to-be-implemented handover algorithm, after it has allocated a new lchan for the MS. Also missing: handling the actual HANDOVER COMPLETE / FAIL messages in response. --- openbsc/doc/handover.txt | 12 +++++++ openbsc/include/openbsc/gsm_04_08.h | 16 +++++++++ openbsc/src/gsm_04_08_utils.c | 51 +++++++++++++++++++++++++---- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/openbsc/doc/handover.txt b/openbsc/doc/handover.txt index 524d38625..ac19e8725 100644 --- a/openbsc/doc/handover.txt +++ b/openbsc/doc/handover.txt @@ -75,3 +75,15 @@ were achieved with the following settings: * RXQUAL >= 6: 1 dB + +== Actual Handover on a protocol level == + +After the BSC has decided a handover shall be done, it has to + +# allocate a channel at the new BTS +# allocate a handover reference +# activate the channel on the BTS side using RSL CHANNEL ACTIVATION, + indicating the HO reference +# BTS responds with CHAN ACT ACK, including GSM frame number +# BSC sends 04.08 HO CMD to MS using old BTS + diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index cd85dff8f..359aa1b39 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -90,6 +90,22 @@ struct gsm48_ass_cmd { u_int8_t data[0]; } __attribute__((packed)); +/* Chapter 10.5.2.2 */ +struct gsm48_cell_desc { + u_int8_t bcc:3, + ncc:3, + arfcn_hi:2; + u_int8_t arfcn_lo; +} __attribute__((packed)); + +/* Chapter 9.1.15 */ +struct gsm48_ho_cmd { + struct gsm48_cell_desc cell_desc; + struct gsm48_chan_desc chan_desc; + u_int8_t ho_ref; + u_int8_t power_command; + u_int8_t data[0]; +} __attribute__((packed)); /* Chapter 9.1.18 */ struct gsm48_imm_ass { diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index ad038fba6..d3e4689b5 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -519,6 +519,50 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv) return rsl_encryption_cmd(msg); } +static void gsm48_cell_desc(struct gsm48_cell_desc *cd, + const struct gsm_bts *bts) +{ + cd->ncc = (bts->bsic >> 3 & 0x7); + cd->bcc = (bts->bsic & 0x7); + cd->arfcn_hi = bts->c0->arfcn >> 8; + cd->arfcn_lo = bts->c0->arfcn & 0xff; +} + +static void gsm48_chan_desc(struct gsm48_chan_desc *cd, + const struct gsm_lchan *lchan) +{ + u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; + + cd->chan_nr = lchan2chan_nr(lchan); + cd->h0.tsc = lchan->ts->trx->bts->tsc; + cd->h0.h = 0; + cd->h0.arfcn_high = arfcn >> 8; + cd->h0.arfcn_low = arfcn & 0xff; +} + +/* Chapter 9.1.15: Handover Command */ +int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, + struct gsm_lchan *new_lchan, u_int8_t power_command) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + struct gsm48_ho_cmd *ho = + (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho)); + static u_int8_t ho_ref; + + msg->lchan = old_lchan; + + /* mandatory bits */ + gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts); + gsm48_chan_desc(&ho->chan_desc, new_lchan); + ho->ho_ref = ho_ref++; + ho->power_command = power_command; + + /* FIXME: optional bits for type of synchronization? */ + + return gsm48_sendmsg(msg, NULL); +} + /* Chapter 9.1.2: Assignment Command */ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) { @@ -526,7 +570,6 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); struct gsm48_ass_cmd *ass = (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass)); - u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode); @@ -542,11 +585,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) * the chan_desc. But as long as multi-slot configurations * are not used we seem to be fine. */ - ass->chan_desc.chan_nr = lchan2chan_nr(lchan); - ass->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc; - ass->chan_desc.h0.h = 0; - ass->chan_desc.h0.arfcn_high = arfcn >> 8; - ass->chan_desc.h0.arfcn_low = arfcn & 0xff; + gsm48_chan_desc(&ass->chan_desc, lchan); ass->power_command = power_command; /* in case of multi rate we need to attach a config */ From d011e8b958f3d5a09d1c66852292974d9dc52786 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 22:45:52 +0100 Subject: [PATCH 028/365] [handover] Introduce new handover related LCHAN signals This introduces the signals S_LCHAN_ACTIVATE_{ACK,NACK} and S_LCAN_HANDOVER_{FAIL,COMPL,DETECT} as well as code that actually issues those signals. The signals are relevant for a yet-to-be-written handover control logic. --- openbsc/include/openbsc/signal.h | 5 +++++ openbsc/src/abis_rsl.c | 30 ++++++++++++++++++++++++++++- openbsc/src/gsm_04_08.c | 33 ++++++++++++++++++++++++++++---- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index fee9d5bfd..fbd61ae9e 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -78,6 +78,11 @@ enum signal_lchan { * signal handler. */ S_LCHAN_UNEXPECTED_RELEASE, + S_LCHAN_ACTIVATE_ACK, /* 08.58 Channel Activate ACK */ + S_LCHAN_ACTIVATE_NACK, /* 08.58 Channel Activate NACK */ + S_LCHAN_HANDOVER_COMPL, /* 04.08 Handover Completed */ + S_LCHAN_HANDOVER_FAIL, /* 04.08 Handover Failed */ + S_LCHAN_HANDOVER_DETECT, /* 08.58 Handover Detect */ }; /* SS_SUBSCR signals */ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 743dc5f2b..8033a3c74 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -907,7 +907,9 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) * to assign the activated channel to the MS */ if (rslh->ie_chan != RSL_IE_CHAN_NR) return -EINVAL; - + + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan); + return 0; } @@ -926,6 +928,8 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan); + lchan_free(msg->lchan); return 0; } @@ -1050,6 +1054,27 @@ static int rsl_rx_meas_res(struct msgb *msg) return 0; } +/* Chapter 8.4.7 */ +static int rsl_rx_hando_det(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tp; + + DEBUGP(DRSL, "HANDOVER DETECT "); + + rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); + + if (TLVP_PRESENT(&tp, RSL_IE_ACCESS_DELAY)) + DEBUGPC(DRSL, "access delay = %u\n", + *TLVP_VAL(&tp, RSL_IE_ACCESS_DELAY)); + else + DEBUGPC(DRSL, "\n"); + + dispatch_signal(SS_LCHAN, S_LCHAN_HANDOVER_DETECT, msg->lchan); + + return 0; +} + static int abis_rsl_rx_dchan(struct msgb *msg) { struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); @@ -1077,6 +1102,9 @@ static int abis_rsl_rx_dchan(struct msgb *msg) case RSL_MT_MEAS_RES: rc = rsl_rx_meas_res(msg); break; + case RSL_MT_HANDO_DET: + rc = rsl_rx_hando_det(msg); + break; case RSL_MT_RF_CHAN_REL_ACK: DEBUGPC(DRSL, "RF CHANNEL RELEASE ACK\n"); lchan_free(msg->lchan); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index eeeb739f1..e225bf3a1 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1563,6 +1563,33 @@ static int gsm48_rx_rr_app_info(struct msgb *msg) return db_apdu_blob_store(msg->lchan->subscr, apdu_id_flags, apdu_len, apdu_data); } +/* Chapter 9.1.16 Handover complete */ +static gsm48_rx_rr_ho_compl(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DRR, "HANDOVER COMPLETE cause = %s\n", + rr_cause_name(gh->data[0])); + + dispatch_signal(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, msg->lchan); + /* FIXME: release old channel */ + + return 0; +} + +/* Chapter 9.1.17 Handover Failure */ +static gsm48_rx_rr_ho_fail(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DRR, "HANDOVER FAILED cause = %s\n", + rr_cause_name(gh->data[0])); + + dispatch_signal(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, msg->lchan); + /* FIXME: release allocated new channel */ + + return 0; +} /* Receive a GSM 04.08 Radio Resource (RR) message */ static int gsm0408_rcv_rr(struct msgb *msg) @@ -1597,12 +1624,10 @@ static int gsm0408_rcv_rr(struct msgb *msg) /* FIXME: check for MI (if any) */ break; case GSM48_MT_RR_HANDO_COMPL: - DEBUGP(DRR, "HANDOVER COMPLETE\n"); - /* FIXME: release old channel */ + rc = gsm48_rx_rr_ho_compl(msg); break; case GSM48_MT_RR_HANDO_FAIL: - DEBUGP(DRR, "HANDOVER FAILED\n"); - /* FIXME: release allocated new channel */ + rc = gsm48_rx_rr_ho_fail(msg); break; default: fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n", From 798418a068fcc95f8f5bcad5ba923ab065d7fa86 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 22:56:14 +0100 Subject: [PATCH 029/365] [handover] Implement handover control logic Code to implement handover control logic. A yet-to-be-implemented handover algorithm will call bsc_handover_start(old_lchan, new_bts) to start the handover process. --- openbsc/include/openbsc/gsm_04_08.h | 2 + openbsc/src/Makefile.am | 2 +- openbsc/src/handover_logic.c | 251 ++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/handover_logic.c diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 359aa1b39..4a5cebf46 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -757,6 +757,8 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, u_int8_t apdu_len, const u_int8_t *apdu); int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); +int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, + struct gsm_lchan *new_lchan, u_int8_t power_command); int bsc_upqueue(struct gsm_network *net); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 9c8fa7b4d..4d18692db 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -7,7 +7,7 @@ noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ - msgb.c select.c chan_alloc.c timer.c debug.c \ + msgb.c select.c chan_alloc.c timer.c debug.c handover_logic.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c new file mode 100644 index 000000000..d4a888487 --- /dev/null +++ b/openbsc/src/handover_logic.c @@ -0,0 +1,251 @@ +/* Handover Logic for Inter-BTS (Intra-BSC) Handover. This does not + * actually implement the handover algorithm/decision, but executes a + * handover decision */ + +/* (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 +#include +#include +#include +#include +#include +#include + +struct bsc_handover { + struct llist_head list; + + struct gsm_lchan *old_lchan; + struct gsm_lchan *new_lchan; + + struct timer_list T3103; + + u_int8_t ho_ref; +}; + +static LLIST_HEAD(bsc_handovers); + +static struct bsc_handover *bsc_ho_by_new_lchan(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + llist_for_each_entry(ho, &bsc_handovers, list) { + if (ho->new_lchan == new_lchan) + return ho; + } + + return NULL; +} + +static struct bsc_handover *bsc_ho_by_old_lchan(struct gsm_lchan *old_lchan) +{ + struct bsc_handover *ho; + + llist_for_each_entry(ho, &bsc_handovers, list) { + if (ho->old_lchan == old_lchan) + return ho; + } + + return NULL; +} + +/* Hand over the specified logical channel to the specified new BTS. + * This is the main entry point for the actual handover algorithm, + * after it has decided it wants to initiate HO to a specific BTS */ +int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) +{ + struct gsm_lchan *new_lchan; + struct bsc_handover *ho; + int rc; + + new_lchan = lchan_alloc(bts, old_lchan->type); + if (!new_lchan) + return -ENOSPC; + + ho = talloc_zero(NULL, struct bsc_handover); + if (!ho) { + lchan_free(new_lchan); + return -ENOMEM; + } + ho->old_lchan = old_lchan; + ho->new_lchan = new_lchan; + + /* FIXME: do we have a better idea of the timing advance? */ + rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0); + if (rc < 0) { + talloc_free(ho); + lchan_free(new_lchan); + return rc; + } + + llist_add(&ho->list, &bsc_handovers); + /* we continue in the SS_LCHAN handler / ho_chan_activ_ack */ + + return 0; +} + +/* T3103 expired: Handover has failed without HO COMPLETE or HO FAIL */ +static void ho_T3103_cb(void *_ho) +{ + struct bsc_handover *ho = _ho; + + lchan_free(ho->new_lchan); + llist_del(&ho->list); + talloc_free(ho); +} + +/* RSL has acknowledged activation of the new lchan */ +static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + int rc; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) + return -ENODEV; + + /* we can now send the 04.08 HANDOVER COMMAND to the MS + * using the old lchan */ + + rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0); + + /* start T3103. We can continue either with T3103 expiration, + * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ + ho->T3103.cb = ho_T3103_cb; + bsc_schedule_timer(&ho->T3103, 10, 0); + + return 0; +} + +/* RSL has not acknowledged activation of the new lchan */ +static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) + return -ENODEV; + + llist_del(&ho->list); + talloc_free(ho); + + /* FIXME: maybe we should try to allocate a new LCHAN here? */ + + return 0; +} + +/* GSM 04.08 HANDOVER COMPLETE has been received on new channel */ +static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) + return -ENODEV; + + bsc_del_timer(&ho->T3103); + llist_del(&ho->list); + + /* do something to re-route the actual speech frames ! */ + //tch_remap(ho->old_lchan, ho->new_lchan); + + /* release old lchan */ + put_lchan(ho->old_lchan); + + talloc_free(ho); + + return 0; +} + +/* GSM 04.08 HANDOVER FAIL has been received */ +static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_old_lchan(old_lchan); + if (!ho) + return -ENODEV; + + bsc_del_timer(&ho->T3103); + llist_del(&ho->list); + put_lchan(ho->new_lchan); + talloc_free(ho); + + return 0; +} + +/* GSM 08.58 HANDOVER DETECT has been received */ +static int ho_rsl_detect(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_old_lchan(new_lchan); + if (!ho) + return -ENODEV; + + /* FIXME: do we actually want to do something here ? */ + + return 0; +} + +static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct gsm_lchan *lchan; + + switch (subsys) { + case SS_LCHAN: + lchan = signal_data; + switch (signal) { + case S_LCHAN_ACTIVATE_ACK: + return ho_chan_activ_ack(lchan); + case S_LCHAN_ACTIVATE_NACK: + return ho_chan_activ_nack(lchan); + case S_LCHAN_HANDOVER_DETECT: + return ho_rsl_detect(lchan); + case S_LCHAN_HANDOVER_COMPL: + return ho_gsm48_ho_compl(lchan); + case S_LCHAN_HANDOVER_FAIL: + return ho_gsm48_ho_fail(lchan); + } + break; + default: + break; + } + + return 0; +} + +static __attribute__((constructor)) void on_dso_load_ho_logic(void) +{ + register_signal_handler(SS_LCHAN, ho_logic_sig_cb, NULL); +} From dbb1d883594ba8796acbc7831d4ad042c7070d12 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 30 Nov 2009 19:16:47 +0100 Subject: [PATCH 030/365] [handover] export measurement reports via signal This patch introduces the S_LCHAN_MEAS_REP signal which is used to export measurement reports as input to the yet-to-be-written handover algorithm. --- openbsc/include/openbsc/meas_rep.h | 2 ++ openbsc/include/openbsc/signal.h | 1 + openbsc/src/abis_rsl.c | 5 ++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/meas_rep.h b/openbsc/include/openbsc/meas_rep.h index 0c2bdabde..b1ad2daa8 100644 --- a/openbsc/include/openbsc/meas_rep.h +++ b/openbsc/include/openbsc/meas_rep.h @@ -30,6 +30,8 @@ struct gsm_meas_rep_unidir { /* parsed uplink and downlink measurement result */ struct gsm_meas_rep { + struct gsm_lchan *lchan; + u_int8_t nr; unsigned int flags; diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index fbd61ae9e..5156fcb79 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -83,6 +83,7 @@ enum signal_lchan { S_LCHAN_HANDOVER_COMPL, /* 04.08 Handover Completed */ S_LCHAN_HANDOVER_FAIL, /* 04.08 Handover Failed */ S_LCHAN_HANDOVER_DETECT, /* 08.58 Handover Detect */ + S_LCHAN_MEAS_REP, /* 08.58 Measurement Report */ }; /* SS_SUBSCR signals */ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 8033a3c74..b049c3c8a 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1005,6 +1005,8 @@ static int rsl_rx_meas_res(struct msgb *msg) memset(&mr, 0, sizeof(mr)); + mr.lchan = msg->lchan; + rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (!TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR) || @@ -1048,9 +1050,10 @@ static int rsl_rx_meas_res(struct msgb *msg) return rc; } - /* FIXME: do something with the actual result*/ print_meas_rep(&mr); + dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, &mr); + return 0; } From b84ddfc22f60ed42c0c0ee5367c42a56157a7c75 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 1 Dec 2009 17:36:54 +0530 Subject: [PATCH 031/365] Assign default values for T3101 and T3113 Without those default values, old config files will no longer work after commit 23975e718fd456ff8be7effbb915903f1bc173be --- openbsc/include/openbsc/gsm_data.h | 3 +++ openbsc/src/gsm_data.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 638b03506..b4a8ef550 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -407,6 +407,9 @@ enum gsm_auth_policy { GSM_AUTH_POLICY_TOKEN, /* accept first, send token per sms, then revoke authorization */ }; +#define GSM_T3101_DEFAULT 10 +#define GSM_T3113_DEFAULT 60 + struct gsm_network { /* global parameters */ u_int16_t country_code; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 8212346ec..88de4c462 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -198,6 +198,9 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c net->country_code = country_code; net->network_code = network_code; net->num_bts = 0; + net->T3101 = GSM_T3101_DEFAULT; + net->T3113 = GSM_T3113_DEFAULT; + /* FIXME: initialize all other timers! */ INIT_LLIST_HEAD(&net->trans_list); INIT_LLIST_HEAD(&net->upqueue); From 3961fcc0313f1d87ab64806638e416f2603e7345 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 30 Nov 2009 19:37:18 +0100 Subject: [PATCH 032/365] Introduce new S_GLOBAL_SHUTDOWN signal This is used to notify various parts of OpenBSC that we're shutting down. --- openbsc/include/openbsc/signal.h | 5 +++++ openbsc/src/bsc_hack.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 5156fcb79..d59bb9726 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -40,6 +40,7 @@ enum signal_subsystems { SS_LCHAN, SS_SUBSCR, SS_SCALL, + SS_GLOBAL, }; /* SS_PAGING signals */ @@ -99,6 +100,10 @@ enum signal_scall { S_SCALL_DETACHED, }; +enum signal_global { + S_GLOBAL_SHUTDOWN, +}; + typedef int signal_cbfn(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data); diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index c256f864e..ee37a6115 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -35,6 +35,7 @@ #include #include #include +#include /* MCC and MNC for the Location Area Identifier */ struct gsm_network *bsc_gsmnet = 0; @@ -143,6 +144,7 @@ static void signal_handler(int signal) switch (signal) { case SIGINT: bsc_shutdown_net(bsc_gsmnet); + dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); sleep(3); exit(0); break; From 29b9cf844686b84c5f19ee9b6d62fe921d68f3fc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 30 Nov 2009 19:43:54 +0100 Subject: [PATCH 033/365] make use of new S_GLOBAL_SHUTDOWN signal to properly close pcap_fd This avoids broken pcap files with partial packets due to non-flushed buffers. --- openbsc/src/e1_input.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index e46533838..15495fbbb 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #define NUM_E1_TS 32 @@ -523,8 +524,24 @@ int e1inp_line_update(struct e1inp_line *line) return mi_e1_line_update(line); } +static int e1i_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + if (subsys != SS_GLOBAL || + signal != S_GLOBAL_SHUTDOWN) + return 0; + + if (pcap_fd) { + close(pcap_fd); + pcap_fd = -1; + } + + return 0; +} + static __attribute__((constructor)) void on_dso_load_e1_inp(void) { tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1, "e1inp_sign_link"); + register_signal_handler(SS_GLOBAL, e1i_sig_cb, NULL); } From a43f789a0a124c322146280ab00935b75f505617 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 1 Dec 2009 18:04:30 +0530 Subject: [PATCH 034/365] Replace template-based SYSTEM INFORMATION with real implementation Before this commit, OpenBSC used templates for the SYSTEM INFO 1, 2, 3, 4, 5 and 6 messages. Those templates were patched in various places to reflect the network config like ARFCN. Now, we actually generate those SI messages ourselves, using values from the configuration file, and even calculating neighbor cell lists. All bts'es that you have configured in OpenBSC will end up in the neighbor cell list - which should be more than sufficient for the current small-single-site networks. --- openbsc/include/openbsc/bitvec.h | 59 +++ openbsc/include/openbsc/gsm_04_08.h | 23 +- openbsc/include/openbsc/gsm_data.h | 11 +- openbsc/include/openbsc/rest_octets.h | 122 ++++++ openbsc/include/openbsc/system_information.h | 6 + openbsc/src/Makefile.am | 2 +- openbsc/src/abis_rsl.c | 10 +- openbsc/src/bitvec.c | 123 ++++++ openbsc/src/bsc_init.c | 329 +++----------- openbsc/src/paging.c | 2 +- openbsc/src/rest_octets.c | 393 +++++++++++++++++ openbsc/src/system_information.c | 427 +++++++++++++++++++ openbsc/src/vty_interface.c | 7 +- 13 files changed, 1220 insertions(+), 294 deletions(-) create mode 100644 openbsc/include/openbsc/bitvec.h create mode 100644 openbsc/include/openbsc/rest_octets.h create mode 100644 openbsc/include/openbsc/system_information.h create mode 100644 openbsc/src/bitvec.c create mode 100644 openbsc/src/rest_octets.c create mode 100644 openbsc/src/system_information.c diff --git a/openbsc/include/openbsc/bitvec.h b/openbsc/include/openbsc/bitvec.h new file mode 100644 index 000000000..80ed4ad0a --- /dev/null +++ b/openbsc/include/openbsc/bitvec.h @@ -0,0 +1,59 @@ +#ifndef _BITVEC_H +#define _BITVEC_H + +/* bit vector utility routines */ + +/* (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. + * + */ + + +/* In GSM mac blocks, every bit can be 0 or 1, or L or H. L/H are + * defined relative to the 0x2b padding pattern */ +enum bit_value { + ZERO = 0, + ONE = 1, + L = 2, + H = 3, +}; + +struct bitvec { + unsigned int cur_bit; /* curser to the next unused bit */ + unsigned int data_len; /* length of data array in bytes */ + u_int8_t *data; /* pointer to data array */ +}; + +/* Set a bit at given position */ +int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum, + enum bit_value bit); + +/* Set the next bit in the vector */ +int bitvec_set_bit(struct bitvec *bv, enum bit_value bit); + +/* Set multiple bits at the current position */ +int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count); + +/* Add an unsigned integer (of length count bits) to current position */ +int bitvec_set_uint(struct bitvec *bv, unsigned int in, int count); + + +/* Pad the bit vector up to a certain bit position */ +int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit); + +#endif /* _BITVEC_H */ diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 4a5cebf46..a3b77a8ab 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -187,6 +187,13 @@ struct gsm48_control_channel_descr { u_int8_t t3212; } __attribute__ ((packed)); +struct gsm48_cell_options { + u_int8_t radio_link_timeout:4, + dtx:2, + pwrc:1, + spare:1; +} __attribute__ ((packed)); + /* Section 9.2.9 CM service request */ struct gsm48_service_request { u_int8_t cm_service_type : 4, @@ -203,7 +210,7 @@ struct gsm48_system_information_type_1 { struct gsm48_system_information_type_header header; u_int8_t cell_channel_description[16]; struct gsm48_rach_control rach_control; - u_int8_t s1_reset; + u_int8_t rest_octets[0]; /* NCH position on the CCCH */ } __attribute__ ((packed)); /* Section 9.1.32 System information Type 2 */ @@ -220,10 +227,10 @@ struct gsm48_system_information_type_3 { u_int16_t cell_identity; struct gsm48_loc_area_id lai; struct gsm48_control_channel_descr control_channel_desc; - u_int8_t cell_options; + struct gsm48_cell_options cell_options; struct gsm48_cell_sel_par cell_sel_par; struct gsm48_rach_control rach_control; - u_int8_t s3_reset_octets[4]; + u_int8_t rest_octets[0]; } __attribute__ ((packed)); /* Section 9.1.36 System information Type 4 */ @@ -253,9 +260,15 @@ struct gsm48_system_information_type_6 { u_int8_t system_information; u_int16_t cell_identity; struct gsm48_loc_area_id lai; - u_int8_t cell_options; + struct gsm48_cell_options cell_options; u_int8_t ncc_permitted; - u_int8_t si_6_reset[0]; + u_int8_t rest_octets[0]; +} __attribute__ ((packed)); + +/* Section 9.1.43a System Information type 13 */ +struct gsm48_system_information_type_13 { + struct gsm48_system_information_type_header header; + u_int8_t rest_octets[0]; } __attribute__ ((packed)); /* Section 9.2.12 IMSI Detach Indication */ diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index b4a8ef550..fcd623fe6 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -356,8 +356,6 @@ struct gsm_bts { /* number of this BTS on given E1 link */ u_int8_t bts_nr; - struct gsm48_control_channel_descr chan_desc; - /* paging state and control */ struct gsm_bts_paging_state paging; @@ -368,6 +366,15 @@ struct gsm_bts { struct gsm_nm_state nm_state; } site_mgr; + /* parameters from which we build SYSTEM INFORMATION */ + struct { + struct gsm48_rach_control rach_control; + u_int8_t ncc_permitted; + struct gsm48_cell_sel_par cell_sel_par; + struct gsm48_cell_options cell_options; + struct gsm48_control_channel_descr chan_desc; + } si_common; + /* ip.accesss Unit ID's have Site/BTS/TRX layout */ union { struct { diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h new file mode 100644 index 000000000..4e72c0f87 --- /dev/null +++ b/openbsc/include/openbsc/rest_octets.h @@ -0,0 +1,122 @@ +#ifndef _REST_OCTETS_H +#define _REST_OCTETS_H + +#include +#include + +/* generate SI1 rest octets */ +int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos); + +struct gsm48_si_selection_params { + u_int16_t penalty_time:5, + temp_offs:3, + cell_resel_off:6, + cbq:1, + present:1; +}; + +struct gsm48_si_power_offset { + u_int8_t power_offset:2, + present:1; +}; + +struct gsm48_si3_gprs_ind { + u_int8_t si13_position:1, + ra_colour:3, + present:1; +}; + +struct gsm48_lsa_params { + u_int32_t prio_thr:3, + lsa_offset:3, + mcc:12, + mnc:12; + unsigned int present; +}; + +struct gsm48_si_ro_info { + struct gsm48_si_selection_params selection_params; + struct gsm48_si_power_offset power_offset; + u_int8_t si2ter_indicator; + u_int8_t early_cm_ctrl; + struct { + u_int8_t where:3, + present:1; + } scheduling; + struct gsm48_si3_gprs_ind gprs_ind; + + /* SI 4 specific */ + struct gsm48_lsa_params lsa_params; + u_int16_t cell_id; + u_int8_t break_ind; /* do we have SI7 + SI8 ? */ +}; + + +/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */ +int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3); + +/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */ +int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4); + +enum pbcch_carrier_type { + PBCCH_BCCH, + PBCCH_ARFCN, + PBCCH_MAIO +}; + +/* TS 03.60 Chapter 6.3.3.1: Network Mode of Operation */ +enum gprs_nmo { + GPRS_NMO_I = 0, /* CS pagin on GPRS paging or traffic channel */ + GPRS_NMO_II = 1, /* all paging on CCCH */ + GPRS_NMO_III = 2, /* no paging coordination */ +}; + +struct gprs_cell_options { + enum gprs_nmo nmo; + /* T3168: wait for packet uplink assignment message */ + u_int32_t t3168; /* in milliseconds */ + /* T3192: wait for release of the TBF after reception of the final block */ + u_int32_t t3192; /* in milliseconds */ + u_int32_t drx_timer_max;/* in seconds */ + u_int32_t bs_cv_max; +}; + +/* TS 04.60 Table 12.9.2 */ +struct gprs_power_ctrl_pars { + u_int8_t alpha; + u_int8_t t_avg_w; + u_int8_t t_avg_t; + u_int8_t pc_meas_chan; + u_int8_t n_avg_i; +}; + +struct gsm48_si13_info { + struct gprs_cell_options cell_opts; + struct gprs_power_ctrl_pars pwr_ctrl_pars; + u_int8_t bcch_change_mark; + u_int8_t si_change_field; + u_int8_t pbcch_present; + + union { + struct { + u_int8_t rac; + u_int8_t spgc_ccch_sup; + u_int8_t net_ctrl_ord; + u_int8_t prio_acc_thr; + } no_pbcch; + struct { + u_int8_t psi1_rep_per; + u_int8_t pb; + u_int8_t tsc; + u_int8_t tn; + enum pbcch_carrier_type carrier_type; + u_int16_t arfcn; + u_int8_t maio; + } pbcch; + }; +}; + +/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */ +int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13); + +#endif /* _REST_OCTETS_H */ diff --git a/openbsc/include/openbsc/system_information.h b/openbsc/include/openbsc/system_information.h new file mode 100644 index 000000000..982a9ac63 --- /dev/null +++ b/openbsc/include/openbsc/system_information.h @@ -0,0 +1,6 @@ +#ifndef _SYSTEM_INFO_H +#define _SYSTEM_INFO_H + +int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type); + +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 4d18692db..f22582122 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -11,7 +11,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ - talloc_ctx.c + talloc_ctx.c system_information.c bitvec.c rest_octets.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index b049c3c8a..1d41d2b5d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1729,11 +1729,11 @@ int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf) /* From Table 10.5.33 of GSM 04.08 */ int rsl_number_of_paging_subchannels(struct gsm_bts *bts) { - if (bts->chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) { - return MAX(1, (3 - bts->chan_desc.bs_ag_blks_res)) - * (bts->chan_desc.bs_pa_mfrms + 2); + if (bts->si_common.chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) { + return MAX(1, (3 - bts->si_common.chan_desc.bs_ag_blks_res)) + * (bts->si_common.chan_desc.bs_pa_mfrms + 2); } else { - return (9 - bts->chan_desc.bs_ag_blks_res) - * (bts->chan_desc.bs_pa_mfrms + 2); + return (9 - bts->si_common.chan_desc.bs_ag_blks_res) + * (bts->si_common.chan_desc.bs_pa_mfrms + 2); } } diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c new file mode 100644 index 000000000..ac2554475 --- /dev/null +++ b/openbsc/src/bitvec.c @@ -0,0 +1,123 @@ +/* bit vector utility routines */ + +/* (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 + +#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit) + +static inline unsigned int bytenum_from_bitnum(unsigned int bitnum) +{ + unsigned int bytenum = bitnum / 8; + + return bytenum; +} + +int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, + enum bit_value bit) +{ + unsigned int bytenum = bytenum_from_bitnum(bitnr); + unsigned int bitnum = 7 - (bitnr % 8); + u_int8_t bitval; + + if (bytenum >= bv->data_len) + return -EINVAL; + + switch (bit) { + case ZERO: + bitval = (0 << bitnum); + break; + case ONE: + bitval = (1 << bitnum); + break; + case L: + bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum)); + break; + case H: + bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum)); + break; + default: + return -EINVAL; + } + + /* first clear the bit */ + bv->data[bytenum] &= ~(1 << bitnum); + + /* then set it to desired value */ + bv->data[bytenum] |= bitval; + + return 0; +} + +int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) +{ + int rc; + + rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit); + if (!rc) + bv->cur_bit++; + + return rc; +} + +int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) +{ + int i, rc; + + for (i = 0; i < count; i++) { + rc = bitvec_set_bit(bv, bits[i]); + if (rc) + return rc; + } + + return 0; +} + +int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits) +{ + int i, rc; + + for (i = 0; i < num_bits; i++) { + int bit = 0; + if (ui & (1 << (num_bits - i - 1))) + bit = 1; + rc = bitvec_set_bit(bv, bit); + if (rc) + return rc; + } + + return 0; +} + +/* pad all remaining bits up to num_bits */ +int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) +{ + unsigned int i; + + for (i = bv->cur_bit; i <= up_to_bit; i++) + bitvec_set_bit(bv, L); + + return 0; +} diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 153e024e4..d21f71a0c 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ extern struct gsm_network *bsc_gsmnet; extern int ipacc_rtp_direct; static void patch_nm_tables(struct gsm_bts *bts); -static void patch_si_tables(struct gsm_bts *bts); /* The following definitions are for OM and NM packets that we cannot yet * generate by code but we just pass on */ @@ -667,219 +667,42 @@ int bsc_shutdown_net(struct gsm_network *net) return 0; } -struct bcch_info { - u_int8_t type; - u_int8_t len; - const u_int8_t *data; -}; - -/* -SYSTEM INFORMATION TYPE 1 - Cell channel description - Format-ID bit map 0 - CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 -*/ -static u_int8_t si1[] = { - /* header */0x55, 0x06, 0x19, - /* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/, - /* rach */0xD5, 0x04, 0x00, - /* s1 reset*/0x2B -}; - -/* - SYSTEM INFORMATION TYPE 2 - Neighbour Cells Description - EXT-IND: Carries the complete BA - BA-IND = 0 - Format-ID bit map 0 - CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - NCC permitted (NCC) = FF - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 -*/ -static u_int8_t si2[] = { - /* header */0x59, 0x06, 0x1A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ncc */0xFF, - /* rach*/0xD5, 0x04, 0x00 -}; - -/* -SYSTEM INFORMATION TYPE 3 - Cell identity = 00001 (1h) - Location area identification - Mobile Country Code (MCC): 001 - Mobile Network Code (MNC): 01 - Location Area Code (LAC): 00001 (1h) - Control Channel Description - Attach-detach: MSs in the cell are not allowed to apply IMSI attach /detach - 0 blocks reserved for access grant - 1 channel used for CCCH, with SDCCH - 5 multiframes period for PAGING REQUEST - Time-out T3212 = 0 - Cell Options BCCH - Power control indicator: not set - MSs shall not use uplink DTX - Radio link timeout = 36 - Cell Selection Parameters - Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection - max.TX power level MS may use for CCH = 2 <- according to GSM05.05 39dBm (max) - Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters - Half rate support (NECI): New establishment causes are not supported - min.RX signal level for MS = 0 - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 - SI 3 Rest Octets (not present) -*/ -static u_int8_t si3[] = { - /* header */0x49, 0x06, 0x1B, - /* cell */0x00, 0x01, - /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, - /* desc */0x01, 0x03, 0x00, - /* option*/0x28, - /* selection*/0x62, 0x00, - /* rach */0xD5, 0x04, 0x00, - /* rest */ 0x2B, 0x2B, 0x2B, 0x2B -}; - -/* -SYSTEM INFORMATION TYPE 4 - Location area identification - Mobile Country Code (MCC): 001 - Mobile Network Code (MNC): 01 - Location Area Code (LAC): 00001 (1h) - Cell Selection Parameters - Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection - max.TX power level MS may use for CCH = 2 - Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters - Half rate support (NECI): New establishment causes are not supported - min.RX signal level for MS = 0 - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 - CBCH Channel Description - Type = SDCCH/4[2] - Timeslot Number: 0 - Training Sequence Code: 7h - ARFCN: 1 - SI Rest Octets (not present) -*/ -static u_int8_t si4[] = { - /* header */0x41, 0x06, 0x1C, - /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, - /* sel */0x62, 0x00, - /* rach*/0xD5, 0x04, 0x00, - /* cbch chan desc */ 0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, - /* rest octets */ 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B -}; - -/* - SYSTEM INFORMATION TYPE 5 - Neighbour Cells Description - EXT-IND: Carries the complete BA - BA-IND = 0 - Format-ID bit map 0 - CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -*/ - -static u_int8_t si5[] = { - /* header without l2 len*/0x06, 0x1D, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -// SYSTEM INFORMATION TYPE 6 - -/* -SACCH FILLING - System Info Type: SYSTEM INFORMATION 6 - L3 Information (Hex): 06 1E 00 01 xx xx 10 00 01 28 FF - -SYSTEM INFORMATION TYPE 6 - Cell identity = 00001 (1h) - Location area identification - Mobile Country Code (MCC): 001 - Mobile Network Code (MNC): 01 - Location Area Code (LAC): 00001 (1h) - Cell Options SACCH - Power control indicator: not set - MSs shall not use uplink DTX on a TCH-F. MS shall not use uplink DTX on TCH-H. - Radio link timeout = 36 - NCC permitted (NCC) = FF -*/ - -static u_int8_t si6[] = { - /* header */0x06, 0x1E, - /* cell id*/ 0x00, 0x01, - /* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01, - /* options */ 0x28, - /* ncc */ 0xFF, -}; - - - -static const struct bcch_info bcch_infos[] = { - { - .type = RSL_SYSTEM_INFO_1, - .len = sizeof(si1), - .data = si1, - }, { - .type = RSL_SYSTEM_INFO_2, - .len = sizeof(si2), - .data = si2, - }, { - .type = RSL_SYSTEM_INFO_3, - .len = sizeof(si3), - .data = si3, - }, { - .type = RSL_SYSTEM_INFO_4, - .len = sizeof(si4), - .data = si4, - }, -}; - -static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1) -static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2) -static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3) -static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4) -static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5) -static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6) - /* set all system information types */ static int set_system_infos(struct gsm_bts_trx *trx) { - int i; + int i, rc; + u_int8_t si_tmp[23]; if (trx == trx->bts->c0) { - for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) { - rsl_bcch_info(trx, bcch_infos[i].type, - bcch_infos[i].data, - bcch_infos[i].len); + for (i = 1; i <= 4; i++) { + rc = gsm_generate_si(si_tmp, trx->bts, i); + if (rc < 0) + goto err_out; + rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } } - rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5)); - rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6)); +#ifdef GPRS + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); + if (rc < 0) + goto err_out; + rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); +#endif + rc = gsm_generate_si(si_tmp, trx->bts, 5); + if (rc < 0) + goto err_out; + rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si_tmp, rc); + + rc = gsm_generate_si(si_tmp, trx->bts, 6); + if (rc < 0) + goto err_out; + rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc); return 0; +err_out: + fprintf(stderr, "Cannot generate SI for BTS %u, most likely " + "a problem with neighbor cell list generation\n", + trx->bts->nr); + return rc; } /* @@ -913,81 +736,12 @@ static void patch_nm_tables(struct gsm_bts *bts) nanobts_attr_radio[1] = bts->c0->max_power_red / 2; } -/* - * Patch the various SYSTEM INFORMATION tables to update - * the LAI - */ -static void patch_si_tables(struct gsm_bts *bts) -{ - u_int8_t arfcn_low = bts->c0->arfcn & 0xff; - u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f; - - /* covert the raw packet to the struct */ - struct gsm48_system_information_type_1 *type_1 = - (struct gsm48_system_information_type_1*)&si1; - struct gsm48_system_information_type_2 *type_2 = - (struct gsm48_system_information_type_2*)&si2; - struct gsm48_system_information_type_3 *type_3 = - (struct gsm48_system_information_type_3*)&si3; - struct gsm48_system_information_type_4 *type_4 = - (struct gsm48_system_information_type_4*)&si4; - struct gsm48_system_information_type_6 *type_6 = - (struct gsm48_system_information_type_6*)&si6; - struct gsm48_loc_area_id lai; - - gsm0408_generate_lai(&lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); - - /* assign the MCC and MNC */ - type_3->lai = lai; - type_4->lai = lai; - type_6->lai = lai; - - /* set the CI */ - type_3->cell_identity = htons(bts->cell_identity); - type_6->cell_identity = htons(bts->cell_identity); - - type_4->data[2] &= 0xf0; - type_4->data[2] |= arfcn_high; - type_4->data[3] = arfcn_low; - - /* patch Control Channel Description 10.5.2.11 */ - type_3->control_channel_desc = bts->chan_desc; - - /* patch TSC */ - si4[15] &= ~0xe0; - si4[15] |= (bts->tsc & 7) << 5; - - /* patch MS max power for CCH */ - type_4->cell_sel_par.ms_txpwr_max_ccch = - ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); - - /* Set NECI to influence channel request */ - type_3->cell_sel_par.neci = bts->network->neci; - type_4->cell_sel_par.neci = bts->network->neci; - - if (bts->cell_barred) { - type_1->rach_control.cell_bar = 1; - type_2->rach_control.cell_bar = 1; - type_3->rach_control.cell_bar = 1; - type_4->rach_control.cell_bar = 1; - } else { - type_1->rach_control.cell_bar = 0; - type_2->rach_control.cell_bar = 0; - type_3->rach_control.cell_bar = 0; - type_4->rach_control.cell_bar = 0; - } -} - - static void bootstrap_rsl(struct gsm_bts_trx *trx) { fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", trx->bts->nr, trx->nr, bsc_gsmnet->country_code, bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc); - patch_si_tables(trx->bts); set_system_infos(trx); } @@ -1042,11 +796,32 @@ static int bootstrap_bts(struct gsm_bts *bts) } /* Control Channel Description */ - bts->chan_desc.att = 1; - bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; - bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; + bts->si_common.chan_desc.att = 1; + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; + bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; + if (bts->cell_barred) + bts->si_common.rach_control.cell_bar = 1; /* T3212 is set from vty/config */ + /* some defaults for our system information */ + bts->si_common.rach_control.re = 1; /* no re-establishment */ + bts->si_common.rach_control.tx_integer = 5; /* 8 slots spread */ + bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */ + bts->si_common.rach_control.t2 = 4; /* no emergency calls */ + + bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */ + bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */ + bts->si_common.cell_options.pwrc = 0; /* PWRC not set */ + + bts->si_common.cell_sel_par.ms_txpwr_max_ccch = + ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); + bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ + bts->si_common.cell_sel_par.rxlev_acc_min = 0; + bts->si_common.cell_sel_par.acs = 0; + bts->si_common.cell_sel_par.neci = bts->network->neci; + + bts->si_common.ncc_permitted = 0xff; + paging_init(bts); return 0; diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index fe6ea52d1..b273419c3 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -55,7 +55,7 @@ static unsigned int calculate_group(struct gsm_bts *bts, struct gsm_subscriber * int blocks; unsigned int group; - ccch_conf = bts->chan_desc.ccch_conf; + ccch_conf = bts->si_common.chan_desc.ccch_conf; bs_cc_chans = rsl_ccch_conf_to_bs_cc_chans(ccch_conf); /* code word + 2, as 2 channels equals 0x0 */ blocks = rsl_number_of_paging_subchannels(bts); diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c new file mode 100644 index 000000000..6efd47515 --- /dev/null +++ b/openbsc/src/rest_octets.c @@ -0,0 +1,393 @@ +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface, + * rest octet handling according to + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (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 + +/* generate SI1 rest octets */ +int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 2; + + if (nch_pos) { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, *nch_pos, 5); + } else + bitvec_set_bit(&bv, L); + + bitvec_spare_padding(&bv, 15); + return 0; +} + +/* Append selection parameters to bitvec */ +static void append_selection_params(struct bitvec *bv, + const struct gsm48_si_selection_params *sp) +{ + if (sp->present) { + bitvec_set_bit(bv, H); + bitvec_set_bit(bv, sp->cbq); + bitvec_set_uint(bv, sp->cell_resel_off, 6); + bitvec_set_uint(bv, sp->temp_offs, 3); + bitvec_set_uint(bv, sp->penalty_time, 5); + } else + bitvec_set_bit(bv, L); +} + +/* Append power offset to bitvec */ +static void append_power_offset(struct bitvec *bv, + const struct gsm48_si_power_offset *po) +{ + if (po->present) { + bitvec_set_bit(bv, H); + bitvec_set_uint(bv, po->power_offset, 2); + } else + bitvec_set_bit(bv, L); +} + +/* Append GPRS indicator to bitvec */ +static void append_gprs_ind(struct bitvec *bv, + const struct gsm48_si3_gprs_ind *gi) +{ + if (gi->present) { + bitvec_set_bit(bv, H); + bitvec_set_uint(bv, gi->ra_colour, 3); + /* 0 == SI13 in BCCH Norm, 1 == SI13 sent on BCCH Ext */ + bitvec_set_bit(bv, gi->si13_position); + } else + bitvec_set_bit(bv, L); +} + + +/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */ +int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 5; + + /* Optional Selection Parameters */ + append_selection_params(&bv, &si3->selection_params); + + /* Optional Power Offset */ + append_power_offset(&bv, &si3->power_offset); + + /* Do we have a SI2ter on the BCCH? */ + if (si3->si2ter_indicator) + bitvec_set_bit(&bv, H); + else + bitvec_set_bit(&bv, L); + + /* Early Classmark Sending Control */ + if (si3->early_cm_ctrl) + bitvec_set_bit(&bv, H); + else + bitvec_set_bit(&bv, L); + + /* Do we have a SI Type 9 on the BCCH? */ + if (si3->scheduling.present) { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, si3->scheduling.where, 3); + } else + bitvec_set_bit(&bv, L); + + /* GPRS Indicator */ + append_gprs_ind(&bv, &si3->gprs_ind); + + return bitvec_spare_padding(&bv, (bv.data_len*8)-1); +} + +static int append_lsa_params(struct bitvec *bv, + const struct gsm48_lsa_params *lsa_params) +{ + /* FIXME */ +} + +/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */ +int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 11; /* FIXME: up to ? */ + + /* SI4 Rest Octets O */ + append_selection_params(&bv, &si4->selection_params); + append_power_offset(&bv, &si4->power_offset); + append_gprs_ind(&bv, &si4->gprs_ind); + + if (0 /* FIXME */) { + /* H and SI4 Rest Octets S */ + bitvec_set_bit(&bv, H); + + /* LSA Parameters */ + if (si4->lsa_params.present) { + bitvec_set_bit(&bv, H); + append_lsa_params(&bv, &si4->lsa_params); + } else + bitvec_set_bit(&bv, L); + + /* Cell Identity */ + if (1) { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, si4->cell_id, 16); + } else + bitvec_set_bit(&bv, L); + + /* LSA ID Information */ + if (0) { + bitvec_set_bit(&bv, H); + /* FIXME */ + } else + bitvec_set_bit(&bv, L); + } else { + /* L and break indicator */ + bitvec_set_bit(&bv, L); + bitvec_set_bit(&bv, si4->break_ind ? H : L); + } + + return 0; +} + +/* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a: + < GPRS Mobile Allocation IE > ::= + < HSN : bit (6) > + { 0 | 1 < RFL number list : < RFL number list struct > > } + { 0 < MA_LENGTH : bit (6) > + < MA_BITMAP: bit (val(MA_LENGTH) + 1) > + | 1 { 0 | 1 > } } ; + + < RFL number list struct > :: = + < RFL_NUMBER : bit (4) > + { 0 | 1 < RFL number list struct > } ; + < ARFCN index list struct > ::= + < ARFCN_INDEX : bit(6) > + { 0 | 1 < ARFCN index list struct > } ; + */ +static int append_gprs_mobile_alloc(struct bitvec *bv) +{ + /* Hopping Sequence Number */ + bitvec_set_uint(bv, 0, 6); + + if (0) { + /* We want to use a RFL number list */ + bitvec_set_bit(bv, 1); + /* FIXME: RFL number list */ + } else + bitvec_set_bit(bv, 0); + + if (0) { + /* We want to use a MA_BITMAP */ + bitvec_set_bit(bv, 0); + /* FIXME: MA_LENGTH, MA_BITMAP, ... */ + } else { + bitvec_set_bit(bv, 1); + if (0) { + /* We want to provide an ARFCN index list */ + bitvec_set_bit(bv, 1); + /* FIXME */ + } else + bitvec_set_bit(bv, 0); + } + return 0; +} + +static int encode_t3192(unsigned int t3192) +{ + if (t3192 == 0) + return 3; + else if (t3192 <= 80) + return 4; + else if (t3192 <= 120) + return 5; + else if (t3192 <= 160) + return 6; + else if (t3192 <= 200) + return 7; + else if (t3192 <= 500) + return 0; + else if (t3192 <= 1000) + return 1; + else if (t3192 <= 1500) + return 2; + else + return -EINVAL; +} + +static int encode_drx_timer(unsigned int drx) +{ + if (drx == 0) + return 0; + else if (drx == 1) + return 1; + else if (drx == 2) + return 2; + else if (drx <= 4) + return 3; + else if (drx <= 8) + return 4; + else if (drx <= 16) + return 5; + else if (drx <= 32) + return 6; + else if (drx <= 64) + return 7; + else + return -EINVAL; +} + +/* GPRS Cell Options as per TS 04.60 Chapter 12.24 + < GPRS Cell Options IE > ::= + < NMO : bit(2) > + < T3168 : bit(3) > + < T3192 : bit(3) > + < DRX_TIMER_MAX: bit(3) > + < ACCESS_BURST_TYPE: bit > + < CONTROL_ACK_TYPE : bit > + < BS_CV_MAX: bit(4) > + { 0 | 1 < PAN_DEC : bit(3) > + < PAN_INC : bit(3) > + < PAN_MAX : bit(3) > + { 0 | 1 < Extension Length : bit(6) > + < bit (val(Extension Length) + 1 + & { < Extension Information > ! { bit ** = } } ; + < Extension Information > ::= + { 0 | 1 < EGPRS_PACKET_CHANNEL_REQUEST : bit > + < BEP_PERIOD : bit(4) > } + < PFC_FEATURE_MODE : bit > + < DTM_SUPPORT : bit > + + ** ; + */ +static int append_gprs_cell_opt(struct bitvec *bv, struct gprs_cell_options *gco) +{ + int t3192, drx_timer_max; + + t3192 = encode_t3192(gco->t3192); + if (t3192 < 0) + return t3192; + + drx_timer_max = encode_drx_timer(gco->drx_timer_max); + if (drx_timer_max < 0) + return drx_timer_max; + + bitvec_set_uint(bv, gco->nmo, 2); + bitvec_set_uint(bv, gco->t3168 / 500, 3); + bitvec_set_uint(bv, t3192, 3); + bitvec_set_uint(bv, drx_timer_max, 3); + /* ACCESS_BURST_TYPE: Hard-code 8bit */ + bitvec_set_bit(bv, 0); + /* CONTROL_ACK_TYPE: Hard-code to RLC/MAC control block */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, gco->bs_cv_max, 4); + + /* hard-code no PAN_{DEC,INC,MAX} */ + bitvec_set_bit(bv, 0); + + /* no extension information (EDGE) */ + bitvec_set_bit(bv, 0); + + return 0; +} + +static void append_gprs_pwr_ctrl_pars(struct bitvec *bv, + struct gprs_power_ctrl_pars *pcp) +{ + bitvec_set_uint(bv, pcp->alpha, 4); + bitvec_set_uint(bv, pcp->t_avg_w, 5); + bitvec_set_uint(bv, pcp->t_avg_t, 5); + bitvec_set_uint(bv, pcp->pc_meas_chan, 1); + bitvec_set_uint(bv, pcp->n_avg_i, 4); +} + +/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */ +int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 21; + + if (0) { + /* No rest octets */ + bitvec_set_bit(&bv, L); + } else { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, si13->bcch_change_mark, 3); + bitvec_set_uint(&bv, si13->si_change_field, 4); + if (0) { + bitvec_set_bit(&bv, 0); + } else { + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->bcch_change_mark, 2); + append_gprs_mobile_alloc(&bv); + } + if (!si13->pbcch_present) { + /* PBCCH not present in cell */ + bitvec_set_bit(&bv, 0); + bitvec_set_uint(&bv, si13->no_pbcch.rac, 8); + bitvec_set_bit(&bv, si13->no_pbcch.spgc_ccch_sup); + bitvec_set_uint(&bv, si13->no_pbcch.prio_acc_thr, 3); + bitvec_set_uint(&bv, si13->no_pbcch.net_ctrl_ord, 2); + append_gprs_cell_opt(&bv, &si13->cell_opts); + append_gprs_pwr_ctrl_pars(&bv, &si13->pwr_ctrl_pars); + } else { + /* PBCCH present in cell */ + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->pbcch.psi1_rep_per, 4); + /* PBCCH Descripiton */ + bitvec_set_uint(&bv, si13->pbcch.pb, 4); + bitvec_set_uint(&bv, si13->pbcch.tsc, 3); + bitvec_set_uint(&bv, si13->pbcch.tn, 3); + switch (si13->pbcch.carrier_type) { + case PBCCH_BCCH: + bitvec_set_bit(&bv, 0); + bitvec_set_bit(&bv, 0); + break; + case PBCCH_ARFCN: + bitvec_set_bit(&bv, 0); + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->pbcch.arfcn, 10); + break; + case PBCCH_MAIO: + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->pbcch.maio, 6); + break; + } + } + } + return bitvec_spare_padding(&bv, (bv.data_len*8)-1); +} diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c new file mode 100644 index 000000000..d6d166c79 --- /dev/null +++ b/openbsc/src/system_information.c @@ -0,0 +1,427 @@ +/* GSM 04.08 System Information (SI) encoding and decoding + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2008-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 + +#define GSM48_CELL_CHAN_DESC_SIZE 16 +#define GSM_MACBLOCK_LEN 23 +#define GSM_MACBLOCK_PADDING 0x2b + +static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +{ + unsigned int byte, bit; + + if (arfcn > 124) + return -EINVAL; + + byte = arfcn / 8; + bit = arfcn % 8; + + chan_list[GSM48_CELL_CHAN_DESC_SIZE-byte] |= (1 << bit); + + return 0; +} + +static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +{ + unsigned int byte, bit; + unsigned int min_arfcn; + unsigned int bitno; + + min_arfcn = (chan_list[0] & 1) << 9; + min_arfcn |= chan_list[1] << 1; + min_arfcn |= (chan_list[2] >> 7) & 1; + + /* The lower end of our bitmaks is always implicitly included */ + if (arfcn == min_arfcn) + return 0; + + if (arfcn < min_arfcn) + return -EINVAL; + if (arfcn > min_arfcn + 111) + return -EINVAL; + + bitno = (arfcn - min_arfcn); + byte = bitno / 8; + bit = bitno % 8; + + chan_list[2 + byte] |= 1 << (7 - bit); + + return 0; +} + +/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ +static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; + int rc, min = 1024, max = 0; + + memset(chan_list, 0, 16); + + /* GSM900-only handsets only support 'bit map 0 format' */ + if (bts->band == GSM_BAND_900) { + chan_list[0] = 0; + llist_for_each_entry(trx, &bts->trx_list, list) { + rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + return 0; + } + + /* We currently only support the 'Variable bitmap format' */ + chan_list[0] = 0x8e; + + llist_for_each_entry(trx, &bts->trx_list, list) { + if (trx->arfcn < min) + min = trx->arfcn; + if (trx->arfcn > max) + max = trx->arfcn; + } + + if ((max - min) > 111) + return -EINVAL; + + chan_list[0] |= (min >> 9) & 1; + chan_list[1] = (min >> 1); + chan_list[2] = (min & 1) << 7; + + llist_for_each_entry(trx, &bts->trx_list, list) { + rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + + return 0; +} + +/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ +static int generate_bcch_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +{ + struct gsm_bts *cur_bts; + struct gsm_bts_trx *trx; + int rc, min = 1024, max = 0; + + memset(chan_list, 0, 16); + + /* GSM900-only handsets only support 'bit map 0 format' */ + if (bts->band == GSM_BAND_900) { + chan_list[0] = 0; + llist_for_each_entry(cur_bts, &bts->list, list) { + trx = cur_bts->c0; + rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + return 0; + } + + /* We currently only support the 'Variable bitmap format' */ + chan_list[0] = 0x8e; + + llist_for_each_entry(cur_bts, &bts->list, list) { + if (&cur_bts->list == &bts->network->bts_list) + continue; + trx = cur_bts->c0; + if (trx->arfcn < min) + min = trx->arfcn; + if (trx->arfcn > max) + max = trx->arfcn; + } + + if ((max - min) > 111) + return -EINVAL; + + chan_list[0] |= (min >> 9) & 1; + chan_list[1] = (min >> 1); + chan_list[2] = (min & 1) << 7; + + llist_for_each_entry(cur_bts, &bts->list, list) { + if (&cur_bts->list == &bts->network->bts_list) + continue; + trx = cur_bts->c0; + rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + + return 0; +} + +static int generate_si1(u_int8_t *output, const struct gsm_bts *bts) +{ + int rc; + struct gsm48_system_information_type_1 *si1 = + (struct gsm48_system_information_type_1 *) output; + + memset(si1, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si1->header.l2_plen = (21 << 2) | 1; + si1->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si1->header.skip_indicator = 0; + si1->header.system_information = GSM48_MT_RR_SYSINFO_1; + + rc = generate_cell_chan_list(si1->cell_channel_description, bts); + if (rc < 0) + return rc; + + si1->rach_control = bts->si_common.rach_control; + + /* SI1 Rest Octets (10.5.2.32), contains NCH position */ + rest_octets_si1(si1->rest_octets, NULL); + + return GSM_MACBLOCK_LEN; +} + +static int generate_si2(u_int8_t *output, const struct gsm_bts *bts) +{ + int rc; + struct gsm48_system_information_type_2 *si2 = + (struct gsm48_system_information_type_2 *) output; + + memset(si2, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si2->header.l2_plen = (22 << 2) | 1; + si2->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si2->header.skip_indicator = 0; + si2->header.system_information = GSM48_MT_RR_SYSINFO_2; + + rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts); + if (rc < 0) + return rc; + + si2->ncc_permitted = bts->si_common.ncc_permitted; + si2->rach_control = bts->si_common.rach_control; + + return GSM_MACBLOCK_LEN; +} + +struct gsm48_si_ro_info si_info = { + .selection_params = { + .present = 0, + }, + .power_offset = { + .present = 0, + }, + .si2ter_indicator = 0, + .early_cm_ctrl = 1, + .scheduling = { + .present = 0, + }, + .gprs_ind = { + .si13_position = 0, + .ra_colour = 0, + .present = 0, + }, + .lsa_params = { + .present = 0, + }, + .cell_id = 0, /* FIXME: doesn't the bts have this? */ + .break_ind = 0, +}; + +static int generate_si3(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_3 *si3 = + (struct gsm48_system_information_type_3 *) output; + + memset(si3, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si3->header.l2_plen = (18 << 2) | 1; + si3->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si3->header.skip_indicator = 0; + si3->header.system_information = GSM48_MT_RR_SYSINFO_3; + + si3->cell_identity = htons(bts->cell_identity); + gsm0408_generate_lai(&si3->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); + si3->control_channel_desc = bts->si_common.chan_desc; + si3->cell_options = bts->si_common.cell_options; + si3->cell_sel_par = bts->si_common.cell_sel_par; + si3->rach_control = bts->si_common.rach_control; + + /* SI3 Rest Octets (10.5.2.34), containing + CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME + Power Offset, 2ter Indicator, Early Classmark Sending, + Scheduling if and WHERE, GPRS Indicator, SI13 position */ + rest_octets_si3(si3->rest_octets, &si_info); + + return GSM_MACBLOCK_LEN; +} + +static int generate_si4(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_4 *si4 = + (struct gsm48_system_information_type_4 *) output; + + /* length of all IEs present except SI4 rest octets and l2_plen */ + int l2_plen = sizeof(*si4) - 1; + + memset(si4, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si4->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si4->header.skip_indicator = 0; + si4->header.system_information = GSM48_MT_RR_SYSINFO_4; + + gsm0408_generate_lai(&si4->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); + si4->cell_sel_par = bts->si_common.cell_sel_par; + si4->rach_control = bts->si_common.rach_control; + + /* Optional: CBCH Channel Description + CBCH Mobile Allocation */ + + si4->header.l2_plen = (l2_plen << 2) | 1; + + /* SI4 Rest Octets (10.5.2.35), containing + Optional Power offset, GPRS Indicator, + Cell Identity, LSA ID, Selection Parameter */ + rest_octets_si4(si4->data, &si_info); + + return GSM_MACBLOCK_LEN; +} + +static int generate_si5(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_5 *si5 = + (struct gsm48_system_information_type_5 *) output; + int rc; + + memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + /* l2 pseudo length, not part of msg: 18 */ + si5->rr_protocol_discriminator = GSM48_PDISC_RR; + si5->skip_indicator = 0; + si5->system_information = GSM48_MT_RR_SYSINFO_5; + rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts); + if (rc < 0) + return rc; + + /* 04.08 9.1.37: L2 Pseudo Length of 18 */ + return 18; +} + +static int generate_si6(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_6 *si6 = + (struct gsm48_system_information_type_6 *) output; + + memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + /* l2 pseudo length, not part of msg: 11 */ + si6->rr_protocol_discriminator = GSM48_PDISC_RR; + si6->skip_indicator = 0; + si6->system_information = GSM48_MT_RR_SYSINFO_6; + si6->cell_identity = htons(bts->cell_identity); + gsm0408_generate_lai(&si6->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); + si6->cell_options = bts->si_common.cell_options; + si6->ncc_permitted = bts->si_common.ncc_permitted; + + /* SI6 Rest Octets: 10.5.2.35a: PCH / NCH info, VBS/VGCS options */ + + return 18; +} + +static struct gsm48_si13_info si13_default = { + .cell_opts = { + .nmo = GPRS_NMO_III, + .t3168 = 1000, + .t3192 = 1000, + .drx_timer_max = 1, + .bs_cv_max = 15, + }, + .pwr_ctrl_pars = { + .alpha = 10, /* a = 1.0 */ + .t_avg_w = 25, + .t_avg_t = 25, + .pc_meas_chan = 0, /* downling measured on CCCH */ + .n_avg_i = 15, + }, + .bcch_change_mark = 0, + .si_change_field = 0, + .pbcch_present = 0, + { + .no_pbcch = { + .rac = 0, + .spgc_ccch_sup = 0, + .net_ctrl_ord = 0, + .prio_acc_thr = 0, + }, + }, +}; + +static int generate_si13(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_13 *si13 = + (struct gsm48_system_information_type_13 *) output; + int ret; + + memset(si13, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si13->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si13->header.skip_indicator = 0; + si13->header.system_information = GSM48_MT_RR_SYSINFO_13; + + ret = rest_octets_si13(si13->rest_octets, &si13_default); + if (ret < 0) + return ret; + + si13->header.l2_plen = ret & 0xff; + + return GSM_MACBLOCK_LEN; +} + +int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type) +{ + switch (type) { + case RSL_SYSTEM_INFO_1: + return generate_si1(output, bts); + case RSL_SYSTEM_INFO_2: + return generate_si2(output, bts); + case RSL_SYSTEM_INFO_3: + return generate_si3(output, bts); + case RSL_SYSTEM_INFO_4: + return generate_si4(output, bts); + case RSL_SYSTEM_INFO_5: + return generate_si5(output, bts); + case RSL_SYSTEM_INFO_6: + return generate_si6(output, bts); + case RSL_SYSTEM_INFO_13: + return generate_si13(output, bts); + default: + return -EINVAL; + } + + return 0; +} diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 066dfd5a9..3b150b2ea 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -234,9 +234,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE); vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE); vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE); - if (bts->chan_desc.t3212) + if (bts->si_common.chan_desc.t3212) vty_out(vty, " periodic location update %u%s", - bts->chan_desc.t3212 * 10, VTY_NEWLINE); + bts->si_common.chan_desc.t3212 * 10, VTY_NEWLINE); vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); @@ -951,6 +951,7 @@ DEFUN(cfg_bts_lac, return CMD_SUCCESS; } + DEFUN(cfg_bts_tsc, cfg_bts_tsc_cmd, "training_sequence_code <0-255>", @@ -1094,7 +1095,7 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, { struct gsm_bts *bts = vty->index; - bts->chan_desc.t3212 = atoi(argv[0]) / 10; + bts->si_common.chan_desc.t3212 = atoi(argv[0]) / 10; return CMD_SUCCESS; } From 2c828991352f94c1be7d860d0d151f719c1ecc6f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 2 Dec 2009 01:56:49 +0530 Subject: [PATCH 035/365] move RTP socket information from timeslot to lchan With ip.access, in case of TCH/H, we have one RTP stream for each half-slot (lchan), not just one per on-air timeslot. This is quite different from a classic BTS where the TRAU frames of the two TCH/H channels would be part of the same 16k sub-slot in a E1 timeslot. --- openbsc/include/openbsc/gsm_data.h | 15 ++++---- openbsc/src/abis_rsl.c | 12 +++---- openbsc/src/gsm_04_08.c | 55 +++++++++++++----------------- openbsc/src/vty_interface.c | 19 +++++------ 4 files changed, 47 insertions(+), 54 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index fcd623fe6..bd7b79b27 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -185,6 +185,14 @@ struct gsm_lchan { /* use count. how many users use this channel */ unsigned int use_count; + + struct { + u_int32_t bound_ip; + u_int16_t bound_port; + u_int8_t rtp_payload2; + u_int16_t conn_id; + struct rtp_socket *rtp_socket; + } abis_ip; }; struct gsm_e1_subslot { @@ -212,13 +220,6 @@ struct gsm_bts_trx_ts { /* To which E1 subslot are we connected */ struct gsm_e1_subslot e1_link; - struct { - u_int32_t bound_ip; - u_int16_t bound_port; - u_int8_t rtp_payload2; - u_int16_t conn_id; - struct rtp_socket *rtp_socket; - } abis_ip; struct gsm_lchan lchan[TS_MAX_LCHAN]; }; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 1d41d2b5d..e7be9baa4 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1555,7 +1555,7 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; - struct gsm_bts_trx_ts *ts = msg->lchan->ts; + struct gsm_lchan *lchan = msg->lchan; struct in_addr ip; u_int16_t port, attr_f8; @@ -1578,16 +1578,16 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) inet_ntoa(ip), ntohs(port), ntohs(attr_f8)); if (TLVP_PRESENT(&tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { - ts->abis_ip.rtp_payload2 = + lchan->abis_ip.rtp_payload2 = *TLVP_VAL(&tv, RSL_IE_IPAC_RTP_PAYLOAD2); DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", - ts->abis_ip.rtp_payload2); + lchan->abis_ip.rtp_payload2); } /* update our local information about this TS */ - ts->abis_ip.bound_ip = ntohl(ip.s_addr); - ts->abis_ip.bound_port = ntohs(port); - ts->abis_ip.conn_id = ntohs(attr_f8); + lchan->abis_ip.bound_ip = ntohl(ip.s_addr); + lchan->abis_ip.bound_port = ntohs(port); + lchan->abis_ip.conn_id = ntohs(attr_f8); dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index e225bf3a1..f262dbebf 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1844,7 +1844,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct gsm_lchan *lchan = signal_data; - struct gsm_bts_trx_ts *ts; int rc; if (subsys != SS_ABISIP) @@ -1854,32 +1853,30 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, if (ipacc_rtp_direct) return 0; - ts = lchan->ts; - switch (signal) { case S_ABISIP_CRCX_ACK: /* the BTS has successfully bound a TCH to a local ip/port, * which means we can connect our UDP socket to it */ - if (ts->abis_ip.rtp_socket) { - rtp_socket_free(ts->abis_ip.rtp_socket); - ts->abis_ip.rtp_socket = NULL; + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; } - ts->abis_ip.rtp_socket = rtp_socket_create(); - if (!ts->abis_ip.rtp_socket) + lchan->abis_ip.rtp_socket = rtp_socket_create(); + if (!lchan->abis_ip.rtp_socket) goto out_err; - rc = rtp_socket_connect(ts->abis_ip.rtp_socket, - ts->abis_ip.bound_ip, - ts->abis_ip.bound_port); + rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, + lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port); if (rc < 0) goto out_err; break; case S_ABISIP_DLCX_IND: /* the BTS tells us a RTP stream has been disconnected */ - if (ts->abis_ip.rtp_socket) { - rtp_socket_free(ts->abis_ip.rtp_socket); - ts->abis_ip.rtp_socket = NULL; + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; } break; } @@ -1893,15 +1890,14 @@ out_err: /* bind rtp proxy to local IP/port and tell BTS to connect to it */ static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) { - struct gsm_bts_trx_ts *ts = lchan->ts; - struct rtp_socket *rs = ts->abis_ip.rtp_socket; + struct rtp_socket *rs = lchan->abis_ip.rtp_socket; int rc; rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), ntohs(rs->rtp.sin_local.sin_port), - ts->abis_ip.conn_id, + lchan->abis_ip.conn_id, /* FIXME: use RTP payload of bound socket, not BTS*/ - ts->abis_ip.rtp_payload2); + lchan->abis_ip.rtp_payload2); return rc; } @@ -1911,7 +1907,6 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) { struct gsm_bts *bts = lchan->ts->trx->bts; struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts; - struct gsm_bts_trx_ts *ts; int rc; DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n", @@ -1933,22 +1928,20 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) rc = ipacc_connect_proxy_bind(remote_lchan); /* connect them with each other */ - rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket, - remote_lchan->ts->abis_ip.rtp_socket); + rtp_socket_proxy(lchan->abis_ip.rtp_socket, + remote_lchan->abis_ip.rtp_socket); } else { /* directly connect TCH RTP streams to each other */ - ts = remote_lchan->ts; - rc = rsl_ipacc_mdcx(lchan, ts->abis_ip.bound_ip, - ts->abis_ip.bound_port, - lchan->ts->abis_ip.conn_id, - ts->abis_ip.rtp_payload2); + rc = rsl_ipacc_mdcx(lchan, remote_lchan->abis_ip.bound_ip, + remote_lchan->abis_ip.bound_port, + lchan->abis_ip.conn_id, + remote_lchan->abis_ip.rtp_payload2); if (rc < 0) return rc; - ts = lchan->ts; - rc = rsl_ipacc_mdcx(remote_lchan, ts->abis_ip.bound_ip, - ts->abis_ip.bound_port, - remote_lchan->ts->abis_ip.conn_id, - ts->abis_ip.rtp_payload2); + rc = rsl_ipacc_mdcx(remote_lchan, lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port, + remote_lchan->abis_ip.conn_id, + lchan->abis_ip.rtp_payload2); } break; case GSM_BTS_TYPE_BS11: diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 3b150b2ea..39fc41429 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -365,24 +365,15 @@ DEFUN(show_trx, static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts) { - struct in_addr ia; - vty_out(vty, "Timeslot %u of TRX %u in BTS %u, phys cfg %s%s", ts->nr, ts->trx->nr, ts->trx->bts->nr, gsm_pchan_name(ts->pchan), VTY_NEWLINE); vty_out(vty, " NM State: "); net_dump_nmstate(vty, &ts->nm_state); - if (is_ipaccess_bts(ts->trx->bts)) { - ia.s_addr = ts->abis_ip.bound_ip; - vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s", - inet_ntoa(ia), ts->abis_ip.bound_port, - ts->abis_ip.rtp_payload2, ts->abis_ip.conn_id, - VTY_NEWLINE); - } else { + if (!is_ipaccess_bts(ts->trx->bts)) vty_out(vty, " E1 Line %u, Timeslot %u, Subslot %u%s", ts->e1_link.e1_nr, ts->e1_link.e1_ts, ts->e1_link.e1_ts_ss, VTY_NEWLINE); - } } DEFUN(show_ts, @@ -471,6 +462,14 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) subscr_dump_vty(vty, lchan->subscr); } else vty_out(vty, " No Subscriber%s", VTY_NEWLINE); + if (is_ipaccess_bts(lchan->ts->trx->bts)) { + struct in_addr ia; + ia.s_addr = lchan->abis_ip.bound_ip; + vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s", + inet_ntoa(ia), lchan->abis_ip.bound_port, + lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id, + VTY_NEWLINE); + } } #if 0 From 0603c9d9e58b5d29105361a89ab8cb295da29366 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 2 Dec 2009 01:58:23 +0530 Subject: [PATCH 036/365] ip.access speech mode for TCH/H channels --- openbsc/src/abis_rsl.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index e7be9baa4..8a4ed9b76 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1442,19 +1442,40 @@ static int abis_rsl_rx_rll(struct msgb *msg) return rc; } -static u_int8_t ipa_smod_s_for_tch_mode(u_int8_t tch_mode) +static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) { - switch (tch_mode) { + switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_V1: - return 0x00; + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return 0x00; + case GSM_LCHAN_TCH_H: + return 0x03; + default: + break; + } case GSM48_CMODE_SPEECH_EFR: - return 0x01; + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return 0x01; + /* there's no half-rate EFR */ + default: + break; + } case GSM48_CMODE_SPEECH_AMR: - return 0x02; - /* FIXME: Type1 half-rate and type3 half-rate */ + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return 0x02; + case GSM_LCHAN_TCH_H: + return 0x05; + default: + break; + } + default: + break; } DEBUGPC(DRSL, "Cannot determine ip.access speech mode for " - "tch_mode == 0x%02x\n", tch_mode); + "tch_mode == 0x%02x\n", lchan->tch_mode); return 0; } @@ -1471,7 +1492,7 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) dh->chan_nr = lchan2chan_nr(lchan); /* 0x1- == receive-only, 0x-1 == EFR codec */ - speech_mode = 0x10 | ipa_smod_s_for_tch_mode(lchan->tch_mode); + speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND " @@ -1498,7 +1519,7 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, dh->chan_nr = lchan2chan_nr(lchan); /* 0x0- == both directions, 0x-1 == EFR codec */ - speech_mode = 0x00 | ipa_smod_s_for_tch_mode(lchan->tch_mode); + speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); ia.s_addr = htonl(ip); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_MDCX " From d6575f9d29ff279ab843333a88c43a5ce40888b9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 2 Dec 2009 02:45:23 +0530 Subject: [PATCH 037/365] ip.access: add nanoBTS channel combination constraints --- openbsc/src/abis_nm.c | 80 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index b1fe97ddf..30b3ec632 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1755,7 +1755,8 @@ static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) /* As it turns out, the BS-11 has some very peculiar restrictions * on the channel combinations it allows */ - if (ts->trx->bts->type == GSM_BTS_TYPE_BS11) { + switch (ts->trx->bts->type) { + case GSM_BTS_TYPE_BS11: switch (chan_comb) { case NM_CHANC_TCHHalf: case NM_CHANC_TCHHalf2: @@ -1801,6 +1802,83 @@ static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) /* FIXME: only one CBCH allowed per cell */ break; } + break; + case GSM_BTS_TYPE_NANOBTS: + switch (ts->nr) { + case 0: + if (ts->trx->nr == 0) { + /* only on TRX0 */ + switch (chan_comb) { + case NM_CHANC_BCCH: + case NM_CHANC_mainBCCH: + case NM_CHANC_BCCHComb: + return 0; + break; + default: + return -EINVAL; + } + } else { + switch (chan_comb) { + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + return 0; + default: + return -EINVAL; + } + } + break; + case 1: + if (ts->trx->nr == 0) { + switch (chan_comb) { + case NM_CHANC_SDCCH_CBCH: + if (ts->trx->ts[0].nm_chan_comb == + NM_CHANC_mainBCCH) + return 0; + return -EINVAL; + case NM_CHANC_SDCCH: + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + case NM_CHANC_IPAC_TCHFull_PDCH: + return 0; + } + } else { + switch (chan_comb) { + case NM_CHANC_SDCCH: + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + return 0; + default: + return -EINVAL; + } + } + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + switch (chan_comb) { + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + return 0; + case NM_CHANC_IPAC_PDCH: + case NM_CHANC_IPAC_TCHFull_PDCH: + if (ts->trx->nr == 0) + return 0; + else + return -EINVAL; + } + break; + } + return -EINVAL; + default: + /* unknown BTS type */ + return 0; } return 0; } From 1dfd0e254acdb44b150c53c1dd029ce25780f2f2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 4 Dec 2009 11:23:12 +0530 Subject: [PATCH 038/365] [BS11] don't put invalid channel combination into the config file --- openbsc/src/openbsc.cfg.1-1 | 2 +- openbsc/src/openbsc.cfg.2-2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/openbsc.cfg.1-1 b/openbsc/src/openbsc.cfg.1-1 index d312843b0..a25804f63 100644 --- a/openbsc/src/openbsc.cfg.1-1 +++ b/openbsc/src/openbsc.cfg.1-1 @@ -31,7 +31,7 @@ network phys_chan_config CCCH+SDCCH4 e1 line 0 timeslot 1 sub-slot full timeslot 1 - phys_chan_config SDCCH8 + phys_chan_config TCH/F e1 line 0 timeslot 2 sub-slot 1 timeslot 2 phys_chan_config TCH/F diff --git a/openbsc/src/openbsc.cfg.2-2 b/openbsc/src/openbsc.cfg.2-2 index c1468a647..9ae800342 100644 --- a/openbsc/src/openbsc.cfg.2-2 +++ b/openbsc/src/openbsc.cfg.2-2 @@ -31,7 +31,7 @@ network phys_chan_config CCCH+SDCCH4 e1 line 0 timeslot 1 sub-slot full timeslot 1 - phys_chan_config SDCCH8 + phys_chan_config TCH/F e1 line 0 timeslot 2 sub-slot 1 timeslot 2 phys_chan_config TCH/F From a897bf3dedfa0e9ce83434389c23993b84079656 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 5 Dec 2009 11:58:24 +0530 Subject: [PATCH 039/365] [system_information] fix BCCH list generation for GSM900 We have to make sure to skip the global list header --- openbsc/src/system_information.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index d6d166c79..30d15ac65 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -136,6 +136,8 @@ static int generate_bcch_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt if (bts->band == GSM_BAND_900) { chan_list[0] = 0; llist_for_each_entry(cur_bts, &bts->list, list) { + if (&cur_bts->list == &bts->network->bts_list) + continue; trx = cur_bts->c0; rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); if (rc < 0) From ad69d7f8b2f4dff55b6244cad506113f33eed65c Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Thu, 26 Nov 2009 23:38:41 +0100 Subject: [PATCH 040/365] [sms] trivial: Removed unneeded double check in unbcdify --- openbsc/src/gsm_04_11.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 8e3c64974..4930e5c85 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -218,8 +218,7 @@ static u_int8_t unbcdify(u_int8_t value) DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); ret = (value&0x0F)*10; - if (ret > 90) - ret += value>>4; + ret += value>>4; return ret; } From f49fac278544f321456dcf96912b68059ad8d1af Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 24 Nov 2009 20:06:41 +0100 Subject: [PATCH 041/365] [bsc_hack] Ignore the sigpipe... We might read or write on the OML link when the BTS is reset and will get SIGPIPE interrupt and be gone... Just ignore the SIGPIPE we will get the "exception" on the next run of bsc_select and kill the (old) OML link. --- openbsc/src/bsc_hack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index ee37a6115..0033e1c50 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -193,6 +193,7 @@ int main(int argc, char **argv) signal(SIGINT, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); + signal(SIGPIPE, SIG_IGN); while (1) { bsc_upqueue(bsc_gsmnet); From 7fc57adf16f2099fd5ce02784625567e28f5217b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 6 Dec 2009 04:29:26 +0100 Subject: [PATCH 042/365] Fix make distcheck by adding the new headers... --- openbsc/include/openbsc/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 8bb64eb91..161a9a66e 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -4,4 +4,5 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ - silent_call.h mgcp.h + silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \ + system_information.h From 1085c097e3abc7b76f71e33c01f0e2f87c031e74 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 18 Nov 2009 20:33:19 +0100 Subject: [PATCH 043/365] location updating reject cause now specified on VTY rather than command line argument --- openbsc/include/openbsc/gsm_04_08.h | 1 - openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/bsc_hack.c | 5 ----- openbsc/src/gsm_04_08.c | 9 ++------- openbsc/src/vty_interface.c | 15 +++++++++++++++ 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index a3b77a8ab..01afe05b0 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -748,7 +748,6 @@ struct gsm_trans; /* config options controlling the behaviour of the lower leves */ void gsm0408_allow_everyone(int allow); -void gsm0408_set_reject_cause(int cause); int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id); void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index bd7b79b27..7184a85a5 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -425,6 +425,7 @@ struct gsm_network { char *name_long; char *name_short; enum gsm_auth_policy auth_policy; + enum gsm48_reject_value reject_cause; int a5_encryption; int neci; diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 0033e1c50..1dd5e1020 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -73,7 +73,6 @@ static void print_help() printf(" -s --disable-color\n"); printf(" -c --config-file filename The config file to use.\n"); printf(" -l --database db-name The database to use\n"); - printf(" -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n"); printf(" -p --pcap file The filename of the pcap file\n"); printf(" -T --timestamp Prefix every log line with a timestamp\n"); } @@ -89,7 +88,6 @@ static void handle_options(int argc, char** argv) {"disable-color", 0, 0, 's'}, {"database", 1, 0, 'l'}, {"authorize-everyone", 0, 0, 'a'}, - {"reject-cause", 1, 0, 'r'}, {"pcap", 1, 0, 'p'}, {"timestamp", 0, 0, 'T'}, {"rtp-proxy", 0, 0, 'P'}, @@ -118,9 +116,6 @@ static void handle_options(int argc, char** argv) case 'c': config_file = strdup(optarg); break; - case 'r': - gsm0408_set_reject_cause(atoi(optarg)); - break; case 'p': create_pcap_file(optarg); break; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f262dbebf..a8e8bd76a 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -241,12 +241,6 @@ struct gsm_lai { u_int16_t lac; }; -static int reject_cause = 0; -void gsm0408_set_reject_cause(int cause) -{ - reject_cause = cause; -} - static u_int32_t new_callref = 0x80000001; static int authorize_subscriber(struct gsm_loc_updating_operation *loc, @@ -978,9 +972,10 @@ static int mm_rx_id_resp(struct msgb *msg) static void loc_upd_rej_cb(void *data) { struct gsm_lchan *lchan = data; + struct gsm_bts *bts = lchan->ts->trx->bts; release_loc_updating_req(lchan); - gsm0408_loc_upd_rej(lchan, reject_cause); + gsm0408_loc_upd_rej(lchan, bts->network->reject_cause); lchan_auto_release(lchan); } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 39fc41429..0ebd2bd9d 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -85,6 +85,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) net->name_short, VTY_NEWLINE); vty_out(vty, " Authentication policy: %s%s", gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE); + vty_out(vty, " Location updating reject cause: %u%s", + net->reject_cause, VTY_NEWLINE); vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption, VTY_NEWLINE); vty_out(vty, " NECI (TCH/H): %u%s", net->neci, @@ -273,6 +275,8 @@ static int config_write_net(struct vty *vty) vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE); vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE); vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); + vty_out(vty, " location updating reject cause %u%s", + gsmnet->reject_cause, VTY_NEWLINE); vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); @@ -792,6 +796,16 @@ DEFUN(cfg_net_auth_policy, return CMD_SUCCESS; } +DEFUN(cfg_net_reject_cause, + cfg_net_reject_cause_cmd, + "location updating reject cause <2-111>", + "Set the reject cause of location updating reject\n") +{ + gsmnet->reject_cause = atoi(argv[0]); + + return CMD_SUCCESS; +} + DEFUN(cfg_net_encryption, cfg_net_encryption_cmd, "encryption a5 (0|1|2)", @@ -1292,6 +1306,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_name_short_cmd); install_element(GSMNET_NODE, &cfg_net_name_long_cmd); install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd); + install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); From 7bcb893eb78148250ed2b513e5e2a06fef7d47f3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 6 Dec 2009 12:23:47 +0530 Subject: [PATCH 044/365] remove execute permission from abis_nm.c --- openbsc/src/abis_nm.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 openbsc/src/abis_nm.c diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c old mode 100755 new mode 100644 From 24766091d8e389b5e5f55124ef00e73c160ed5da Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 9 Dec 2009 19:18:32 +0100 Subject: [PATCH 045/365] mark lchan2chan_nr() using a 'const' parameter which fixes some compile warnings at some callers. --- openbsc/include/openbsc/abis_rsl.h | 2 +- openbsc/src/abis_rsl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index a911be355..b76d0facc 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -547,7 +547,7 @@ unsigned int get_paging_group(u_int64_t imsi, unsigned int bs_cc_chans, int n_pag_blocks); unsigned int n_pag_blocks(int bs_ccch_sdcch_comb, unsigned int bs_ag_blks_res); u_int64_t str_to_imsi(const char *imsi_str); -u_int8_t lchan2chan_nr(struct gsm_lchan *lchan); +u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan); int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id); /* to be provided by external code */ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 8a4ed9b76..d5c883e57 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -241,7 +241,7 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) } /* See Table 10.5.25 of GSM04.08 */ -u_int8_t lchan2chan_nr(struct gsm_lchan *lchan) +u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan) { struct gsm_bts_trx_ts *ts = lchan->ts; u_int8_t cbits, chan_nr; From 4669f3d9c8743305e1f808f084064d98feaccd77 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 9 Dec 2009 19:19:45 +0100 Subject: [PATCH 046/365] fix compile warning in db.c --- openbsc/src/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 369505a2c..5dfefb53f 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -265,7 +265,7 @@ static int get_equipment_by_subscr(struct gsm_subscriber *subscr) { dbi_result result; const char *string; - unsigned int cm1; + unsigned char cm1; const unsigned char *cm2, *cm3; struct gsm_equipment *equip = &subscr->equipment; From d6aa52488a19674fb142e9619b579f600b2fec9a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 13:44:19 +0100 Subject: [PATCH 047/365] add warning about accept-all network on non-barred cells --- openbsc/src/bsc_init.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index d21f71a0c..c46fb2cdc 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -795,6 +795,14 @@ static int bootstrap_bts(struct gsm_bts *bts) return -EINVAL; } + if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && + !bts->cell_barred) + fprintf(stderr, "\nWARNING: You are running an 'accept-all' " + "network on a BTS that is not barred. This " + "configuration is likely to interfere with production " + "GSM networks and should only be used in a RF " + "shielded environment such as a faraday cage!\n\n"); + /* Control Channel Description */ bts->si_common.chan_desc.att = 1; bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; From 854b9b33afc1b9719ef91624fbb1f4861bfdc1f1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 14:21:16 +0100 Subject: [PATCH 048/365] fix some integer underflows in MS power calculation --- openbsc/src/gsm_utils.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gsm_utils.c b/openbsc/src/gsm_utils.c index ddfd7f3de..fe0b496bf 100644 --- a/openbsc/src/gsm_utils.c +++ b/openbsc/src/gsm_utils.c @@ -90,8 +90,10 @@ int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm) return 0; else if (dbm < 5) return 19; - else + else { + /* we are guaranteed to have (5 <= dbm < 39) */ return 2 + ((39 - dbm) / 2); + } break; case GSM_BAND_1800: if (dbm >= 36) @@ -100,16 +102,24 @@ int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm) return 30; else if (dbm >= 32) return 31; - else + else if (dbm == 31) + return 0; + else { + /* we are guaranteed to have (0 <= dbm < 31) */ return (30 - dbm) / 2; + } break; case GSM_BAND_1900: if (dbm >= 33) return 30; else if (dbm >= 32) return 31; - else + else if (dbm == 31) + return 0; + else { + /* we are guaranteed to have (0 <= dbm < 31) */ return (30 - dbm) / 2; + } break; } return -EINVAL; From 4bb4738d217596582a689169d12fdd6eb1ed8785 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 15:37:54 +0100 Subject: [PATCH 049/365] utility functions to convert RXLEV into dBm and vice versa --- openbsc/include/openbsc/gsm_utils.h | 4 ++++ openbsc/src/gsm_utils.c | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/openbsc/include/openbsc/gsm_utils.h b/openbsc/include/openbsc/gsm_utils.h index 1bd1bc55a..5809221a3 100644 --- a/openbsc/include/openbsc/gsm_utils.h +++ b/openbsc/include/openbsc/gsm_utils.h @@ -33,5 +33,9 @@ int gsm_7bit_encode(u_int8_t *result, const char *data); int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm); int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl); +/* According to TS 08.05 Chapter 8.1.4 */ +int rxlev2dbm(u_int8_t rxlev); +u_int8_t dbm2rxlev(int dbm); + void generate_backtrace(); #endif diff --git a/openbsc/src/gsm_utils.c b/openbsc/src/gsm_utils.c index fe0b496bf..9439993db 100644 --- a/openbsc/src/gsm_utils.c +++ b/openbsc/src/gsm_utils.c @@ -160,6 +160,28 @@ int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl) return -EINVAL; } +/* According to TS 08.05 Chapter 8.1.4 */ +int rxlev2dbm(u_int8_t rxlev) +{ + if (rxlev > 63) + rxlev = 63; + + return -110 + rxlev; +} + +/* According to TS 08.05 Chapter 8.1.4 */ +u_int8_t dbm2rxlev(int dbm) +{ + int rxlev = dbm + 110; + + if (rxlev > 63) + rxlev = 63; + else if (rxlev < 0) + rxlev = 0; + + return rxlev; +} + void generate_backtrace() { int i, nptrs; From 1d8dbc4630b7d3e23aad8b5ebf043579afe2baa5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 15:38:16 +0100 Subject: [PATCH 050/365] print some more RF related information about BTS in VTY --- openbsc/src/vty_interface.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 0ebd2bd9d..809598fa4 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -128,6 +128,12 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) bts->cell_identity, bts->location_area_code, bts->bsic, bts->tsc, bts->num_trx, VTY_NEWLINE); + vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE); + vty_out(vty, "Minimum Rx Level for Access: %u dBm%s", + rxlev2dbm(bts->si_common.cell_sel_par.rxlev_acc_min), + VTY_NEWLINE); + vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", + bts->si_common.cell_sel_par.cell_resel_hyst, VTY_NEWLINE); if (bts->cell_barred) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) From 7322528ca1a331dc8cf404aae23aa8c2984a9190 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 18:17:25 +0100 Subject: [PATCH 051/365] [VTY] add more cell reselection parameters to VTY allow setting of 'cell reselection hysteresis' and 'rxlev access min' from VTY for experiments with cell reselection. --- openbsc/src/bsc_init.c | 2 -- openbsc/src/gsm_data.c | 2 ++ openbsc/src/vty_interface.c | 39 +++++++++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index c46fb2cdc..54aeb28cb 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -823,8 +823,6 @@ static int bootstrap_bts(struct gsm_bts *bts) bts->si_common.cell_sel_par.ms_txpwr_max_ccch = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); - bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ - bts->si_common.cell_sel_par.rxlev_acc_min = 0; bts->si_common.cell_sel_par.acs = 0; bts->si_common.cell_sel_par.neci = bts->network->neci; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 88de4c462..fef1127eb 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -167,6 +167,8 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, bts->num_trx = 0; INIT_LLIST_HEAD(&bts->trx_list); bts->ms_max_power = 15; /* dBm */ + bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ + bts->si_common.cell_sel_par.rxlev_acc_min = 0; for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { bts->gprs.nsvc[i].bts = bts; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 809598fa4..529b0d481 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -129,11 +129,11 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) bts->location_area_code, bts->bsic, bts->tsc, bts->num_trx, VTY_NEWLINE); vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE); - vty_out(vty, "Minimum Rx Level for Access: %u dBm%s", + vty_out(vty, "Minimum Rx Level for Access: %i dBm%s", rxlev2dbm(bts->si_common.cell_sel_par.rxlev_acc_min), VTY_NEWLINE); vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", - bts->si_common.cell_sel_par.cell_resel_hyst, VTY_NEWLINE); + bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); if (bts->cell_barred) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) @@ -242,6 +242,10 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE); vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE); vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE); + vty_out(vty, " cell reselection hysteresis %u%s", + bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); + vty_out(vty, " rxlev access min %u%s", + bts->si_common.cell_sel_par.rxlev_acc_min, VTY_NEWLINE); if (bts->si_common.chan_desc.t3212) vty_out(vty, " periodic location update %u%s", bts->si_common.chan_desc.t3212 * 10, VTY_NEWLINE); @@ -465,8 +469,11 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) lchan->ts->trx->bts->nr, gsm_lchan_name(lchan->type), VTY_NEWLINE); vty_out(vty, " Use Count: %u%s", lchan->use_count, VTY_NEWLINE); - vty_out(vty, " BS Power %u, MS Power %u%s", lchan->bs_power, - lchan->ms_power, VTY_NEWLINE); + vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s", + lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red + - lchan->bs_power*2, + ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power), + VTY_NEWLINE); if (lchan->subscr) { vty_out(vty, " Subscriber:%s", VTY_NEWLINE); subscr_dump_vty(vty, lchan->subscr); @@ -1108,6 +1115,28 @@ DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_cell_resel_hyst, cfg_bts_cell_resel_hyst_cmd, + "cell reselection hysteresis <0-14>", + "Cell Re-Selection Hysteresis in dB") +{ + struct gsm_bts *bts = vty->index; + + bts->si_common.cell_sel_par.cell_resel_hyst = atoi(argv[0])/2; + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_rxlev_acc_min, cfg_bts_rxlev_acc_min_cmd, + "rxlev access min <0-63>", + "Minimum RxLev needed for cell access (better than -110dBm)") +{ + struct gsm_bts *bts = vty->index; + + bts->si_common.cell_sel_par.rxlev_acc_min = atoi(argv[0]); + + return CMD_SUCCESS; +} + DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, "periodic location update <0-1530>", "Periodic Location Updating Interval in Minutes") @@ -1344,6 +1373,8 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_cell_barred_cmd); install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd); install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd); + install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd); + install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd); install_element(BTS_NODE, &cfg_trx_cmd); From 9e2748ed3a2e8fa3d2939d145129937da7bcf785 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 20:53:23 +0100 Subject: [PATCH 052/365] [RSL] print human-readable channel type during channel allocation failure --- openbsc/src/abis_rsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index d5c883e57..c6675c840 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1236,8 +1236,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { - DEBUGP(DRSL, "CHAN RQD: no resources for %u 0x%x\n", - lctype, rqd_ref->ra); + DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", + gsm_lchan_name(lctype), rqd_ref->ra); /* FIXME: send some kind of reject ?!? */ return -ENOMEM; } From 9385c1172791e2bd1cdd4081648ad55ffa4b6f28 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 20:57:52 +0100 Subject: [PATCH 053/365] If we establish a TCH/H voice call, the reason is CALL, not OTHER --- openbsc/src/gsm_04_08_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index d3e4689b5..8497fa842 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -308,7 +308,7 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = { [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL, [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER, [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_CALL, [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD, [CHREQ_T_PAG_R_ANY_NECI1] = GSM_CHREQ_REASON_PAG, From 210c850a3663eaf333ad44270415220aa1fe9d70 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 20:58:20 +0100 Subject: [PATCH 054/365] If we're trying to allocate TCH/H but don't have it, fallback to TCH/F The rationale is as following: If we have NECI=1, then the phone will request a channel with CHREQ "0100xxxx Originating speech call from dual-rate mobile station when TCH/H is sufficient and supported by the MS for speech calls", then we will try to allocate a TCH/H [as it is sufficient]. However, if there are no free TCH/H slots on the BTS, we abandon and can't handle the MO call at all :( --- openbsc/src/chan_alloc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 7ba679c87..6bf65f325 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -203,6 +203,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) break; case GSM_LCHAN_TCH_H: lchan =_lc_find_bts(bts, GSM_PCHAN_TCH_H); + /* If we don't have TCH/H available, fall-back to TCH/F */ + if (!lchan) + lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); break; default: fprintf(stderr, "Unknown gsm_chan_t %u\n", type); From b83d938565d3f47d8b6f813e5f326429bc31857d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 21:00:48 +0100 Subject: [PATCH 055/365] [04.08] use lchan_auto_release to quickly close channel In some cases, we can try to close the lchan a bit faster than our lchan release timeout: * After we've sent LOC UPD ACCEPT and MM INFO * After a phone has confirmed the RELEASE of a call --- openbsc/src/gsm_04_08.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index a8e8bd76a..a1fa5462b 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -299,11 +299,16 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) db_subscriber_alloc_tmsi(lchan->subscr); release_loc_updating_req(lchan); rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi); + /* send MM INFO with network name */ + rc = gsm48_tx_mm_info(msg->lchan); + /* call subscr_update after putting the loc_upd_acc * in the transmit queue, since S_SUBSCR_ATTACHED might * trigger further action like SMS delivery */ subscr_update(lchan->subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_ATTACHED); + /* try to close channel ASAP */ + lchan_auto_release(lchan); return rc; } @@ -885,7 +890,6 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) struct gsm48_hdr *gh; struct gsm48_loc_area_id *lai; u_int8_t *mid; - int ret; msg->lchan = lchan; @@ -902,12 +906,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - ret = gsm48_sendmsg(msg, NULL); - - /* send MM INFO with network name */ - ret = gsm48_tx_mm_info(lchan); - - return ret; + return gsm48_sendmsg(msg, NULL); } /* Transmit Chapter 9.2.10 Identity Request */ @@ -1374,6 +1373,8 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) } else DEBUGP(DMM, "Unknown Subscriber ?!?\n"); + /* subscriber is detached: should we release lchan? */ + return 0; } @@ -2726,6 +2727,9 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg) case GSM_CSTATE_RELEASE_REQ: rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel); + /* FIXME: in case of multiple calls, we can't simply + * hang up here ! */ + lchan_auto_release(msg->lchan); break; default: rc = mncc_recvmsg(trans->subscr->net, trans, From 487e6befb85a8e6f114d916045b65174c35810a8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 21:16:38 +0100 Subject: [PATCH 056/365] make speech calls with NECI=1 work Fix minor bug with speech calls in case of NECI=1 --- openbsc/src/chan_alloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 6bf65f325..2f0d7b93f 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -204,8 +204,10 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) case GSM_LCHAN_TCH_H: lchan =_lc_find_bts(bts, GSM_PCHAN_TCH_H); /* If we don't have TCH/H available, fall-back to TCH/F */ - if (!lchan) + if (!lchan) { lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); + type = GSM_LCHAN_TCH_F; + } break; default: fprintf(stderr, "Unknown gsm_chan_t %u\n", type); From 09b7e7fa43c74d35e8ea935f3096993e3360f33a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 21:36:53 +0100 Subject: [PATCH 057/365] Gracefully reject non-speech calls As we currently really only deal with voice/speech calls and don't support FAX and DATA (CSD) calls, we now gracefully reject them. --- openbsc/include/openbsc/mncc.h | 8 +++++ openbsc/src/gsm_04_08.c | 54 +++++++++++++++++++++------------- openbsc/src/mncc.c | 33 +++++++++++++++++---- 3 files changed, 70 insertions(+), 25 deletions(-) diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h index 68d76abf8..766c09f1d 100644 --- a/openbsc/include/openbsc/mncc.h +++ b/openbsc/include/openbsc/mncc.h @@ -162,6 +162,14 @@ struct gsm_mncc_cccap { int pcp; }; +enum { + GSM_MNCC_BCAP_SPEECH = 0, + GSM_MNCC_BCAP_UNR_DIG = 1, + GSM_MNCC_BCAP_AUDIO = 2, + GSM_MNCC_BCAP_FAX_G3 = 3, + GSM_MNCC_BCAP_OTHER_ITC = 5, + GSM_MNCC_BCAP_RESERVED = 7, +}; struct gsm_mncc { /* context based information */ diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index a1fa5462b..e1374c9ae 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -439,18 +439,29 @@ static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap, bcap->coding = (lv[1] & 0x10) >> 4; bcap->radio = (lv[1] & 0x60) >> 5; - i = 1; - s = 0; - while(!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - bcap->speech_ver[s++] = lv[i] & 0x0f; - bcap->speech_ver[s] = -1; /* end of list */ - if (i == 2) /* octet 3a */ - bcap->speech_ctm = (lv[i] & 0x20) >> 5; - if (s == 7) /* maximum speech versions + end of list */ - return 0; + if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { + i = 1; + s = 0; + while(!(lv[i] & 0x80)) { + i++; /* octet 3a etc */ + if (in_len < i) + return 0; + bcap->speech_ver[s++] = lv[i] & 0x0f; + bcap->speech_ver[s] = -1; /* end of list */ + if (i == 2) /* octet 3a */ + bcap->speech_ctm = (lv[i] & 0x20) >> 5; + if (s == 7) /* maximum speech versions + end of list */ + return 0; + } + } else { + i = 1; + while (!(lv[i] & 0x80)) { + i++; /* octet 3a etc */ + if (in_len < i) + return 0; + /* ignore them */ + } + /* FIXME: implement OCTET 4+ parsing */ } return 0; @@ -461,21 +472,24 @@ static int encode_bearer_cap(struct msgb *msg, int lv_only, const struct gsm_mncc_bearer_cap *bcap) { u_int8_t lv[32 + 1]; - int i, s; + int i = 1, s; lv[1] = bcap->transfer; lv[1] |= bcap->mode << 3; lv[1] |= bcap->coding << 4; lv[1] |= bcap->radio << 5; - i = 1; - for (s = 0; bcap->speech_ver[s] >= 0; s++) { - i++; /* octet 3a etc */ - lv[i] = bcap->speech_ver[s]; - if (i == 2) /* octet 3a */ - lv[i] |= bcap->speech_ctm << 5; + if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { + for (s = 0; bcap->speech_ver[s] >= 0; s++) { + i++; /* octet 3a etc */ + lv[i] = bcap->speech_ver[s]; + if (i == 2) /* octet 3a */ + lv[i] |= bcap->speech_ctm << 5; + } + lv[i] |= 0x80; /* last IE of octet 3 etc */ + } else { + /* FIXME: implement OCTET 4+ encoding */ } - lv[i] |= 0x80; /* last IE of octet 3 etc */ lv[0] = i; if (lv_only) diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index f62541c05..de1765761 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -136,19 +137,36 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, struct gsm_mncc mncc; struct gsm_call *remote; + memset(&mncc, 0, sizeof(struct gsm_mncc)); + mncc.callref = call->callref; + /* already have remote call */ if (call->remote_ref) return 0; + /* transfer mode 1 would be packet mode, which was never specified */ + if (setup->bearer_cap.mode != 0) { + DEBUGP(DMNCC, "(call %x) We don't support packet mode\n", + call->callref); + mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); + goto out_reject; + } + + /* we currently only do speech */ + if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) { + DEBUGP(DMNCC, "(call %x) We only support voice calls\n", + call->callref); + mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); + goto out_reject; + } + /* create remote call */ if (!(remote = talloc(tall_call_ctx, struct gsm_call))) { - memset(&mncc, 0, sizeof(struct gsm_mncc)); - mncc.callref = call->callref; mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_RESOURCE_UNAVAIL); - mncc_send(call->net, MNCC_REJ_REQ, &mncc); - free_call(call); - return 0; + goto out_reject; } llist_add_tail(&remote->entry, &call_list); remote->net = call->net; @@ -179,6 +197,11 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, setup->callref = remote->callref; DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref); return mncc_send(remote->net, MNCC_SETUP_REQ, setup); + +out_reject: + mncc_send(call->net, MNCC_REJ_REQ, &mncc); + free_call(call); + return 0; } static int mncc_alert_ind(struct gsm_call *call, int msg_type, From eab84a112c3ef8c35835a2ba23fa978fff4d218b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Dec 2009 10:53:12 +0100 Subject: [PATCH 058/365] [RRLP] make RRLP mode configurable from config file We now support different RRLP modes (including "none" to disable RRLP), you can configure it via "rrlp mode" in the "network" section of openbsc.cfg. --- openbsc/include/openbsc/gsm_data.h | 15 ++++++++++ openbsc/src/gsm_data.c | 23 ++++++++++++++++ openbsc/src/rrlp.c | 44 +++++++++++++++++++++++++----- openbsc/src/vty_interface.c | 14 ++++++++++ 4 files changed, 89 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 7184a85a5..57665386d 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -38,6 +38,13 @@ enum gsm_chan_t { GSM_LCHAN_UNKNOWN, }; +/* RRLP mode of operation */ +enum rrlp_mode { + RRLP_MODE_NONE, + RRLP_MODE_MS_BASED, + RRLP_MODE_MS_PREF, + RRLP_MODE_ASS_PREF, +}; /* Channel Request reason */ enum gsm_chreq_reason_t { @@ -449,6 +456,11 @@ struct gsm_network { int T3117; int T3119; int T3141; + + /* Radio Resource Location Protocol (TS 04.31) */ + struct { + enum rrlp_mode mode; + } rrlp; }; #define SMS_HDR_SIZE 128 @@ -533,6 +545,9 @@ static inline int is_siemens_bts(struct gsm_bts *bts) enum gsm_auth_policy gsm_auth_policy_parse(const char *arg); const char *gsm_auth_policy_name(enum gsm_auth_policy policy); +enum rrlp_mode rrlp_mode_parse(const char *arg); +const char *rrlp_mode_name(enum rrlp_mode mode); + void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); #endif diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index fef1127eb..cdaba9e52 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -367,3 +367,26 @@ const char *gsm_auth_policy_name(enum gsm_auth_policy policy) return gsm_auth_policy_names[policy]; } +static const char *rrlp_mode_names[] = { + [RRLP_MODE_NONE] = "none", + [RRLP_MODE_MS_BASED] = "ms-based", + [RRLP_MODE_MS_PREF] = "ms-preferred", + [RRLP_MODE_ASS_PREF] = "ass-preferred", +}; + +enum rrlp_mode rrlp_mode_parse(const char *arg) +{ + int i; + for (i = 0; i < ARRAY_SIZE(rrlp_mode_names); i++) { + if (!strcmp(arg, rrlp_mode_names[i])) + return i; + } + return RRLP_MODE_NONE; +} + +const char *rrlp_mode_name(enum rrlp_mode mode) +{ + if (mode > ARRAY_SIZE(rrlp_mode_names)) + return "none"; + return rrlp_mode_names[mode]; +} diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c index 523b53f0b..60ce750ad 100644 --- a/openbsc/src/rrlp.c +++ b/openbsc/src/rrlp.c @@ -1,4 +1,4 @@ - +/* Radio Resource LCS (Location) Protocol, GMS TS 04.31 */ /* (C) 2009 by Harald Welte * @@ -28,9 +28,42 @@ #include #include -/* RRLP MS based position request */ +/* RRLP msPositionReq, nsBased, + * Accuracy=60, Method=gps, ResponseTime=2, oneSet */ static const u_int8_t ms_based_pos_req[] = { 0x40, 0x01, 0x78, 0xa8 }; +/* RRLP msPositionReq, msBasedPref, + Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */ +static const u_int8_t ms_pref_pos_req[] = { 0x40, 0x02, 0x79, 0x50 }; + +/* RRLP msPositionReq, msAssistedPref, + Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */ +static const u_int8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 }; + +static int send_rrlp_req(struct gsm_lchan *lchan) +{ + struct gsm_network *net = lchan->ts->trx->bts->network; + const u_int8_t *req; + + switch (net->rrlp.mode) { + case RRLP_MODE_MS_BASED: + req = ms_based_pos_req; + break; + case RRLP_MODE_MS_PREF: + req = ms_pref_pos_req; + break; + case RRLP_MODE_ASS_PREF: + req = ass_pref_pos_req; + break; + case RRLP_MODE_NONE: + default: + return 0; + } + + return gsm48_send_rr_app_info(lchan, 0x00, + sizeof(ms_based_pos_req), req); +} + static int subscr_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { @@ -44,8 +77,7 @@ static int subscr_sig_cb(unsigned int subsys, unsigned int signal, lchan = lchan_for_subscr(subscr); if (!lchan) break; - gsm48_send_rr_app_info(lchan, 0x00, sizeof(ms_based_pos_req), - ms_based_pos_req); + send_rrlp_req(lchan); break; } return 0; @@ -59,9 +91,7 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_PAGING_COMPLETED: /* A subscriber has attached. */ - gsm48_send_rr_app_info(psig_data->lchan, 0x00, - sizeof(ms_based_pos_req), - ms_based_pos_req); + send_rrlp_req(psig_data->lchan); break; } return 0; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 529b0d481..adef1480a 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -91,6 +91,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " NECI (TCH/H): %u%s", net->neci, VTY_NEWLINE); + vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode), + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -289,6 +291,8 @@ static int config_write_net(struct vty *vty) gsmnet->reject_cause, VTY_NEWLINE); vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); + vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), + VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -838,6 +842,15 @@ DEFUN(cfg_net_neci, return CMD_SUCCESS; } +DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd, + "rrlp mode (none|ms-based|ms-preferred|ass-preferred)", + "Set the Radio Resource Location Protocol Mode") +{ + gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]); + + return CMD_SUCCESS; +} + #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ @@ -1344,6 +1357,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); + install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); From 7659de1bcbd22f48c41f76ea9e41dc71c9ed1cee Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Dec 2009 12:39:18 +0100 Subject: [PATCH 059/365] introduce new signal every time we get a mobile identity --- openbsc/include/openbsc/signal.h | 1 + openbsc/src/gsm_04_08.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index d59bb9726..10fcddda3 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -91,6 +91,7 @@ enum signal_lchan { enum signal_subscr { S_SUBSCR_ATTACHED, S_SUBSCR_DETACHED, + S_SUBSCR_IDENTITY, /* we've received some identity information */ }; /* SS_SCALL signals */ diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index e1374c9ae..ce93f0130 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -954,6 +954,8 @@ static int mm_rx_id_resp(struct msgb *msg) DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n", mi_type, mi_string); + dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, gh->data); + switch (mi_type) { case GSM_MI_TYPE_IMSI: /* look up subscriber based on IMSI, create if not found */ @@ -1034,6 +1036,8 @@ static int mm_rx_loc_upd_req(struct msgb *msg) DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string, lupd_name(lu->type)); + dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, &lu->mi_len); + /* * Pseudo Spoof detection: Just drop a second/concurrent * location updating request. @@ -1317,6 +1321,8 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n", req->cm_service_type, mi_type, mi_string); + dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len)); + if (is_siemens_bts(bts)) send_siemens_mrpci(msg->lchan, classmark2-1); From 37600be76cb022dbd51d768500613d9a8066990f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Dec 2009 12:56:47 +0100 Subject: [PATCH 060/365] fix segfault in token_auth on SS_SUBSCR != ATTACH --- openbsc/src/token_auth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/token_auth.c b/openbsc/src/token_auth.c index 0931007ef..f6be0bc98 100644 --- a/openbsc/src/token_auth.c +++ b/openbsc/src/token_auth.c @@ -60,10 +60,10 @@ static int token_subscr_cb(unsigned int subsys, unsigned int signal, struct gsm_sms *sms; int rc = 0; - if (subscr->net->auth_policy != GSM_AUTH_POLICY_TOKEN) + if (signal != S_SUBSCR_ATTACHED) return 0; - if (signal != S_SUBSCR_ATTACHED) + if (subscr->net->auth_policy != GSM_AUTH_POLICY_TOKEN) return 0; if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) { From 648b6ce083e3826b5df912de61214961f4950321 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 09:00:24 +0100 Subject: [PATCH 061/365] Add VTY setting for whether or not to sending MM INFO --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/gsm_04_08.c | 6 ++++-- openbsc/src/vty_interface.c | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 57665386d..9bddd7aad 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -435,6 +435,7 @@ struct gsm_network { enum gsm48_reject_value reject_cause; int a5_encryption; int neci; + int send_mm_info; /* layer 4 */ int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index ce93f0130..9e01d9c70 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -299,8 +299,10 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) db_subscriber_alloc_tmsi(lchan->subscr); release_loc_updating_req(lchan); rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi); - /* send MM INFO with network name */ - rc = gsm48_tx_mm_info(msg->lchan); + if (lchan->ts->trx->bts->network->send_mm_info) { + /* send MM INFO with network name */ + rc = gsm48_tx_mm_info(msg->lchan); + } /* call subscr_update after putting the loc_upd_acc * in the transmit queue, since S_SUBSCR_ATTACHED might diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index adef1480a..7b7f4d158 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -93,6 +93,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode), VTY_NEWLINE); + vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off", + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -293,6 +295,7 @@ static int config_write_net(struct vty *vty) vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), VTY_NEWLINE); + vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -851,6 +854,15 @@ DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd, return CMD_SUCCESS; } +DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd, + "mm info (0|1)", + "Whether to send MM INFO after LOC UPD ACCEPT") +{ + gsmnet->send_mm_info = atoi(argv[0]); + + return CMD_SUCCESS; +} + #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ From 3d23db43a486994e4ab1709955775da854f89537 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 17:49:15 +0100 Subject: [PATCH 062/365] [PATCH] fix MM INFO parsing in vty_interface --- openbsc/src/vty_interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 7b7f4d158..d5344edac 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1370,6 +1370,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); + install_element(GSMNET_NODE, &cfg_net_mm_info_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); From ade7a14e750116ebe6a9de431772ff84df845fbe Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 17:49:52 +0100 Subject: [PATCH 063/365] make sure BSIC is patched into NM tables before initializing BS11 --- openbsc/src/bsc_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 54aeb28cb..ef68ef936 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -575,6 +575,7 @@ static void nm_reconfig_bts(struct gsm_bts *bts) switch (bts->type) { case GSM_BTS_TYPE_BS11: + patch_nm_tables(bts); abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/ abis_nm_set_bts_attr(bts, bs11_attr_bts, sizeof(bs11_attr_bts)); abis_nm_raw_msg(bts, sizeof(msg_3), msg_3); /* set BTS handover attr */ From 1e191c59f6130c04b4e02a27dbd91900078e1c14 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 17:51:15 +0100 Subject: [PATCH 064/365] fix compiler warnings in gsm_04_08.c --- openbsc/src/gsm_04_08.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 9e01d9c70..88b1b6900 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1582,7 +1582,7 @@ static int gsm48_rx_rr_app_info(struct msgb *msg) } /* Chapter 9.1.16 Handover complete */ -static gsm48_rx_rr_ho_compl(struct msgb *msg) +static int gsm48_rx_rr_ho_compl(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -1596,7 +1596,7 @@ static gsm48_rx_rr_ho_compl(struct msgb *msg) } /* Chapter 9.1.17 Handover Failure */ -static gsm48_rx_rr_ho_fail(struct msgb *msg) +static int gsm48_rx_rr_ho_fail(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); From da760d3d19bc6da3ef676a2fbaa65fb841cd5af5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 20:25:05 +0100 Subject: [PATCH 065/365] [system_information] fix bit map 0 frequency list generation Our frequency lists for GSM900 were completely wrong, as the bit map 0 encoding was not used correctly. This patch should fix it. --- openbsc/src/system_information.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 30d15ac65..60a8219b2 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -35,21 +35,28 @@ #define GSM_MACBLOCK_LEN 23 #define GSM_MACBLOCK_PADDING 0x2b +/* Frequency Lists as per TS 04.08 10.5.2.13 */ + +/* 10.5.2.13.2: Bit map 0 format */ static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; - if (arfcn > 124) + if (arfcn > 124 || arfcn < 1) return -EINVAL; + /* the bitmask is from 1..124, not from 0..123 */ + arfcn--; + byte = arfcn / 8; bit = arfcn % 8; - chan_list[GSM48_CELL_CHAN_DESC_SIZE-byte] |= (1 << bit); + chan_list[GSM48_CELL_CHAN_DESC_SIZE-1-byte] |= (1 << bit); return 0; } +/* 10.5.2.13.7: Variable bit map format */ static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; From d57f163bd4040cddf59cb145affba2c2d2570c42 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:04:31 +0100 Subject: [PATCH 066/365] bitvec updates and code simplification * introduce a new bitvec_get_bit_pos() function to determine the bit value at a given position inside a bit vector * make sure bitvec_{get,set}_bit_pos() share code as possible --- openbsc/include/openbsc/bitvec.h | 3 ++ openbsc/src/bitvec.c | 49 ++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/openbsc/include/openbsc/bitvec.h b/openbsc/include/openbsc/bitvec.h index 80ed4ad0a..a365e2a2d 100644 --- a/openbsc/include/openbsc/bitvec.h +++ b/openbsc/include/openbsc/bitvec.h @@ -39,6 +39,9 @@ struct bitvec { u_int8_t *data; /* pointer to data array */ }; +/* check if the bit is 0 or 1 for a given position inside a bitvec */ +enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr); + /* Set a bit at given position */ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum, enum bit_value bit); diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c index ac2554475..8c82b8776 100644 --- a/openbsc/src/bitvec.c +++ b/openbsc/src/bitvec.c @@ -35,15 +35,10 @@ static inline unsigned int bytenum_from_bitnum(unsigned int bitnum) return bytenum; } -int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, - enum bit_value bit) +/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */ +static u_int8_t bitval2mask(enum bit_value bit, u_int8_t bitnum) { - unsigned int bytenum = bytenum_from_bitnum(bitnr); - unsigned int bitnum = 7 - (bitnr % 8); - u_int8_t bitval; - - if (bytenum >= bv->data_len) - return -EINVAL; + int bitval; switch (bit) { case ZERO: @@ -59,8 +54,41 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum)); break; default: - return -EINVAL; + return 0; } + return bitval; +} + +/* check if the bit is 0 or 1 for a given position inside a bitvec */ +enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr) +{ + unsigned int bytenum = bytenum_from_bitnum(bitnr); + unsigned int bitnum = 7 - (bitnr % 8); + u_int8_t bitval; + + if (bytenum >= bv->data_len) + return -EINVAL; + + bitval = bitval2mask(ONE, bitnum); + + if (bv->data[bytenum] & bitval) + return ONE; + + return ZERO; +} + +/* set the bit at a given position inside a bitvec */ +int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, + enum bit_value bit) +{ + unsigned int bytenum = bytenum_from_bitnum(bitnr); + unsigned int bitnum = 7 - (bitnr % 8); + u_int8_t bitval; + + if (bytenum >= bv->data_len) + return -EINVAL; + + bitval = bitval2mask(ONE, bitnum); /* first clear the bit */ bv->data[bytenum] &= ~(1 << bitnum); @@ -71,6 +99,7 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, return 0; } +/* set the next bit inside a bitvec */ int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) { int rc; @@ -82,6 +111,7 @@ int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) return rc; } +/* set multiple bits (based on array of bitvals) at current pos */ int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) { int i, rc; @@ -95,6 +125,7 @@ int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) return 0; } +/* set multiple bits (based on numeric value) at current pos */ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits) { int i, rc; From 6c40def716b757a1aa683d9414b2320d3fc20c8a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:07:14 +0100 Subject: [PATCH 067/365] system_information: use bitvec to generate frequency lists We use a 1024-bit-sized bitvec to generate the BA and neighbor frequency list. This bitvec is still generated from the list of all BTS's inside the BSC, but this patch is the first step to generalize this, i.e. generate arbitrary neighbor lists. --- openbsc/include/openbsc/gsm_data.h | 8 ++ openbsc/src/gsm_data.c | 6 ++ openbsc/src/system_information.c | 125 +++++++++++++---------------- 3 files changed, 68 insertions(+), 71 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 9bddd7aad..52c6a030b 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -60,6 +60,7 @@ enum gsm_chreq_reason_t { #include #include #include +#include #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -381,6 +382,13 @@ struct gsm_bts { struct gsm48_cell_sel_par cell_sel_par; struct gsm48_cell_options cell_options; struct gsm48_control_channel_descr chan_desc; + struct bitvec neigh_list; + struct bitvec cell_alloc; + struct { + /* bitmask large enough for all possible ARFCN's */ + u_int8_t neigh_list[1024/8]; + u_int8_t cell_alloc[1024/8]; + } data; } si_common; /* ip.accesss Unit ID's have Site/BTS/TRX layout */ diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index cdaba9e52..3cf9e3c4d 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -169,6 +169,12 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, bts->ms_max_power = 15; /* dBm */ bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ bts->si_common.cell_sel_par.rxlev_acc_min = 0; + bts->si_common.neigh_list.data = bts->si_common.data.neigh_list; + bts->si_common.neigh_list.data_len = + sizeof(bts->si_common.data.neigh_list); + bts->si_common.cell_alloc.data = bts->si_common.data.cell_alloc; + bts->si_common.cell_alloc.data_len = + sizeof(bts->si_common.data.cell_alloc); for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { bts->gprs.nsvc[i].bts = bts; diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 60a8219b2..2d4ba20a4 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #define GSM48_CELL_CHAN_DESC_SIZE 16 #define GSM_MACBLOCK_LEN 23 @@ -38,7 +40,7 @@ /* Frequency Lists as per TS 04.08 10.5.2.13 */ /* 10.5.2.13.2: Bit map 0 format */ -static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +static int freq_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; @@ -57,7 +59,7 @@ static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) } /* 10.5.2.13.7: Variable bit map format */ -static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; unsigned int min_arfcn; @@ -86,20 +88,23 @@ static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) } /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ -static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, + const struct gsm_bts *bts) { - struct gsm_bts_trx *trx; - int rc, min = 1024, max = 0; + int i, rc, min = 1024, max = 0; memset(chan_list, 0, 16); /* GSM900-only handsets only support 'bit map 0 format' */ if (bts->band == GSM_BAND_900) { chan_list[0] = 0; - llist_for_each_entry(trx, &bts->trx_list, list) { - rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); - if (rc < 0) - return rc; + + for (i = 0; i < bv->data_len*8; i++) { + if (bitvec_get_bit_pos(bv, i)) { + rc = freq_list_bm0_set_arfcn(chan_list, i); + if (rc < 0) + return rc; + } } return 0; } @@ -107,11 +112,13 @@ static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt /* We currently only support the 'Variable bitmap format' */ chan_list[0] = 0x8e; - llist_for_each_entry(trx, &bts->trx_list, list) { - if (trx->arfcn < min) - min = trx->arfcn; - if (trx->arfcn > max) - max = trx->arfcn; + for (i = 0; i < bv->data_len*8; i++) { + if (bitvec_get_bit_pos(bv, i)) { + if (i < min) + min = i; + if (i > max) + max = i; + } } if ((max - min) > 111) @@ -121,8 +128,8 @@ static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt chan_list[1] = (min >> 1); chan_list[2] = (min & 1) << 7; - llist_for_each_entry(trx, &bts->trx_list, list) { - rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); + for (i = 0; i < bv->data_len*8; i++) { + rc = freq_list_bmrel_set_arfcn(chan_list, i); if (rc < 0) return rc; } @@ -131,61 +138,37 @@ static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt } /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ -static int generate_bcch_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +static int generate_cell_chan_list(u_int8_t *chan_list, struct gsm_bts *bts) { - struct gsm_bts *cur_bts; struct gsm_bts_trx *trx; - int rc, min = 1024, max = 0; + struct bitvec *bv = &bts->si_common.cell_alloc; - memset(chan_list, 0, 16); + /* first we generate a bitvec of all TRX ARFCN's in our BTS */ + llist_for_each_entry(trx, &bts->trx_list, list) + bitvec_set_bit_pos(bv, trx->arfcn, 1); - /* GSM900-only handsets only support 'bit map 0 format' */ - if (bts->band == GSM_BAND_900) { - chan_list[0] = 0; - llist_for_each_entry(cur_bts, &bts->list, list) { - if (&cur_bts->list == &bts->network->bts_list) - continue; - trx = cur_bts->c0; - rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); - if (rc < 0) - return rc; - } - return 0; - } - - /* We currently only support the 'Variable bitmap format' */ - chan_list[0] = 0x8e; - - llist_for_each_entry(cur_bts, &bts->list, list) { - if (&cur_bts->list == &bts->network->bts_list) - continue; - trx = cur_bts->c0; - if (trx->arfcn < min) - min = trx->arfcn; - if (trx->arfcn > max) - max = trx->arfcn; - } - - if ((max - min) > 111) - return -EINVAL; - - chan_list[0] |= (min >> 9) & 1; - chan_list[1] = (min >> 1); - chan_list[2] = (min & 1) << 7; - - llist_for_each_entry(cur_bts, &bts->list, list) { - if (&cur_bts->list == &bts->network->bts_list) - continue; - trx = cur_bts->c0; - rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); - if (rc < 0) - return rc; - } - - return 0; + /* then we generate a GSM 04.08 frequency list from the bitvec */ + return bitvec2freq_list(chan_list, bv, bts); } -static int generate_si1(u_int8_t *output, const struct gsm_bts *bts) +/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ +static int generate_bcch_chan_list(u_int8_t *chan_list, struct gsm_bts *bts) +{ + struct gsm_bts *cur_bts; + struct bitvec *bv = &bts->si_common.neigh_list; + + /* first we generate a bitvec of the BCCH ARFCN's in our BSC */ + llist_for_each_entry(cur_bts, &bts->network->bts_list, list) { + if (cur_bts == bts) + continue; + bitvec_set_bit_pos(bv, cur_bts->c0->arfcn, 1); + } + + /* then we generate a GSM 04.08 frequency list from the bitvec */ + return bitvec2freq_list(chan_list, bv, bts); +} + +static int generate_si1(u_int8_t *output, struct gsm_bts *bts) { int rc; struct gsm48_system_information_type_1 *si1 = @@ -210,7 +193,7 @@ static int generate_si1(u_int8_t *output, const struct gsm_bts *bts) return GSM_MACBLOCK_LEN; } -static int generate_si2(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si2(u_int8_t *output, struct gsm_bts *bts) { int rc; struct gsm48_system_information_type_2 *si2 = @@ -257,7 +240,7 @@ struct gsm48_si_ro_info si_info = { .break_ind = 0, }; -static int generate_si3(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si3(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_3 *si3 = (struct gsm48_system_information_type_3 *) output; @@ -287,7 +270,7 @@ static int generate_si3(u_int8_t *output, const struct gsm_bts *bts) return GSM_MACBLOCK_LEN; } -static int generate_si4(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si4(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_4 *si4 = (struct gsm48_system_information_type_4 *) output; @@ -319,7 +302,7 @@ static int generate_si4(u_int8_t *output, const struct gsm_bts *bts) return GSM_MACBLOCK_LEN; } -static int generate_si5(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si5(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_5 *si5 = (struct gsm48_system_information_type_5 *) output; @@ -339,7 +322,7 @@ static int generate_si5(u_int8_t *output, const struct gsm_bts *bts) return 18; } -static int generate_si6(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si6(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_6 *si6 = (struct gsm48_system_information_type_6 *) output; @@ -390,7 +373,7 @@ static struct gsm48_si13_info si13_default = { }, }; -static int generate_si13(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si13(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_13 *si13 = (struct gsm48_system_information_type_13 *) output; From 7f73a1ac58d6b9f2f8ec793123bf0ee3038fb3a4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:23:27 +0100 Subject: [PATCH 068/365] bitvec: Introduce bitvec_get_nth_set_bit() function This is particularly important for determining the ARFCN for cells reported in 04.08 MEAS REP. --- openbsc/include/openbsc/bitvec.h | 3 +++ openbsc/src/bitvec.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/openbsc/include/openbsc/bitvec.h b/openbsc/include/openbsc/bitvec.h index a365e2a2d..b35aebf16 100644 --- a/openbsc/include/openbsc/bitvec.h +++ b/openbsc/include/openbsc/bitvec.h @@ -42,6 +42,9 @@ struct bitvec { /* check if the bit is 0 or 1 for a given position inside a bitvec */ enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr); +/* get the Nth set bit inside the bit vector */ +unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n); + /* Set a bit at given position */ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum, enum bit_value bit); diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c index 8c82b8776..ad03958f3 100644 --- a/openbsc/src/bitvec.c +++ b/openbsc/src/bitvec.c @@ -77,6 +77,22 @@ enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr) return ZERO; } +/* get the Nth set bit inside the bit vector */ +unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n) +{ + unsigned int i, k = 0; + + for (i = 0; i < bv->data_len*8; i++) { + if (bitvec_get_bit_pos(bv, i) == ONE) { + k++; + if (k == n) + return i; + } + } + + return 0; +} + /* set the bit at a given position inside a bitvec */ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, enum bit_value bit) From f1dae1924a80e614982513707b4ee568d2126e1b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:24:28 +0100 Subject: [PATCH 069/365] 04.08 MEAS REP: Convert relative cell number to ARFCN Since we are keeping a bitvec of the neighbor cells, we can now use bitvec_get_nth_set_bit() to determine the ARFCN for each reported cell in the 04.08 MEASUREMENT REPORT. --- openbsc/include/openbsc/meas_rep.h | 2 +- openbsc/src/gsm_04_08.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/meas_rep.h b/openbsc/include/openbsc/meas_rep.h index b1ad2daa8..d44c9b766 100644 --- a/openbsc/include/openbsc/meas_rep.h +++ b/openbsc/include/openbsc/meas_rep.h @@ -4,8 +4,8 @@ /* extracted from a L3 measurement report IE */ struct gsm_meas_rep_cell { u_int8_t rxlev; - u_int8_t bcch_freq; /* FIXME: translate to ARFCN */ u_int8_t bsic; + u_int16_t arfcn; }; /* RX Level and RX Quality */ diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 88b1b6900..6d05a20ad 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -171,6 +172,8 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) struct gsm48_hdr *gh = msgb_l3(msg); unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); u_int8_t *data = gh->data; + struct gsm_bts *bts = msg->lchan->ts->trx->bts; + struct bitvec *nbv = &bts->si_common.neigh_list; if (gh->msg_type != GSM48_MT_RR_MEAS_REP) return -EINVAL; @@ -194,37 +197,39 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) /* an encoding nightmare in perfection */ rep->cell[0].rxlev = data[4] & 0x3f; - rep->cell[0].bcch_freq = data[5] >> 2; + rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[5] >> 2); rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5); if (rep->num_cell < 2) return 0; rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7); - rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f; + rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[7] >> 2) & 0x1f); rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4); if (rep->num_cell < 3) return 0; rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6); - rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f; + rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[9] >> 1) & 0x1f); rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3); if (rep->num_cell < 4) return 0; rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5); - rep->cell[3].bcch_freq = data[11] & 0x1f; + rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[11] & 0x1f); rep->cell[3].bsic = data[12] >> 2; if (rep->num_cell < 5) return 0; rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4); - rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7); + rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[13] & 0xf) << 1) | (data[14] >> 7)); rep->cell[4].bsic = (data[14] >> 1) & 0x3f; if (rep->num_cell < 6) return 0; rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3); - rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6); + rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[15] & 0x07) << 2) | (data[16] >> 6)); rep->cell[5].bsic = data[16] & 0x3f; return 0; From 84874c9005fd568d423f6fde9caedd36dc5bff57 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:33:02 +0100 Subject: [PATCH 070/365] Implement gsm_bts_neighbor() function to determine neighbor BTS We will need this for the actual handover algorithm implementation, as we will only know the current BTS and the BCCH ARFCN of the strongest cell in the measurement reports. Using this new function, we can resolve the matching gsm_bts. --- openbsc/include/openbsc/gsm_data.h | 4 ++++ openbsc/src/gsm_data.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 52c6a030b..33ec328fc 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -501,6 +501,10 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts); struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num); + +/* Get reference to a neighbor cell on a given BCCH ARFCN */ +struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn); + struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num); const char *gsm_pchan_name(enum gsm_phys_chan_config c); diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 3cf9e3c4d..9fb4526f0 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -234,6 +234,23 @@ struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num) return NULL; } +/* Get reference to a neighbor cell on a given BCCH ARFCN */ +struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn) +{ + struct gsm_bts *neigh; + /* FIXME: use some better heuristics here to determine which cell + * using this ARFCN really is closest to the target cell. For + * now we simply assume that each ARFCN will only be used by one + * cell */ + + llist_for_each_entry(neigh, &bts->network->bts_list, list) { + if (neigh->c0->arfcn == arfcn) + return neigh; + } + + return NULL; +} + struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num) { struct gsm_bts_trx *trx; From 0b12103965c824b0dae1ae10df00d87d4ef1ec7b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 15 Dec 2009 00:21:31 +0100 Subject: [PATCH 071/365] add BSIC parameter to gsm_bts_neighbor() When looking for the gsm_bts of a neighbor cell, use BSIC and ARFCN tuple rather than just ARFCN for better identification purpose. --- openbsc/include/openbsc/gsm_data.h | 3 ++- openbsc/src/gsm_data.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 33ec328fc..012481a5f 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -503,7 +503,8 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts); struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num); /* Get reference to a neighbor cell on a given BCCH ARFCN */ -struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn); +struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, + u_int16_t arfcn, u_int8_t bsic); struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num); diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 9fb4526f0..91a854f46 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -235,7 +235,8 @@ struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num) } /* Get reference to a neighbor cell on a given BCCH ARFCN */ -struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn) +struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, + u_int16_t arfcn, u_int8_t bsic) { struct gsm_bts *neigh; /* FIXME: use some better heuristics here to determine which cell @@ -244,7 +245,8 @@ struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn) * cell */ llist_for_each_entry(neigh, &bts->network->bts_list, list) { - if (neigh->c0->arfcn == arfcn) + if (neigh->c0->arfcn == arfcn && + neigh->bsic == bsic) return neigh; } From d12b0fdf51b76f906d5ee5f5b7f266fe791eb800 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 15 Dec 2009 21:36:05 +0100 Subject: [PATCH 072/365] introduce cache of 6 last recently received measurement reports for each lchan --- openbsc/include/openbsc/gsm_data.h | 6 +++++ openbsc/src/abis_rsl.c | 36 ++++++++++++++---------------- openbsc/src/chan_alloc.c | 9 ++++++++ openbsc/src/gsm_04_08.c | 4 ++-- openbsc/src/gsm_data.c | 13 +++++++++++ 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 012481a5f..b21f8aa05 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -194,6 +194,10 @@ struct gsm_lchan { /* use count. how many users use this channel */ unsigned int use_count; + /* cache of last measurement reports on this lchan */ + struct gsm_meas_rep meas_rep[6]; + int meas_rep_idx; + struct { u_int32_t bound_ip; u_int16_t bound_port; @@ -564,4 +568,6 @@ const char *rrlp_mode_name(enum rrlp_mode mode); void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); +struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan); + #endif diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index c6675c840..51d524459 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -998,14 +998,12 @@ static int rsl_rx_meas_res(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - struct gsm_meas_rep mr; + struct gsm_meas_rep *mr = lchan_next_meas_rep(msg->lchan); u_int8_t len; const u_int8_t *val; int rc; - memset(&mr, 0, sizeof(mr)); - - mr.lchan = msg->lchan; + memset(mr, 0, sizeof(*mr)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1015,44 +1013,44 @@ static int rsl_rx_meas_res(struct msgb *msg) return -EIO; /* Mandatory Parts */ - mr.nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); + mr->nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); if (len >= 3) { if (val[0] & 0x40) - mr.flags |= MEAS_REP_F_DL_DTX; - mr.ul.full.rx_lev = val[0] & 0x3f; - mr.ul.sub.rx_lev = val[1] & 0x3f; - mr.ul.full.rx_qual = val[2]>>3 & 0x7; - mr.ul.sub.rx_qual = val[2] & 0x7; + mr->flags |= MEAS_REP_F_DL_DTX; + mr->ul.full.rx_lev = val[0] & 0x3f; + mr->ul.sub.rx_lev = val[1] & 0x3f; + mr->ul.full.rx_qual = val[2]>>3 & 0x7; + mr->ul.sub.rx_qual = val[2] & 0x7; } - mr.bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); + mr->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); /* Optional Parts */ if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET)) - mr.ms_timing_offset = + mr->ms_timing_offset = *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET); if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) { val = TLVP_VAL(&tp, RSL_IE_L1_INFO); - mr.flags |= MEAS_REP_F_MS_L1; - mr.ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); + mr->flags |= MEAS_REP_F_MS_L1; + mr->ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); if (val[0] & 0x04) - mr.flags |= MEAS_REP_F_FPC; - mr.ms_l1.ta = val[1]; + mr->flags |= MEAS_REP_F_FPC; + mr->ms_l1.ta = val[1]; } if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { msg->l3h = (u_int8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); - rc = gsm48_parse_meas_rep(&mr, msg); + rc = gsm48_parse_meas_rep(mr, msg); if (rc < 0) return rc; } - print_meas_rep(&mr); + print_meas_rep(mr); - dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, &mr); + dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, mr); return 0; } diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 2f0d7b93f..0a2984773 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -235,6 +235,8 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) /* Free a logical channel */ void lchan_free(struct gsm_lchan *lchan) { + int i; + lchan->type = GSM_LCHAN_NONE; if (lchan->subscr) { subscr_put(lchan->subscr); @@ -250,6 +252,13 @@ void lchan_free(struct gsm_lchan *lchan) /* stop the timer */ bsc_del_timer(&lchan->release_timer); + /* clear cached measuement reports */ + lchan->meas_rep_idx = 0; + for (i = 0; i < ARRAY_SIZE(lchan->meas_rep); i++) { + lchan->meas_rep[i].flags = 0; + lchan->meas_rep[i].nr = 0; + } + /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 6d05a20ad..ef29b29cc 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1558,13 +1558,13 @@ static int gsm48_rx_rr_status(struct msgb *msg) static int gsm48_rx_rr_meas_rep(struct msgb *msg) { - static struct gsm_meas_rep meas_rep; + struct gsm_meas_rep *meas_rep = lchan_next_meas_rep(msg->lchan); /* This shouldn't actually end up here, as RSL treats * L3 Info of 08.58 MEASUREMENT REPORT different by calling * directly into gsm48_parse_meas_rep */ DEBUGP(DMEAS, "DIRECT GSM48 MEASUREMENT REPORT ?!? "); - gsm48_parse_meas_rep(&meas_rep, msg); + gsm48_parse_meas_rep(meas_rep, msg); return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 91a854f46..94ed91ba5 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -415,3 +415,16 @@ const char *rrlp_mode_name(enum rrlp_mode mode) return "none"; return rrlp_mode_names[mode]; } + +struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) +{ + struct gsm_meas_rep *meas_rep; + + meas_rep = &lchan->meas_rep[lchan->meas_rep_idx]; + memset(meas_rep, 0, sizeof(*meas_rep)); + meas_rep->lchan = lchan; + lchan->meas_rep_idx = (lchan->meas_rep_idx + 1) + % ARRAY_SIZE(lchan->meas_rep); + + return meas_rep; +} From 7f2d25b0956f0e9fb6cdf0056d9371a00cc239e4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 15 Dec 2009 21:36:59 +0100 Subject: [PATCH 073/365] mroe comments on meas_rep data structures --- openbsc/include/openbsc/meas_rep.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/include/openbsc/meas_rep.h b/openbsc/include/openbsc/meas_rep.h index d44c9b766..c36352e2a 100644 --- a/openbsc/include/openbsc/meas_rep.h +++ b/openbsc/include/openbsc/meas_rep.h @@ -30,11 +30,15 @@ struct gsm_meas_rep_unidir { /* parsed uplink and downlink measurement result */ struct gsm_meas_rep { + /* back-pointer to the logical channel */ struct gsm_lchan *lchan; + /* number of the measurement report */ u_int8_t nr; + /* flags, see MEAS_REP_F_* */ unsigned int flags; + /* uplink and downlink rxlev, rxqual; full and sub */ struct gsm_meas_rep_unidir ul; struct gsm_meas_rep_unidir dl; @@ -45,6 +49,7 @@ struct gsm_meas_rep { u_int8_t ta; /* MS timing advance */ } ms_l1; + /* neighbor measurement reports for up to 6 cells */ int num_cell; struct gsm_meas_rep_cell cell[6]; }; From 152b6261f88ac085cd96b63374ad5847ac7b3ce2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 11:57:48 +0100 Subject: [PATCH 074/365] [system_information] Print more debugging about what's going on --- openbsc/src/bsc_init.c | 16 +++++++++++----- openbsc/src/system_information.c | 21 +++++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index ef68ef936..aed0dad42 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -684,25 +684,31 @@ static int set_system_infos(struct gsm_bts_trx *trx) } #ifdef GPRS rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); - if (rc < 0) + if (rc < 0) { + i = 13; goto err_out; + } rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); #endif rc = gsm_generate_si(si_tmp, trx->bts, 5); - if (rc < 0) + if (rc < 0) { + i = 5; goto err_out; + } rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si_tmp, rc); rc = gsm_generate_si(si_tmp, trx->bts, 6); - if (rc < 0) + if (rc < 0) { + i = 6; goto err_out; + } rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc); return 0; err_out: - fprintf(stderr, "Cannot generate SI for BTS %u, most likely " + fprintf(stderr, "Cannot generate SI %u for BTS %u, most likely " "a problem with neighbor cell list generation\n", - trx->bts->nr); + i, trx->bts->nr); return rc; } diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 2d4ba20a4..644abb432 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -32,6 +32,7 @@ #include #include #include +#include #define GSM48_CELL_CHAN_DESC_SIZE 16 #define GSM_MACBLOCK_LEN 23 @@ -73,10 +74,14 @@ static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) if (arfcn == min_arfcn) return 0; - if (arfcn < min_arfcn) + if (arfcn < min_arfcn) { + DEBUGP(DRR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn); return -EINVAL; - if (arfcn > min_arfcn + 111) + } + if (arfcn > min_arfcn + 111) { + DEBUGP(DRR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn); return -EINVAL; + } bitno = (arfcn - min_arfcn); byte = bitno / 8; @@ -121,17 +126,21 @@ static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, } } - if ((max - min) > 111) + if ((max - min) > 111) { + DEBUGP(DRR, "min_arfcn=%u, max_arfcn=%u, distance > 111\n", min, max); return -EINVAL; + } chan_list[0] |= (min >> 9) & 1; chan_list[1] = (min >> 1); chan_list[2] = (min & 1) << 7; for (i = 0; i < bv->data_len*8; i++) { - rc = freq_list_bmrel_set_arfcn(chan_list, i); - if (rc < 0) - return rc; + if (bitvec_get_bit_pos(bv, i)) { + rc = freq_list_bmrel_set_arfcn(chan_list, i); + if (rc < 0) + return rc; + } } return 0; From 680e2eccef2bffb462e5854db87139126fb1920d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 15:59:24 +0100 Subject: [PATCH 075/365] fix bug in bitvec resulting in all bits being set to 0xff --- openbsc/src/bitvec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c index ad03958f3..d6f5679cf 100644 --- a/openbsc/src/bitvec.c +++ b/openbsc/src/bitvec.c @@ -104,12 +104,12 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, if (bytenum >= bv->data_len) return -EINVAL; - bitval = bitval2mask(ONE, bitnum); - /* first clear the bit */ - bv->data[bytenum] &= ~(1 << bitnum); + bitval = bitval2mask(ONE, bitnum); + bv->data[bytenum] &= ~bitval; /* then set it to desired value */ + bitval = bitval2mask(bit, bitnum); bv->data[bytenum] |= bitval; return 0; From a2f74b847782a2578fe5b0a79f5479379493d4ba Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 16:49:21 +0100 Subject: [PATCH 076/365] 04.08: fix off-by-one error while parsing measurement results --- openbsc/src/gsm_04_08.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index ef29b29cc..0815d6dde 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -190,47 +190,47 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; - rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2); + rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); if (rep->num_cell < 1) return 0; /* an encoding nightmare in perfection */ - rep->cell[0].rxlev = data[4] & 0x3f; - rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[5] >> 2); - rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5); + rep->cell[0].rxlev = data[3] & 0x3f; + rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); + rep->cell[0].bsic = ((data[4] & 0x03) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; - rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7); - rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[7] >> 2) & 0x1f); - rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4); + rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); + rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); + rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); if (rep->num_cell < 3) return 0; - rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6); - rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[9] >> 1) & 0x1f); - rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3); + rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); + rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); + rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); if (rep->num_cell < 4) return 0; - rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5); - rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[11] & 0x1f); - rep->cell[3].bsic = data[12] >> 2; + rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); + rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); + rep->cell[3].bsic = data[11] >> 2; if (rep->num_cell < 5) return 0; - rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4); + rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[13] & 0xf) << 1) | (data[14] >> 7)); - rep->cell[4].bsic = (data[14] >> 1) & 0x3f; + ((data[12] & 0xf) << 1) | (data[13] >> 7)); + rep->cell[4].bsic = (data[13] >> 1) & 0x3f; if (rep->num_cell < 6) return 0; - rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3); + rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[15] & 0x07) << 2) | (data[16] >> 6)); - rep->cell[5].bsic = data[16] & 0x3f; + ((data[14] & 0x07) << 2) | (data[15] >> 6)); + rep->cell[5].bsic = data[15] & 0x3f; return 0; } From 6739dfb7053a4a8d788f15c018ccca39b119f831 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 16:52:07 +0100 Subject: [PATCH 077/365] print measurement reports more verbosely --- openbsc/src/abis_rsl.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 51d524459..37b9a47dc 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -957,14 +957,17 @@ static int rsl_rx_conn_fail(struct msgb *msg) static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru, const char *prefix) { - DEBUGPC(DMEAS, "RXL-FULL-%s=%d RXL-SUB-%s=%d ", - prefix, mru->full.rx_lev, prefix, mru->sub.rx_lev); + DEBUGPC(DMEAS, "RXL-FULL-%s=%3ddBm RXL-SUB-%s=%3ddBm ", + prefix, rxlev2dbm(mru->full.rx_lev), + prefix, rxlev2dbm(mru->sub.rx_lev)); DEBUGPC(DMEAS, "RXQ-FULL-%s=%d RXQ-SUB-%s=%d ", prefix, mru->full.rx_qual, prefix, mru->sub.rx_qual); } static void print_meas_rep(struct gsm_meas_rep *mr) { + int i; + DEBUGP(DMEAS, "MEASUREMENT RESULT NR=%d ", mr->nr); if (mr->flags & MEAS_REP_F_DL_DTX) @@ -976,7 +979,7 @@ static void print_meas_rep(struct gsm_meas_rep *mr) DEBUGPC(DMEAS, "MS_TO=%d ", mr->ms_timing_offset); if (mr->flags & MEAS_REP_F_MS_L1) { - DEBUGPC(DMEAS, "L1_MS_PWR=%ddBm ", mr->ms_l1.pwr); + DEBUGPC(DMEAS, "L1_MS_PWR=%3ddBm ", mr->ms_l1.pwr); DEBUGPC(DMEAS, "L1_FPC=%u ", mr->flags & MEAS_REP_F_FPC ? 1 : 0); DEBUGPC(DMEAS, "L1_TA=%u ", mr->ms_l1.ta); @@ -992,6 +995,11 @@ static void print_meas_rep(struct gsm_meas_rep *mr) print_meas_rep_uni(&mr->dl, "dl"); DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell); + for (i = 0; i < mr->num_cell; i++) { + struct gsm_meas_rep_cell *mrc = &mr->cell[i]; + DEBUGP(DMEAS, "ARFCN=%u BSIC=%u => %d dBm\n", mrc->arfcn, mrc->bsic, + rxlev2dbm(mrc->rxlev)); + } } static int rsl_rx_meas_res(struct msgb *msg) From 88a412ac80e182fc8a1fa470f846783d79ab7d52 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 17:32:37 +0100 Subject: [PATCH 078/365] ip.access: Keep OML/RSL up/down state per-bts for multi-BTS setups --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/input/ipaccess.c | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index b21f8aa05..f9b0b6340 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -400,6 +400,7 @@ struct gsm_bts { struct { u_int16_t site_id; u_int16_t bts_id; + u_int32_t flags; } ip_access; struct { struct { diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 2d9f51ef9..143712e1c 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -247,9 +247,8 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, return 0; } -/* FIXME: this is per BTS */ -static int oml_up = 0; -static int rsl_up = 0; +#define OML_UP 0x0001 +#define RSL_UP 0x0002 /* * read one ipa message from the socket @@ -348,16 +347,16 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (link->type) { case E1INP_SIGN_RSL: - if (!rsl_up) { + if (!(msg->trx->bts->ip_access.flags & RSL_UP)) { e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); - rsl_up = 1; + msg->trx->bts->ip_access.flags |= RSL_UP; } ret = abis_rsl_rcvmsg(msg); break; case E1INP_SIGN_OML: - if (!oml_up) { + if (!(msg->trx->bts->ip_access.flags & OML_UP)) { e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); - oml_up = 1; + msg->trx->bts->ip_access.flags |= OML_UP; } ret = abis_nm_rcvmsg(msg); break; From 73ddaeddd2b4666abe90843e5ff89f00d6b1c934 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 23:29:12 +0100 Subject: [PATCH 079/365] measurement report: correctly parse BSIC of first neighbor cell --- openbsc/src/gsm_04_08.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 0815d6dde..5fea6bfbf 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -198,7 +198,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) rep->cell[0].rxlev = data[3] & 0x3f; rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); - rep->cell[0].bsic = ((data[4] & 0x03) << 3) | (data[5] >> 5); + rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; From 33e65977204c4d35deb7c48069bf504353618da5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 23:29:34 +0100 Subject: [PATCH 080/365] assign measurement report lchan member after memset'ing it --- openbsc/src/abis_rsl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 37b9a47dc..1fbea837d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1012,6 +1012,7 @@ static int rsl_rx_meas_res(struct msgb *msg) int rc; memset(mr, 0, sizeof(*mr)); + mr->lchan = msg->lchan; rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); From 7a7a0d54289114e6a49087a555b7a4f1e6cb3016 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 00:25:18 +0100 Subject: [PATCH 081/365] make handover reference a function call argument --- openbsc/include/openbsc/gsm_04_08.h | 4 ++-- openbsc/src/gsm_04_08_utils.c | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 01afe05b0..b8671554e 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -769,8 +769,8 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, u_int8_t apdu_len, const u_int8_t *apdu); int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); -int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, - struct gsm_lchan *new_lchan, u_int8_t power_command); +int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, + u_int8_t power_command, u_int8_t ho_ref); int bsc_upqueue(struct gsm_network *net); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 8497fa842..e96a1ca09 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -541,21 +541,22 @@ static void gsm48_chan_desc(struct gsm48_chan_desc *cd, } /* Chapter 9.1.15: Handover Command */ -int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, - struct gsm_lchan *new_lchan, u_int8_t power_command) +int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, + u_int8_t power_command, u_int8_t ho_ref) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho)); - static u_int8_t ho_ref; msg->lchan = old_lchan; + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_HANDO_CMD; /* mandatory bits */ gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts); gsm48_chan_desc(&ho->chan_desc, new_lchan); - ho->ho_ref = ho_ref++; + ho->ho_ref = ho_ref; ho->power_command = power_command; /* FIXME: optional bits for type of synchronization? */ From 8d77b9540a907fb36afbb324df549c9261e1ca02 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 00:31:10 +0100 Subject: [PATCH 082/365] [handover] first functional handover implementation With this commit, we can successfully hand over a channel from one cell to another cell. We implement asynchronous intra-BSC (but inter-BTS) handover. Changes: * introduce new DHO log category * extend rsl_chan_activate_lchan() with argument for HO reference * introduce actual minimal handover decision making in handover_decision.c * various fixes to bsc_handover_start() in handover_logic.c --- openbsc/include/openbsc/abis_rsl.h | 2 +- openbsc/include/openbsc/debug.h | 2 + openbsc/include/openbsc/handover.h | 8 +++ openbsc/src/Makefile.am | 3 +- openbsc/src/abis_rsl.c | 15 +++- openbsc/src/bsc_hack.c | 1 + openbsc/src/bsc_init.c | 1 + openbsc/src/debug.c | 3 +- openbsc/src/handover_decision.c | 111 +++++++++++++++++++++++++++++ openbsc/src/handover_logic.c | 27 ++++++- 10 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 openbsc/include/openbsc/handover.h create mode 100644 openbsc/src/handover_decision.c diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index b76d0facc..6d0ab6182 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -497,7 +497,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr, u_int8_t bs_power, u_int8_t ms_power, u_int8_t ta); int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, - u_int8_t ta); + u_int8_t ta, u_int8_t ho_ref); int rsl_chan_mode_modify_req(struct gsm_lchan *ts); int rsl_encryption_cmd(struct msgb *msg); int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len, diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 447c3584f..c1098a53c 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -25,6 +25,8 @@ #define DMGCP 0x40000 +#define DHO 0x80000 + #ifdef DEBUG #define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args) #define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args) diff --git a/openbsc/include/openbsc/handover.h b/openbsc/include/openbsc/handover.h new file mode 100644 index 000000000..8ab1b0642 --- /dev/null +++ b/openbsc/include/openbsc/handover.h @@ -0,0 +1,8 @@ +#ifndef _HANDOVER_H +#define _HANDOVER_H +/* Hand over the specified logical channel to the specified new BTS. + * This is the main entry point for the actual handover algorithm, + * after it has decided it wants to initiate HO to a specific BTS */ +int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts); + +#endif /* _HANDOVER_H */ diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index f22582122..5692ac4e4 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -11,7 +11,8 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ - talloc_ctx.c system_information.c bitvec.c rest_octets.c + talloc_ctx.c system_information.c bitvec.c rest_octets.c \ + handover_decision.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 1fbea837d..d42daf5f2 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -576,7 +576,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr, #endif int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, - u_int8_t ta) + u_int8_t ta, u_int8_t ho_ref) { struct abis_rsl_dchan_hdr *dh; struct msgb *msg; @@ -603,9 +603,9 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, dh->chan_nr = chan_nr; msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type); - /* For compatibility with Phase 1 */ msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm), (u_int8_t *) &cm); + /* For compatibility with Phase 1 */ msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4, (u_int8_t *) &ci); @@ -616,6 +616,15 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info); } + switch (act_type) { + case RSL_ACT_INTER_ASYNC: + case RSL_ACT_INTER_SYNC: + msgb_tv_put(msg, RSL_IE_HANDO_REF, ho_ref); + break; + default: + break; + } + msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power); msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power); msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); @@ -1258,7 +1267,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) lchan->bs_power = 0; /* 0dB reduction, output power = Pn */ lchan->rsl_cmode = RSL_CMOD_SPD_SIGN; lchan->tch_mode = GSM48_CMODE_SIGN; - rsl_chan_activate_lchan(lchan, 0x00, rqd_ta); + rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, 0); /* create IMMEDIATE ASSIGN 04.08 messge */ memset(&ia, 0, sizeof(ia)); diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 1dd5e1020..b0f8d6c3f 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -162,6 +162,7 @@ int main(int argc, char **argv) talloc_ctx_init(); on_dso_load_token(); on_dso_load_rrlp(); + on_dso_load_ho_dec(); /* parse options */ handle_options(argc, argv); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index aed0dad42..ce3d0b4f8 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -679,6 +679,7 @@ static int set_system_infos(struct gsm_bts_trx *trx) rc = gsm_generate_si(si_tmp, trx->bts, i); if (rc < 0) goto err_out; + DEBUGP(DRR, "SI%u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } } diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 5dc2e0ff7..9c6cb4963 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -28,7 +28,7 @@ #include -unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB|DMEAS); +unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB); struct debug_info { const char *name; @@ -60,6 +60,7 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DSCCP, "DSCCP", "", "") DEBUG_CATEGORY(DMSC, "DMSC", "", "") DEBUG_CATEGORY(DMGCP, "DMGCP", "", "") + DEBUG_CATEGORY(DHO, "DHO", "", "") }; static int use_color = 1; diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c new file mode 100644 index 000000000..06eb86507 --- /dev/null +++ b/openbsc/src/handover_decision.c @@ -0,0 +1,111 @@ +/* Handover Decision making for Inter-BTS (Intra-BSC) Handover. This + * only implements the handover algorithm/decision, but not execution + * of it */ + +/* (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 + +static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, + u_int16_t arfcn, u_int8_t bsic) +{ + struct gsm_bts *new_bts; + + /* resolve the gsm_bts structure for the best neighbor */ + new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic); + if (!new_bts) { + DEBUGP(DHO, "unable to determine neighbor BTS for ARFCN %u BSIC %u ?!?\n", arfcn, bsic); + return -EINVAL; + } + + /* and actually try to handover to that cell */ + return bsc_handover_start(lchan, new_bts); +} + +#define RXLEV_HYST 3 + +/* process an already parsed measurement report */ +static int process_meas_rep(struct gsm_meas_rep *mr) +{ + struct gsm_meas_rep_cell *mr_cell = NULL; + unsigned int best_better_db; + int i; + + DEBUGP(DHO, "process meas res: "); + + /* FIXME: implement actual averaging over multiple measurement + * reports */ + + /* find the best cell in this report that is at least RXLEV_HYST + * better than the current serving cell */ + for (i = 0; i < mr->num_cell; i++) { + unsigned int better; + if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST) + continue; + + better = mr->cell[i].rxlev - mr->dl.full.rx_lev; + if (better > best_better_db) { + mr_cell = &mr->cell[i]; + best_better_db = better; + } + } + + if (mr_cell) { + DEBUGPC(DHO, "Cell on ARFCN %u is better, starting handover\n", mr_cell->arfcn); + return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, + mr_cell->bsic); + } + + DEBUGPC(DHO, "No better cell\n"); + return 0; +} + +static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct gsm_meas_rep *mr; + + if (subsys != SS_LCHAN) + return 0; + + switch (signal) { + case S_LCHAN_MEAS_REP: + mr = signal_data; + process_meas_rep(mr); + break; + } + + return 0; +} + +void on_dso_load_ho_dec(void) +{ + register_signal_handler(SS_LCHAN, ho_dec_sig_cb, NULL); +} diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index d4a888487..99b3c0139 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -85,23 +85,40 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) { struct gsm_lchan *new_lchan; struct bsc_handover *ho; + static u_int8_t ho_ref; int rc; + DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u): ", + old_lchan->ts->trx->bts->nr, bts->nr); + new_lchan = lchan_alloc(bts, old_lchan->type); - if (!new_lchan) + if (!new_lchan) { + DEBUGPC(DHO, "No free channel\n"); return -ENOSPC; + } ho = talloc_zero(NULL, struct bsc_handover); if (!ho) { + DEBUGPC(DHO, "Out of Memory\n"); lchan_free(new_lchan); return -ENOMEM; } ho->old_lchan = old_lchan; ho->new_lchan = new_lchan; + ho->ho_ref = ho_ref++; + + /* copy some parameters from old lchan */ + memcpy(&new_lchan->encr, &old_lchan->encr, sizeof(new_lchan->encr)); + new_lchan->ms_power = old_lchan->ms_power; + new_lchan->bs_power = old_lchan->bs_power; + new_lchan->rsl_cmode = old_lchan->rsl_cmode; + new_lchan->tch_mode = old_lchan->tch_mode; /* FIXME: do we have a better idea of the timing advance? */ - rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0); + rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0, + ho->ho_ref); if (rc < 0) { + DEBUGPC(DHO, "could not activate channel\n"); talloc_free(ho); lchan_free(new_lchan); return rc; @@ -118,6 +135,8 @@ static void ho_T3103_cb(void *_ho) { struct bsc_handover *ho = _ho; + DEBUGP(DHO, "HO T3103 expired\n"); + lchan_free(ho->new_lchan); llist_del(&ho->list); talloc_free(ho); @@ -129,6 +148,8 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) struct bsc_handover *ho; int rc; + DEBUGP(DHO, "handover activate ack, send HO Command\n"); + ho = bsc_ho_by_new_lchan(new_lchan); if (!ho) return -ENODEV; @@ -136,7 +157,7 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) /* we can now send the 04.08 HANDOVER COMMAND to the MS * using the old lchan */ - rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0); + rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0, ho->ho_ref); /* start T3103. We can continue either with T3103 expiration, * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ From cc9beb53663c9660c7e7a225256a9e71d3c9165e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 17:13:28 +0100 Subject: [PATCH 083/365] introduce trans_lchan_change() to update transaction about lchan change --- openbsc/include/openbsc/transaction.h | 5 +++++ openbsc/src/transaction.c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 961a64923..6314f987f 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -65,4 +65,9 @@ void trans_free(struct gsm_trans *trans); int trans_assign_trans_id(struct gsm_subscriber *subscr, u_int8_t protocol, u_int8_t ti_flag); + +/* update all transactions to use a different LCHAN, e.g. + * after handover has succeeded */ +int trans_lchan_change(struct gsm_lchan *lchan_old, + struct gsm_lchan *lchan_new); #endif diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 04eaa3c99..9f1bbf36d 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -140,3 +140,22 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, return -1; } + +/* update all transactions to use a different LCHAN, e.g. + * after handover has succeeded */ +int trans_lchan_change(struct gsm_lchan *lchan_old, + struct gsm_lchan *lchan_new) +{ + struct gsm_network *net = lchan_old->ts->trx->bts->network; + struct gsm_trans *trans; + int num = 0; + + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->lchan == lchan_old) { + trans->lchan = lchan_new; + num++; + } + } + + return num; +} From fe18d5cba426cd537140a09cb0c74e5d3be0a0ec Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 17:14:43 +0100 Subject: [PATCH 084/365] call trans_lchan_change() from ho_gsm48_ho_compl() --- openbsc/src/handover_logic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 99b3c0139..68cdcba07 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -196,6 +196,9 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) bsc_del_timer(&ho->T3103); llist_del(&ho->list); + /* update lchan pointer of transaction */ + trans_lchan_change(ho->old_lchan, new_lchan); + /* do something to re-route the actual speech frames ! */ //tch_remap(ho->old_lchan, ho->new_lchan); From 7cb7a73b4fe7152dc89f4450c43d5f10daf9900a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 21:32:19 +0100 Subject: [PATCH 085/365] [vty] ensure we mark fd in writefd once we vty_out() something --- openbsc/src/vty/vty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index affe28d8d..788c7fd6f 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -236,6 +236,8 @@ int vty_out(struct vty *vty, const char *format, ...) talloc_free(p); } + vty_event(VTY_WRITE, vty->fd, vty); + return len; } From 66706812514c4baca743ad3a07e4556d48b6cded Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 22:23:21 +0100 Subject: [PATCH 086/365] don't try multiple concurrent handovers for 1 channel --- openbsc/src/handover_logic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 68cdcba07..9da8baf91 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -88,6 +88,11 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) static u_int8_t ho_ref; int rc; + /* don't attempt multiple handovers for the same lchan at + * the same time */ + if (bsc_ho_by_old_lchan(old_lchan)) + return -EBUSY; + DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u): ", old_lchan->ts->trx->bts->nr, bts->nr); From b1d4c8ed9d2b4ecb76355d71a152c22934c48504 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 23:10:46 +0100 Subject: [PATCH 087/365] logging: introduce log levels at caller site This introduces a new LOGP() macro together with LOGL_* definition to support multiple log levels (severities) throughout the codebase. Please note that the actual logging system does not use them yet, in this patch we simply introduce the new macros at the caller site. --- openbsc/include/openbsc/debug.h | 11 ++++++ openbsc/src/abis_nm.c | 16 ++++----- openbsc/src/abis_rsl.c | 58 ++++++++++++++++---------------- openbsc/src/bsc_init.c | 28 +++++++-------- openbsc/src/chan_alloc.c | 8 ++--- openbsc/src/e1_config.c | 5 +-- openbsc/src/e1_input.c | 14 ++++---- openbsc/src/handover_decision.c | 8 ++--- openbsc/src/handover_logic.c | 28 ++++++++++----- openbsc/src/mncc.c | 13 ++++--- openbsc/src/msgb.c | 5 ++- openbsc/src/rtp_proxy.c | 2 +- openbsc/src/system_information.c | 11 +++--- openbsc/src/telnet_interface.c | 13 ++++--- openbsc/src/trau_frame.c | 18 ++++++---- openbsc/src/trau_mux.c | 4 ++- 16 files changed, 140 insertions(+), 102 deletions(-) diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index c1098a53c..fc387cec3 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -44,4 +44,15 @@ void debug_use_color(int use_color); void debug_timestamp(int enable); extern unsigned int debug_mask; +/* new logging interface */ +#define LOGP(ss, level, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ##args) +#define LOGPC(ss, level, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ##args) + +/* different levels */ +#define LOGL_DEBUG 1 /* debugging information */ +#define LOGL_INFO 3 +#define LOGL_NOTICE 5 /* abnormal/unexpected condition */ +#define LOGL_ERROR 7 /* error condition, requires user action */ +#define LOGL_FATAL 8 /* fatal, program aborted */ + #endif /* _DEBUG_H */ diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 30b3ec632..e7e3bf004 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1088,8 +1088,8 @@ static int abis_nm_rcvmsg_manuf(struct msgb *mb) rc = abis_nm_rx_ipacc(mb); break; default: - fprintf(stderr, "don't know how to parse OML for this " - "BTS type (%u)\n", bts_type); + LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this " + "BTS type (%u)\n", bts_type); rc = 0; break; } @@ -1106,12 +1106,12 @@ int abis_nm_rcvmsg(struct msgb *msg) /* Various consistency checks */ if (oh->placement != ABIS_OM_PLACEMENT_ONLY) { - fprintf(stderr, "ABIS OML placement 0x%x not supported\n", + LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n", oh->placement); return -EINVAL; } if (oh->sequence != 0) { - fprintf(stderr, "ABIS OML sequence 0x%x != 0x00\n", + LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n", oh->sequence); return -EINVAL; } @@ -1119,12 +1119,12 @@ int abis_nm_rcvmsg(struct msgb *msg) unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg); unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr); if (oh->length + hlen > l2_len) { - fprintf(stderr, "ABIS OML truncated message (%u > %u)\n", + LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n", oh->length + sizeof(*oh), l2_len); return -EINVAL; } if (oh->length + hlen < l2_len) - fprintf(stderr, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len); + LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len); #endif msg->l3h = (unsigned char *)oh + sizeof(*oh); @@ -1137,11 +1137,11 @@ int abis_nm_rcvmsg(struct msgb *msg) break; case ABIS_OM_MDISC_MMI: case ABIS_OM_MDISC_TRAU: - fprintf(stderr, "unimplemented ABIS OML message discriminator 0x%x\n", + LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n", oh->mdisc); break; default: - fprintf(stderr, "unknown ABIS OML message discriminator 0x%x\n", + LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n", oh->mdisc); return -EINVAL; } diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index d42daf5f2..c4bb4bd11 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -206,32 +206,32 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) if (ts->pchan != GSM_PCHAN_TCH_F && ts->pchan != GSM_PCHAN_PDCH && ts->pchan != GSM_PCHAN_TCH_F_PDCH) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if ((cbits & 0x1e) == 0x02) { lch_idx = cbits & 0x1; /* TCH/H */ if (ts->pchan != GSM_PCHAN_TCH_H) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if ((cbits & 0x1c) == 0x04) { lch_idx = cbits & 0x3; /* SDCCH/4 */ if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if ((cbits & 0x18) == 0x08) { lch_idx = cbits & 0x7; /* SDCCH/8 */ if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) { lch_idx = 0; if (ts->pchan != GSM_PCHAN_CCCH && ts->pchan != GSM_PCHAN_CCCH_SDCCH4) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); /* FIXME: we should not return first sdcch4 !!! */ } else { - fprintf(stderr, "unknown chan_nr=0x%02x\n", chan_nr); + LOGP(DRSL, LOGL_ERROR, "unknown chan_nr=0x%02x\n", chan_nr); return NULL; } @@ -491,7 +491,7 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && lchan->tch_mode != GSM48_CMODE_SIGN) - DEBUGP(DRSL, "unsupported: rsl_mode == signalling, " + LOGP(DRSL, LOGL_ERROR, "unsupported: rsl_mode == signalling, " "but tch_mode != signalling\n"); switch (lchan->type) { @@ -848,7 +848,7 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id) struct abis_rsl_rll_hdr *rh; if (msg->lchan == NULL) { - fprintf(stderr, "cannot send DATA REQUEST to unknown lchan\n"); + LOGP(DRSL, LOGL_ERROR, "cannot send DATA REQUEST to unknown lchan\n"); return -EINVAL; } @@ -949,7 +949,8 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - DEBUGPC(DRSL, "CONNECTION FAIL: "); + /* FIXME: print which channel */ + LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING\n"); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -957,8 +958,6 @@ static int rsl_rx_conn_fail(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); - DEBUGPC(DRSL, "RELEASING.\n"); - /* FIXME: only free it after channel release ACK */ return rsl_rf_chan_release(msg->lchan); } @@ -1171,7 +1170,7 @@ static int rsl_rx_error_rep(struct msgb *msg) struct abis_rsl_common_hdr *rslh = msgb_l2(msg); struct tlv_parsed tp; - DEBUGP(DRSL, "ERROR REPORT "); + LOGP(DRSL, LOGL_ERROR, "ERROR REPORT "); rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh)); @@ -1179,7 +1178,7 @@ static int rsl_rx_error_rep(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); - DEBUGPC(DRSL, "\n"); + LOGPC(DRSL, LOGL_ERROR, "\n"); return 0; } @@ -1199,7 +1198,7 @@ static int abis_rsl_rx_trx(struct msgb *msg) break; case RSL_MT_OVERLOAD: /* indicate CCCH / ACCH / processor overload */ - DEBUGP(DRSL, "TRX: CCCH/ACCH/CPU Overload\n"); + LOGP(DRSL, LOGL_ERROR, "TRX: CCCH/ACCH/CPU Overload\n"); break; default: DEBUGP(DRSL, "Unknown Abis RSL TRX message type 0x%02x\n", @@ -1350,12 +1349,12 @@ static int abis_rsl_rx_cchan(struct msgb *msg) /* CCCH overloaded, IMM_ASSIGN was dropped */ case RSL_MT_CBCH_LOAD_IND: /* current load on the CBCH */ - fprintf(stderr, "Unimplemented Abis RSL TRX message type " - "0x%02x\n", rslh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "Unimplemented Abis RSL TRX message " + "type 0x%02x\n", rslh->c.msg_type); break; default: - fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n", - rslh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "Unknown Abis RSL TRX message type " + "0x%02x\n", rslh->c.msg_type); return -EINVAL; } @@ -1367,7 +1366,7 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); u_int8_t *rlm_cause = rllh->data; - DEBUGPC(DRLL, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]); + LOGP(DRLL, LOGL_ERROR, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]); rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); @@ -1448,12 +1447,12 @@ static int abis_rsl_rx_rll(struct msgb *msg) rc = rsl_rx_rll_err_ind(msg); break; case RSL_MT_UNIT_DATA_IND: - DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x\n", - rllh->c.msg_type); + LOGP(DRLL, LOGL_NOTICE, "unimplemented Abis RLL message " + "type 0x%02x\n", rllh->c.msg_type); break; default: - DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x\n", - rllh->c.msg_type); + LOGP(DRLL, LOGL_NOTICE, "unknown Abis RLL message " + "type 0x%02x\n", rllh->c.msg_type); } return rc; } @@ -1490,7 +1489,7 @@ static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) default: break; } - DEBUGPC(DRSL, "Cannot determine ip.access speech mode for " + LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access speech mode for " "tch_mode == 0x%02x\n", lchan->tch_mode); return 0; } @@ -1604,7 +1603,7 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) if (!TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_PORT) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_IP) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_CONN_ID)) { - DEBUGPC(DRSL, "mandatory IE missing"); + LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing"); return -EINVAL; } ip.s_addr = *((u_int32_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_IP)); @@ -1680,7 +1679,8 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) rc = abis_rsl_rx_ipacc_dlcx_ind(msg); break; default: - DEBUGPC(DRSL, "Unknown ip.access msg_type 0x%02x", rllh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x", + rllh->c.msg_type); break; } DEBUGPC(DRSL, "\n"); @@ -1709,15 +1709,15 @@ int abis_rsl_rcvmsg(struct msgb *msg) rc = abis_rsl_rx_trx(msg); break; case ABIS_RSL_MDISC_LOC: - fprintf(stderr, "unimplemented RSL msg disc 0x%02x\n", + LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL msg disc 0x%02x\n", rslh->msg_discr); break; case ABIS_RSL_MDISC_IPACCESS: rc = abis_rsl_rx_ipacc(msg); break; default: - fprintf(stderr, "unknown RSL message discriminator 0x%02x\n", - rslh->msg_discr); + LOGP(DRSL, LOGL_NOTICE, "unknown RSL message discriminator " + "0x%02x\n", rslh->msg_discr); return -EINVAL; } msgb_free(msg); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index ce3d0b4f8..744eacb24 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -453,7 +453,7 @@ static int sw_activ_rep(struct msgb *mb) static int oml_msg_nack(u_int8_t mt) { if (mt == NM_MT_SET_BTS_ATTR_NACK) { - fprintf(stderr, "Failed to set BTS attributes. That is fatal. " + LOGP(DNM, LOGL_FATAL, "Failed to set BTS attributes. That is fatal. " "Was the bts type and frequency properly specified?\n"); exit(-1); } @@ -556,7 +556,7 @@ static void nm_reconfig_trx(struct gsm_bts_trx *trx) trx->nominal_power = 23; break; default: - fprintf(stderr, "Unsupported nanoBTS GSM band %s\n", + LOGP(DNM, LOGL_ERROR, "Unsupported nanoBTS GSM band %s\n", gsm_band_name(trx->bts->band)); break; } @@ -621,7 +621,7 @@ static void bootstrap_om_bs11(struct gsm_bts *bts) static void bootstrap_om(struct gsm_bts *bts) { - fprintf(stdout, "bootstrapping OML for BTS %u\n", bts->nr); + LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr); switch (bts->type) { case GSM_BTS_TYPE_BS11: @@ -631,13 +631,13 @@ static void bootstrap_om(struct gsm_bts *bts) bootstrap_om_nanobts(bts); break; default: - fprintf(stderr, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type); + LOGP(DNM, LOGL_ERROR, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type); } } static int shutdown_om(struct gsm_bts *bts) { - fprintf(stdout, "shutting down OML for BTS %u\n", bts->nr); + LOGP(DNM, LOGL_NOTICE, "shutting down OML for BTS %u\n", bts->nr); /* stop sending event reports */ abis_nm_event_reports(bts, 0); @@ -707,7 +707,7 @@ static int set_system_infos(struct gsm_bts_trx *trx) return 0; err_out: - fprintf(stderr, "Cannot generate SI %u for BTS %u, most likely " + LOGP(DRR, LOGL_ERROR, "Cannot generate SI %u for BTS %u, most likely " "a problem with neighbor cell list generation\n", i, trx->bts->nr); return rc; @@ -746,7 +746,7 @@ static void patch_nm_tables(struct gsm_bts *bts) static void bootstrap_rsl(struct gsm_bts_trx *trx) { - fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " + LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) " "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", trx->bts->nr, trx->nr, bsc_gsmnet->country_code, bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc); @@ -769,7 +769,7 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) } break; case EVT_E1_TEI_DN: - fprintf(stderr, "Lost some E1 TEI link\n"); + LOGP(DMI, LOGL_NOTICE, "Lost some E1 TEI link\n"); /* FIXME: deal with TEI or L1 link loss */ break; default: @@ -782,30 +782,30 @@ static int bootstrap_bts(struct gsm_bts *bts) switch (bts->band) { case GSM_BAND_1800: if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) { - fprintf(stderr, "GSM1800 channel must be between 512-885.\n"); + LOGP(DNM, LOGL_ERROR, "GSM1800 channel must be between 512-885.\n"); return -EINVAL; } break; case GSM_BAND_1900: if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) { - fprintf(stderr, "GSM1900 channel must be between 512-810.\n"); + LOGP(DNM, LOGL_ERROR, "GSM1900 channel must be between 512-810.\n"); return -EINVAL; } break; case GSM_BAND_900: if (bts->c0->arfcn < 1 || bts->c0->arfcn > 124) { - fprintf(stderr, "GSM900 channel must be between 1-124.\n"); + LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 1-124.\n"); return -EINVAL; } break; default: - fprintf(stderr, "Unsupported frequency band.\n"); + LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n"); return -EINVAL; } if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && !bts->cell_barred) - fprintf(stderr, "\nWARNING: You are running an 'accept-all' " + LOGP(DNM, LOG_ERROR, "\nWARNING: You are running an 'accept-all' " "network on a BTS that is not barred. This " "configuration is likely to interfere with production " "GSM networks and should only be used in a RF " @@ -858,7 +858,7 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, int, void *), telnet_init(bsc_gsmnet, 4242); rc = vty_read_config_file(config_file); if (rc < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file); return rc; } diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 0a2984773..786e8b11b 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -210,7 +210,7 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) } break; default: - fprintf(stderr, "Unknown gsm_chan_t %u\n", type); + LOGP(DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type); } if (lchan) { @@ -276,9 +276,9 @@ int lchan_auto_release(struct gsm_lchan *lchan) } /* spoofed? message */ - if (lchan->use_count < 0) { - DEBUGP(DRLL, "Channel count is negative: %d\n", lchan->use_count); - } + if (lchan->use_count < 0) + LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n", + lchan->use_count); DEBUGP(DRLL, "Recycling the channel with: %d (%x)\n", lchan->nr, lchan->nr); rsl_release_request(lchan, 0); diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c index 62bacf2ca..6a2abd85b 100644 --- a/openbsc/src/e1_config.c +++ b/openbsc/src/e1_config.c @@ -10,6 +10,7 @@ #include #include #include +#include #define SAPI_L2ML 0 #define SAPI_OML 62 @@ -25,7 +26,7 @@ int e1_reconfig_ts(struct gsm_bts_trx_ts *ts) struct e1inp_line *line; struct e1inp_ts *e1_ts; - printf("e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr); + DEBUGP(DMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr); if (!e1_link->e1_ts) return 0; @@ -87,7 +88,7 @@ int e1_reconfig_bts(struct gsm_bts *bts) struct e1inp_sign_link *oml_link; struct gsm_bts_trx *trx; - printf("e1_reconfig_bts(%u)\n", bts->nr); + DEBUGP(DMI, "e1_reconfig_bts(%u)\n", bts->nr); if (!e1_link->e1_ts) return -EINVAL; diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index 15495fbbb..083d8f8de 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -235,7 +235,7 @@ int abis_rsl_sendmsg(struct msgb *msg) msg->l2h = msg->data; if (!msg->trx || !msg->trx->rsl_link) { - fprintf(stderr, "rsl_sendmsg: msg->trx == NULL\n"); + LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL\n"); talloc_free(msg); return -EINVAL; } @@ -264,7 +264,7 @@ int _abis_nm_sendmsg(struct msgb *msg) msg->l2h = msg->data; if (!msg->trx || !msg->trx->bts || !msg->trx->bts->oml_link) { - fprintf(stderr, "nm_sendmsg: msg->trx == NULL\n"); + LOGP(DRSL, LOGL_ERROR, "nm_sendmsg: msg->trx == NULL\n"); return -EINVAL; } @@ -306,7 +306,7 @@ int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line, subch_demux_init(&ts->trau.demux); break; default: - fprintf(stderr, "unsupported E1 timeslot type %u\n", + LOGP(DMI, LOGL_ERROR, "unsupported E1 timeslot type %u\n", ts->type); return -EINVAL; } @@ -431,7 +431,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, write_pcap_packet(PCAP_INPUT, sapi, tei, msg); link = e1inp_lookup_sign_link(ts, tei, sapi); if (!link) { - fprintf(stderr, "didn't find signalling link for " + LOGP(DMI, LOGL_ERROR, "didn't find signalling link for " "tei %d, sapi %d\n", tei, sapi); return -EINVAL; } @@ -446,7 +446,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, break; default: ret = -EINVAL; - fprintf(stderr, "unknown link type %u\n", link->type); + LOGP(DMI, LOGL_ERROR, "unknown link type %u\n", link->type); break; } break; @@ -455,7 +455,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, break; default: ret = -EINVAL; - fprintf(stderr, "unknown TS type %u\n", ts->type); + LOGP(DMI, LOGL_ERROR, "unknown TS type %u\n", ts->type); break; } @@ -492,7 +492,7 @@ struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts, msgb_put(msg, 40); break; default: - fprintf(stderr, "unsupported E1 TS type %u\n", e1i_ts->type); + LOGP(DMI, LOGL_ERROR, "unsupported E1 TS type %u\n", e1i_ts->type); return NULL; } return msg; diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 06eb86507..a1956868d 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -41,7 +41,8 @@ static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, /* resolve the gsm_bts structure for the best neighbor */ new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic); if (!new_bts) { - DEBUGP(DHO, "unable to determine neighbor BTS for ARFCN %u BSIC %u ?!?\n", arfcn, bsic); + LOGP(DHO, LOGL_NOTICE, "unable to determine neighbor BTS " + "for ARFCN %u BSIC %u ?!?\n", arfcn, bsic); return -EINVAL; } @@ -58,8 +59,6 @@ static int process_meas_rep(struct gsm_meas_rep *mr) unsigned int best_better_db; int i; - DEBUGP(DHO, "process meas res: "); - /* FIXME: implement actual averaging over multiple measurement * reports */ @@ -78,7 +77,8 @@ static int process_meas_rep(struct gsm_meas_rep *mr) } if (mr_cell) { - DEBUGPC(DHO, "Cell on ARFCN %u is better, starting handover\n", mr_cell->arfcn); + LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better, starting " + "handover\n", mr_cell->arfcn); return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, mr_cell->bsic); } diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 9da8baf91..66ff77362 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -93,18 +93,18 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) if (bsc_ho_by_old_lchan(old_lchan)) return -EBUSY; - DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u): ", + DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); new_lchan = lchan_alloc(bts, old_lchan->type); if (!new_lchan) { - DEBUGPC(DHO, "No free channel\n"); + LOGP(DHO, LOGL_NOTICE, "No free channel\n"); return -ENOSPC; } ho = talloc_zero(NULL, struct bsc_handover); if (!ho) { - DEBUGPC(DHO, "Out of Memory\n"); + LOGP(DHO, LOGL_FATAL, "Out of Memory\n"); lchan_free(new_lchan); return -ENOMEM; } @@ -123,7 +123,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0, ho->ho_ref); if (rc < 0) { - DEBUGPC(DHO, "could not activate channel\n"); + LOGP(DHO, LOGL_ERROR, "could not activate channel\n"); talloc_free(ho); lchan_free(new_lchan); return rc; @@ -156,8 +156,10 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) DEBUGP(DHO, "handover activate ack, send HO Command\n"); ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } /* we can now send the 04.08 HANDOVER COMMAND to the MS * using the old lchan */ @@ -178,8 +180,10 @@ static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) struct bsc_handover *ho; ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } llist_del(&ho->list); talloc_free(ho); @@ -195,8 +199,10 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) struct bsc_handover *ho; ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } bsc_del_timer(&ho->T3103); llist_del(&ho->list); @@ -221,8 +227,10 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) struct bsc_handover *ho; ho = bsc_ho_by_old_lchan(old_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } bsc_del_timer(&ho->T3103); llist_del(&ho->list); @@ -238,8 +246,10 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) struct bsc_handover *ho; ho = bsc_ho_by_old_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } /* FIXME: do we actually want to do something here ? */ diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index de1765761..a5efc7312 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -85,8 +85,7 @@ static struct mncc_names { {"GSM_TRAU_FRAME", 0x0300}, - {NULL, 0} -}; + {NULL, 0} }; static LLIST_HEAD(call_list); @@ -146,8 +145,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, /* transfer mode 1 would be packet mode, which was never specified */ if (setup->bearer_cap.mode != 0) { - DEBUGP(DMNCC, "(call %x) We don't support packet mode\n", - call->callref); + LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support " + "packet mode\n", call->callref); mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); goto out_reject; @@ -155,8 +154,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, /* we currently only do speech */ if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) { - DEBUGP(DMNCC, "(call %x) We only support voice calls\n", - call->callref); + LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support " + "voice calls\n", call->callref); mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); goto out_reject; @@ -406,7 +405,7 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) rc = mncc_send(net, MNCC_RETRIEVE_REJ, data); break; default: - DEBUGP(DMNCC, "(call %x) Message unhandled\n", callref); + LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref); break; } diff --git a/openbsc/src/msgb.c b/openbsc/src/msgb.c index edeb975a9..48a5a7b03 100644 --- a/openbsc/src/msgb.c +++ b/openbsc/src/msgb.c @@ -26,6 +26,7 @@ #include #include #include +#include static void *tall_msgb_ctx; @@ -35,8 +36,10 @@ struct msgb *msgb_alloc(u_int16_t size, const char *name) msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name); - if (!msg) + if (!msg) { + LOGP(DRSL, LOGL_FATAL, "unable to allocate msgb\n"); return NULL; + } msg->data_len = size; msg->len = 0; diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 59c0735a5..bfd494856 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -211,7 +211,7 @@ static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss) written = write(rss->bfd.fd, msg->data, msg->len); if (written < msg->len) { - perror("short write"); + LOGP(DMIB, LOGL_ERROR, "short write"); msgb_free(msg); return -EIO; } diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 644abb432..b404e5151 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -45,8 +45,10 @@ static int freq_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; - if (arfcn > 124 || arfcn < 1) + if (arfcn > 124 || arfcn < 1) { + LOGP(DRR, LOGL_ERROR, "Bitmap 0 only supports ARFCN 1...124\n"); return -EINVAL; + } /* the bitmask is from 1..124, not from 0..123 */ arfcn--; @@ -75,11 +77,11 @@ static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) return 0; if (arfcn < min_arfcn) { - DEBUGP(DRR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn); + LOGP(DRR, LOGL_ERROR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn); return -EINVAL; } if (arfcn > min_arfcn + 111) { - DEBUGP(DRR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn); + LOGP(DRR, LOGL_ERROR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn); return -EINVAL; } @@ -127,7 +129,8 @@ static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, } if ((max - min) > 111) { - DEBUGP(DRR, "min_arfcn=%u, max_arfcn=%u, distance > 111\n", min, max); + LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, " + "distance > 111\n", min, max); return -EINVAL; } diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index 128c34e94..2d7b05c70 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -71,7 +72,7 @@ void telnet_init(struct gsm_network *network, int port) { fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { - perror("Telnet interface socket creation failed"); + LOGP(DNM, LOGL_ERROR, "Telnet interface socket creation failed\n"); return; } @@ -83,12 +84,12 @@ void telnet_init(struct gsm_network *network, int port) { sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) { - perror("Telnet interface failed to bind"); + LOGP(DNM, LOG_ERROR, "Telnet interface failed to bind\n"); return; } if (listen(fd, 0) < 0) { - perror("Telnet interface failed to listen"); + LOGP(DNM, LOG_ERROR, "Telnet interface failed to listen\n"); return; } @@ -154,7 +155,7 @@ static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) { int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len); if (new_connection < 0) { - perror("telnet accept failed"); + LOGP(DNM, LOGL_ERROR, "telnet accept failed\n"); return -1; } @@ -171,8 +172,10 @@ static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) { print_welcome(new_connection); connection->vty = vty_create(new_connection, connection); - if (!connection->vty) + if (!connection->vty) { + LOGP(DNM, LOGL_ERROR, "couldn't create VTY\n"); return -1; + } return 0; } diff --git a/openbsc/src/trau_frame.c b/openbsc/src/trau_frame.c index aa039574b..2bc61a513 100644 --- a/openbsc/src/trau_frame.c +++ b/openbsc/src/trau_frame.c @@ -107,11 +107,13 @@ int decode_trau_frame(struct decoded_trau_frame *fr, const u_int8_t *trau_bits) case TRAU_FT_DATA_DOWN: case TRAU_FT_D145_SYNC: case TRAU_FT_EDATA: - DEBUGP(DMUX, "can't decode unimplemented TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "can't decode unimplemented TRAU " + "Frame Type 0x%02x\n", cbits5); return -1; break; default: - DEBUGP(DMUX, "can't decode unknown TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "can't decode unknown TRAU " + "Frame Type 0x%02x\n", cbits5); return -1; break; } @@ -162,11 +164,13 @@ int trau_frame_up2down(struct decoded_trau_frame *fr) case TRAU_FT_DATA_UP: case TRAU_FT_D145_SYNC: case TRAU_FT_EDATA: - DEBUGP(DMUX, "unimplemented TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; default: - DEBUGP(DMUX, "unknown TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unknown TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; } @@ -224,11 +228,13 @@ int encode_trau_frame(u_int8_t *trau_bits, const struct decoded_trau_frame *fr) case TRAU_FT_DATA_DOWN: case TRAU_FT_D145_SYNC: case TRAU_FT_EDATA: - DEBUGP(DMUX, "unimplemented TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; default: - DEBUGP(DMUX, "unknown TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unknown TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; } diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c index 6a19f0c99..7ea65ce35 100644 --- a/openbsc/src/trau_mux.c +++ b/openbsc/src/trau_mux.c @@ -56,8 +56,10 @@ int trau_mux_map(const struct gsm_e1_subslot *src, struct map_entry *me; me = talloc(tall_map_ctx, struct map_entry); - if (!me) + if (!me) { + LOGP(DMIB, LOGL_FATAL, "Out of memory\n"); return -ENOMEM; + } DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) " "and (e1=%u,ts=%u,ss=%u)\n", From fa5aad789b794f3d24f97351b6ab85775b601c0e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 23:13:38 +0100 Subject: [PATCH 088/365] add handover.h file to Makefile.am to make distcheck happy --- openbsc/include/openbsc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 161a9a66e..27c88b770 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -5,4 +5,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \ - system_information.h + system_information.h handover.h From e47f96b80c42809b99e5a875de949c843abd6957 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 11:49:03 +0100 Subject: [PATCH 089/365] fix segfault in case of handover timer expiration --- openbsc/src/handover_logic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 66ff77362..93870aa4c 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -169,6 +169,7 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) /* start T3103. We can continue either with T3103 expiration, * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ ho->T3103.cb = ho_T3103_cb; + ho->T3103.data = ho; bsc_schedule_timer(&ho->T3103, 10, 0); return 0; From 386cd2b777ea24b55264c884ccb52efd44e04073 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 11:49:20 +0100 Subject: [PATCH 090/365] for now we only do handover of TCH channels --- openbsc/src/handover_decision.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index a1956868d..c0ec0a931 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -59,6 +59,15 @@ static int process_meas_rep(struct gsm_meas_rep *mr) unsigned int best_better_db; int i; + /* we currently only do handover for TCH channels */ + switch (mr->lchan->type) { + case GSM_LCHAN_TCH_F: + case GSM_LCHAN_TCH_H: + break; + default: + return 0; + } + /* FIXME: implement actual averaging over multiple measurement * reports */ From 6f7a5a7843877a82dc288a89ac0553333769b7ec Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 11:52:03 +0100 Subject: [PATCH 091/365] handover: use correct handover lookup function --- openbsc/src/handover_logic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 93870aa4c..d852f8e3c 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -246,7 +246,7 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) { struct bsc_handover *ho; - ho = bsc_ho_by_old_lchan(new_lchan); + ho = bsc_ho_by_new_lchan(new_lchan); if (!ho) { LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; From a9fa8dca33e10c98db0ff6dddc2f999c37b25e63 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 14:50:08 +0100 Subject: [PATCH 092/365] [handover]: make sure the new lchan keeps the subscriber pointer of the old lchan also, ensure that we don't print debug messages about handover in non-handover channel activation cases. --- openbsc/src/handover_logic.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index d852f8e3c..f3f5d6c21 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -118,6 +118,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) new_lchan->bs_power = old_lchan->bs_power; new_lchan->rsl_cmode = old_lchan->rsl_cmode; new_lchan->tch_mode = old_lchan->tch_mode; + new_lchan->subscr = subscr_get(old_lchan->subscr); /* FIXME: do we have a better idea of the timing advance? */ rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0, @@ -153,13 +154,13 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) struct bsc_handover *ho; int rc; - DEBUGP(DHO, "handover activate ack, send HO Command\n"); - + /* we need to check if this channel activation is related to + * a handover at all (and if, which particular handover) */ ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) { - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); + if (!ho) return -ENODEV; - } + + DEBUGP(DHO, "handover activate ack, send HO Command\n"); /* we can now send the 04.08 HANDOVER COMMAND to the MS * using the old lchan */ From 3b104996946b66e6956da2d299557a1486dc26ed Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 14:50:57 +0100 Subject: [PATCH 093/365] remove call_handling.h, a reminescent of old days --- openbsc/include/openbsc/call_handling.h | 64 ------------------------- 1 file changed, 64 deletions(-) delete mode 100644 openbsc/include/openbsc/call_handling.h diff --git a/openbsc/include/openbsc/call_handling.h b/openbsc/include/openbsc/call_handling.h deleted file mode 100644 index 02027889e..000000000 --- a/openbsc/include/openbsc/call_handling.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * (C) 2008 by Holger Hans Peter Freyther - * (C) 2008 by Stefan Schmidt - * 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. - * - */ - -#ifndef _CALL_HANDLING_H -#define _CALL_HANDLING_H - -#include "linuxlist.h" -#include "gsm_subscriber.h" -#include "timer.h" - -/* - * State transitions to be seen from the outside - */ -#define CALL_STATE_NULL 0 -#define CALL_STATE_SETUP 1 -#define CALL_STATE_PROCEED 2 -#define CALL_STATE_ALERT 3 -#define CALL_STATE_CONNECT 4 -#define CALL_STATE_ACTIVE 5 -#define CALL_STATE_RELEASE 6 - -struct call_data { - struct llist_head entry; - void (*state_change_cb)(int oldstate, int newstate, int event, void *data); - void *data; - char *destination_number; - - /* Internal */ - int state; - char tmsi[GSM_TMSI_LENGTH]; - struct timer_list t30x; /* to be added for... */ -}; - - -int call_initiate(struct call_data *call, char *tmsi); -void call_abort(struct call_data *call); - -/** - * Get notified about new incoming calls. The call_data is owned - * and managed by the internal call handling. - */ -void call_set_callback(void (*cb)(struct call_data *call, void *data), void* data); -void call_proceed(struct call_data *call_data); -void call_connect(struct call_data *call_data); - -#endif /* _CALL_HANDLING_H */ From 18750cf1df7d7a134c5dbfc2544800f746927bb0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 14:51:48 +0100 Subject: [PATCH 094/365] [handover] lchan use count handling in case of trans_lchan_change() --- openbsc/src/transaction.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 9f1bbf36d..026928876 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -152,7 +152,12 @@ int trans_lchan_change(struct gsm_lchan *lchan_old, llist_for_each_entry(trans, &net->trans_list, entry) { if (trans->lchan == lchan_old) { + /* drop old channel use cound */ + put_lchan(trans->lchan); + /* assign new channel */ trans->lchan = lchan_new; + /* bump new channel use count */ + use_lchan(trans->lchan); num++; } } From 1d9efd6c9c318ec2ffdff537d80fbaf78f8a92c4 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:07 +0100 Subject: [PATCH 095/365] Fix typos in debug message / comments Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 4930e5c85..a87c6ed3d 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -173,7 +173,7 @@ static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans, DEBUGP(DSMS, "TX: CP-ACK "); break; case GSM411_MT_CP_ERROR: - DEBUGP(DSMS, "TX: CP-ACK "); + DEBUGP(DSMS, "TX: CP-ERROR "); break; } From c56a14181cf73e0530ecb791b2ae3bd913c998bd Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:08 +0100 Subject: [PATCH 096/365] Fix transaction_id displayed in debug message In SMS debug messages, we always display the transaction ID as if we were 'sending' the message. Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index a87c6ed3d..38f585b22 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -906,7 +906,7 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) return -EIO; /* FIXME: send some error message */ - DEBUGP(DSMS, "trans_id=%x ", gh->proto_discr >> 4); + DEBUGP(DSMS, "trans_id=%x ", transaction_id); trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS, transaction_id); if (!trans) { From feaca92fc0dde67f392e1245a6fe0ea52d1022d5 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:09 +0100 Subject: [PATCH 097/365] Use 'new' rather than 'unknown' when starting transaction 'unknown' has a negative connotation for a case that's totally normal so refer to it as 'new' so it doesn't sound like a problem. Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 38f585b22..31526e979 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -910,7 +910,7 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS, transaction_id); if (!trans) { - DEBUGPC(DSMS, "(unknown) "); + DEBUGPC(DSMS, "(new) "); trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { From ea3f674710c8fab1bf06150b4cba67e139b5e04e Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:10 +0100 Subject: [PATCH 098/365] Fix subscr ref leak for multi CM SERV REQ Multiple CM SERVICE REQUEST can happen on a single RR connection, in this case, since the subscr reference is tracked through lchan->subscr and will only be put'd once on lchan_free, we need to make sure we don't get several reference .... Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_08.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 5fea6bfbf..f87b3358f 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1343,7 +1343,9 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) if (!msg->lchan->subscr) msg->lchan->subscr = subscr; - else if (msg->lchan->subscr != subscr) { + else if (msg->lchan->subscr == subscr) + subscr_put(subscr); /* lchan already has a ref, don't need another one */ + else { DEBUGP(DMM, "<- CM Channel already owned by someone else?\n"); subscr_put(subscr); } From b9f3dce0ae8e7064e3be4951d81c351a0b76ed41 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:11 +0100 Subject: [PATCH 099/365] Never allocate transaction ID 7 According to GSM 04.07 11.2.3.1.3 , TID 7 is "reserved for future extensions". Signed-off-by: Sylvain Munaut --- openbsc/src/transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 026928876..e49f75b28 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -133,7 +133,7 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, used_tid_bitmask |= (1 << trans->transaction_id); } - for (i = 0; i <= 7; i++) { + for (i = 0; i < 7; i++) { if ((used_tid_bitmask & (1 << (i | ti_flag))) == 0) return i | ti_flag; } From f314f6899b89cacae521daf12db85531a5e20dc5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 15:05:02 +0100 Subject: [PATCH 100/365] add --help message about --rtp-proxy argument --- openbsc/src/bsc_hack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index b0f8d6c3f..c0695ef35 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -75,6 +75,7 @@ static void print_help() printf(" -l --database db-name The database to use\n"); printf(" -p --pcap file The filename of the pcap file\n"); printf(" -T --timestamp Prefix every log line with a timestamp\n"); + printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC\n"); } static void handle_options(int argc, char** argv) From 5e3d91bff71a9c456069bbf4a459b66a32f9656e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 16:42:06 +0100 Subject: [PATCH 101/365] ip.access: Keep a full copy of local and remote IP/PORT in lchan Keeping all parameters for each RTP connection in the abis_ip member of lchan will help us with actual TCH handover later on. --- openbsc/include/openbsc/abis_rsl.h | 3 +- openbsc/include/openbsc/gsm_data.h | 5 +- openbsc/include/openbsc/signal.h | 1 + openbsc/include/openbsc/tlv.h | 1 + openbsc/src/abis_rsl.c | 141 +++++++++++++++++++---------- openbsc/src/gsm_04_08.c | 3 - 6 files changed, 98 insertions(+), 56 deletions(-) diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 6d0ab6182..f0a5619ad 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -537,8 +537,7 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci); /* ip.access specfic RSL extensions */ int rsl_ipacc_crcx(struct gsm_lchan *lchan); int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, - u_int16_t port, u_int16_t conn_id, - u_int8_t rtp_payload2); + u_int16_t port, u_int8_t rtp_payload2); int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan); int abis_rsl_rcvmsg(struct msgb *msg); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index f9b0b6340..67465e460 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -200,9 +200,12 @@ struct gsm_lchan { struct { u_int32_t bound_ip; + u_int32_t connect_ip; u_int16_t bound_port; - u_int8_t rtp_payload2; + u_int16_t connect_port; u_int16_t conn_id; + u_int8_t rtp_payload2; + u_int8_t speech_mode; struct rtp_socket *rtp_socket; } abis_ip; }; diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 10fcddda3..8c815f89e 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -59,6 +59,7 @@ enum signal_sms { /* SS_ABISIP signals */ enum signal_abisip { S_ABISIP_CRCX_ACK, + S_ABISIP_MDCX_ACK, S_ABISIP_DLCX_IND, }; diff --git a/openbsc/include/openbsc/tlv.h b/openbsc/include/openbsc/tlv.h index 0cf4388d8..e970ce468 100644 --- a/openbsc/include/openbsc/tlv.h +++ b/openbsc/include/openbsc/tlv.h @@ -119,6 +119,7 @@ static inline u_int8_t *tv_put(u_int8_t *buf, u_int8_t tag, return buf; } +/* 'val' is still in host byte order! */ static inline u_int8_t *tv16_put(u_int8_t *buf, u_int8_t tag, u_int16_t val) { diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index c4bb4bd11..3310c5724 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1495,11 +1495,63 @@ static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) } /* ip.access specific RSL extensions */ +static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv) +{ + struct in_addr ip; + u_int16_t port, conn_id; + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_IP)) { + ip.s_addr = *((u_int32_t *) TLVP_VAL(tv, RSL_IE_IPAC_LOCAL_IP)); + DEBUGPC(DRSL, "LOCAL_IP=%s ", inet_ntoa(ip)); + lchan->abis_ip.bound_ip = ntohl(ip.s_addr); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_PORT)) { + port = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_LOCAL_PORT)); + port = ntohs(port); + DEBUGPC(DRSL, "LOCAL_PORT=%u ", port); + lchan->abis_ip.bound_port = port; + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_CONN_ID)) { + conn_id = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_CONN_ID)); + conn_id = ntohs(conn_id); + DEBUGPC(DRSL, "CON_ID=%u ", conn_id); + lchan->abis_ip.conn_id = conn_id; + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { + lchan->abis_ip.rtp_payload2 = + *TLVP_VAL(tv, RSL_IE_IPAC_RTP_PAYLOAD2); + DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", + lchan->abis_ip.rtp_payload2); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_SPEECH_MODE)) { + lchan->abis_ip.speech_mode = + *TLVP_VAL(tv, RSL_IE_IPAC_SPEECH_MODE); + DEBUGPC(DRSL, "speech_mode=0x%02x ", + lchan->abis_ip.speech_mode); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_IP)) { + ip.s_addr = *((u_int32_t *) TLVP_VAL(tv, RSL_IE_IPAC_REMOTE_IP)); + DEBUGPC(DRSL, "REMOTE_IP=%s ", inet_ntoa(ip)); + lchan->abis_ip.connect_ip = ntohl(ip.s_addr); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_PORT)) { + port = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_REMOTE_PORT)); + port = ntohs(port); + DEBUGPC(DRSL, "REMOTE_PORT=%u ", port); + lchan->abis_ip.connect_port = port; + } +} + int rsl_ipacc_crcx(struct gsm_lchan *lchan) { struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; - u_int8_t speech_mode; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_IPAC_CRCX); @@ -1507,12 +1559,12 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) dh->chan_nr = lchan2chan_nr(lchan); /* 0x1- == receive-only, 0x-1 == EFR codec */ - speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); + lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND " "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), - dh->chan_nr, speech_mode); + dh->chan_nr, lchan->abis_ip.speech_mode); msg->trx = lchan->ts->trx; @@ -1520,12 +1572,11 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) } int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, - u_int16_t conn_id, u_int8_t rtp_payload2) + u_int8_t rtp_payload2) { struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; - u_int8_t *att_f8, *att_ip, *att_port; - u_int8_t speech_mode; + u_int32_t *att_ip; struct in_addr ia; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); @@ -1533,34 +1584,26 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = lchan2chan_nr(lchan); + /* we need to store these now as MDCX_ACK does not return them :( */ + lchan->abis_ip.rtp_payload2 = rtp_payload2; + lchan->abis_ip.connect_port = port; + lchan->abis_ip.connect_ip = ip; + /* 0x0- == both directions, 0x-1 == EFR codec */ - speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); + lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); ia.s_addr = htonl(ip); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_MDCX " "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d speech_mode=0x%02x\n", - gsm_ts_name(lchan->ts), dh->chan_nr, - inet_ntoa(ia), port, rtp_payload2, conn_id, speech_mode); + gsm_ts_name(lchan->ts), dh->chan_nr, inet_ntoa(ia), port, + rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode); - att_f8 = msgb_put(msg, sizeof(conn_id)+1); - att_f8[0] = RSL_IE_IPAC_CONN_ID; - att_f8[1] = conn_id >> 8; - att_f8[2] = conn_id & 0xff; - - att_ip = msgb_put(msg, sizeof(ip)+1); - att_ip[0] = RSL_IE_IPAC_REMOTE_IP; - att_ip[1] = ip >> 24; - att_ip[2] = ip >> 16; - att_ip[3] = ip >> 8; - att_ip[4] = ip & 0xff; - //att_ip[4] = 11; - - att_port = msgb_put(msg, sizeof(port)+1); - att_port[0] = RSL_IE_IPAC_REMOTE_PORT; - att_port[1] = port >> 8; - att_port[2] = port & 0xff; - - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); + msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id); + msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP); + att_ip = (u_int32_t *) msgb_put(msg, sizeof(ip)); + *att_ip = ia.s_addr; + msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port); + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); if (rtp_payload2) msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2); @@ -1592,8 +1635,6 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; struct gsm_lchan *lchan = msg->lchan; - struct in_addr ip; - u_int16_t port, attr_f8; /* the BTS has acknowledged a local bind, it now tells us the IP * address and port number to which it has bound the given logical @@ -1606,30 +1647,29 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing"); return -EINVAL; } - ip.s_addr = *((u_int32_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_IP)); - port = *((u_int16_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_PORT)); - attr_f8 = *((u_int16_t *) TLVP_VAL(&tv, 0xf8)); - - DEBUGPC(DRSL, "IP=%s PORT=%d CONN_ID=%d ", - inet_ntoa(ip), ntohs(port), ntohs(attr_f8)); - - if (TLVP_PRESENT(&tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { - lchan->abis_ip.rtp_payload2 = - *TLVP_VAL(&tv, RSL_IE_IPAC_RTP_PAYLOAD2); - DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", - lchan->abis_ip.rtp_payload2); - } - - /* update our local information about this TS */ - lchan->abis_ip.bound_ip = ntohl(ip.s_addr); - lchan->abis_ip.bound_port = ntohs(port); - lchan->abis_ip.conn_id = ntohs(attr_f8); - + ipac_parse_rtp(lchan, &tv); dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); return 0; } +static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tv; + struct gsm_lchan *lchan = msg->lchan; + + /* the BTS has acknowledged a remote connect request and + * it now tells us the IP address and port number to which it has + * connected the given logical channel */ + + rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); + ipac_parse_rtp(lchan, &tv); + dispatch_signal(SS_ABISIP, S_ABISIP_MDCX_ACK, msg->lchan); + + return 0; +} + static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); @@ -1668,6 +1708,7 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) case RSL_MT_IPAC_MDCX_ACK: /* the BTS tells us that a connect operation was successful */ DEBUGPC(DRSL, "IPAC_MDCX_ACK "); + rc = abis_rsl_rx_ipacc_mdcx_ack(msg); break; case RSL_MT_IPAC_MDCX_NACK: /* somehow the BTS was unable to connect the lchan to a remote diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f87b3358f..589133e27 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1920,7 +1920,6 @@ static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), ntohs(rs->rtp.sin_local.sin_port), - lchan->abis_ip.conn_id, /* FIXME: use RTP payload of bound socket, not BTS*/ lchan->abis_ip.rtp_payload2); @@ -1959,13 +1958,11 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) /* directly connect TCH RTP streams to each other */ rc = rsl_ipacc_mdcx(lchan, remote_lchan->abis_ip.bound_ip, remote_lchan->abis_ip.bound_port, - lchan->abis_ip.conn_id, remote_lchan->abis_ip.rtp_payload2); if (rc < 0) return rc; rc = rsl_ipacc_mdcx(remote_lchan, lchan->abis_ip.bound_ip, lchan->abis_ip.bound_port, - remote_lchan->abis_ip.conn_id, lchan->abis_ip.rtp_payload2); } break; From 51cec5f7259e14e4c6f78a69c3d411964b1baf4c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 16:45:29 +0100 Subject: [PATCH 102/365] measurement report parsing: NO-NCELL-M of 7 tells us no neighbors --- openbsc/src/gsm_04_08.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 589133e27..d59d7d7ca 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -191,7 +191,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); - if (rep->num_cell < 1) + if (rep->num_cell < 1 || rep->num_cell > 6) return 0; /* an encoding nightmare in perfection */ From 479015bc1fc46ff7e0082d4636ef5b83e1af0412 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 18:33:05 +0100 Subject: [PATCH 103/365] don't print measurement reports that have no cells --- openbsc/src/abis_rsl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 3310c5724..2d55806a1 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1003,6 +1003,8 @@ static void print_meas_rep(struct gsm_meas_rep *mr) print_meas_rep_uni(&mr->dl, "dl"); DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell); + if (mr->num_cell == 7) + return; for (i = 0; i < mr->num_cell; i++) { struct gsm_meas_rep_cell *mrc = &mr->cell[i]; DEBUGP(DMEAS, "ARFCN=%u BSIC=%u => %d dBm\n", mrc->arfcn, mrc->bsic, From e2d0d5fa8c596cf22f266471995f96215b39fc9d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:26:54 +0100 Subject: [PATCH 104/365] system_information: ip.access wants L2_PLEN, BS-11 doesn't It seems that depending on the manufacturer, there is a need to include the L2 pseudo-length in the SI5+SI6 messasges (SACCH FILLING) Thanks to Dieter for pointing this out. --- openbsc/src/system_information.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index b404e5151..df4f1a0c8 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -316,10 +316,16 @@ static int generate_si4(u_int8_t *output, struct gsm_bts *bts) static int generate_si5(u_int8_t *output, struct gsm_bts *bts) { - struct gsm48_system_information_type_5 *si5 = - (struct gsm48_system_information_type_5 *) output; - int rc; + struct gsm48_system_information_type_5 *si5; + int rc, l2_plen = 18; + /* ip.access nanoBTS needs l2_plen!! */ + if (is_ipaccess_bts(bts)) { + *output++ = (l2_plen << 2) | 1; + l2_plen++; + } + + si5 = (struct gsm48_system_information_type_5 *) output; memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); /* l2 pseudo length, not part of msg: 18 */ @@ -331,14 +337,21 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts) return rc; /* 04.08 9.1.37: L2 Pseudo Length of 18 */ - return 18; + return l2_plen; } static int generate_si6(u_int8_t *output, struct gsm_bts *bts) { - struct gsm48_system_information_type_6 *si6 = - (struct gsm48_system_information_type_6 *) output; + struct gsm48_system_information_type_6 *si6; + int l2_plen = 11; + /* ip.access nanoBTS needs l2_plen!! */ + if (is_ipaccess_bts(bts)) { + *output++ = (l2_plen << 2) | 1; + l2_plen++; + } + + si6 = (struct gsm48_system_information_type_6 *) output; memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); /* l2 pseudo length, not part of msg: 11 */ @@ -354,7 +367,7 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) /* SI6 Rest Octets: 10.5.2.35a: PCH / NCH info, VBS/VGCS options */ - return 18; + return l2_plen; } static struct gsm48_si13_info si13_default = { From 50e7fec9b892c32655ce74431e45437669bffac6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:29:00 +0100 Subject: [PATCH 105/365] system_information: DEBUGP() SI13/5/6 during startup --- openbsc/src/bsc_init.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 744eacb24..7065833bf 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -679,30 +679,30 @@ static int set_system_infos(struct gsm_bts_trx *trx) rc = gsm_generate_si(si_tmp, trx->bts, i); if (rc < 0) goto err_out; - DEBUGP(DRR, "SI%u: %s\n", i, hexdump(si_tmp, rc)); + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } } #ifdef GPRS + i = 13 rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); - if (rc < 0) { - i = 13; + if (rc < 0) goto err_out; - } + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); #endif - rc = gsm_generate_si(si_tmp, trx->bts, 5); - if (rc < 0) { - i = 5; + i = 5; + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_5); + if (rc < 0) goto err_out; - } + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si_tmp, rc); - rc = gsm_generate_si(si_tmp, trx->bts, 6); - if (rc < 0) { - i = 6; + i = 6; + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_6); + if (rc < 0) goto err_out; - } + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc); return 0; From e786c32bc935bb7767335758e92c886322c8aeb5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:29:19 +0100 Subject: [PATCH 106/365] [handover] don't use measurement reports with NCELL=7 NCELL=7 inidicates that there was no neighbor cell info in the SI5 on the SACCH. --- openbsc/src/handover_decision.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index c0ec0a931..3605a8e0a 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -71,6 +71,9 @@ static int process_meas_rep(struct gsm_meas_rep *mr) /* FIXME: implement actual averaging over multiple measurement * reports */ + if (mr->num_cell > 6) + return 0; + /* find the best cell in this report that is at least RXLEV_HYST * better than the current serving cell */ for (i = 0; i < mr->num_cell; i++) { From bc814501e8a28f72e16a4662250af01aaa2a1489 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:41:52 +0100 Subject: [PATCH 107/365] [handover] add VTY parameter to enable/disable handover --- openbsc/include/openbsc/gsm_data.h | 3 +++ openbsc/src/handover_decision.c | 18 +++++++++++------- openbsc/src/vty_interface.c | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 67465e460..f4e4d2172 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -452,6 +452,9 @@ struct gsm_network { int a5_encryption; int neci; int send_mm_info; + struct { + int active; + } handover; /* layer 4 */ int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg); diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 3605a8e0a..4c08c6664 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -88,15 +88,19 @@ static int process_meas_rep(struct gsm_meas_rep *mr) } } - if (mr_cell) { - LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better, starting " - "handover\n", mr_cell->arfcn); - return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, - mr_cell->bsic); + if (!mr_cell) { + DEBUGPC(DHO, "No better cell\n"); + return 0; } - DEBUGPC(DHO, "No better cell\n"); - return 0; + LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better: ", mr_cell->arfcn); + if (!mr->lchan->ts->trx->bts->network->handover.active) { + LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); + return 0; + } + + LOGPC(DHO, LOGL_INFO, "Starting handover\n"); + return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, mr_cell->bsic); } static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal, diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index d5344edac..20df9091d 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -95,6 +95,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off", VTY_NEWLINE); + vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off", + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -296,6 +298,7 @@ static int config_write_net(struct vty *vty) vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), VTY_NEWLINE); vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); + vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -863,6 +866,16 @@ DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd, return CMD_SUCCESS; } +DEFUN(cfg_net_handover, cfg_net_handover_cmd, + "handover (0|1)", + "Whether or not to use in-call handover") +{ + gsmnet->handover.active = atoi(argv[0]); + + return CMD_SUCCESS; +} + + #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ @@ -1371,6 +1384,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); install_element(GSMNET_NODE, &cfg_net_mm_info_cmd); + install_element(GSMNET_NODE, &cfg_net_handover_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); From da7ab74298b9fdb5eb27d6575e8a15683b69889f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 22:23:05 +0100 Subject: [PATCH 108/365] RTP-enable MNCC API for LCR + ip.access Instead of passing TRAU frames down the MNCC API to the call control application like MNCC, we now decode the TRAU frame into the actual codec frame. We do the same with the RTP packets in case of ip.access and thus have a unified format of passing codec data from the BTS to an application, independent of the BTS type. This is only implemented for V1 full-rate at the moment, and needs to be fixed. --- openbsc/include/openbsc/mncc.h | 4 +- openbsc/include/openbsc/rtp_proxy.h | 16 +- openbsc/include/openbsc/transaction.h | 3 + openbsc/include/openbsc/trau_mux.h | 2 +- openbsc/src/gsm_04_08.c | 119 ++++++++++---- openbsc/src/rtp_proxy.c | 227 +++++++++++++++++++++++++- openbsc/src/trau_mux.c | 92 ++++++++++- 7 files changed, 410 insertions(+), 53 deletions(-) diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h index 766c09f1d..16fa05365 100644 --- a/openbsc/include/openbsc/mncc.h +++ b/openbsc/include/openbsc/mncc.h @@ -87,7 +87,7 @@ struct gsm_call { #define MNCC_FRAME_DROP 0x0202 #define MNCC_LCHAN_MODIFY 0x0203 -#define GSM_TRAU_FRAME 0x0300 +#define GSM_TCHF_FRAME 0x0300 #define GSM_MAX_FACILITY 128 #define GSM_MAX_SSVERSION 128 @@ -207,7 +207,7 @@ struct gsm_mncc { unsigned char lchan_mode; }; -struct gsm_trau_frame { +struct gsm_data_frame { u_int32_t msg_type; u_int32_t callref; unsigned char data[0]; diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h index e9fc157cf..a3e45964c 100644 --- a/openbsc/include/openbsc/rtp_proxy.h +++ b/openbsc/include/openbsc/rtp_proxy.h @@ -34,6 +34,11 @@ enum rtp_rx_action { RTP_RECV_UPSTREAM, }; +enum rtp_tx_action { + RTP_SEND_NONE, + RTP_SEND_DOWNSTREAM, +}; + struct rtp_sub_socket { struct sockaddr_in sin_local; struct sockaddr_in sin_remote; @@ -56,15 +61,24 @@ struct rtp_socket { struct rtp_socket *other_sock; } proxy; struct { - void (*recv_cb)(struct msgb *msg); + struct gsm_network *net; + u_int32_t callref; } receive; }; + enum rtp_tx_action tx_action; + struct { + u_int16_t sequence; + u_int32_t timestamp; + u_int32_t ssrc; + } transmit; }; struct rtp_socket *rtp_socket_create(void); int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip); int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port); int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other); +int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref); int rtp_socket_free(struct rtp_socket *rs); +int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame); #endif /* _RTP_PROXY_H */ diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 6314f987f..cf9410082 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -26,6 +26,9 @@ struct gsm_trans { /* reference from MNCC or other application */ u_int32_t callref; + /* if traffic channel receive was requested */ + int tch_recv; + union { struct { diff --git a/openbsc/include/openbsc/trau_mux.h b/openbsc/include/openbsc/trau_mux.h index 90535add4..8deb708de 100644 --- a/openbsc/include/openbsc/trau_mux.h +++ b/openbsc/include/openbsc/trau_mux.h @@ -46,4 +46,4 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref); /* send trau from application */ -int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf); +int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index d59d7d7ca..f36723937 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1864,12 +1864,16 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, return 0; } +static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable); + /* some other part of the code sends us a signal */ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct gsm_lchan *lchan = signal_data; int rc; + struct gsm_network *net; + struct gsm_trans *trans; if (subsys != SS_ABISIP) return 0; @@ -1896,6 +1900,15 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, lchan->abis_ip.bound_port); if (rc < 0) goto out_err; + /* check if any transactions on this lchan still have + * a tch_recv_mncc request pending */ + net = lchan->ts->trx->bts->network; + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->lchan == lchan && trans->tch_recv) { + DEBUGP(DCC, "pending tch_recv_mncc request\n"); + tch_recv_mncc(net, trans->callref, 1); + } + } break; case S_ABISIP_DLCX_IND: /* the BTS tells us a RTP stream has been disconnected */ @@ -1941,7 +1954,8 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n"); return -EINVAL; } - + + // todo: map between different bts types switch (bts->type) { case GSM_BTS_TYPE_NANOBTS: if (!ipacc_rtp_direct) { @@ -1950,6 +1964,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) if (rc < 0) return rc; rc = ipacc_connect_proxy_bind(remote_lchan); +#warning do we need a check of rc here? /* connect them with each other */ rtp_socket_proxy(lchan->abis_ip.rtp_socket, @@ -1971,8 +1986,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) break; default: DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); - rc = -EINVAL; - break; + return -EINVAL; } return 0; @@ -1994,45 +2008,61 @@ static int tch_bridge(struct gsm_network *net, u_int32_t *refs) return tch_map(trans1->lchan, trans2->lchan); } -/* enable receive of channels to upqueue */ -static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable) +/* enable receive of channels to MNCC upqueue */ +static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable) { struct gsm_trans *trans; + struct gsm_lchan *lchan; + struct gsm_bts *bts; + int rc; /* Find callref */ - trans = trans_find_by_callref(net, data->callref); + trans = trans_find_by_callref(net, callref); if (!trans) return -EIO; if (!trans->lchan) return 0; + lchan = trans->lchan; + bts = lchan->ts->trx->bts; - // todo IPACCESS - if (enable) - return trau_recv_lchan(trans->lchan, data->callref); - return trau_mux_unmap(NULL, data->callref); + switch (bts->type) { + case GSM_BTS_TYPE_NANOBTS: + if (ipacc_rtp_direct) { + DEBUGP(DCC, "Error: RTP proxy is disabled\n"); + return -EINVAL; + } + /* in case, we don't have a RTP socket yet, we note this + * in the transaction and try later */ + if (!lchan->abis_ip.rtp_socket) { + trans->tch_recv = enable; + DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable); + return 0; + } + if (enable) { + /* connect the TCH's to our RTP proxy */ + rc = ipacc_connect_proxy_bind(lchan); + if (rc < 0) + return rc; + /* assign socket to application interface */ + rtp_socket_upstream(lchan->abis_ip.rtp_socket, + net, callref); + } else + rtp_socket_upstream(lchan->abis_ip.rtp_socket, + net, 0); + break; + case GSM_BTS_TYPE_BS11: + if (enable) + return trau_recv_lchan(lchan, callref); + return trau_mux_unmap(NULL, callref); + break; + default: + DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); + return -EINVAL; + } + + return 0; } -/* send a frame to channel */ -static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame) -{ - struct gsm_trans *trans; - - /* Find callref */ - trans = trans_find_by_callref(net, frame->callref); - if (!trans) - return -EIO; - if (!trans->lchan) - return 0; - if (trans->lchan->type != GSM_LCHAN_TCH_F && - trans->lchan->type != GSM_LCHAN_TCH_H) - return 0; - - // todo IPACCESS - return trau_send_lchan(trans->lchan, - (struct decoded_trau_frame *)frame->data); -} - - static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg) { DEBUGP(DCC, "-> STATUS ENQ\n"); @@ -3262,11 +3292,30 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) case MNCC_BRIDGE: return tch_bridge(net, arg); case MNCC_FRAME_DROP: - return tch_recv(net, arg, 0); + return tch_recv_mncc(net, data->callref, 0); case MNCC_FRAME_RECV: - return tch_recv(net, arg, 1); - case GSM_TRAU_FRAME: - return tch_frame(net, arg); + return tch_recv_mncc(net, data->callref, 1); + case GSM_TCHF_FRAME: + /* Find callref */ + trans = trans_find_by_callref(net, data->callref); + if (!trans) + return -EIO; + if (!trans->lchan) + return 0; + if (trans->lchan->type != GSM_LCHAN_TCH_F) + return 0; + bts = trans->lchan->ts->trx->bts; + switch (bts->type) { + case GSM_BTS_TYPE_NANOBTS: + if (!trans->lchan->abis_ip.rtp_socket) + return 0; + return rtp_send_frame(trans->lchan->abis_ip.rtp_socket, arg); + case GSM_BTS_TYPE_BS11: + return trau_send_frame(trans->lchan, arg); + default: + DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); + } + return -EINVAL; } memset(&rel, 0, sizeof(struct gsm_mncc)); diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index bfd494856..f9207d661 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -24,6 +24,10 @@ #include #include #include +#include /* gettimeofday() */ +#include /* get..() */ +#include /* clock() */ +#include /* uname() */ #include #include @@ -57,6 +61,169 @@ struct rtcp_hdr { #define RTCP_IE_CNAME 1 +/* according to RFC 3550 */ +struct rtp_hdr { + u_int8_t csrc_count:4, + extension:1, + padding:1, + version:2; + u_int8_t payload_type:7, + marker:1; + u_int16_t sequence; + u_int32_t timestamp; + u_int32_t ssrc; +} __attribute__((packed)); + +struct rtp_x_hdr { + u_int16_t by_profile; + u_int16_t length; +} __attribute__((packed)); + +#define RTP_VERSION 2 + +#define RTP_PT_GSM_FULL 3 + +/* decode an rtp frame and create a new buffer with payload */ +static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) +{ + struct msgb *new_msg; + struct gsm_data_frame *frame; + struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data; + struct rtp_x_hdr *rtpxh; + u_int8_t *payload; + int payload_len; + int msg_type; + int x_len; + + if (msg->len < 12) { + DEBUGPC(DMUX, "received RTP frame too short (len = %d)\n", + msg->len); + return -EINVAL; + } + if (rtph->version != RTP_VERSION) { + DEBUGPC(DMUX, "received RTP version %d not supported.\n", + rtph->version); + return -EINVAL; + } + payload = msg->data + sizeof(struct rtp_hdr) + (rtph->csrc_count << 2); + payload_len = msg->len - sizeof(struct rtp_hdr) - (rtph->csrc_count << 2); + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame too short (len = %d, " + "csrc count = %d)\n", msg->len, rtph->csrc_count); + return -EINVAL; + } + if (rtph->extension) { + if (payload_len < sizeof(struct rtp_x_hdr)) { + DEBUGPC(DMUX, "received RTP frame too short for " + "extension header\n"); + return -EINVAL; + } + rtpxh = (struct rtp_x_hdr *)payload; + x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr); + payload += x_len; + payload_len -= x_len; + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame too short, " + "extension header exceeds frame length\n"); + return -EINVAL; + } + } + if (rtph->padding) { + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame too short for " + "padding length\n"); + return -EINVAL; + } + payload_len -= payload[payload_len - 1]; + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame with padding " + "greater than payload\n"); + return -EINVAL; + } + } + + switch (rtph->payload_type) { + case RTP_PT_GSM_FULL: + msg_type = GSM_TCHF_FRAME; + if (payload_len != 33) { + DEBUGPC(DMUX, "received RTP full rate frame with " + "payload length != 32 (len = %d)\n", + payload_len); + return -EINVAL; + } + break; + default: + DEBUGPC(DMUX, "received RTP frame with unknown payload " + "type %d\n", rtph->payload_type); + return -EINVAL; + } + + new_msg = msgb_alloc(sizeof(struct gsm_data_frame) + payload_len, + "GSM-DATA"); + if (!new_msg) + return -ENOMEM; + frame = (struct gsm_data_frame *)(new_msg->data); + frame->msg_type = msg_type; + frame->callref = callref; + memcpy(frame->data, payload, payload_len); + msgb_put(new_msg, sizeof(struct gsm_data_frame) + payload_len); + + *data = new_msg; + return 0; +} + +/* encode and send a rtp frame */ +int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) +{ + struct rtp_sub_socket *rss = &rs->rtp; + struct msgb *msg; + struct rtp_hdr *rtph; + int payload_type; + int payload_len; + int duration; /* in samples */ + + if (rs->tx_action != RTP_SEND_DOWNSTREAM) { + /* initialize sequences */ + rs->tx_action = RTP_SEND_DOWNSTREAM; + rs->transmit.ssrc = rand(); + rs->transmit.sequence = random(); + rs->transmit.timestamp = random(); + } + + switch (frame->msg_type) { + case GSM_TCHF_FRAME: + payload_type = RTP_PT_GSM_FULL; + payload_len = 33; + duration = 160; + break; + default: + DEBUGPC(DMUX, "unsupported message type %d\n", + frame->msg_type); + return -EINVAL; + } + + msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM-FULL"); + if (!msg) + return -ENOMEM; + rtph = (struct rtp_hdr *)msg->data; + rtph->version = RTP_VERSION; + rtph->padding = 0; + rtph->extension = 0; + rtph->csrc_count = 0; + rtph->marker = 0; + rtph->payload_type = payload_type; + rtph->sequence = htons(rs->transmit.sequence++); + rtph->timestamp = htonl(rs->transmit.timestamp); + rs->transmit.timestamp += duration; + rtph->ssrc = htonl(rs->transmit.ssrc); + memcpy(msg->data + sizeof(struct rtp_hdr), frame->data, payload_len); + msgb_put(msg, sizeof(struct rtp_hdr) + payload_len); + msgb_enqueue(&rss->tx_queue, msg); + rss->bfd.when |= BSC_FD_WRITE; + + return 0; +} + /* iterate over all chunks in one RTCP message, look for CNAME IEs and * replace all of those with 'new_cname' */ static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh, @@ -123,10 +290,16 @@ static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs) if (!mangle_rtcp_cname) return 0; + printf("RTCP\n"); /* iterate over list of RTCP messages */ rtph = (struct rtcp_hdr *)msg->data; - while ((void *)rtph + sizeof(*rtph) < (void *)msg->data + msg->len) { + while ((void *)rtph + sizeof(*rtph) <= (void *)msg->data + msg->len) { old_len = (ntohs(rtph->length) + 1) * 4; + if ((void *)rtph + old_len > (void *)msg->data + msg->len) { + DEBUGPC(DMUX, "received RTCP packet too short for " + "length element\n"); + return -EINVAL; + } if (rtph->type == RTCP_TYPE_SDES) { char new_cname[255]; strncpy(new_cname, inet_ntoa(rss->sin_local.sin_addr), @@ -148,6 +321,7 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss) { int rc; struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP"); + struct msgb *new_msg; struct rtp_sub_socket *other_rss; if (!msg) @@ -184,13 +358,40 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss) break; case RTP_RECV_UPSTREAM: - case RTP_NONE: - /* FIXME: other cases */ - DEBUGP(DMUX, "unhandled action: %d\n", rs->rx_action); + if (!rs->receive.callref || !rs->receive.net) { + rc = -EIO; + goto out_free; + } + if (rss->bfd.priv_nr == RTP_PRIV_RTCP) { + if (!mangle_rtcp_cname) { + msgb_free(msg); + break; + } + /* modify RTCP SDES CNAME */ + rc = rtcp_mangle(msg, rs); + if (rc < 0) + goto out_free; + msgb_enqueue(&rss->tx_queue, msg); + rss->bfd.when |= BSC_FD_WRITE; + break; + } + if (rss->bfd.priv_nr != RTP_PRIV_RTP) { + rc = -EINVAL; + goto out_free; + } + rc = rtp_decode(msg, rs->receive.callref, &new_msg); + if (rc < 0) + goto out_free; + msgb_free(msg); + msgb_enqueue(&rs->receive.net->upqueue, new_msg); + break; + + case RTP_NONE: /* if socket exists, but disabled by app */ + msgb_free(msg); break; } - return rc; + return 0; out_free: msgb_free(msg); @@ -420,6 +621,22 @@ int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other) return 0; } +/* bind RTP/RTCP socket to application */ +int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref) +{ + DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%lu)\n", + this, callref); + + if (callref) { + this->rx_action = RTP_RECV_UPSTREAM; + this->receive.net = net; + this->receive.callref = callref; + } else + this->rx_action = RTP_NONE; + + return 0; +} + static void free_tx_queue(struct rtp_sub_socket *rss) { struct msgb *msg; diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c index 7ea65ce35..477ea21e5 100644 --- a/openbsc/src/trau_mux.c +++ b/openbsc/src/trau_mux.c @@ -32,6 +32,19 @@ #include #include +u_int8_t gsm_fr_map[] = { + 6, 6, 5, 5, 4, 4, 3, 3, + 7, 2, 2, 6, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 7, 2, 2, 6, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 7, 2, 2, 6, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 7, 2, 2, 6, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3 +}; + struct map_entry { struct llist_head list; struct gsm_e1_subslot src, dst; @@ -144,6 +157,8 @@ lookup_trau_upqueue(const struct gsm_e1_subslot *src) return NULL; } +static const u_int8_t c_bits_check[] = { 0, 0, 0, 1, 0 }; + /* we get called by subchan_demux */ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, const u_int8_t *trau_bits, int num_bits) @@ -153,8 +168,6 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss); struct subch_mux *mx; struct upqueue_entry *ue; - struct msgb *msg; - struct gsm_trau_frame *frame; int rc; /* decode TRAU, change it to downlink, re-encode */ @@ -163,19 +176,44 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, return rc; if (!dst_e1_ss) { + struct msgb *msg; + struct gsm_data_frame *frame; + unsigned char *data; + int i, j, k, l, o; /* frame shall be sent to upqueue */ if (!(ue = lookup_trau_upqueue(src_e1_ss))) return -EINVAL; if (!ue->callref) return -EINVAL; - msg = msgb_alloc(sizeof(struct gsm_trau_frame) + sizeof(tf), - "TRAU"); + if (memcpy(tf.c_bits, c_bits_check, sizeof(c_bits_check))) + DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n", + hexdump(tf.c_bits, sizeof(c_bits_check))); + msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33, + "GSM-DATA"); if (!msg) return -ENOMEM; - frame = (struct gsm_trau_frame *)msg->data; - frame->msg_type = GSM_TRAU_FRAME; + + frame = (struct gsm_data_frame *)msg->data; + memset(frame, 0, sizeof(struct gsm_data_frame)); + data = frame->data; + data[0] = 0xd << 4; + /* reassemble d-bits */ + i = 0; /* counts bits */ + j = 4; /* counts output bits */ + k = gsm_fr_map[0]-1; /* current number bit in element */ + l = 0; /* counts element bits */ + o = 0; /* offset input bits */ + while (i < 260) { + data[j/8] |= (tf.d_bits[k+o] << (7-(j%8))); + if (--k < 0) { + o += gsm_fr_map[l]; + k = gsm_fr_map[++l]-1; + } + i++; + j++; + } + frame->msg_type = GSM_TCHF_FRAME; frame->callref = ue->callref; - memcpy(frame->data, &tf, sizeof(tf)); msgb_enqueue(&ue->net->upqueue, msg); return 0; @@ -221,17 +259,53 @@ int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref) return 0; } -int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf) +int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame) { u_int8_t trau_bits_out[TRAU_FRAME_BITS]; struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link; struct subch_mux *mx; + int i, j, k, l, o; + unsigned char *data = frame->data; + struct decoded_trau_frame tf; mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts); if (!mx) return -EINVAL; - encode_trau_frame(trau_bits_out, tf); + switch (frame->msg_type) { + case GSM_TCHF_FRAME: + /* set c-bits and t-bits */ + tf.c_bits[0] = 1; + tf.c_bits[1] = 1; + tf.c_bits[2] = 1; + tf.c_bits[3] = 0; + tf.c_bits[4] = 0; + memset(&tf.c_bits[5], 0, 6); + memset(&tf.c_bits[11], 1, 10); + memset(&tf.t_bits[0], 1, 4); + /* reassemble d-bits */ + i = 0; /* counts bits */ + j = 4; /* counts input bits */ + k = gsm_fr_map[0]-1; /* current number bit in element */ + l = 0; /* counts element bits */ + o = 0; /* offset output bits */ + while (i < 260) { + tf.d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1; + if (--k < 0) { + o += gsm_fr_map[l]; + k = gsm_fr_map[++l]-1; + } + i++; + j++; + } + break; + default: + DEBUGPC(DMUX, "unsupported message type %d\n", + frame->msg_type); + return -EINVAL; + } + + encode_trau_frame(trau_bits_out, &tf); /* and send it to the muxer */ return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, From aca8f158bccfc129a9eae234339a2b9c96d6f230 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 23:06:41 +0100 Subject: [PATCH 109/365] Add RTP support for EFR This is just the minimal support to receive and send EFR codec RTP frames. We are missing the code to convert TRAU frames in EFR format! --- openbsc/include/openbsc/mncc.h | 1 + openbsc/src/mncc.c | 2 +- openbsc/src/rtp_proxy.c | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h index 16fa05365..fbf3cab1f 100644 --- a/openbsc/include/openbsc/mncc.h +++ b/openbsc/include/openbsc/mncc.h @@ -88,6 +88,7 @@ struct gsm_call { #define MNCC_LCHAN_MODIFY 0x0203 #define GSM_TCHF_FRAME 0x0300 +#define GSM_TCHF_FRAME_EFR 0x0301 #define GSM_MAX_FACILITY 128 #define GSM_MAX_SSVERSION 128 diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index a5efc7312..f53b15dcb 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -83,7 +83,7 @@ static struct mncc_names { {"MNCC_FRAME_DROP", 0x0202}, {"MNCC_LCHAN_MODIFY", 0x0203}, - {"GSM_TRAU_FRAME", 0x0300}, + {"GSM_TCH_FRAME", 0x0300}, {NULL, 0} }; diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index f9207d661..551349750 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -82,6 +82,7 @@ struct rtp_x_hdr { #define RTP_VERSION 2 #define RTP_PT_GSM_FULL 3 +#define RTP_PT_GSM_EFR 97 /* decode an rtp frame and create a new buffer with payload */ static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) @@ -152,6 +153,9 @@ static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) return -EINVAL; } break; + case RTP_PT_GSM_EFR: + msg_type = GSM_TCHF_FRAME_EFR; + break; default: DEBUGPC(DMUX, "received RTP frame with unknown payload " "type %d\n", rtph->payload_type); @@ -196,6 +200,11 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) payload_len = 33; duration = 160; break; + case GSM_TCHF_FRAME_EFR: + payload_type = RTP_PT_GSM_EFR; + payload_len = 31; + duration = 160; + break; default: DEBUGPC(DMUX, "unsupported message type %d\n", frame->msg_type); From 9f16c871060d0f607360d7d720c10325f9b99ce9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 00:04:57 +0100 Subject: [PATCH 110/365] handover: don't create negative lchan use counts trans_lchan_change() takes care of use counts for us. --- openbsc/src/handover_logic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index f3f5d6c21..2c7549761 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -215,9 +215,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) /* do something to re-route the actual speech frames ! */ //tch_remap(ho->old_lchan, ho->new_lchan); - /* release old lchan */ - put_lchan(ho->old_lchan); - talloc_free(ho); return 0; From ea09002e73bf70ac9c88ab6046b17fdc2033b40a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 00:05:38 +0100 Subject: [PATCH 111/365] handover: no debug message for ever non-handover measurement report --- openbsc/src/handover_decision.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 4c08c6664..736679ab1 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -88,10 +88,8 @@ static int process_meas_rep(struct gsm_meas_rep *mr) } } - if (!mr_cell) { - DEBUGPC(DHO, "No better cell\n"); + if (!mr_cell) return 0; - } LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better: ", mr_cell->arfcn); if (!mr->lchan->ts->trx->bts->network->handover.active) { From 5e68183a201ab92f29cd2467df5209f7b351a66d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 00:06:02 +0100 Subject: [PATCH 112/365] handover: disable default-printing of every measurement report --- openbsc/src/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 9c6cb4963..6e99d4144 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -28,7 +28,7 @@ #include -unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB); +unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB|DMEAS); struct debug_info { const char *name; From 0b7b61c6b79eb2e69a9418af611e67bdbc70b353 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 09:48:28 +0100 Subject: [PATCH 113/365] fix segfault in rrlp code in case of unsuccessful paging PAGING_COMPLETED can be signalled without an active lchan in case it was unable to page the repsective subscriber. --- openbsc/src/rrlp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c index 60ce750ad..d4665d570 100644 --- a/openbsc/src/rrlp.c +++ b/openbsc/src/rrlp.c @@ -90,6 +90,10 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_PAGING_COMPLETED: + /* paging might have "completed' unsucessfully, + * in this case we don't have a lchan */ + if (!psig_data->lchan) + break; /* A subscriber has attached. */ send_rrlp_req(psig_data->lchan); break; From 31981a0051682c59fc5bcebfa1ac4e3086103b25 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 09:58:40 +0100 Subject: [PATCH 114/365] add FIXME to IMSI DETACH INDICATION: we need to release all transactions --- openbsc/src/gsm_04_08.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f36723937..227131671 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1402,6 +1402,9 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) } else DEBUGP(DMM, "Unknown Subscriber ?!?\n"); + /* FIXME: iterate over all transactions and release them, + * imagine an IMSI DETACH happening during an active call! */ + /* subscriber is detached: should we release lchan? */ return 0; From 392736d38bf9dae29800bde630c9ceee8a3914f3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 13:16:14 +0100 Subject: [PATCH 115/365] RTP Proxy: Fix RTP sequence number and timestamp in case of dropped frames During handover, we will not send RTP frames for quite some time. However, the way the rtp_send code is structured, it will increment the timestamp with a fixed amount every time we send a frame, independent how much wallclock time has actually passed. This code is a hack to update the sequence number and timestamp in case it seems to be wrong. It makes handover much more reliable. --- openbsc/include/openbsc/rtp_proxy.h | 1 + openbsc/src/rtp_proxy.c | 35 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h index a3e45964c..d128e4f23 100644 --- a/openbsc/include/openbsc/rtp_proxy.h +++ b/openbsc/include/openbsc/rtp_proxy.h @@ -70,6 +70,7 @@ struct rtp_socket { u_int16_t sequence; u_int32_t timestamp; u_int32_t ssrc; + struct timeval last_tv; } transmit; }; diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 551349750..02938125a 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -176,6 +176,21 @@ static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) return 0; } +/* "to - from" */ +static void tv_difference(struct timeval *diff, const struct timeval *from, + const struct timeval *__to) +{ + struct timeval _to = *__to, *to = &_to; + + if (to->tv_usec < from->tv_usec) { + to->tv_sec -= 1; + to->tv_usec += 1000000; + } + + diff->tv_usec = to->tv_usec - from->tv_usec; + diff->tv_sec = to->tv_sec - from->tv_sec; +} + /* encode and send a rtp frame */ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) { @@ -211,6 +226,26 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) return -EINVAL; } + { + struct timeval tv, tv_diff; + long int usec_diff, frame_diff; + + gettimeofday(&tv, NULL); + tv_difference(&tv_diff, &rs->transmit.last_tv, &tv); + rs->transmit.last_tv = tv; + + usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec; + frame_diff = (usec_diff / 20000); + + if (abs(frame_diff) > 1) { + long int frame_diff_excess = frame_diff - 1; + + DEBUGP(DMUX, "Correcting frame difference of %ld frames\n", frame_diff_excess); + rs->transmit.sequence += frame_diff_excess; + rs->transmit.timestamp += frame_diff_excess * duration; + } + } + msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM-FULL"); if (!msg) return -ENOMEM; From f88c8a02fc35fbcc8b85e3b51733f1a20ceadf13 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 13:48:15 +0100 Subject: [PATCH 116/365] remove hand full of 'extern ipacc_rtp_direct' definitions and instead declare it in gsm_data.h --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/bsc_hack.c | 1 - openbsc/src/bsc_init.c | 1 - openbsc/src/gsm_04_08.c | 2 -- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index f4e4d2172..f3ec9eb2b 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -542,6 +542,7 @@ char *gsm_band_name(enum gsm_band band); enum gsm_band gsm_band_parse(const char *mhz); extern void *tall_bsc_ctx; +extern int ipacc_rtp_direct; static inline int is_ipaccess_bts(struct gsm_bts *bts) { diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index c0695ef35..a9a5d372f 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -41,7 +41,6 @@ struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; -extern int ipacc_rtp_direct; extern int bsc_bootstrap_network(int (*mmc_rev)(struct gsm_network *, int, void *), const char *cfg_file); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 7065833bf..8450af6d0 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -35,7 +35,6 @@ /* global pointer to the gsm network data structure */ extern struct gsm_network *bsc_gsmnet; -extern int ipacc_rtp_direct; static void patch_nm_tables(struct gsm_bts *bts); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 227131671..2985d385c 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -57,8 +57,6 @@ void *tall_locop_ctx; -extern int ipacc_rtp_direct; - static const struct tlv_definition rsl_att_tlvdef = { .def = { [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, From edbc0f7aea00a6441adc05e904fb2351c99ad7b5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 14:22:11 +0100 Subject: [PATCH 117/365] Introduce new MNCC based proxy mode Since the MNCC API can now send and receive frames to/from the MNCC application, we can also implement a proxy this way. Not at the RTP/UDP packet level, but at the 'TCH speech frame' level. Especially for handover, we need this mode as the receiver in the BTS needs a persistent SSRC and monotonic frame numbers / timestamps. --- openbsc/src/mncc.c | 63 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index f53b15dcb..15e2978e6 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include void *tall_call_ctx; @@ -232,7 +234,8 @@ static int mncc_notify_ind(struct gsm_call *call, int msg_type, static int mncc_setup_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *connect) { - struct gsm_mncc connect_ack; + struct gsm_mncc connect_ack, frame_recv; + struct gsm_network *net = call->net; struct gsm_call *remote; u_int32_t refs[2]; @@ -253,7 +256,26 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type, refs[0] = call->callref; refs[1] = call->remote_ref; DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref); - return mncc_send(call->net, MNCC_BRIDGE, refs); + + /* in direct mode, we always have to bridge the channels */ + if (ipacc_rtp_direct) + return mncc_send(call->net, MNCC_BRIDGE, refs); + + /* proxy mode */ + if (!net->handover.active) { + /* in the no-handover case, we can bridge, i.e. use + * the old RTP proxy code */ + return mncc_send(call->net, MNCC_BRIDGE, refs); + } else { + /* in case of handover, we need to re-write the RTP + * SSRC, sequence and timestamp values and thus + * need to enable RTP receive for both directions */ + memset(&frame_recv, 0, sizeof(struct gsm_mncc)); + frame_recv.callref = call->callref; + mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv); + frame_recv.callref = call->remote_ref; + return mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv); + } } static int mncc_disc_ind(struct gsm_call *call, int msg_type, @@ -301,6 +323,28 @@ static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *re return 0; } +/* receiving a TCH/F frame from the BSC code */ +static int mncc_rcv_tchf(struct gsm_call *call, int msg_type, + struct gsm_data_frame *dfr) +{ + struct gsm_trans *remote_trans; + + remote_trans = trans_find_by_callref(call->net, call->remote_ref); + + /* this shouldn't really happen */ + if (!remote_trans || !remote_trans->lchan) { + LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n"); + return -EIO; + } + + /* RTP socket of remote end has meanwhile died */ + if (!remote_trans->lchan->abis_ip.rtp_socket) + return -EIO; + + return rtp_send_frame(remote_trans->lchan->abis_ip.rtp_socket, dfr); +} + + int mncc_recv(struct gsm_network *net, int msg_type, void *arg) { struct gsm_mncc *data = arg; @@ -342,8 +386,15 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref); } - DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref, - get_mncc_name(msg_type)); + switch (msg_type) { + case GSM_TCHF_FRAME: + case GSM_TCHF_FRAME_EFR: + break; + default: + DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref, + get_mncc_name(msg_type)); + break; + } switch(msg_type) { case MNCC_SETUP_IND: @@ -404,6 +455,10 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) call->callref, data->cause.value); rc = mncc_send(net, MNCC_RETRIEVE_REJ, data); break; + case GSM_TCHF_FRAME: + case GSM_TCHF_FRAME_EFR: + rc = mncc_rcv_tchf(call, msg_type, arg); + break; default: LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref); break; From fe03f0d002b146370542f9d59a344dd0c3bcf78d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 13:51:01 +0100 Subject: [PATCH 118/365] don't enable handover unless RTP Proxy is enabled We cannot support in-call handover of calls without a RTP proxy, since at the time of the handover the SSRC, sequence number and timestamp of the RTP frames change. --- openbsc/src/vty_interface.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 20df9091d..82fd00472 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -870,6 +870,12 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd, "handover (0|1)", "Whether or not to use in-call handover") { + if (ipacc_rtp_direct) { + vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode " + "is enabled by using the -P command line option%s", + VTY_NEWLINE); + return CMD_WARNING; + } gsmnet->handover.active = atoi(argv[0]); return CMD_SUCCESS; From 17f5bf64f1ac514a90324cb9506f674c5833a974 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 15:42:44 +0100 Subject: [PATCH 119/365] Move RTP socket handling out of signal handlers into abis_rsl This is not really nice, but we will soon have multiple users of the CRCX / MDCX / DLCX signals, and we cannot guarantee the ordering of them. So as a workaround, we move the RTP socket creation and deletion into the core abis_rsl codebase. --- openbsc/src/abis_rsl.c | 33 +++++++++++++++++++++++++++++++++ openbsc/src/gsm_04_08.c | 26 -------------------------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 2d55806a1..05735ee5a 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -39,6 +39,7 @@ #include #include #include +#include #define RSL_ALLOC_SIZE 1024 #define RSL_ALLOC_HEADROOM 128 @@ -1649,10 +1650,35 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing"); return -EINVAL; } + ipac_parse_rtp(lchan, &tv); + + /* in case we don't use direct BTS-to-BTS RTP */ + if (!ipacc_rtp_direct) { + int rc; + /* the BTS has successfully bound a TCH to a local ip/port, + * which means we can connect our UDP socket to it */ + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; + } + + lchan->abis_ip.rtp_socket = rtp_socket_create(); + if (!lchan->abis_ip.rtp_socket) + goto out_err; + + rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, + lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port); + if (rc < 0) + goto out_err; + } + dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); return 0; +out_err: + return -EIO; } static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg) @@ -1676,6 +1702,7 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; + struct gsm_lchan *lchan = msg->lchan; rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1683,6 +1710,12 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tv, RSL_IE_CAUSE), TLVP_LEN(&tv, RSL_IE_CAUSE)); + /* the BTS tells us a RTP stream has been disconnected */ + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; + } + dispatch_signal(SS_ABISIP, S_ABISIP_DLCX_IND, msg->lchan); return 0; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 2985d385c..2dad42083 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1885,22 +1885,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, switch (signal) { case S_ABISIP_CRCX_ACK: - /* the BTS has successfully bound a TCH to a local ip/port, - * which means we can connect our UDP socket to it */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - - lchan->abis_ip.rtp_socket = rtp_socket_create(); - if (!lchan->abis_ip.rtp_socket) - goto out_err; - - rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, - lchan->abis_ip.bound_ip, - lchan->abis_ip.bound_port); - if (rc < 0) - goto out_err; /* check if any transactions on this lchan still have * a tch_recv_mncc request pending */ net = lchan->ts->trx->bts->network; @@ -1911,18 +1895,8 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, } } break; - case S_ABISIP_DLCX_IND: - /* the BTS tells us a RTP stream has been disconnected */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - break; } - return 0; -out_err: - /* FIXME: do something */ return 0; } From a72273e176cf19a4d1352736a71698445d79b8fd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 16:51:09 +0100 Subject: [PATCH 120/365] rename ipacc_connect_proxy_bind() to rsl_ipacc_mdcx_to_rtpsock() Our RTP sockets are no longer just for the proxy mode, so having "proxy" in the function name is really misleading. --- openbsc/include/openbsc/abis_rsl.h | 1 + openbsc/src/abis_rsl.c | 14 ++++++++++++++ openbsc/src/gsm_04_08.c | 20 +++----------------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index f0a5619ad..797b2f349 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -538,6 +538,7 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci); int rsl_ipacc_crcx(struct gsm_lchan *lchan); int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, u_int8_t rtp_payload2); +int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan); int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan); int abis_rsl_rcvmsg(struct msgb *msg); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 05735ee5a..a50d7aa1c 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1615,6 +1615,20 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, return abis_rsl_sendmsg(msg); } +/* tell BTS to connect RTP stream to our local RTP socket */ +int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan) +{ + struct rtp_socket *rs = lchan->abis_ip.rtp_socket; + int rc; + + rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), + ntohs(rs->rtp.sin_local.sin_port), + /* FIXME: use RTP payload of bound socket, not BTS*/ + lchan->abis_ip.rtp_payload2); + + return rc; +} + int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan) { struct msgb *msg = rsl_msgb_alloc(); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 2dad42083..281982e22 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1900,20 +1900,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, return 0; } -/* bind rtp proxy to local IP/port and tell BTS to connect to it */ -static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) -{ - struct rtp_socket *rs = lchan->abis_ip.rtp_socket; - int rc; - - rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), - ntohs(rs->rtp.sin_local.sin_port), - /* FIXME: use RTP payload of bound socket, not BTS*/ - lchan->abis_ip.rtp_payload2); - - return rc; -} - /* map two ipaccess RTP streams onto each other */ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) { @@ -1935,10 +1921,10 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) case GSM_BTS_TYPE_NANOBTS: if (!ipacc_rtp_direct) { /* connect the TCH's to our RTP proxy */ - rc = ipacc_connect_proxy_bind(lchan); + rc = rsl_ipacc_mdcx_to_rtpsock(lchan); if (rc < 0) return rc; - rc = ipacc_connect_proxy_bind(remote_lchan); + rc = rsl_ipacc_mdcx_to_rtpsock(remote_lchan); #warning do we need a check of rc here? /* connect them with each other */ @@ -2015,7 +2001,7 @@ static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable) } if (enable) { /* connect the TCH's to our RTP proxy */ - rc = ipacc_connect_proxy_bind(lchan); + rc = rsl_ipacc_mdcx_to_rtpsock(lchan); if (rc < 0) return rc; /* assign socket to application interface */ From a03790232316edfc87de94012b110d8d8e2067f2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 17:04:40 +0100 Subject: [PATCH 121/365] [handover] implement TCH RTP stream handover This patch takes care of handling the RTP streams / sockets during an in-call handover from one BTS to another BTS. It only works in combination with rtp_proxy mode. --- openbsc/src/handover_logic.c | 70 +++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 2c7549761..3007d2581 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -40,6 +40,7 @@ #include #include #include +#include struct bsc_handover { struct llist_head list; @@ -173,6 +174,10 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) ho->T3103.data = ho; bsc_schedule_timer(&ho->T3103, 10, 0); + /* create a RTP connection */ + if (is_ipaccess_bts(new_lchan->ts->trx->bts)) + rsl_ipacc_crcx(new_lchan); + return 0; } @@ -213,7 +218,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) trans_lchan_change(ho->old_lchan, new_lchan); /* do something to re-route the actual speech frames ! */ - //tch_remap(ho->old_lchan, ho->new_lchan); talloc_free(ho); @@ -255,6 +259,61 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) return 0; } +static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + struct rtp_socket *old_rs, *new_rs, *other_rs; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); + return -ENODEV; + } + + if (ipacc_rtp_direct) { + LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n"); + return 0; + } + + /* RTP Proxy mode */ + new_rs = new_lchan->abis_ip.rtp_socket; + old_rs = ho->old_lchan->abis_ip.rtp_socket; + + if (!new_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socket for new_lchan\n"); + return -EIO; + } + + rsl_ipacc_mdcx_to_rtpsock(new_lchan); + + if (!old_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socekt for old_lchan\n"); + return -EIO; + } + + /* copy rx_action and reference to other sock */ + new_rs->rx_action = old_rs->rx_action; + new_rs->tx_action = old_rs->tx_action; + new_rs->transmit = old_rs->transmit; + + switch (ho->old_lchan->abis_ip.rtp_socket->rx_action) { + case RTP_PROXY: + other_rs = old_rs->proxy.other_sock; + rtp_socket_proxy(new_rs, other_rs); + /* delete reference to other end socket to prevent + * rtp_socket_free() from removing the inverse reference */ + old_rs->proxy.other_sock = NULL; + break; + case RTP_RECV_UPSTREAM: + new_rs->receive = old_rs->receive; + break; + case RTP_NONE: + break; + } + + return 0; +} + static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { @@ -276,6 +335,14 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, return ho_gsm48_ho_fail(lchan); } break; + case SS_ABISIP: + lchan = signal_data; + switch (signal) { + case S_ABISIP_CRCX_ACK: + return ho_ipac_crcx_ack(lchan); + break; + } + break; default: break; } @@ -286,4 +353,5 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, static __attribute__((constructor)) void on_dso_load_ho_logic(void) { register_signal_handler(SS_LCHAN, ho_logic_sig_cb, NULL); + register_signal_handler(SS_ABISIP, ho_logic_sig_cb, NULL); } From 9fb1f1065a8dc5b0fd2cbaad9d438d57f1dd7ac2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 17:07:23 +0100 Subject: [PATCH 122/365] fix compiler warning and coding style in rtp_proxy --- openbsc/src/rtp_proxy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 02938125a..0f4e32799 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -666,9 +666,10 @@ int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other) } /* bind RTP/RTCP socket to application */ -int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref) +int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, + u_int32_t callref) { - DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%lu)\n", + DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%u)\n", this, callref); if (callref) { From a4e2d04b35095d059218ab05ffcd5b69e18edf70 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 17:08:22 +0100 Subject: [PATCH 123/365] Fix some compiler warnings regarding missing const in rest_octets.c --- openbsc/src/rest_octets.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index 6efd47515..6226203ec 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -291,7 +291,8 @@ static int encode_drx_timer(unsigned int drx) ** ; */ -static int append_gprs_cell_opt(struct bitvec *bv, struct gprs_cell_options *gco) +static int append_gprs_cell_opt(struct bitvec *bv, + const struct gprs_cell_options *gco) { int t3192, drx_timer_max; @@ -323,7 +324,7 @@ static int append_gprs_cell_opt(struct bitvec *bv, struct gprs_cell_options *gco } static void append_gprs_pwr_ctrl_pars(struct bitvec *bv, - struct gprs_power_ctrl_pars *pcp) + const struct gprs_power_ctrl_pars *pcp) { bitvec_set_uint(bv, pcp->alpha, 4); bitvec_set_uint(bv, pcp->t_avg_w, 5); From d5778fc4c7497e1b7310811c881f8cb21b742ec8 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut <246tnt@gmail.com> Date: Mon, 21 Dec 2009 01:09:57 +0100 Subject: [PATCH 124/365] [db] Fix queries for unsent SMS - Need to use sms.id for the ORDER BY since 'subscriber' also has 'id' - Need to add the join clause between 'SMS' and 'subscriber' - Add a LIMIT 1 (probably no impact for the db size we're dealing with here, but with large DB and mysql/postgresql this can help the planner) - (fix a wrong comment in passing ...) Signed-off-by: Sylvain Munaut --- openbsc/src/db.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 5dfefb53f..d85386548 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -769,8 +769,9 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) result = dbi_conn_queryf(conn, "SELECT * FROM SMS,Subscriber " "WHERE sms.id >= %llu AND sms.sent is NULL " + "AND sms.receiver_id = subscriber.id " "AND subscriber.lac > 0 " - "ORDER BY id", + "ORDER BY sms.id LIMIT 1", min_id); if (!result) return NULL; @@ -787,7 +788,7 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) return sms; } -/* retrieve the next unsent SMS with ID >= min_id */ +/* retrieve the next unsent SMS for a given subscriber */ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) { dbi_result result; @@ -796,8 +797,9 @@ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) result = dbi_conn_queryf(conn, "SELECT * FROM SMS,Subscriber " "WHERE sms.receiver_id = %llu AND sms.sent is NULL " + "AND sms.receiver_id = subscriber.id " "AND subscriber.lac > 0 " - "ORDER BY id", + "ORDER BY sms.id LIMIT 1", subscr->id); if (!result) return NULL; From f77af1fb302ba624bf401c56104a16d79e221916 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut <246tnt@gmail.com> Date: Mon, 21 Dec 2009 01:11:25 +0100 Subject: [PATCH 125/365] chan_alloc: Delete T3101 on lchan_free as well If a RF channel is assigned but no response is ever heard from the phone, we will receive a CONNECTION FAIL from the BTS, triggering a RF release freeing the channel. Then sometime later, T3101 will expire as well and free the channel again ... Signed-off-by: Sylvain Munaut --- openbsc/src/chan_alloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 786e8b11b..a23192ae6 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -251,6 +251,7 @@ void lchan_free(struct gsm_lchan *lchan) /* stop the timer */ bsc_del_timer(&lchan->release_timer); + bsc_del_timer(&lchan->T3101); /* clear cached measuement reports */ lchan->meas_rep_idx = 0; From 56315f02bb88f0595d369c2d80f6556922758f62 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 21 Dec 2009 01:18:44 +0100 Subject: [PATCH 126/365] Fix typo s/memcpy/memcmp in trau_frame.c --- openbsc/src/trau_mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c index 477ea21e5..9930751a5 100644 --- a/openbsc/src/trau_mux.c +++ b/openbsc/src/trau_mux.c @@ -185,7 +185,7 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, return -EINVAL; if (!ue->callref) return -EINVAL; - if (memcpy(tf.c_bits, c_bits_check, sizeof(c_bits_check))) + if (memcmp(tf.c_bits, c_bits_check, sizeof(c_bits_check))) DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n", hexdump(tf.c_bits, sizeof(c_bits_check))); msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33, From 38fe2a67e1a376e4370ddfed2f75687075cc9e6b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 09:26:17 +0100 Subject: [PATCH 127/365] meas_rep: utility function for processing of measurement reports This provides two functions: get_meas_rep_avg() to obtain the sliding window average of one particular field, and meas_rep_n_out_of_m_be() to check if at least N out of M measurments are >= BE. --- openbsc/include/openbsc/meas_rep.h | 27 +++++++ openbsc/src/Makefile.am | 2 +- openbsc/src/meas_rep.c | 114 +++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/meas_rep.c diff --git a/openbsc/include/openbsc/meas_rep.h b/openbsc/include/openbsc/meas_rep.h index c36352e2a..fd5fced43 100644 --- a/openbsc/include/openbsc/meas_rep.h +++ b/openbsc/include/openbsc/meas_rep.h @@ -1,11 +1,14 @@ #ifndef _MEAS_REP_H #define _MEAS_REP_H +#define MRC_F_PROCESSED 0x0001 + /* extracted from a L3 measurement report IE */ struct gsm_meas_rep_cell { u_int8_t rxlev; u_int8_t bsic; u_int16_t arfcn; + unsigned int flags; }; /* RX Level and RX Quality */ @@ -54,4 +57,28 @@ struct gsm_meas_rep { struct gsm_meas_rep_cell cell[6]; }; +enum meas_rep_field { + MEAS_REP_DL_RXLEV_FULL, + MEAS_REP_DL_RXLEV_SUB, + MEAS_REP_DL_RXQUAL_FULL, + MEAS_REP_DL_RXQUAL_SUB, + MEAS_REP_UL_RXLEV_FULL, + MEAS_REP_UL_RXLEV_SUB, + MEAS_REP_UL_RXQUAL_FULL, + MEAS_REP_UL_RXQUAL_SUB, +}; + +/* obtain an average over the last 'num' fields in the meas reps */ +int get_meas_rep_avg(const struct gsm_lchan *lchan, + enum meas_rep_field field, unsigned int num); + +/* Check if N out of M last values for FIELD are >= bd */ +int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan, + enum meas_rep_field field, + unsigned int n, unsigned int m, int be); + +unsigned int calc_initial_idx(unsigned int array_size, + unsigned int meas_rep_idx, + unsigned int num_values); + #endif /* _MEAS_REP_H */ diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 5692ac4e4..f36a701bc 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,7 +12,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - handover_decision.c + handover_decision.c meas_rep.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/meas_rep.c b/openbsc/src/meas_rep.c new file mode 100644 index 000000000..4b9cc1a0c --- /dev/null +++ b/openbsc/src/meas_rep.c @@ -0,0 +1,114 @@ +/* Measurement Report Processing */ + +/* (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 + +static int get_field(const struct gsm_meas_rep *rep, + enum meas_rep_field field) +{ + switch (field) { + case MEAS_REP_DL_RXLEV_FULL: + return rep->dl.full.rx_lev; + case MEAS_REP_DL_RXLEV_SUB: + return rep->dl.sub.rx_lev; + case MEAS_REP_DL_RXQUAL_FULL: + return rep->dl.full.rx_qual; + case MEAS_REP_DL_RXQUAL_SUB: + return rep->dl.sub.rx_qual; + case MEAS_REP_UL_RXLEV_FULL: + return rep->ul.full.rx_lev; + case MEAS_REP_UL_RXLEV_SUB: + return rep->ul.sub.rx_lev; + case MEAS_REP_UL_RXQUAL_FULL: + return rep->ul.full.rx_qual; + case MEAS_REP_UL_RXQUAL_SUB: + return rep->ul.sub.rx_qual; + } + + return 0; +} + + +unsigned int calc_initial_idx(unsigned int array_size, + unsigned int meas_rep_idx, + unsigned int num_values) +{ + int offs, idx; + + /* from which element do we need to start if we're interested + * in an average of 'num' elements */ + offs = meas_rep_idx - num_values; + + if (offs < 0) + idx = array_size + offs; + else + idx = offs; + + return idx; +} + +/* obtain an average over the last 'num' fields in the meas reps */ +int get_meas_rep_avg(const struct gsm_lchan *lchan, + enum meas_rep_field field, unsigned int num) +{ + unsigned int i, idx; + int avg = 0; + + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, num); + + for (i = 0; i < num; i++) { + int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep); + + avg += get_field(&lchan->meas_rep[j], field); + } + + return avg / num; +} + +/* Check if N out of M last values for FIELD are >= bd */ +int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan, + enum meas_rep_field field, + unsigned int n, unsigned int m, int be) +{ + unsigned int i, idx; + int count = 0; + + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, m); + + for (i = 0; i < m; i++) { + int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep); + int val = get_field(&lchan->meas_rep[j], field); + + if (val >= be) + count++; + + if (count >= n) + return 1; + } + + return 0; +} From b8bfc567b7b8c705c1a2ec7654ce7184ab6c295f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 13:27:11 +0100 Subject: [PATCH 128/365] RSL: keep track if a channel is active or not This allows us to block packets that we have received after the channel is no longer being used. This is visible during handover, where we still receive a measurement report after the MS has switched to the new channel. This leftover measurement report then attempts to trigger another handover, which si bogus and will fail - and thus only consumes resources. With the new LCHAN_S_ACTIVE state, we can check for this when processing the measurement report. --- openbsc/include/openbsc/gsm_data.h | 9 +++++++++ openbsc/src/abis_rsl.c | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index f3ec9eb2b..d19f38bc1 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -151,6 +151,13 @@ struct gsm_loc_updating_operation { #define LCHAN_SAPI_MS 1 #define LCHAN_SAPI_NET 2 +/* state of a logical channel */ +enum gsm_lchan_state { + LCHAN_S_NONE, /* channel is not active */ + LCHAN_S_ACTIVE, /* channel is active and operational */ + LCHAN_S_INACTIVE, /* channel is set inactive */ +}; + struct gsm_lchan { /* The TS that we're part of */ struct gsm_bts_trx_ts *ts; @@ -162,6 +169,8 @@ struct gsm_lchan { enum rsl_cmod_spd rsl_cmode; /* If TCH, traffic channel mode */ enum gsm48_chan_mode tch_mode; + /* State */ + enum gsm_lchan_state state; /* Power levels for MS and BTS */ u_int8_t bs_power; u_int8_t ms_power; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index a50d7aa1c..72ae9dbb6 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -918,6 +918,8 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) if (rslh->ie_chan != RSL_IE_CHAN_NR) return -EINVAL; + msg->lchan->state = LCHAN_S_ACTIVE; + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan); return 0; @@ -938,6 +940,8 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); + msg->lchan->state = LCHAN_S_NONE; + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan); lchan_free(msg->lchan); @@ -1022,6 +1026,11 @@ static int rsl_rx_meas_res(struct msgb *msg) const u_int8_t *val; int rc; + /* check if this channel is actually active */ + /* FIXME: maybe this check should be way more generic/centralized */ + if (msg->lchan->state != LCHAN_S_ACTIVE) + return 0; + memset(mr, 0, sizeof(*mr)); mr->lchan = msg->lchan; @@ -1128,6 +1137,7 @@ static int abis_rsl_rx_dchan(struct msgb *msg) break; case RSL_MT_RF_CHAN_REL_ACK: DEBUGPC(DRSL, "RF CHANNEL RELEASE ACK\n"); + msg->lchan->state = LCHAN_S_NONE; lchan_free(msg->lchan); break; case RSL_MT_MODE_MODIFY_ACK: From ade773f44193052ade3be70b794130dd6a39ee06 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 13:29:19 +0100 Subject: [PATCH 129/365] handover: set old channel to INACTIVE state After receiving the HANDOVER COMPLETE on the new channel, we mark the old channel as INACTIVE and try to release it ASAP. --- openbsc/src/handover_logic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 3007d2581..94d3d0d1e 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -212,13 +212,16 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) } bsc_del_timer(&ho->T3103); - llist_del(&ho->list); /* update lchan pointer of transaction */ trans_lchan_change(ho->old_lchan, new_lchan); + ho->old_lchan->state = LCHAN_S_INACTIVE; + lchan_auto_release(ho->old_lchan); + /* do something to re-route the actual speech frames ! */ + llist_del(&ho->list); talloc_free(ho); return 0; From f7c28b099f928cc6fb48fc9cc072656d8c3bb902 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 13:30:17 +0100 Subject: [PATCH 130/365] [handover] Real handover algorithm This implements the handover algorithm (and associated parameters) as described in Chapter 8 of the book "Performance Enhancements in a Frequency |Hopping GSM Network" by Thomas Toftegard Nielsen and Jeroen Wigard. The parameters such as averaging windows are configured in struct gsm_network. We keep some state to trakc up to 10 neighbors as they are being reported from the MS. This has so far only been tested in a network with two BTS that have each other as neighbor. Networks with morge neighbors might encounter bugs. --- openbsc/include/openbsc/gsm_data.h | 30 ++++ openbsc/src/chan_alloc.c | 2 + openbsc/src/gsm_04_08.c | 1 + openbsc/src/gsm_data.c | 8 + openbsc/src/handover_decision.c | 233 +++++++++++++++++++++++++---- 5 files changed, 244 insertions(+), 30 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index d19f38bc1..876955824 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -143,6 +143,20 @@ struct gsm_loc_updating_operation { unsigned int waiting_for_imei : 1; }; +/* Maximum number of neighbor cells whose average we track */ +#define MAX_NEIGH_MEAS 10 +/* Maximum size of the averaging window for neighbor cells */ +#define MAX_WIN_NEIGH_AVG 10 + +/* processed neighbor measurements for one cell */ +struct neigh_meas_proc { + u_int16_t arfcn; + u_int8_t bsic; + u_int8_t rxlev[MAX_WIN_NEIGH_AVG]; + unsigned int rxlev_cnt; + u_int8_t last_seen_nr; +}; + #define MAX_A5_KEY_LEN (128/8) #define RSL_ENC_ALG_A5(x) (x+1) @@ -207,6 +221,9 @@ struct gsm_lchan { struct gsm_meas_rep meas_rep[6]; int meas_rep_idx; + /* table of neighbor cell measurements */ + struct neigh_meas_proc neigh_meas[MAX_NEIGH_MEAS]; + struct { u_int32_t bound_ip; u_int32_t connect_ip; @@ -463,6 +480,19 @@ struct gsm_network { int send_mm_info; struct { int active; + /* Window RXLEV averaging */ + unsigned int win_rxlev_avg; /* number of SACCH frames */ + /* Window RXQUAL averaging */ + unsigned int win_rxqual_avg; /* number of SACCH frames */ + /* Window RXLEV neighbouring cells averaging */ + unsigned int win_rxlev_avg_neigh; /* number of SACCH frames */ + + /* how often should we check for power budget HO */ + unsigned int pwr_interval; /* SACCH frames */ + /* how much better does a neighbor cell have to be ? */ + unsigned int pwr_hysteresis; /* dBm */ + /* maximum distacne before we try a handover */ + unsigned int max_distance; /* TA values */ } handover; /* layer 4 */ diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index a23192ae6..c42b60b46 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -259,6 +259,8 @@ void lchan_free(struct gsm_lchan *lchan) lchan->meas_rep[i].flags = 0; lchan->meas_rep[i].nr = 0; } + for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) + lchan->neigh_meas[i].arfcn = 0; /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 281982e22..156927f56 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1404,6 +1404,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) * imagine an IMSI DETACH happening during an active call! */ /* subscriber is detached: should we release lchan? */ + lchan_auto_release(msg->lchan); return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 94ed91ba5..12f439be2 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -210,6 +210,14 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c net->T3113 = GSM_T3113_DEFAULT; /* FIXME: initialize all other timers! */ + /* default set of handover parameters */ + net->handover.win_rxlev_avg = 10; + net->handover.win_rxqual_avg = 1; + net->handover.win_rxlev_avg_neigh = 10; + net->handover.pwr_interval = 6; + net->handover.pwr_hysteresis = 3; + net->handover.max_distance = 9999; + INIT_LLIST_HEAD(&net->trans_list); INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->bts_list); diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 736679ab1..b37cecddb 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -32,7 +32,9 @@ #include #include #include +#include +/* issue handover to a cell identified by ARFCN and BSIC */ static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, u_int16_t arfcn, u_int8_t bsic) { @@ -50,14 +52,184 @@ static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, return bsc_handover_start(lchan, new_bts); } -#define RXLEV_HYST 3 +/* did we get a RXLEV for a given cell in the given report? */ +static int rxlev_for_cell_in_rep(struct gsm_meas_rep *mr, + u_int16_t arfcn, u_int8_t bsic) +{ + int i; -/* process an already parsed measurement report */ + for (i = 0; i < mr->num_cell; i++) { + struct gsm_meas_rep_cell *mrc = &mr->cell[i]; + + /* search for matching report */ + if (!(mrc->arfcn == arfcn && mrc->bsic == bsic)) + continue; + + mrc->flags |= MRC_F_PROCESSED; + return mrc->rxlev; + } + return -ENODEV; +} + +/* obtain averaged rxlev for given neighbor */ +static int neigh_meas_avg(struct neigh_meas_proc *nmp, int window) +{ + unsigned int i, idx; + int avg = 0; + + idx = calc_initial_idx(ARRAY_SIZE(nmp->rxlev), + nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev), + window); + + for (i = 0; i < window; i++) { + int j = (idx+i) % ARRAY_SIZE(nmp->rxlev); + + avg += nmp->rxlev[j]; + } + + return avg / window; +} + +/* find empty or evict bad neighbor */ +static struct neigh_meas_proc *find_evict_neigh(struct gsm_lchan *lchan) +{ + int j, worst = 999999; + struct neigh_meas_proc *nmp_worst; + + /* first try to find an empty/unused slot */ + for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) { + struct neigh_meas_proc *nmp = &lchan->neigh_meas[j]; + if (!nmp->arfcn) + return nmp; + } + + /* no empty slot found. evict worst neighbor from list */ + for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) { + struct neigh_meas_proc *nmp = &lchan->neigh_meas[j]; + int avg = neigh_meas_avg(nmp, MAX_WIN_NEIGH_AVG); + if (avg < worst) { + worst = avg; + nmp_worst = nmp; + } + } + + return nmp_worst; +} + +/* process neighbor cell measurement reports */ +static void process_meas_neigh(struct gsm_meas_rep *mr) +{ + int i, j, idx; + + /* for each reported cell, try to update global state */ + for (j = 0; j < ARRAY_SIZE(mr->lchan->neigh_meas); j++) { + struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[j]; + unsigned int idx; + int rxlev; + + /* skip unused entries */ + if (!nmp->arfcn) + continue; + + rxlev = rxlev_for_cell_in_rep(mr, nmp->arfcn, nmp->bsic); + idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev); + if (rxlev >= 0) { + nmp->rxlev[idx] = rxlev; + nmp->last_seen_nr = mr->nr; + } else + nmp->rxlev[idx] = 0; + nmp->rxlev_cnt++; + } + + /* iterate over list of reported cells, check if we did not + * process all of them */ + for (i = 0; i < mr->num_cell; i++) { + struct gsm_meas_rep_cell *mrc = &mr->cell[i]; + struct neigh_meas_proc *nmp; + + if (mrc->flags & MRC_F_PROCESSED) + continue; + + nmp = find_evict_neigh(mr->lchan); + + nmp->arfcn = mrc->arfcn; + nmp->bsic = mrc->bsic; + + idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev); + nmp->rxlev[idx] = mrc->rxlev; + nmp->rxlev_cnt++; + nmp->last_seen_nr = mr->nr; + + mrc->flags |= MRC_F_PROCESSED; + } +} + +/* attempt to do a handover */ +static int attempt_handover(struct gsm_meas_rep *mr) +{ + struct gsm_network *net = mr->lchan->ts->trx->bts->network; + struct neigh_meas_proc *best_cell = NULL; + unsigned int best_better_db = 0; + int i, rc; + + /* find the best cell in this report that is at least RXLEV_HYST + * better than the current serving cell */ + + for (i = 0; i < ARRAY_SIZE(mr->lchan->neigh_meas); i++) { + struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[i]; + int avg, better; + + /* skip empty slots */ + if (nmp->arfcn == 0) + continue; + + /* caculate average rxlev for this cell over the window */ + avg = neigh_meas_avg(nmp, net->handover.win_rxlev_avg_neigh); + + /* check if hysteresis is fulfilled */ + if (avg < mr->dl.full.rx_lev + net->handover.pwr_hysteresis) + continue; + + better = avg - mr->dl.full.rx_lev; + if (better > best_better_db) { + best_cell = nmp; + best_better_db = better; + } + } + + if (!best_cell) + return 0; + + LOGP(DHO, LOGL_INFO, "%s: Cell on ARFCN %u is better: ", + gsm_ts_name(mr->lchan->ts), best_cell->arfcn); + if (!net->handover.active) { + LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); + return 0; + } + + rc = handover_to_arfcn_bsic(mr->lchan, best_cell->arfcn, best_cell->bsic); + switch (rc) { + case 0: + LOGPC(DHO, LOGL_INFO, "Starting handover\n"); + break; + case -ENOSPC: + LOGPC(DHO, LOGL_INFO, "No channel available\n"); + break; + case -EBUSY: + LOGPC(DHO, LOGL_INFO, "Handover already active\n"); + break; + default: + LOGPC(DHO, LOGL_ERROR, "Unknown error\n"); + } + return rc; +} + +/* process an already parsed measurement report and decide if we want to + * attempt a handover */ static int process_meas_rep(struct gsm_meas_rep *mr) { - struct gsm_meas_rep_cell *mr_cell = NULL; - unsigned int best_better_db; - int i; + struct gsm_network *net = mr->lchan->ts->trx->bts->network; + int av_rxlev; /* we currently only do handover for TCH channels */ switch (mr->lchan->type) { @@ -68,37 +240,38 @@ static int process_meas_rep(struct gsm_meas_rep *mr) return 0; } - /* FIXME: implement actual averaging over multiple measurement - * reports */ + /* parse actual neighbor cell info */ + if (mr->num_cell > 0 && mr->num_cell < 7) + process_meas_neigh(mr); - if (mr->num_cell > 6) - return 0; + av_rxlev = get_meas_rep_avg(mr->lchan, MEAS_REP_DL_RXLEV_FULL, + net->handover.win_rxlev_avg); - /* find the best cell in this report that is at least RXLEV_HYST - * better than the current serving cell */ - for (i = 0; i < mr->num_cell; i++) { - unsigned int better; - if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST) - continue; + /* Interference HO */ + if (rxlev2dbm(av_rxlev) > -85 && + meas_rep_n_out_of_m_be(mr->lchan, MEAS_REP_DL_RXQUAL_FULL, + 3, 4, 5)) + return attempt_handover(mr); - better = mr->cell[i].rxlev - mr->dl.full.rx_lev; - if (better > best_better_db) { - mr_cell = &mr->cell[i]; - best_better_db = better; - } - } + /* Bad Quality */ + if (meas_rep_n_out_of_m_be(mr->lchan, MEAS_REP_DL_RXQUAL_FULL, + 3, 4, 5)) + return attempt_handover(mr); - if (!mr_cell) - return 0; + /* Low Level */ + if (rxlev2dbm(av_rxlev) <= -110) + return attempt_handover(mr); - LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better: ", mr_cell->arfcn); - if (!mr->lchan->ts->trx->bts->network->handover.active) { - LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); - return 0; - } + /* Distance */ + if (mr->ms_l1.ta > net->handover.max_distance) + return attempt_handover(mr); + + /* Power Budget AKA Better Cell */ + if ((mr->nr % net->handover.pwr_interval) == 0) + return attempt_handover(mr); + + return 0; - LOGPC(DHO, LOGL_INFO, "Starting handover\n"); - return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, mr_cell->bsic); } static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal, From b720bd3678b461b1973d194ba51f4c824dc4c98c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 16:51:50 +0100 Subject: [PATCH 131/365] make handover algorithm parameters configurable from VTY --- openbsc/src/vty_interface.c | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 82fd00472..0e518efd4 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -299,6 +299,18 @@ static int config_write_net(struct vty *vty) VTY_NEWLINE); vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE); + vty_out(vty, " handover window rxlev averaging %u%s", + gsmnet->handover.win_rxlev_avg, VTY_NEWLINE); + vty_out(vty, " handover window rxqual averaging %u%s", + gsmnet->handover.win_rxqual_avg, VTY_NEWLINE); + vty_out(vty, " handover window rxlev neighbor averaging %u%s", + gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE); + vty_out(vty, " handover power budget interval %u%s", + gsmnet->handover.pwr_interval, VTY_NEWLINE); + vty_out(vty, " handover power budget hysteresis %u%s", + gsmnet->handover.pwr_hysteresis, VTY_NEWLINE); + vty_out(vty, " handover maximum distance %u%s", + gsmnet->handover.max_distance, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -881,6 +893,53 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd, return CMD_SUCCESS; } +DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd, + "handover window rxlev averaging <1-10>", + "How many RxLev measurements are used for averaging") +{ + gsmnet->handover.win_rxlev_avg = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd, + "handover window rxqual averaging <1-10>", + "How many RxQual measurements are used for averaging") +{ + gsmnet->handover.win_rxqual_avg = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd, + "handover window rxlev neighbor averaging <1-10>", + "How many RxQual measurements are used for averaging") +{ + gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd, + "handover power budget interval <1-99>", + "How often to check if we have a better cell (SACCH frames)") +{ + gsmnet->handover.pwr_interval = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd, + "handover power budget hysteresis <0-999>", + "How many dB does a neighbor to be stronger to become a HO candidate") +{ + gsmnet->handover.pwr_hysteresis = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, + "handover maximum distance <0-9999>", + "How big is the maximum timing advance before HO is forced") +{ + gsmnet->handover.max_distance = atoi(argv[0]); + return CMD_SUCCESS; +} #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ @@ -1391,6 +1450,12 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); install_element(GSMNET_NODE, &cfg_net_mm_info_cmd); install_element(GSMNET_NODE, &cfg_net_handover_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); From 17c24c905785f967161dacde8b849c5b1ad275c4 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 21 Dec 2009 16:56:28 +0100 Subject: [PATCH 132/365] [abis] Properly compare obj_inst->trx_nr to bts->num_trx * Use >= in this case as we start counting the trx from 0 * This is fixing a problem with multi trx config --- openbsc/src/abis_nm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index e7e3bf004..fc00ca8d6 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -635,7 +635,7 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, nm_state = &trx->bb_transc.nm_state; break; case NM_OC_CHANNEL: - if (obj_inst->trx_nr > bts->num_trx) { + if (obj_inst->trx_nr >= bts->num_trx) { DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; } @@ -719,7 +719,7 @@ objclass2obj(struct gsm_bts *bts, u_int8_t obj_class, obj = &trx->bb_transc; break; case NM_OC_CHANNEL: - if (obj_inst->trx_nr > bts->num_trx) { + if (obj_inst->trx_nr >= bts->num_trx) { DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; } From 306b7219ac616980b99a78f45b181aa980672d86 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 21 Dec 2009 17:06:07 +0100 Subject: [PATCH 133/365] [abis] Do not access an array with N elements at index N Possible crash fixes by preventing accessing the array out of bounds. --- openbsc/src/abis_nm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index fc00ca8d6..bb7248be7 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -671,7 +671,7 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, nm_state = &bts->bs11.rack.nm_state; break; case NM_OC_BS11_ENVABTSE: - if (obj_inst->trx_nr > ARRAY_SIZE(bts->bs11.envabtse)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse)) return NULL; nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state; break; @@ -682,7 +682,7 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, nm_state = &bts->gprs.cell.nm_state; break; case NM_OC_GPRS_NSVC: - if (obj_inst->trx_nr > ARRAY_SIZE(bts->gprs.nsvc)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc)) return NULL; nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state; break; @@ -738,7 +738,7 @@ objclass2obj(struct gsm_bts *bts, u_int8_t obj_class, obj = &bts->gprs.cell; break; case NM_OC_GPRS_NSVC: - if (obj_inst->trx_nr > ARRAY_SIZE(bts->gprs.nsvc)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc)) return NULL; obj = &bts->gprs.nsvc[obj_inst->trx_nr]; break; From 31b0347e7221375ff811c0cb2842505816b543c2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 19:04:47 +0100 Subject: [PATCH 134/365] fix crash in A-bis OML plugin in recent wireshark versions --- wireshark/abis_oml.patch | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/wireshark/abis_oml.patch b/wireshark/abis_oml.patch index dc51f76c1..1b2439c86 100644 --- a/wireshark/abis_oml.patch +++ b/wireshark/abis_oml.patch @@ -1,8 +1,8 @@ Index: wireshark/epan/dissectors/Makefile.common =================================================================== ---- wireshark.orig/epan/dissectors/Makefile.common 2009-10-21 23:03:44.000000000 +0200 -+++ wireshark/epan/dissectors/Makefile.common 2009-10-21 23:03:57.000000000 +0200 -@@ -472,6 +472,7 @@ +--- wireshark.orig/epan/dissectors/Makefile.common ++++ wireshark/epan/dissectors/Makefile.common +@@ -474,6 +474,7 @@ packet-gsm_a_gm.c \ packet-gsm_a_rp.c \ packet-gsm_a_rr.c \ @@ -12,8 +12,8 @@ Index: wireshark/epan/dissectors/Makefile.common packet-gsm_bssmap_le.c \ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c =================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ wireshark/epan/dissectors/packet-gsm_abis_oml.c 2009-10-22 10:06:18.000000000 +0200 +--- /dev/null ++++ wireshark/epan/dissectors/packet-gsm_abis_oml.c @@ -0,0 +1,1365 @@ +/* packet-abis_oml.c + * Routines for packet dissection of GSM A-bis over IP (3GPP TS 12.21) @@ -1377,13 +1377,13 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c +{ + dissector_handle_t abis_oml_handle; + -+ abis_oml_handle = find_dissector("abis_oml"); ++ abis_oml_handle = create_dissector_handle(dissect_abis_oml, proto_abis_oml); + dissector_add("lapd.gsm.sapi", LAPD_GSM_SAPI_OM_PROC, abis_oml_handle); +} Index: wireshark/epan/dissectors/packet-gsm_abis_oml.h =================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ wireshark/epan/dissectors/packet-gsm_abis_oml.h 2009-10-21 23:03:57.000000000 +0200 +--- /dev/null ++++ wireshark/epan/dissectors/packet-gsm_abis_oml.h @@ -0,0 +1,786 @@ +/* GSM Network Management messages on the A-bis interface + * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ From 6a22c0135a6ac49d716d38a92c9d9c9a329da980 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 17:02:32 +0100 Subject: [PATCH 135/365] [gprs] SI 13 should only be generated on C0 (BCCH-carrying TRX) --- openbsc/src/bsc_init.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 8450af6d0..48d90d700 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -681,15 +681,16 @@ static int set_system_infos(struct gsm_bts_trx *trx) DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } - } #ifdef GPRS - i = 13 - rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); - if (rc < 0) - goto err_out; - DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); - rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); + i = 13 + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); + if (rc < 0) + goto err_out; + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); + rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); #endif + } + i = 5; rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_5); if (rc < 0) From 1394fea03f888408616cac3a669191f2e6923c8f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:01:33 +0100 Subject: [PATCH 136/365] ipaccess: Fix two minor bugs regarding multi-TRX setup we need to set newbfd->priv_nr to 2+trx_id, rather than keeping it '2' all the time, as it is used to look-up the e1i_ts when we receive a packet. A constant '2' would always match to TRX 0. we also need to keep one separate bit for each TRX state in order to properly generate the EVT_E1_TEI_UP event for trx > 0. --- openbsc/src/input/ipaccess.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 143712e1c..6bd501df1 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -238,6 +238,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, trx->rsl_tei, 0); /* get rid of our old temporary bfd */ memcpy(newbfd, bfd, sizeof(*newbfd)); + newbfd->priv_nr = 2+trx_id; bsc_unregister_fd(bfd); bsc_register_fd(newbfd); talloc_free(bfd); @@ -347,9 +348,9 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (link->type) { case E1INP_SIGN_RSL: - if (!(msg->trx->bts->ip_access.flags & RSL_UP)) { + if (!(msg->trx->bts->ip_access.flags & (RSL_UP << msg->trx->nr))) { e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); - msg->trx->bts->ip_access.flags |= RSL_UP; + msg->trx->bts->ip_access.flags |= (RSL_UP << msg->trx->nr); } ret = abis_rsl_rcvmsg(msg); break; From 713550120cb9231de49090c01abb6e867a93137d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:08:18 +0100 Subject: [PATCH 137/365] remove duplicate flag for cell barring it's sufficient if we keep the state of cell barring in one place --- openbsc/include/openbsc/gsm_data.h | 1 - openbsc/src/bsc_init.c | 4 +--- openbsc/src/vty_interface.c | 6 +++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 876955824..9d2549ca1 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -381,7 +381,6 @@ struct gsm_bts { /* should the channel allocator allocate channels from high TRX to TRX0, * rather than starting from TRX0 and go upwards? */ int chan_alloc_reverse; - int cell_barred; /* maximum Tx power that the MS is permitted to use in this cell */ int ms_max_power; diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 48d90d700..86a93a1a9 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -804,7 +804,7 @@ static int bootstrap_bts(struct gsm_bts *bts) } if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && - !bts->cell_barred) + !bts->si_common.rach_control.cell_bar) LOGP(DNM, LOG_ERROR, "\nWARNING: You are running an 'accept-all' " "network on a BTS that is not barred. This " "configuration is likely to interfere with production " @@ -815,8 +815,6 @@ static int bootstrap_bts(struct gsm_bts *bts) bts->si_common.chan_desc.att = 1; bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; - if (bts->cell_barred) - bts->si_common.rach_control.cell_bar = 1; /* T3212 is set from vty/config */ /* some defaults for our system information */ diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 0e518efd4..b13dc5f58 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -140,7 +140,7 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) VTY_NEWLINE); vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); - if (bts->cell_barred) + if (bts->si_common.rach_control.cell_bar) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) vty_out(vty, " Unit ID: %u/%u/0, OML Stream ID 0x%02x%s", @@ -258,7 +258,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); - if (bts->cell_barred) + if (bts->si_common.rach_control.cell_bar) vty_out(vty, " cell barred 1%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) { vty_out(vty, " ip.access unit_id %u %u%s", @@ -1202,7 +1202,7 @@ DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd, { struct gsm_bts *bts = vty->index; - bts->cell_barred = atoi(argv[0]); + bts->si_common.rach_control.cell_bar = atoi(argv[0]); return CMD_SUCCESS; } From 73d4fce151b587ae28692448ea7094212e7eab7b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:12:19 +0100 Subject: [PATCH 138/365] make sure bootstrap_bts() only contains static initialization values that might change at runtime are moved to set_system_infos() which we might now also call at runtime to update the BTS with changes in the SI --- openbsc/src/bsc_init.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 86a93a1a9..61510435b 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -672,6 +672,11 @@ static int set_system_infos(struct gsm_bts_trx *trx) { int i, rc; u_int8_t si_tmp[23]; + struct gsm_bts *bts = trx->bts; + + bts->si_common.cell_sel_par.ms_txpwr_max_ccch = + ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); + bts->si_common.cell_sel_par.neci = bts->network->neci; if (trx == trx->bts->c0) { for (i = 1; i <= 4; i++) { @@ -827,10 +832,7 @@ static int bootstrap_bts(struct gsm_bts *bts) bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */ bts->si_common.cell_options.pwrc = 0; /* PWRC not set */ - bts->si_common.cell_sel_par.ms_txpwr_max_ccch = - ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); bts->si_common.cell_sel_par.acs = 0; - bts->si_common.cell_sel_par.neci = bts->network->neci; bts->si_common.ncc_permitted = 0xff; From ac0c13c02c16a2ae3188978665606ac8061f84e8 Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Sat, 5 Dec 2009 12:44:41 +0100 Subject: [PATCH 139/365] [sms] bugfix: additional functionality indicator only appears in TP_VPF_ENHANCED - not in TP_VPF_ABSOLUTE --- openbsc/src/gsm_04_11.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 31526e979..17a583113 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -560,7 +560,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) case GSM340_TP_VPF_ENHANCED: sms_vp = smsp; /* the additional functionality indicator... */ - if (*smsp & (1<<7)) smsp++; + if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7)) + smsp++; smsp += 7; break; case GSM340_TP_VPF_NONE: From a992a36d5f9e7a2d1bb7948784c69ea2e342b7d3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:36:45 +0100 Subject: [PATCH 140/365] it's LOGL_ERROR, not LOG_ERROR --- openbsc/src/bsc_init.c | 2 +- openbsc/src/telnet_interface.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 61510435b..a8a202e93 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -810,7 +810,7 @@ static int bootstrap_bts(struct gsm_bts *bts) if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && !bts->si_common.rach_control.cell_bar) - LOGP(DNM, LOG_ERROR, "\nWARNING: You are running an 'accept-all' " + LOGP(DNM, LOGL_ERROR, "\nWARNING: You are running an 'accept-all' " "network on a BTS that is not barred. This " "configuration is likely to interfere with production " "GSM networks and should only be used in a RF " diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index 2d7b05c70..bc91ca333 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -84,12 +84,12 @@ void telnet_init(struct gsm_network *network, int port) { sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) { - LOGP(DNM, LOG_ERROR, "Telnet interface failed to bind\n"); + LOGP(DNM, LOGL_ERROR, "Telnet interface failed to bind\n"); return; } if (listen(fd, 0) < 0) { - LOGP(DNM, LOG_ERROR, "Telnet interface failed to listen\n"); + LOGP(DNM, LOGL_ERROR, "Telnet interface failed to listen\n"); return; } From 24ff6ee0a343d46823771b9a86e867780eb2099b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 00:41:05 +0100 Subject: [PATCH 141/365] keep some internal statistics inside OpenBSC the statistics will give us some idea about the network load and performance. --- openbsc/include/openbsc/gsm_data.h | 45 ++++++++++++++++++++++++++++++ openbsc/src/abis_rsl.c | 3 ++ openbsc/src/gsm_04_08.c | 19 +++++++++++++ openbsc/src/gsm_04_08_utils.c | 2 ++ openbsc/src/gsm_04_11.c | 9 +++++- openbsc/src/handover_logic.c | 8 ++++++ openbsc/src/paging.c | 7 +++++ openbsc/src/vty_interface.c | 36 ++++++++++++++++++++++++ 8 files changed, 128 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 9d2549ca1..74e193832 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -457,6 +457,49 @@ struct gsm_bts { struct llist_head trx_list; }; +/* Some statistics of our network */ +struct gsmnet_stats { + struct { + unsigned long total; + unsigned long no_channel; + } chreq; + struct { + unsigned long attempted; + unsigned long no_channel; /* no channel available */ + unsigned long timeout; /* T3103 timeout */ + unsigned long completed; /* HO COMPL received */ + unsigned long failed; /* HO FAIL received */ + } handover; + struct { + unsigned long attach; + unsigned long normal; + unsigned long periodic; + unsigned long detach; + } loc_upd_type; + struct { + unsigned long reject; + unsigned long accept; + } loc_upd_resp; + struct { + unsigned long attempted; + unsigned long detached; + unsigned long completed; + unsigned long expired; + } paging; + struct { + unsigned long submitted; /* MO SMS submissions */ + unsigned long no_receiver; + unsigned long delivered; /* MT SMS deliveries */ + unsigned long rp_err_mem; + unsigned long rp_err_other; + } sms; + struct { + unsigned long dialled; /* total number of dialled calls */ + unsigned long alerted; /* we alerted the other end */ + unsigned long connected;/* how many calls were accepted */ + } call; +}; + enum gsm_auth_policy { GSM_AUTH_POLICY_CLOSED, /* only subscribers authorized in DB */ GSM_AUTH_POLICY_ACCEPT_ALL, /* accept everyone, even if not authorized in DB */ @@ -494,6 +537,8 @@ struct gsm_network { unsigned int max_distance; /* TA values */ } handover; + struct gsmnet_stats stats; + /* layer 4 */ int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg); struct llist_head upqueue; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 72ae9dbb6..ae1d6af5d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1261,11 +1261,14 @@ static int rsl_rx_chan_rqd(struct msgb *msg) lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci); chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci); + bts->network->stats.chreq.total++; + /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", gsm_lchan_name(lctype), rqd_ref->ra); + bts->network->stats.chreq.no_channel++; /* FIXME: send some kind of reject ?!? */ return -ENOMEM; } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 156927f56..2b9dcc238 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -886,6 +886,7 @@ static int encode_more(struct msgb *msg) /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) { + struct gsm_bts *bts = lchan->ts->trx->bts; struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -897,6 +898,8 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) gh->data[0] = cause; DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr); + + bts->network->stats.loc_upd_resp.reject++; return gsm48_sendmsg(msg, NULL); } @@ -925,6 +928,8 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); + bts->network->stats.loc_upd_resp.accept++; + return gsm48_sendmsg(msg, NULL); } @@ -1043,6 +1048,18 @@ static int mm_rx_loc_upd_req(struct msgb *msg) dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, &lu->mi_len); + switch (lu->type) { + case GSM48_LUPD_NORMAL: + bts->network->stats.loc_upd_type.normal++; + break; + case GSM48_LUPD_IMSI_ATT: + bts->network->stats.loc_upd_type.attach++; + break; + case GSM48_LUPD_PERIODIC: + bts->network->stats.loc_upd_type.periodic++; + break; + } + /* * Pseudo Spoof detection: Just drop a second/concurrent * location updating request. @@ -1369,6 +1386,8 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ", mi_type, mi_string); + bts->network->stats.loc_upd_type.detach++; + switch (mi_type) { case GSM_MI_TYPE_TMSI: subscr = subscr_get_by_tmsi(bts->network, diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index e96a1ca09..2cd571e24 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -488,6 +488,8 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr) sig_data.bts = msg->lchan->ts->trx->bts; sig_data.lchan = msg->lchan; + bts->network->stats.paging.completed++; + dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); /* Stop paging on the bts we received the paging response */ diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 17a583113..579bb55d1 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -517,6 +517,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; + bts->network->stats.sms.submitted++; + gsms = sms_alloc(); if (!gsms) return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; @@ -605,6 +607,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr); if (!gsms->receiver) { rc = 1; /* cause 1: unknown subscriber */ + bts->network->stats.sms.no_receiver++; goto out; } @@ -791,7 +794,9 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, * to store this in our database and wati for a SMMA message */ /* FIXME */ dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr); - } + trans->lchan->ts->trx->bts->network->stats.sms.rp_err_mem++; + } else + trans->lchan->ts->trx->bts->network->stats.sms.rp_err_other++; sms_free(sms); trans->sms.sms = NULL; @@ -1064,6 +1069,8 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) DEBUGP(DSMS, "TX: SMS DELIVER\n"); + lchan->ts->trx->bts->network->stats.sms.delivered++; + return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref); /* FIXME: enter 'wait for RP-ACK' state, start TR1N */ } diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 94d3d0d1e..393b0f2ad 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -97,9 +97,12 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); + bts->network->stats.handover.attempted++; + new_lchan = lchan_alloc(bts, old_lchan->type); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); + bts->network->stats.handover.no_channel++; return -ENOSPC; } @@ -143,6 +146,7 @@ static void ho_T3103_cb(void *_ho) struct bsc_handover *ho = _ho; DEBUGP(DHO, "HO T3103 expired\n"); + ho->new_lchan->ts->trx->bts->network->stats.handover.timeout++; lchan_free(ho->new_lchan); llist_del(&ho->list); @@ -211,6 +215,8 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) return -ENODEV; } + new_lchan->ts->trx->bts->network->stats.handover.completed++; + bsc_del_timer(&ho->T3103); /* update lchan pointer of transaction */ @@ -238,6 +244,8 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) return -ENODEV; } + old_lchan->ts->trx->bts->network->stats.handover.failed++; + bsc_del_timer(&ho->T3103); llist_del(&ho->list); put_lchan(ho->new_lchan); diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index b273419c3..538e0a8ec 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -212,6 +212,8 @@ static void paging_T3113_expired(void *data) cbfn = req->cbfn; paging_remove_request(&req->bts->paging, req); + req->bts->network->stats.paging.expired++; + dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); if (cbfn) cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL, @@ -254,6 +256,8 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, struct gsm_bts *bts = NULL; int num_pages = 0; + network->stats.paging.attempted++; + /* start paging subscriber on all BTS within Location Area */ do { int rc; @@ -269,6 +273,9 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, return rc; } while (1); + if (num_pages == 0) + network->stats.paging.detached++; + return num_pages; } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index b13dc5f58..fa9b45da4 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -761,6 +761,41 @@ DEFUN(show_paging, return CMD_SUCCESS; } +DEFUN(show_stats, + show_stats_cmd, + "show statistics", + SHOW_STR "Display network statistics\n") +{ + struct gsm_network *net = gsmnet; + + vty_out(vty, "Channel Requests: %lu total, %lu no channel%s", + net->stats.chreq.total, net->stats.chreq.no_channel, + VTY_NEWLINE); + vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s", + net->stats.loc_upd_type.attach, net->stats.loc_upd_type.normal, + net->stats.loc_upd_type.periodic, VTY_NEWLINE); + vty_out(vty, "IMSI Detach Indications: %lu%s\n", + net->stats.loc_upd_type.detach, VTY_NEWLINE); + vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", + net->stats.loc_upd_resp.accept, + net->stats.loc_upd_resp.reject, VTY_NEWLINE); + vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s", + net->stats.paging.attempted, net->stats.paging.completed, + net->stats.paging.expired, VTY_NEWLINE); + vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, " + "%lu completed, %lu failed%s", net->stats.handover.attempted, + net->stats.handover.no_channel, net->stats.handover.timeout, + net->stats.handover.completed, net->stats.handover.failed, + VTY_NEWLINE); + vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s", + net->stats.sms.submitted, net->stats.sms.no_receiver, + VTY_NEWLINE); + vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s", + net->stats.sms.delivered, net->stats.sms.rp_err_mem, + net->stats.sms.rp_err_other, VTY_NEWLINE); + return CMD_SUCCESS; +} + DEFUN(cfg_net, cfg_net_cmd, "network", @@ -1435,6 +1470,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &show_e1ts_cmd); install_element(VIEW_NODE, &show_paging_cmd); + install_element(VIEW_NODE, &show_stats_cmd); install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net); From 92ffd926ef61b46a5cab9230a66b6fbb26bec613 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 22 Dec 2009 07:45:17 +0100 Subject: [PATCH 142/365] [gsm48] Move gsm48_parse_meas_rep to gsm_04_08_utils Move the function over to the _utils side as handover measurement is compiled into libbsc and we don't want to end up with linking errors. --- openbsc/src/gsm_04_08.c | 68 ---------------------------------- openbsc/src/gsm_04_08_utils.c | 69 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 2b9dcc238..f89d8c5a2 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -165,74 +165,6 @@ static const char *rr_cause_name(u_int8_t cause) return strbuf; } -int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); - u_int8_t *data = gh->data; - struct gsm_bts *bts = msg->lchan->ts->trx->bts; - struct bitvec *nbv = &bts->si_common.neigh_list; - - if (gh->msg_type != GSM48_MT_RR_MEAS_REP) - return -EINVAL; - - if (data[0] & 0x80) - rep->flags |= MEAS_REP_F_BA1; - if (data[0] & 0x40) - rep->flags |= MEAS_REP_F_UL_DTX; - if ((data[1] & 0x40) == 0x00) - rep->flags |= MEAS_REP_F_DL_VALID; - - rep->dl.full.rx_lev = data[0] & 0x3f; - rep->dl.sub.rx_lev = data[1] & 0x3f; - rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; - rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; - - rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); - if (rep->num_cell < 1 || rep->num_cell > 6) - return 0; - - /* an encoding nightmare in perfection */ - - rep->cell[0].rxlev = data[3] & 0x3f; - rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); - rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); - if (rep->num_cell < 2) - return 0; - - rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); - rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); - rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); - if (rep->num_cell < 3) - return 0; - - rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); - rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); - rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); - if (rep->num_cell < 4) - return 0; - - rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); - rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); - rep->cell[3].bsic = data[11] >> 2; - if (rep->num_cell < 5) - return 0; - - rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); - rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[12] & 0xf) << 1) | (data[13] >> 7)); - rep->cell[4].bsic = (data[13] >> 1) & 0x3f; - if (rep->num_cell < 6) - return 0; - - rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); - rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[14] & 0x07) << 2) | (data[15] >> 6)); - rep->cell[5].bsic = data[15] & 0x3f; - - return 0; -} - int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi); static int gsm48_tx_simple(struct gsm_lchan *lchan, u_int8_t pdisc, u_int8_t msg_type); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 2cd571e24..2db46ca58 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -700,3 +700,72 @@ int gsm48_rx_rr_modif_ack(struct msgb *msg) rsl_ipacc_crcx(msg->lchan); return rc; } + +int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); + u_int8_t *data = gh->data; + struct gsm_bts *bts = msg->lchan->ts->trx->bts; + struct bitvec *nbv = &bts->si_common.neigh_list; + + if (gh->msg_type != GSM48_MT_RR_MEAS_REP) + return -EINVAL; + + if (data[0] & 0x80) + rep->flags |= MEAS_REP_F_BA1; + if (data[0] & 0x40) + rep->flags |= MEAS_REP_F_UL_DTX; + if ((data[1] & 0x40) == 0x00) + rep->flags |= MEAS_REP_F_DL_VALID; + + rep->dl.full.rx_lev = data[0] & 0x3f; + rep->dl.sub.rx_lev = data[1] & 0x3f; + rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; + rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; + + rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); + if (rep->num_cell < 1 || rep->num_cell > 6) + return 0; + + /* an encoding nightmare in perfection */ + + rep->cell[0].rxlev = data[3] & 0x3f; + rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); + rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); + if (rep->num_cell < 2) + return 0; + + rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); + rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); + rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); + if (rep->num_cell < 3) + return 0; + + rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); + rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); + rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); + if (rep->num_cell < 4) + return 0; + + rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); + rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); + rep->cell[3].bsic = data[11] >> 2; + if (rep->num_cell < 5) + return 0; + + rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); + rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[12] & 0xf) << 1) | (data[13] >> 7)); + rep->cell[4].bsic = (data[13] >> 1) & 0x3f; + if (rep->num_cell < 6) + return 0; + + rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); + rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[14] & 0x07) << 2) | (data[15] >> 6)); + rep->cell[5].bsic = data[15] & 0x3f; + + return 0; +} + From 4f5456c040c2dd0c53fe28cb51219d668d464a21 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 22 Dec 2009 07:48:20 +0100 Subject: [PATCH 143/365] [misc] Move rtp_proxy.c into the libbsc.c For the time being RSL has to know about Layer4 and upwards and is using the RTP socket class.... --- openbsc/src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index f36a701bc..4def2e93b 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,10 +12,10 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - handover_decision.c meas_rep.c + handover_decision.c meas_rep.c rtp_proxy.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ - mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ + mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c From 0a64603db961576eaac251f81a577b91a04ddf4d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 22 Dec 2009 08:03:55 +0100 Subject: [PATCH 144/365] [misc] Move handover into libmsc.a Handover is a high level decision, it can span multiple BSCs and belongs mostly into the MSC domain. --- openbsc/src/Makefile.am | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 4def2e93b..7abec6953 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -7,16 +7,17 @@ noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ - msgb.c select.c chan_alloc.c timer.c debug.c handover_logic.c \ + msgb.c select.c chan_alloc.c timer.c debug.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - handover_decision.c meas_rep.c rtp_proxy.c + rtp_proxy.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ - token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c + token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \ + handover_logic.c handover_decision.c meas_rep.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c From c80210641a68a6ca07274f0319ba03d7521c2b3e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 22 Dec 2009 08:27:21 +0100 Subject: [PATCH 145/365] [vty] Document the various T??? we are ausing. Provide a small individual documentation string. --- openbsc/src/vty_interface.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index fa9b45da4..fdc678a3b 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -976,11 +976,11 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, return CMD_SUCCESS; } -#define DECLARE_TIMER(number) \ +#define DECLARE_TIMER(number, doc) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ "timer t" #number " <0-65535>", \ - "Set the T" #number " value.") \ + doc) \ { \ int value = atoi(argv[0]); \ \ @@ -994,17 +994,17 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, return CMD_SUCCESS; \ } -DECLARE_TIMER(3101) -DECLARE_TIMER(3103) -DECLARE_TIMER(3105) -DECLARE_TIMER(3107) -DECLARE_TIMER(3109) -DECLARE_TIMER(3111) -DECLARE_TIMER(3113) -DECLARE_TIMER(3115) -DECLARE_TIMER(3117) -DECLARE_TIMER(3119) -DECLARE_TIMER(3141) +DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.") +DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.") +DECLARE_TIMER(3105, "Currently not used.") +DECLARE_TIMER(3107, "Currently not used.") +DECLARE_TIMER(3109, "Currently not used.") +DECLARE_TIMER(3111, "Currently not used.") +DECLARE_TIMER(3113, "Set the time to try paging a subscriber.") +DECLARE_TIMER(3115, "Currently not used.") +DECLARE_TIMER(3117, "Currently not used.") +DECLARE_TIMER(3119, "Currently not used.") +DECLARE_TIMER(3141, "Currently not used.") /* per-BTS configuration */ From b908cb7e0ed9e10ee7ced8083d4abdfb9ca2e61c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 13:09:29 +0100 Subject: [PATCH 146/365] Display current channel usage load in 'show bts' and 'show network' This is just the load at one given instant. We definitely also want to see some averages and record the measurements in a database later. --- openbsc/include/openbsc/chan_alloc.h | 12 +++++++ openbsc/src/chan_alloc.c | 49 ++++++++++++++++++++++++++++ openbsc/src/vty_interface.c | 32 ++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h index 38855d1ee..fa8663056 100644 --- a/openbsc/include/openbsc/chan_alloc.h +++ b/openbsc/include/openbsc/chan_alloc.h @@ -49,4 +49,16 @@ void lchan_free(struct gsm_lchan *lchan); /* Consider releasing the channel */ int lchan_auto_release(struct gsm_lchan *lchan); +struct load_counter { + unsigned int total; + unsigned int used; +}; + +struct pchan_load { + struct load_counter pchan[GSM_PCHAN_UNKNOWN]; +}; + +void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts); +void network_chan_load(struct pchan_load *pl, struct gsm_network *net); + #endif /* _CHAN_ALLOC_H */ diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index c42b60b46..632860814 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -121,6 +121,7 @@ static const u_int8_t subslots_per_pchan[] = { [GSM_PCHAN_TCH_F] = 1, [GSM_PCHAN_TCH_H] = 2, [GSM_PCHAN_SDCCH8_SACCH8C] = 8, + /* FIXME: what about dynamic TCH_F_TCH_H ? */ }; static struct gsm_lchan * @@ -329,3 +330,51 @@ struct gsm_lchan *lchan_for_subscr(struct gsm_subscriber *subscr) return NULL; } + +void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; + + llist_for_each_entry(trx, &bts->trx_list, list) { + int i; + + /* skip administratively deactivated tranxsceivers */ + if (trx->nm_state.availability != NM_AVSTATE_OK || + trx->bb_transc.nm_state.availability != NM_AVSTATE_OK) + continue; + + for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { + struct gsm_bts_trx_ts *ts = &trx->ts[i]; + struct load_counter *pl = &cl->pchan[ts->pchan]; + int j; + + /* skip administratively deactivated timeslots */ + if (ts->nm_state.availability != NM_AVSTATE_OK) + continue; + + for (j = 0; j < subslots_per_pchan[ts->pchan]; j++) { + struct gsm_lchan *lchan = &ts->lchan[j]; + + pl->total++; + + switch (lchan->state) { + case LCHAN_S_NONE: + break; + default: + pl->used++; + break; + } + } + } + } +} + +void network_chan_load(struct pchan_load *pl, struct gsm_network *net) +{ + struct gsm_bts *bts; + + memset(pl, 0, sizeof(*pl)); + + llist_for_each_entry(bts, &net->bts_list, list) + bts_chan_load(pl, bts); +} diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index fdc678a3b..077e1d03f 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -74,8 +75,30 @@ static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms) nm_avail_name(nms->availability), VTY_NEWLINE); } +static void dump_pchan_load_vty(struct vty *vty, char *prefix, + const struct pchan_load *pl) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pl->pchan); i++) { + const struct load_counter *lc = &pl->pchan[i]; + unsigned int percent; + + if (lc->total == 0) + continue; + + percent = (lc->used * 100) / lc->total; + + vty_out(vty, "%s%20s: %3u%% (%u/%u)%s", prefix, + gsm_pchan_name(i), percent, lc->used, lc->total, + VTY_NEWLINE); + } +} + static void net_dump_vty(struct vty *vty, struct gsm_network *net) { + struct pchan_load pl; + vty_out(vty, "BSC is on Country Code %u, Network Code %u " "and has %u BTS%s", net->country_code, net->network_code, net->num_bts, VTY_NEWLINE); @@ -97,6 +120,9 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off", VTY_NEWLINE); + network_chan_load(&pl, net); + vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE); + dump_pchan_load_vty(vty, " ", &pl); } DEFUN(show_net, show_net_cmd, "show network", @@ -128,6 +154,8 @@ static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l) static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) { + struct pchan_load pl; + vty_out(vty, "BTS %u is of %s type in band %s, has CI %u LAC %u, " "BSIC %u, TSC %u and %u TRX%s", bts->nr, btstype2str(bts->type), gsm_band_name(bts->band), @@ -157,6 +185,10 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) e1isl_dump_vty(vty, bts->oml_link); } /* FIXME: oml_link, chan_desc */ + memset(&pl, 0, sizeof(pl)); + bts_chan_load(&pl, bts); + vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE); + dump_pchan_load_vty(vty, " ", &pl); } DEFUN(show_bts, show_bts_cmd, "show bts [number]", From 9c4f6b5dca610bce313911bb81b3d3081f662d31 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 13:16:27 +0100 Subject: [PATCH 147/365] missing semicolon at end of statement --- openbsc/src/bsc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index a8a202e93..14a9777c1 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -687,7 +687,7 @@ static int set_system_infos(struct gsm_bts_trx *trx) rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } #ifdef GPRS - i = 13 + i = 13; rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); if (rc < 0) goto err_out; From ff1f19e199bbb0cb9da55e0994d9b1443bba85f7 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut <246tnt@gmail.com> Date: Tue, 22 Dec 2009 13:22:29 +0100 Subject: [PATCH 148/365] Implement a better sending of pending SMS The previous implementation had some shortcomings: - If the MIN ID given was not the exact id of the first unsent SMS, it would try to submit the same sms several time until id++ finally made id go to the next one. - If a subscriber had several SMS pending it would try to submit them individually (only to get rejected because a paging for that subscriber was already in progress) Signed-off-by: Sylvain Munaut --- openbsc/src/db.c | 27 +++++++++++++++++++++++++++ openbsc/src/vty_interface_layer3.c | 17 +++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index d85386548..707d877bb 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -788,6 +788,33 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) return sms; } +struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id) +{ + dbi_result result; + struct gsm_sms *sms; + + result = dbi_conn_queryf(conn, + "SELECT * FROM SMS,Subscriber " + "WHERE sms.receiver_id >= %llu AND sms.sent is NULL " + "AND sms.receiver_id = subscriber.id " + "AND subscriber.lac > 0 " + "ORDER BY sms.receiver_id, id LIMIT 1", + min_subscr_id); + if (!result) + return NULL; + + if (!dbi_result_next_row(result)) { + dbi_result_free(result); + return NULL; + } + + sms = sms_from_result(net, result); + + dbi_result_free(result); + + return sms; +} + /* retrieve the next unsent SMS for a given subscriber */ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) { diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 4cc08c2da..70e8445f0 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -143,23 +143,20 @@ DEFUN(show_subscr_cache, DEFUN(sms_send_pend, sms_send_pend_cmd, - "sms send pending MIN_ID", - "Send all pending SMS starting from MIN_ID") + "sms send pending", + "Send all pending SMS") { struct gsm_sms *sms; - int id = atoi(argv[0]); + int id = 0; while (1) { - sms = db_sms_get_unsent(gsmnet, id++); + sms = db_sms_get_unsent_by_subscr(gsmnet, id); if (!sms) - return CMD_WARNING; - - if (!sms->receiver) { - sms_free(sms); - continue; - } + break; gsm411_send_sms_subscr(sms->receiver, sms); + + id = sms->receiver->id + 1; } return CMD_SUCCESS; From 4010f1e6f4d3f1c702be836a2342aefd8de73f2a Mon Sep 17 00:00:00 2001 From: Sylvain Munaut <246tnt@gmail.com> Date: Tue, 22 Dec 2009 13:43:26 +0100 Subject: [PATCH 149/365] bts: Allow config of RACH control parameters tx-integer & max retrans Tweaking theses can be useful especially tx-integer that influence both the spread of rach attemps and the delay between two attemps. Looking up GSM 04.08 3.3.1.1.2 & 10.5.2.29 can help determine good values. The default are choosed with a wide spacing between attemps (tx integer = 9 -> T=12 & S=217 (non-combined CCCH/SDCCH) or 115 (for combined CCCH/SDCCH)). This alleviates the problem of responding to several RACH attempts by a same MS, allocating several RF channels when only 1 is needed. Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/gsm_utils.h | 7 +++++++ openbsc/src/bsc_init.c | 5 ----- openbsc/src/gsm_data.c | 4 ++++ openbsc/src/vty_interface.c | 32 +++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/gsm_utils.h b/openbsc/include/openbsc/gsm_utils.h index 5809221a3..56a4120a5 100644 --- a/openbsc/include/openbsc/gsm_utils.h +++ b/openbsc/include/openbsc/gsm_utils.h @@ -37,5 +37,12 @@ int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl); int rxlev2dbm(u_int8_t rxlev); u_int8_t dbm2rxlev(int dbm); +/* According to GSM 04.08 Chapter 10.5.2.29 */ +static inline int rach_max_trans_val2raw(int val) { return (val >> 1) & 3; } +static inline int rach_max_trans_raw2val(int raw) { + const int tbl[4] = { 1, 2, 4, 7 }; + return tbl[raw & 3]; +} + void generate_backtrace(); #endif diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 14a9777c1..1a70230fc 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -823,11 +823,6 @@ static int bootstrap_bts(struct gsm_bts *bts) /* T3212 is set from vty/config */ /* some defaults for our system information */ - bts->si_common.rach_control.re = 1; /* no re-establishment */ - bts->si_common.rach_control.tx_integer = 5; /* 8 slots spread */ - bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */ - bts->si_common.rach_control.t2 = 4; /* no emergency calls */ - bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */ bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */ bts->si_common.cell_options.pwrc = 0; /* PWRC not set */ diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 12f439be2..d6ebd9224 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -175,6 +175,10 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, bts->si_common.cell_alloc.data = bts->si_common.data.cell_alloc; bts->si_common.cell_alloc.data_len = sizeof(bts->si_common.data.cell_alloc); + bts->si_common.rach_control.re = 1; /* no re-establishment */ + bts->si_common.rach_control.tx_integer = 9; /* 12 slots spread - 217/115 slots delay */ + bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */ + bts->si_common.rach_control.t2 = 4; /* no emergency calls */ for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { bts->gprs.nsvc[i].bts = bts; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 077e1d03f..808db3fb0 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -168,6 +168,11 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) VTY_NEWLINE); vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); + vty_out(vty, "RACH TX-Integer: %u%s", bts->si_common.rach_control.tx_integer, + VTY_NEWLINE); + vty_out(vty, "RACH Max transmissions: %u%s", + rach_max_trans_raw2val(bts->si_common.rach_control.max_trans), + VTY_NEWLINE); if (bts->si_common.rach_control.cell_bar) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) @@ -290,6 +295,11 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); + vty_out(vty, " rach tx integer %u%s", + bts->si_common.rach_control.tx_integer, VTY_NEWLINE); + vty_out(vty, " rach max transmission %u%s", + rach_max_trans_raw2val(bts->si_common.rach_control.max_trans), + VTY_NEWLINE); if (bts->si_common.rach_control.cell_bar) vty_out(vty, " cell barred 1%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) { @@ -1263,6 +1273,26 @@ DEFUN(cfg_bts_challoc, cfg_bts_challoc_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_rach_tx_integer, + cfg_bts_rach_tx_integer_cmd, + "rach tx integer <0-15>", + "Set the raw tx integer value in RACH Control parameters IE") +{ + struct gsm_bts *bts = vty->index; + bts->si_common.rach_control.tx_integer = atoi(argv[0]) & 0xf; + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_rach_max_trans, + cfg_bts_rach_max_trans_cmd, + "rach max transmission (1|2|4|7)", + "Set the maximum number of RACH burst transmissions") +{ + struct gsm_bts *bts = vty->index; + bts->si_common.rach_control.max_trans = rach_max_trans_val2raw(atoi(argv[0])); + return CMD_SUCCESS; +} + DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd, "cell barred (0|1)", "Should this cell be barred from access?") @@ -1550,6 +1580,8 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_oml_e1_cmd); install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd); install_element(BTS_NODE, &cfg_bts_challoc_cmd); + install_element(BTS_NODE, &cfg_bts_rach_tx_integer_cmd); + install_element(BTS_NODE, &cfg_bts_rach_max_trans_cmd); install_element(BTS_NODE, &cfg_bts_cell_barred_cmd); install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd); install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd); From 4983921af1a84ea20c6be7944bf0ff4928578a69 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 13:45:58 +0100 Subject: [PATCH 150/365] [gsm_04_11] Replace hardcoded transaction_id by real allocation Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 579bb55d1..a5f64f170 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -1011,7 +1011,11 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) u_int8_t transaction_id; int rc; - transaction_id = 4; /* FIXME: we always use 4 for now */ + transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0); + if (transaction_id == -1) { + DEBUGP(DSMS, "No available transaction ids\n"); + return -EBUSY; + } msg->lchan = lchan; From ffa55a4e8783419f60932ef2f9e872293cf932b9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 19:07:32 +0100 Subject: [PATCH 151/365] statistics: Introduce 'struct counter' instead of using unsigned long This has the advantage that counters can be added all over the code very easily, while having only one routine that stores all of the current counter values to the database. The counters are synced every 60 seconds, providing relatively fine grained statistics about the network usage as time passes by. --- openbsc/include/openbsc/Makefile.am | 2 +- openbsc/include/openbsc/db.h | 4 ++ openbsc/include/openbsc/gsm_data.h | 51 +++++++++-------- openbsc/include/openbsc/statistics.h | 30 ++++++++++ openbsc/src/Makefile.am | 2 +- openbsc/src/abis_rsl.c | 4 +- openbsc/src/bs11_config.c | 5 ++ openbsc/src/db.c | 28 +++++++++ openbsc/src/gsm_04_08.c | 12 ++-- openbsc/src/gsm_04_11.c | 11 ++-- openbsc/src/gsm_data.c | 27 +++++++++ openbsc/src/handover_logic.c | 13 +++-- openbsc/src/paging.c | 6 +- openbsc/src/statistics.c | 85 ++++++++++++++++++++++++++++ openbsc/src/vty_interface.c | 41 ++++++++------ 15 files changed, 255 insertions(+), 66 deletions(-) create mode 100644 openbsc/include/openbsc/statistics.h create mode 100644 openbsc/src/statistics.c diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 27c88b770..b4760252e 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -5,4 +5,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \ - system_information.h handover.h + system_information.h handover.h statistics.h diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index 07135937b..fca736493 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -53,4 +53,8 @@ int db_sms_mark_sent(struct gsm_sms *sms); int db_apdu_blob_store(struct gsm_subscriber *subscr, u_int8_t apdu_id_flags, u_int8_t len, u_int8_t *apdu); + +/* Statistics counter storage */ +int db_store_counter(struct counter *ctr); + #endif /* _DB_H */ diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 74e193832..c2eec4156 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -61,6 +61,7 @@ enum gsm_chreq_reason_t { #include #include #include +#include #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -460,43 +461,43 @@ struct gsm_bts { /* Some statistics of our network */ struct gsmnet_stats { struct { - unsigned long total; - unsigned long no_channel; + struct counter *total; + struct counter *no_channel; } chreq; struct { - unsigned long attempted; - unsigned long no_channel; /* no channel available */ - unsigned long timeout; /* T3103 timeout */ - unsigned long completed; /* HO COMPL received */ - unsigned long failed; /* HO FAIL received */ + struct counter *attempted; + struct counter *no_channel; /* no channel available */ + struct counter *timeout; /* T3103 timeout */ + struct counter *completed; /* HO COMPL received */ + struct counter *failed; /* HO FAIL received */ } handover; struct { - unsigned long attach; - unsigned long normal; - unsigned long periodic; - unsigned long detach; + struct counter *attach; + struct counter *normal; + struct counter *periodic; + struct counter *detach; } loc_upd_type; struct { - unsigned long reject; - unsigned long accept; + struct counter *reject; + struct counter *accept; } loc_upd_resp; struct { - unsigned long attempted; - unsigned long detached; - unsigned long completed; - unsigned long expired; + struct counter *attempted; + struct counter *detached; + struct counter *completed; + struct counter *expired; } paging; struct { - unsigned long submitted; /* MO SMS submissions */ - unsigned long no_receiver; - unsigned long delivered; /* MT SMS deliveries */ - unsigned long rp_err_mem; - unsigned long rp_err_other; + struct counter *submitted; /* MO SMS submissions */ + struct counter *no_receiver; + struct counter *delivered; /* MT SMS deliveries */ + struct counter *rp_err_mem; + struct counter *rp_err_other; } sms; struct { - unsigned long dialled; /* total number of dialled calls */ - unsigned long alerted; /* we alerted the other end */ - unsigned long connected;/* how many calls were accepted */ + struct counter *dialled; /* total number of dialled calls */ + struct counter *alerted; /* we alerted the other end */ + struct counter *connected;/* how many calls were accepted */ } call; }; diff --git a/openbsc/include/openbsc/statistics.h b/openbsc/include/openbsc/statistics.h new file mode 100644 index 000000000..9291a8c25 --- /dev/null +++ b/openbsc/include/openbsc/statistics.h @@ -0,0 +1,30 @@ +#ifndef _STATISTICS_H +#define _STATISTICS_H + +struct counter { + struct llist_head list; + const char *name; + const char *description; + unsigned long value; +}; + +static inline void counter_inc(struct counter *ctr) +{ + ctr->value++; +} + +static inline unsigned long counter_get(struct counter *ctr) +{ + return ctr->value; +} + +static inline void counter_reset(struct counter *ctr) +{ + ctr->value = 0; +} + +struct counter *counter_alloc(const char *name); +void counter_free(struct counter *ctr); +int counters_store_db(void); + +#endif /* _STATISTICS_H */ diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 7abec6953..de413d5ed 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,7 +12,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - rtp_proxy.c + rtp_proxy.c statistics.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index ae1d6af5d..787a8038b 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1261,14 +1261,14 @@ static int rsl_rx_chan_rqd(struct msgb *msg) lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci); chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci); - bts->network->stats.chreq.total++; + counter_inc(bts->network->stats.chreq.total); /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", gsm_lchan_name(lctype), rqd_ref->ra); - bts->network->stats.chreq.no_channel++; + counter_inc(bts->network->stats.chreq.no_channel); /* FIXME: send some kind of reject ?!? */ return -ENOMEM; } diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index 3e8bf88a3..2a80a49ad 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -71,6 +71,11 @@ static const char *trx1_password = "1111111111"; static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 }; +/* dummy function to keep gsm_data.c happy */ +struct counter *counter_alloc(const char *name) +{ + return NULL; +} int handle_serial_msg(struct msgb *rx_msg); diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 707d877bb..916527de6 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -117,6 +118,12 @@ static char *create_stmts[] = { "subscriber_id INTEGER NOT NULL, " "apdu BLOB " ")", + "CREATE TABLE IF NOT EXISTS Counters (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "timestamp TIMESTAMP NOT NULL, " + "value INTEGER NOT NULL " + "name TEXT NOT NULL, " + ")", }; void db_error_func(dbi_conn conn, void* data) { @@ -902,3 +909,24 @@ int db_apdu_blob_store(struct gsm_subscriber *subscr, dbi_result_free(result); return 0; } + +int db_store_counter(struct counter *ctr) +{ + dbi_result result; + char *q_name; + + dbi_conn_quote_string_copy(conn, ctr->name, &q_name); + + result = dbi_conn_queryf(conn, + "INSERT INTO Counters " + "(timestamp,name,value) VALUES " + "(datetime('now'),%s,%lu)", q_name, ctr->value); + + free(q_name); + + if (!result) + return -EIO; + + dbi_result_free(result); + return 0; +} diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f89d8c5a2..2b22122fb 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -831,7 +831,7 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr); - bts->network->stats.loc_upd_resp.reject++; + counter_inc(bts->network->stats.loc_upd_resp.reject); return gsm48_sendmsg(msg, NULL); } @@ -860,7 +860,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - bts->network->stats.loc_upd_resp.accept++; + counter_inc(bts->network->stats.loc_upd_resp.accept); return gsm48_sendmsg(msg, NULL); } @@ -982,13 +982,13 @@ static int mm_rx_loc_upd_req(struct msgb *msg) switch (lu->type) { case GSM48_LUPD_NORMAL: - bts->network->stats.loc_upd_type.normal++; + counter_inc(bts->network->stats.loc_upd_type.normal); break; case GSM48_LUPD_IMSI_ATT: - bts->network->stats.loc_upd_type.attach++; + counter_inc(bts->network->stats.loc_upd_type.attach); break; case GSM48_LUPD_PERIODIC: - bts->network->stats.loc_upd_type.periodic++; + counter_inc(bts->network->stats.loc_upd_type.periodic); break; } @@ -1318,7 +1318,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ", mi_type, mi_string); - bts->network->stats.loc_upd_type.detach++; + counter_inc(bts->network->stats.loc_upd_type.detach); switch (mi_type) { case GSM_MI_TYPE_TMSI: diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index a5f64f170..d5b011609 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -517,7 +517,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - bts->network->stats.sms.submitted++; + counter_inc(bts->network->stats.sms.submitted); gsms = sms_alloc(); if (!gsms) @@ -607,7 +607,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr); if (!gsms->receiver) { rc = 1; /* cause 1: unknown subscriber */ - bts->network->stats.sms.no_receiver++; + counter_inc(bts->network->stats.sms.no_receiver); goto out; } @@ -761,6 +761,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) { + struct gsm_network *net = trans->lchan->ts->trx->bts->network; struct gsm_sms *sms = trans->sms.sms; u_int8_t cause_len = rph->data[0]; u_int8_t cause = rph->data[1]; @@ -794,9 +795,9 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, * to store this in our database and wati for a SMMA message */ /* FIXME */ dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr); - trans->lchan->ts->trx->bts->network->stats.sms.rp_err_mem++; + counter_inc(net->stats.sms.rp_err_mem); } else - trans->lchan->ts->trx->bts->network->stats.sms.rp_err_other++; + counter_inc(net->stats.sms.rp_err_other); sms_free(sms); trans->sms.sms = NULL; @@ -1073,7 +1074,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) DEBUGP(DSMS, "TX: SMS DELIVER\n"); - lchan->ts->trx->bts->network->stats.sms.delivered++; + counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered); return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref); /* FIXME: enter 'wait for RP-ACK' state, start TR1N */ diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index d6ebd9224..e2f56d539 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -28,6 +28,7 @@ #include #include #include +#include void *tall_bsc_ctx; @@ -226,6 +227,32 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->bts_list); + net->stats.chreq.total = counter_alloc("net.chreq.total"); + net->stats.chreq.no_channel = counter_alloc("net.chreq.no_channel"); + net->stats.handover.attempted = counter_alloc("net.handover.attempted"); + net->stats.handover.no_channel = counter_alloc("net.handover.no_channel"); + net->stats.handover.timeout = counter_alloc("net.handover.timeout"); + net->stats.handover.completed = counter_alloc("net.handover.completed"); + net->stats.handover.failed = counter_alloc("net.handover.failed"); + net->stats.loc_upd_type.attach = counter_alloc("net.loc_upd_type.attach"); + net->stats.loc_upd_type.normal = counter_alloc("net.loc_upd_type.normal"); + net->stats.loc_upd_type.periodic = counter_alloc("net.loc_upd_type.periodic"); + net->stats.loc_upd_type.detach = counter_alloc("net.imsi_detach.count"); + net->stats.loc_upd_resp.reject = counter_alloc("net.loc_upd_resp.reject"); + net->stats.loc_upd_resp.accept = counter_alloc("net.loc_upd_resp.accept"); + net->stats.paging.attempted = counter_alloc("net.paging.attempted"); + net->stats.paging.detached = counter_alloc("net.paging.detached"); + net->stats.paging.completed = counter_alloc("net.paging.completed"); + net->stats.paging.expired = counter_alloc("net.paging.expired"); + net->stats.sms.submitted = counter_alloc("net.sms.submitted"); + net->stats.sms.no_receiver = counter_alloc("net.sms.no_receiver"); + net->stats.sms.delivered = counter_alloc("net.sms.delivered"); + net->stats.sms.rp_err_mem = counter_alloc("net.sms.rp_err_mem"); + net->stats.sms.rp_err_other = counter_alloc("net.sms.rp_err_other"); + net->stats.call.dialled = counter_alloc("net.call.dialled"); + net->stats.call.alerted = counter_alloc("net.call.alerted"); + net->stats.call.connected = counter_alloc("net.call.connected"); + net->mncc_recv = mncc_recv; return net; diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 393b0f2ad..5297ab6ca 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -97,12 +97,12 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); - bts->network->stats.handover.attempted++; + counter_inc(bts->network->stats.handover.attempted); new_lchan = lchan_alloc(bts, old_lchan->type); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - bts->network->stats.handover.no_channel++; + counter_inc(bts->network->stats.handover.no_channel); return -ENOSPC; } @@ -144,9 +144,10 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) static void ho_T3103_cb(void *_ho) { struct bsc_handover *ho = _ho; + struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; DEBUGP(DHO, "HO T3103 expired\n"); - ho->new_lchan->ts->trx->bts->network->stats.handover.timeout++; + counter_inc(net->stats.handover.timeout); lchan_free(ho->new_lchan); llist_del(&ho->list); @@ -207,6 +208,7 @@ static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) /* GSM 04.08 HANDOVER COMPLETE has been received on new channel */ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) { + struct gsm_network *net = new_lchan->ts->trx->bts->network; struct bsc_handover *ho; ho = bsc_ho_by_new_lchan(new_lchan); @@ -215,7 +217,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) return -ENODEV; } - new_lchan->ts->trx->bts->network->stats.handover.completed++; + counter_inc(net->stats.handover.completed); bsc_del_timer(&ho->T3103); @@ -236,6 +238,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) /* GSM 04.08 HANDOVER FAIL has been received */ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) { + struct gsm_network *net = old_lchan->ts->trx->bts->network; struct bsc_handover *ho; ho = bsc_ho_by_old_lchan(old_lchan); @@ -244,7 +247,7 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) return -ENODEV; } - old_lchan->ts->trx->bts->network->stats.handover.failed++; + counter_inc(net->stats.handover.failed); bsc_del_timer(&ho->T3103); llist_del(&ho->list); diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 538e0a8ec..820773a9e 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -212,7 +212,7 @@ static void paging_T3113_expired(void *data) cbfn = req->cbfn; paging_remove_request(&req->bts->paging, req); - req->bts->network->stats.paging.expired++; + counter_inc(req->bts->network->stats.paging.expired); dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); if (cbfn) @@ -256,7 +256,7 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, struct gsm_bts *bts = NULL; int num_pages = 0; - network->stats.paging.attempted++; + counter_inc(network->stats.paging.attempted); /* start paging subscriber on all BTS within Location Area */ do { @@ -274,7 +274,7 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, } while (1); if (num_pages == 0) - network->stats.paging.detached++; + counter_inc(network->stats.paging.detached); return num_pages; } diff --git a/openbsc/src/statistics.c b/openbsc/src/statistics.c new file mode 100644 index 000000000..3429d6ec6 --- /dev/null +++ b/openbsc/src/statistics.c @@ -0,0 +1,85 @@ +/* utility routines for keeping some statistics */ + +/* (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 + +static LLIST_HEAD(counters); + +static struct timer_list db_sync_timer; + +#define DB_SYNC_INTERVAL 60, 0 + +struct counter *counter_alloc(const char *name) +{ + struct counter *ctr = talloc_zero(tall_bsc_ctx, struct counter); + + if (!ctr) + return NULL; + + ctr->name = name; + llist_add_tail(&ctr->list, &counters); + + return ctr; +} + +void counter_free(struct counter *ctr) +{ + llist_del(&ctr->list); + talloc_free(ctr); +} + +int counters_store_db(void) +{ + struct counter *ctr; + int rc = 0; + + llist_for_each_entry(ctr, &counters, list) { + rc = db_store_counter(ctr); + if (rc < 0) + return rc; + } + + return rc; +} + +static void db_sync_timer_cb(void *data) +{ + /* store counters to database and re-schedule */ + counters_store_db(); + bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); +} + +static __attribute__((constructor)) void on_dso_load_stat(void) +{ + db_sync_timer.cb = db_sync_timer_cb; + db_sync_timer.data = NULL; + bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); +} diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 808db3fb0..75fe54c1d 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -811,30 +811,35 @@ DEFUN(show_stats, struct gsm_network *net = gsmnet; vty_out(vty, "Channel Requests: %lu total, %lu no channel%s", - net->stats.chreq.total, net->stats.chreq.no_channel, - VTY_NEWLINE); + counter_get(net->stats.chreq.total), + counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s", - net->stats.loc_upd_type.attach, net->stats.loc_upd_type.normal, - net->stats.loc_upd_type.periodic, VTY_NEWLINE); - vty_out(vty, "IMSI Detach Indications: %lu%s\n", - net->stats.loc_upd_type.detach, VTY_NEWLINE); + counter_get(net->stats.loc_upd_type.attach), + counter_get(net->stats.loc_upd_type.normal), + counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE); + vty_out(vty, "IMSI Detach Indications: %lu%s", + counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - net->stats.loc_upd_resp.accept, - net->stats.loc_upd_resp.reject, VTY_NEWLINE); + counter_get(net->stats.loc_upd_resp.accept), + counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE); vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s", - net->stats.paging.attempted, net->stats.paging.completed, - net->stats.paging.expired, VTY_NEWLINE); + counter_get(net->stats.paging.attempted), + counter_get(net->stats.paging.completed), + counter_get(net->stats.paging.expired), VTY_NEWLINE); vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, " - "%lu completed, %lu failed%s", net->stats.handover.attempted, - net->stats.handover.no_channel, net->stats.handover.timeout, - net->stats.handover.completed, net->stats.handover.failed, - VTY_NEWLINE); + "%lu completed, %lu failed%s", + counter_get(net->stats.handover.attempted), + counter_get(net->stats.handover.no_channel), + counter_get(net->stats.handover.timeout), + counter_get(net->stats.handover.completed), + counter_get(net->stats.handover.failed), VTY_NEWLINE); vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s", - net->stats.sms.submitted, net->stats.sms.no_receiver, - VTY_NEWLINE); + counter_get(net->stats.sms.submitted), + counter_get(net->stats.sms.no_receiver), VTY_NEWLINE); vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s", - net->stats.sms.delivered, net->stats.sms.rp_err_mem, - net->stats.sms.rp_err_other, VTY_NEWLINE); + counter_get(net->stats.sms.delivered), + counter_get(net->stats.sms.rp_err_mem), + counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE); return CMD_SUCCESS; } From f9a43c45ea53d3c2a1bd156bb4ef8e5b5880db5f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 21:40:42 +0100 Subject: [PATCH 152/365] fix sql table creation for 'Counters' table --- openbsc/src/db.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 916527de6..7b864fb43 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -121,8 +121,8 @@ static char *create_stmts[] = { "CREATE TABLE IF NOT EXISTS Counters (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "timestamp TIMESTAMP NOT NULL, " - "value INTEGER NOT NULL " - "name TEXT NOT NULL, " + "value INTEGER NOT NULL, " + "name TEXT NOT NULL " ")", }; From 8387a49e394f6737644b12e53444bb0bf97b86b5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 21:43:14 +0100 Subject: [PATCH 153/365] print last measurement report during 'show lchan' --- openbsc/src/vty_interface.c | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 75fe54c1d..2d59beac8 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -526,8 +527,44 @@ void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE); } +static void meas_rep_dump_uni_vty(struct vty *vty, + struct gsm_meas_rep_unidir *mru, + const char *prefix, + const char *dir) +{ + vty_out(vty, "%s RXL-FULL-%s: %4d dBm, RXL-SUB-%s: %4d dBm ", + prefix, dir, rxlev2dbm(mru->full.rx_lev), + dir, rxlev2dbm(mru->sub.rx_lev)); + vty_out(vty, "RXQ-FULL-%s: %d, RXQ-SUB-%s: %d%s", + dir, mru->full.rx_qual, dir, mru->sub.rx_qual, + VTY_NEWLINE); +} + +static void meas_rep_dump_vty(struct vty *vty, struct gsm_meas_rep *mr, + const char *prefix) +{ + vty_out(vty, "%sMeasurement Report:%s", prefix, VTY_NEWLINE); + vty_out(vty, "%s Flags: %s%s%s%s%s", prefix, + mr->flags & MEAS_REP_F_UL_DTX ? "DTXu " : "", + mr->flags & MEAS_REP_F_DL_DTX ? "DTXd " : "", + mr->flags & MEAS_REP_F_FPC ? "FPC " : "", + mr->flags & MEAS_REP_F_DL_VALID ? " " : "DLinval ", + VTY_NEWLINE); + if (mr->flags & MEAS_REP_F_MS_TO) + vty_out(vty, "%s MS Timing Offset: %u%s", prefix, + mr->ms_timing_offset, VTY_NEWLINE); + if (mr->flags & MEAS_REP_F_MS_L1) + vty_out(vty, "%s L1 MS Power: %u dBm, Timing Advance: %u%s", + prefix, mr->ms_l1.pwr, mr->ms_l1.ta, VTY_NEWLINE); + if (mr->flags & MEAS_REP_F_DL_VALID) + meas_rep_dump_uni_vty(vty, &mr->dl, prefix, "dl"); + meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul"); +} + static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) { + int idx; + vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s", lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, lchan->ts->trx->bts->nr, gsm_lchan_name(lchan->type), @@ -551,6 +588,11 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id, VTY_NEWLINE); } + + /* we want to report the last measurement report */ + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, 1); + meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " "); } #if 0 From e2b8eceee779176320cd0dbe54a80da42380e318 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 21:47:48 +0100 Subject: [PATCH 154/365] pretty-print statistics in 'show statistics' --- openbsc/src/vty_interface.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 2d59beac8..62eee7a80 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -852,33 +852,33 @@ DEFUN(show_stats, { struct gsm_network *net = gsmnet; - vty_out(vty, "Channel Requests: %lu total, %lu no channel%s", + vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", counter_get(net->stats.chreq.total), counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); - vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s", + vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", counter_get(net->stats.loc_upd_type.attach), counter_get(net->stats.loc_upd_type.normal), counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE); - vty_out(vty, "IMSI Detach Indications: %lu%s", + vty_out(vty, "IMSI Detach Indications : %lu%s", counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE); vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", counter_get(net->stats.loc_upd_resp.accept), counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE); - vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s", + vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", counter_get(net->stats.paging.attempted), counter_get(net->stats.paging.completed), counter_get(net->stats.paging.expired), VTY_NEWLINE); - vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, " + vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", counter_get(net->stats.handover.attempted), counter_get(net->stats.handover.no_channel), counter_get(net->stats.handover.timeout), counter_get(net->stats.handover.completed), counter_get(net->stats.handover.failed), VTY_NEWLINE); - vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s", + vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", counter_get(net->stats.sms.submitted), counter_get(net->stats.sms.no_receiver), VTY_NEWLINE); - vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s", + vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", counter_get(net->stats.sms.delivered), counter_get(net->stats.sms.rp_err_mem), counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE); From 0f9141384bc338cdf8db805fbfe502aed622f816 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut <246tnt@gmail.com> Date: Tue, 22 Dec 2009 21:53:22 +0100 Subject: [PATCH 155/365] Import code to generate RRLP ephemeris data from u-blox GPS receiver taken from http://www.246tnt.com/files/rrlp-20091101.tar.bz2 --- rrlp-ephemeris/COPYING | 2 + rrlp-ephemeris/Makefile | 44 + rrlp-ephemeris/asn1/MAP-BS-Code.asn | 131 + rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn | 633 ++++ rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn | 415 +++ .../asn1/MAP-ExtensionDataTypes.asn | 74 + rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn | 657 ++++ rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn | 2780 +++++++++++++++++ rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn | 216 ++ rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn | 270 ++ rrlp-ephemeris/asn1/MAP-SS-Code.asn | 190 ++ rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn | 342 ++ rrlp-ephemeris/asn1/MAP-TS-Code.asn | 92 + rrlp-ephemeris/asn1/RRLP-Components.asn | 1488 +++++++++ rrlp-ephemeris/asn1/RRLP-Messages.asn | 38 + .../asn1/patch-rrlp-components.diff | 36 + rrlp-ephemeris/data.ubx | Bin 0 -> 2872 bytes rrlp-ephemeris/gpl-2.0.txt | 339 ++ rrlp-ephemeris/gpl-3.0.txt | 674 ++++ rrlp-ephemeris/gps.c | 126 + rrlp-ephemeris/gps.h | 171 + rrlp-ephemeris/main.c | 99 + rrlp-ephemeris/rrlp.c | 599 ++++ rrlp-ephemeris/rrlp.h | 64 + rrlp-ephemeris/ubx-parse.c | 165 + rrlp-ephemeris/ubx-parse.h | 45 + rrlp-ephemeris/ubx.c | 81 + rrlp-ephemeris/ubx.h | 232 ++ 28 files changed, 10003 insertions(+) create mode 100644 rrlp-ephemeris/COPYING create mode 100644 rrlp-ephemeris/Makefile create mode 100644 rrlp-ephemeris/asn1/MAP-BS-Code.asn create mode 100644 rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-ExtensionDataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-SS-Code.asn create mode 100644 rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn create mode 100644 rrlp-ephemeris/asn1/MAP-TS-Code.asn create mode 100644 rrlp-ephemeris/asn1/RRLP-Components.asn create mode 100644 rrlp-ephemeris/asn1/RRLP-Messages.asn create mode 100644 rrlp-ephemeris/asn1/patch-rrlp-components.diff create mode 100644 rrlp-ephemeris/data.ubx create mode 100644 rrlp-ephemeris/gpl-2.0.txt create mode 100644 rrlp-ephemeris/gpl-3.0.txt create mode 100644 rrlp-ephemeris/gps.c create mode 100644 rrlp-ephemeris/gps.h create mode 100644 rrlp-ephemeris/main.c create mode 100644 rrlp-ephemeris/rrlp.c create mode 100644 rrlp-ephemeris/rrlp.h create mode 100644 rrlp-ephemeris/ubx-parse.c create mode 100644 rrlp-ephemeris/ubx-parse.h create mode 100644 rrlp-ephemeris/ubx.c create mode 100644 rrlp-ephemeris/ubx.h diff --git a/rrlp-ephemeris/COPYING b/rrlp-ephemeris/COPYING new file mode 100644 index 000000000..8d7088e89 --- /dev/null +++ b/rrlp-ephemeris/COPYING @@ -0,0 +1,2 @@ +See the included gpl-2.0.txt or gpl-3.0.txt depending on your +preferences. diff --git a/rrlp-ephemeris/Makefile b/rrlp-ephemeris/Makefile new file mode 100644 index 000000000..a1f22650c --- /dev/null +++ b/rrlp-ephemeris/Makefile @@ -0,0 +1,44 @@ + +ASN1C=../../../tmp/rrlp/asn1c/asn1c/asn1c +ASN1_INCLUDE=/home/tnt/tmp/rrlp/asn1c/skeletons +CC=gcc +CFLAGS=-I$(ASN1_INCLUDE) -Iasn1_gen -O3 -Wall + +ASN1_FILES=$(wildcard asn1/*.asn) + + +all: rrlp-test + + +rrlp-test: libgsm-asn1.a gps.o ubx.o ubx-parse.o rrlp.o main.o + $(CC) -o $@ gps.o ubx.o ubx-parse.o rrlp.o main.o -L. -lgsm-asn1 + + +# +# ASN1 file autogeneration (need recursive makefile call) +# + +ASN1_SOURCES = $(wildcard asn1_gen/*.c) +ASN1_OBJECTS = $(ASN1_SOURCES:.c=.o) + +libgsm-asn1.a: $(ASN1_FILES) + mkdir -p asn1_gen && \ + cd asn1_gen && \ + $(ASN1C) -fskeletons-copy -fnative-types -gen-PER $(addprefix ../,$^) + @rm asn1_gen/converter-sample.c asn1_gen/Makefile.am.sample + @$(MAKE) libgsm-asn1.a.submake + +libgsm-asn1.a.submake: $(ASN1_OBJECTS) + $(AR) rcs libgsm-asn1.a $^ + +.PHONY: libgsm-asn1.a.submake + + +# +# Clean +# + +clean: + rm -Rf asn1_gen + rm -f libgsm-asn1.a *.o rrlp-test + diff --git a/rrlp-ephemeris/asn1/MAP-BS-Code.asn b/rrlp-ephemeris/asn1/MAP-BS-Code.asn new file mode 100644 index 000000000..1d2536676 --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-BS-Code.asn @@ -0,0 +1,131 @@ +-- $Id: MAP-BS-Code.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.10 Bearer Service Codes + +MAP-BS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-BS-Code (20) version11 (11)} + +DEFINITIONS + +::= + +BEGIN + +BearerServiceCode ::= OCTET STRING (SIZE (1)) + -- This type is used to represent the code identifying a single + -- bearer service, a group of bearer services, or all bearer + -- services. The services are defined in TS 3GPP TS 22.002 [3]. + -- The internal structure is defined as follows: + -- + -- plmn-specific bearer services: + -- bits 87654321: defined by the HPLMN operator + + -- rest of bearer services: + -- bit 8: 0 (unused) + -- bits 7654321: group (bits 7654), and rate, if applicable + -- (bits 321) + +Ext-BearerServiceCode ::= OCTET STRING (SIZE (1..5)) + -- This type is used to represent the code identifying a single + -- bearer service, a group of bearer services, or all bearer + -- services. The services are defined in TS 3GPP TS 22.002 [3]. + -- The internal structure is defined as follows: + -- + -- OCTET 1: + -- plmn-specific bearer services: + -- bits 87654321: defined by the HPLMN operator + -- + -- rest of bearer services: + -- bit 8: 0 (unused) + -- bits 7654321: group (bits 7654), and rate, if applicable + -- (bits 321) + + -- OCTETS 2-5: reserved for future use. If received the + -- Ext-TeleserviceCode shall be + -- treated according to the exception handling defined for the + -- operation that uses this type. + + + -- Ext-BearerServiceCode includes all values defined for BearerServiceCode. + +allBearerServices BearerServiceCode ::= '00000000'B + +allDataCDA-Services BearerServiceCode ::= '00010000'B +dataCDA-300bps BearerServiceCode ::= '00010001'B +dataCDA-1200bps BearerServiceCode ::= '00010010'B +dataCDA-1200-75bps BearerServiceCode ::= '00010011'B +dataCDA-2400bps BearerServiceCode ::= '00010100'B +dataCDA-4800bps BearerServiceCode ::= '00010101'B +dataCDA-9600bps BearerServiceCode ::= '00010110'B +general-dataCDA BearerServiceCode ::= '00010111'B + +allDataCDS-Services BearerServiceCode ::= '00011000'B +dataCDS-1200bps BearerServiceCode ::= '00011010'B +dataCDS-2400bps BearerServiceCode ::= '00011100'B +dataCDS-4800bps BearerServiceCode ::= '00011101'B +dataCDS-9600bps BearerServiceCode ::= '00011110'B +general-dataCDS BearerServiceCode ::= '00011111'B + +allPadAccessCA-Services BearerServiceCode ::= '00100000'B +padAccessCA-300bps BearerServiceCode ::= '00100001'B +padAccessCA-1200bps BearerServiceCode ::= '00100010'B +padAccessCA-1200-75bps BearerServiceCode ::= '00100011'B +padAccessCA-2400bps BearerServiceCode ::= '00100100'B +padAccessCA-4800bps BearerServiceCode ::= '00100101'B +padAccessCA-9600bps BearerServiceCode ::= '00100110'B +general-padAccessCA BearerServiceCode ::= '00100111'B + +allDataPDS-Services BearerServiceCode ::= '00101000'B +dataPDS-2400bps BearerServiceCode ::= '00101100'B +dataPDS-4800bps BearerServiceCode ::= '00101101'B +dataPDS-9600bps BearerServiceCode ::= '00101110'B +general-dataPDS BearerServiceCode ::= '00101111'B + +allAlternateSpeech-DataCDA BearerServiceCode ::= '00110000'B + +allAlternateSpeech-DataCDS BearerServiceCode ::= '00111000'B + +allSpeechFollowedByDataCDA BearerServiceCode ::= '01000000'B + +allSpeechFollowedByDataCDS BearerServiceCode ::= '01001000'B + +-- The following non-hierarchical Compound Bearer Service +-- Groups are defined in TS 3GPP TS 22.030: +allDataCircuitAsynchronous BearerServiceCode ::= '01010000'B + -- covers "allDataCDA-Services", "allAlternateSpeech-DataCDA" and + -- "allSpeechFollowedByDataCDA" +allAsynchronousServices BearerServiceCode ::= '01100000'B + -- covers "allDataCDA-Services", "allAlternateSpeech-DataCDA", + -- "allSpeechFollowedByDataCDA" and "allPadAccessCDA-Services" +allDataCircuitSynchronous BearerServiceCode ::= '01011000'B + -- covers "allDataCDS-Services", "allAlternateSpeech-DataCDS" and + -- "allSpeechFollowedByDataCDS" +allSynchronousServices BearerServiceCode ::= '01101000'B + -- covers "allDataCDS-Services", "allAlternateSpeech-DataCDS", + -- "allSpeechFollowedByDataCDS" and "allDataPDS-Services" +-- +-- Compound Bearer Service Group Codes are only used in call +-- independent supplementary service operations, i.e. they +-- are not used in InsertSubscriberData or in +-- DeleteSubscriberData messages. + +allPLMN-specificBS BearerServiceCode ::= '11010000'B +plmn-specificBS-1 BearerServiceCode ::= '11010001'B +plmn-specificBS-2 BearerServiceCode ::= '11010010'B +plmn-specificBS-3 BearerServiceCode ::= '11010011'B +plmn-specificBS-4 BearerServiceCode ::= '11010100'B +plmn-specificBS-5 BearerServiceCode ::= '11010101'B +plmn-specificBS-6 BearerServiceCode ::= '11010110'B +plmn-specificBS-7 BearerServiceCode ::= '11010111'B +plmn-specificBS-8 BearerServiceCode ::= '11011000'B +plmn-specificBS-9 BearerServiceCode ::= '11011001'B +plmn-specificBS-A BearerServiceCode ::= '11011010'B +plmn-specificBS-B BearerServiceCode ::= '11011011'B +plmn-specificBS-C BearerServiceCode ::= '11011100'B +plmn-specificBS-D BearerServiceCode ::= '11011101'B +plmn-specificBS-E BearerServiceCode ::= '11011110'B +plmn-specificBS-F BearerServiceCode ::= '11011111'B + +END + diff --git a/rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn b/rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn new file mode 100644 index 000000000..f3d202e35 --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn @@ -0,0 +1,633 @@ +-- $Id: MAP-CommonDataTypes.asn 30470 2009-10-10 12:37:56Z krj $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.8 Common data types + +MAP-CommonDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)} + +DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + + -- general data types and values + AddressString, + ISDN-AddressString, + maxISDN-AddressLength, + FTN-AddressString, + ISDN-SubaddressString, + ExternalSignalInfo, + Ext-ExternalSignalInfo, +AccessNetworkSignalInfo, + SignalInfo, + maxSignalInfoLength, + AlertingPattern, + TBCD-STRING, + + -- data types for numbering and identification + IMSI, + TMSI, + Identity, + SubscriberId, + IMEI, + HLR-List, + LMSI, + GlobalCellId, + NetworkResource, + AdditionalNetworkResource, + NAEA-PreferredCI, + NAEA-CIC, + ASCI-CallReference, + SubscriberIdentity, + PLMN-Id, + + -- data types for CAMEL + CellGlobalIdOrServiceAreaIdOrLAI, + CellGlobalIdOrServiceAreaIdFixedLength, + LAIFixedLength, + + -- data types for subscriber management + BasicServiceCode, + Ext-BasicServiceCode, + EMLPP-Info, + EMLPP-Priority, + MC-SS-Info, + MaxMC-Bearers, + MC-Bearers, + Ext-SS-Status, + + -- data types for geographic location + AgeOfLocationInformation, + LCSClientExternalID, + LCSClientInternalID, + LCSServiceTypeID, +--- WS added exports needed by gsm_map.asn (extra asn1 file to handle older prot. ver.) + ProtocolId, + LCSServiceTypeID +; + +IMPORTS + TeleserviceCode, + Ext-TeleserviceCode +FROM MAP-TS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-TS-Code (19) version11 (11)} + + BearerServiceCode, + Ext-BearerServiceCode +FROM MAP-BS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-BS-Code (20) version11 (11)} + + SS-Code +FROM MAP-SS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)} + + ExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} +; + + +-- general data types + +TBCD-STRING ::= OCTET STRING + -- This type (Telephony Binary Coded Decimal String) is used to + -- represent several digits from 0 through 9, *, #, a, b, c, two + -- digits per octet, each digit encoded 0000 to 1001 (0 to 9), + -- 1010 (*), 1011 (#), 1100 (a), 1101 (b) or 1110 (c); 1111 used + -- as filler when there is an odd number of digits. + + -- bits 8765 of octet n encoding digit 2n + -- bits 4321 of octet n encoding digit 2(n-1) +1 + +AddressString ::= OCTET STRING (SIZE (1..maxAddressLength)) + -- This type is used to represent a number for addressing + -- purposes. It is composed of + -- a) one octet for nature of address, and numbering plan + -- indicator. + -- b) digits of an address encoded as TBCD-String. + + -- a) The first octet includes a one bit extension indicator, a + -- 3 bits nature of address indicator and a 4 bits numbering + -- plan indicator, encoded as follows: + + -- bit 8: 1 (no extension) + + -- bits 765: nature of address indicator + -- 000 unknown + -- 001 international number + -- 010 national significant number + -- 011 network specific number + -- 100 subscriber number + -- 101 reserved + -- 110 abbreviated number + -- 111 reserved for extension + + -- bits 4321: numbering plan indicator + -- 0000 unknown + -- 0001 ISDN/Telephony Numbering Plan (Rec ITU-T E.164) + -- 0010 spare + -- 0011 data numbering plan (ITU-T Rec X.121) + -- 0100 telex numbering plan (ITU-T Rec F.69) + -- 0101 spare + -- 0110 land mobile numbering plan (ITU-T Rec E.212) + -- 0111 spare + -- 1000 national numbering plan + -- 1001 private numbering plan + -- 1111 reserved for extension + + -- all other values are reserved. + + -- b) The following octets representing digits of an address + -- encoded as a TBCD-STRING. + +maxAddressLength INTEGER ::= 20 + +ISDN-AddressString ::= + AddressString (SIZE (1..maxISDN-AddressLength)) + -- This type is used to represent ISDN numbers. + +maxISDN-AddressLength INTEGER ::= 9 + +FTN-AddressString ::= + AddressString (SIZE (1..maxFTN-AddressLength)) + -- This type is used to represent forwarded-to numbers. + -- If NAI = international the first digits represent the country code (CC) + -- and the network destination code (NDC) as for E.164. + +maxFTN-AddressLength INTEGER ::= 15 + +ISDN-SubaddressString ::= + OCTET STRING (SIZE (1..maxISDN-SubaddressLength)) + -- This type is used to represent ISDN subaddresses. + -- It is composed of + -- a) one octet for type of subaddress and odd/even indicator. + -- b) 20 octets for subaddress information. + + -- a) The first octet includes a one bit extension indicator, a + -- 3 bits type of subaddress and a one bit odd/even indicator, + -- encoded as follows: + + -- bit 8: 1 (no extension) + + -- bits 765: type of subaddress + -- 000 NSAP (X.213/ISO 8348 AD2) + -- 010 User Specified + -- All other values are reserved + + -- bit 4: odd/even indicator + -- 0 even number of address signals + -- 1 odd number of address signals + -- The odd/even indicator is used when the type of subaddress + -- is "user specified" and the coding is BCD. + + -- bits 321: 000 (unused) + + -- b) Subaddress information. + -- The NSAP X.213/ISO8348AD2 address shall be formatted as specified + -- by octet 4 which contains the Authority and Format Identifier + -- (AFI). The encoding is made according to the "preferred binary + -- encoding" as defined in X.213/ISO834AD2. For the definition + -- of this type of subaddress, see ITU-T Rec I.334. + + -- For User-specific subaddress, this field is encoded according + -- to the user specification, subject to a maximum length of 20 + -- octets. When interworking with X.25 networks BCD coding should + -- be applied. + +maxISDN-SubaddressLength INTEGER ::= 21 + +ExternalSignalInfo ::= SEQUENCE { + protocolId ProtocolId, + signalInfo SignalInfo, + -- Information about the internal structure is given in + -- clause 7.6.9. + extensionContainer ExtensionContainer OPTIONAL, + -- extensionContainer must not be used in version 2 + ...} + +SignalInfo ::= OCTET STRING (SIZE (1..maxSignalInfoLength)) + +maxSignalInfoLength INTEGER ::= 200 + -- This NamedValue represents the theoretical maximum number of octets which is + -- available to carry a single instance of the SignalInfo data type, + -- without requiring segmentation to cope with the network layer service. + -- However, the actual maximum size available for an instance of the data + -- type may be lower, especially when other information elements + -- have to be included in the same component. + +ProtocolId ::= ENUMERATED { + gsm-0408 (1), + gsm-0806 (2), + gsm-BSSMAP (3), + -- Value 3 is reserved and must not be used + ets-300102-1 (4)} + +Ext-ExternalSignalInfo ::= SEQUENCE { + ext-ProtocolId Ext-ProtocolId, + signalInfo SignalInfo, + -- Information about the internal structure is given in + -- clause 7.6.9.10 + extensionContainer ExtensionContainer OPTIONAL, + ...} + +Ext-ProtocolId ::= ENUMERATED { + ets-300356 (1), + ... + } +-- exception handling: +-- For Ext-ExternalSignalInfo sequences containing this parameter with any +-- other value than the ones listed the receiver shall ignore the whole +-- Ext-ExternalSignalInfo sequence. + +AccessNetworkSignalInfo ::= SEQUENCE { + accessNetworkProtocolId AccessNetworkProtocolId, + signalInfo LongSignalInfo, + -- Information about the internal structure is given in clause 7.6.9.1 + + extensionContainer ExtensionContainer OPTIONAL, + ...} + +LongSignalInfo ::= OCTET STRING (SIZE (1..maxLongSignalInfoLength)) + +maxLongSignalInfoLength INTEGER ::= 2560 + -- This Named Value represents the maximum number of octets which is available + -- to carry a single instance of the LongSignalInfo data type using + -- White Book SCCP with the maximum number of segments. + -- It takes account of the octets used by the lower layers of the protocol, and + -- other information elements which may be included in the same component. + +AccessNetworkProtocolId ::= ENUMERATED { + ts3G-48006 (1), + ts3G-25413 (2), + ...} + -- exception handling: + -- For AccessNetworkSignalInfo sequences containing this parameter with any + -- other value than the ones listed the receiver shall ignore the whole + -- AccessNetworkSignalInfo sequence. + +AlertingPattern ::= OCTET STRING (SIZE (1) ) + -- This type is used to represent Alerting Pattern + + -- bits 8765 : 0000 (unused) + + -- bits 43 : type of Pattern + -- 00 level + -- 01 category + -- 10 category + -- all other values are reserved. + + -- bits 21 : type of alerting + +alertingLevel-0 AlertingPattern ::= '00000000'B +alertingLevel-1 AlertingPattern ::= '00000001'B +alertingLevel-2 AlertingPattern ::= '00000010'B + -- all other values of Alerting level are reserved + -- Alerting Levels are defined in GSM 02.07 + +alertingCategory-1 AlertingPattern ::= '00000100'B +alertingCategory-2 AlertingPattern ::= '00000101'B +alertingCategory-3 AlertingPattern ::= '00000110'B +alertingCategory-4 AlertingPattern ::= '00000111'B +alertingCategory-5 AlertingPattern ::= '00001000'B + -- all other values of Alerting Category are reserved + -- Alerting categories are defined in GSM 02.07 + +-- data types for numbering and identification + +IMSI ::= TBCD-STRING (SIZE (3..8)) + -- digits of MCC, MNC, MSIN are concatenated in this order. + +Identity ::= CHOICE { + imsi IMSI, + imsi-WithLMSI IMSI-WithLMSI} + +IMSI-WithLMSI ::= SEQUENCE { + imsi IMSI, + lmsi LMSI, + -- a special value 00000000 indicates that the LMSI is not in use + ...} + +ASCI-CallReference ::= TBCD-STRING (SIZE (1..8)) + -- digits of VGCS/VBS-area,Group-ID are concatenated in this order if there is a + -- VGCS/VBS-area. + +TMSI ::= OCTET STRING (SIZE (1..4)) + +SubscriberId ::= CHOICE { + imsi [0] IMSI, + tmsi [1] TMSI} + +IMEI ::= TBCD-STRING (SIZE (8)) + -- Refers to International Mobile Station Equipment Identity + -- and Software Version Number (SVN) defined in TS 3GPP TS 23.003 [17]. + -- If the SVN is not present the last octet shall contain the + -- digit 0 and a filler. + -- If present the SVN shall be included in the last octet. + +HLR-Id ::= IMSI + -- leading digits of IMSI, i.e. (MCC, MNC, leading digits of + -- MSIN) forming HLR Id defined in TS 3GPP TS 23.003 [17]. + +HLR-List ::= SEQUENCE SIZE (1..maxNumOfHLR-Id) OF + HLR-Id + +maxNumOfHLR-Id INTEGER ::= 50 + +LMSI ::= OCTET STRING (SIZE (4)) + +GlobalCellId ::= OCTET STRING (SIZE (5..7)) + -- Refers to Cell Global Identification defined in TS 3GPP TS 23.003 [17]. + -- The internal structure is defined as follows: + -- octet 1 bits 4321 Mobile Country Code 1st digit + -- bits 8765 Mobile Country Code 2nd digit + -- octet 2 bits 4321 Mobile Country Code 3rd digit + -- bits 8765 Mobile Network Code 3rd digit + -- or filler (1111) for 2 digit MNCs + -- octet 3 bits 4321 Mobile Network Code 1st digit + -- bits 8765 Mobile Network Code 2nd digit + -- octets 4 and 5 Location Area Code according to TS 3GPP TS 24.008 [35] + -- octets 6 and 7 Cell Identity (CI) according to TS 3GPP TS 24.008 [35] + +NetworkResource ::= ENUMERATED { + plmn (0), + hlr (1), + vlr (2), + pvlr (3), + controllingMSC (4), + vmsc (5), + eir (6), + rss (7)} + +AdditionalNetworkResource ::= ENUMERATED { + sgsn (0), + ggsn (1), + gmlc (2), + gsmSCF (3), + nplr (4), + auc (5), + ... , + ue (6), + mme (7)} + -- if unknown value is received in AdditionalNetworkResource + -- it shall be ignored. + + +NAEA-PreferredCI ::= SEQUENCE { + naea-PreferredCIC [0] NAEA-CIC, + extensionContainer [1] ExtensionContainer OPTIONAL, + ...} + +NAEA-CIC ::= OCTET STRING (SIZE (3)) + -- The internal structure is defined by the Carrier Identification + -- parameter in ANSI T1.113.3. Carrier codes between "000" and "999" may + -- be encoded as 3 digits using "000" to "999" or as 4 digits using + -- "0000" to "0999". Carrier codes between "1000" and "9999" are encoded + -- using 4 digits. + +SubscriberIdentity ::= CHOICE { + imsi [0] IMSI, + msisdn [1] ISDN-AddressString + } + +LCSClientExternalID ::= SEQUENCE { + externalAddress [0] ISDN-AddressString OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ... } + +LCSClientInternalID ::= ENUMERATED { + broadcastService (0), + o-andM-HPLMN (1), + o-andM-VPLMN (2), + anonymousLocation (3), + targetMSsubscribedService (4), + ... } +-- for a CAMEL phase 3 PLMN operator client, the value targetMSsubscribedService shall be used + +LCSServiceTypeID ::= INTEGER (0..127) + -- the integer values 0-63 are reserved for Standard LCS service types + -- the integer values 64-127 are reserved for Non Standard LCS service types + +-- Standard LCS Service Types +emergencyServices LCSServiceTypeID ::= 0 +emergencyAlertServices LCSServiceTypeID ::= 1 +personTracking LCSServiceTypeID ::= 2 +fleetManagement LCSServiceTypeID ::= 3 +assetManagement LCSServiceTypeID ::= 4 +trafficCongestionReporting LCSServiceTypeID ::= 5 +roadsideAssistance LCSServiceTypeID ::= 6 +routingToNearestCommercialEnterprise LCSServiceTypeID ::= 7 +navigation LCSServiceTypeID ::= 8 + --this service type is reserved for use in previous releases +citySightseeing LCSServiceTypeID ::= 9 +localizedAdvertising LCSServiceTypeID ::= 10 +mobileYellowPages LCSServiceTypeID ::= 11 +trafficAndPublicTransportationInfo LCSServiceTypeID ::= 12 +weather LCSServiceTypeID ::= 13 +assetAndServiceFinding LCSServiceTypeID ::= 14 +gaming LCSServiceTypeID ::= 15 +findYourFriend LCSServiceTypeID ::= 16 +dating LCSServiceTypeID ::= 17 +chatting LCSServiceTypeID ::= 18 +routeFinding LCSServiceTypeID ::= 19 +whereAmI LCSServiceTypeID ::= 20 + +-- The values of LCSServiceTypeID are defined according to 3GPP TS 22.071. + +-- Non Standard LCS Service Types +serv64 LCSServiceTypeID ::= 64 +serv65 LCSServiceTypeID ::= 65 +serv66 LCSServiceTypeID ::= 66 +serv67 LCSServiceTypeID ::= 67 +serv68 LCSServiceTypeID ::= 68 +serv69 LCSServiceTypeID ::= 69 +serv70 LCSServiceTypeID ::= 70 +serv71 LCSServiceTypeID ::= 71 +serv72 LCSServiceTypeID ::= 72 +serv73 LCSServiceTypeID ::= 73 +serv74 LCSServiceTypeID ::= 74 +serv75 LCSServiceTypeID ::= 75 +serv76 LCSServiceTypeID ::= 76 +serv77 LCSServiceTypeID ::= 77 +serv78 LCSServiceTypeID ::= 78 +serv79 LCSServiceTypeID ::= 79 +serv80 LCSServiceTypeID ::= 80 +serv81 LCSServiceTypeID ::= 81 +serv82 LCSServiceTypeID ::= 82 +serv83 LCSServiceTypeID ::= 83 +serv84 LCSServiceTypeID ::= 84 +serv85 LCSServiceTypeID ::= 85 +serv86 LCSServiceTypeID ::= 86 +serv87 LCSServiceTypeID ::= 87 +serv88 LCSServiceTypeID ::= 88 +serv89 LCSServiceTypeID ::= 89 +serv90 LCSServiceTypeID ::= 90 +serv91 LCSServiceTypeID ::= 91 +serv92 LCSServiceTypeID ::= 92 +serv93 LCSServiceTypeID ::= 93 +serv94 LCSServiceTypeID ::= 94 +serv95 LCSServiceTypeID ::= 95 +serv96 LCSServiceTypeID ::= 96 +serv97 LCSServiceTypeID ::= 97 +serv98 LCSServiceTypeID ::= 98 +serv99 LCSServiceTypeID ::= 99 +serv100 LCSServiceTypeID ::= 100 +serv101 LCSServiceTypeID ::= 101 +serv102 LCSServiceTypeID ::= 102 +serv103 LCSServiceTypeID ::= 103 +serv104 LCSServiceTypeID ::= 104 +serv105 LCSServiceTypeID ::= 105 +serv106 LCSServiceTypeID ::= 106 +serv107 LCSServiceTypeID ::= 107 +serv108 LCSServiceTypeID ::= 108 +serv109 LCSServiceTypeID ::= 109 +serv110 LCSServiceTypeID ::= 110 +serv111 LCSServiceTypeID ::= 111 +serv112 LCSServiceTypeID ::= 112 +serv113 LCSServiceTypeID ::= 113 +serv114 LCSServiceTypeID ::= 114 +serv115 LCSServiceTypeID ::= 115 +serv116 LCSServiceTypeID ::= 116 +serv117 LCSServiceTypeID ::= 117 +serv118 LCSServiceTypeID ::= 118 +serv119 LCSServiceTypeID ::= 119 +serv120 LCSServiceTypeID ::= 120 +serv121 LCSServiceTypeID ::= 121 +serv122 LCSServiceTypeID ::= 122 +serv123 LCSServiceTypeID ::= 123 +serv124 LCSServiceTypeID ::= 124 +serv125 LCSServiceTypeID ::= 125 +serv126 LCSServiceTypeID ::= 126 +serv127 LCSServiceTypeID ::= 127 + +PLMN-Id ::= OCTET STRING (SIZE (3)) + -- The internal structure is defined as follows: + -- octet 1 bits 4321 Mobile Country Code 1st digit + -- bits 8765 Mobile Country Code 2nd digit + -- octet 2 bits 4321 Mobile Country Code 3rd digit + -- bits 8765 Mobile Network Code 3rd digit + -- or filler (1111) for 2 digit MNCs + -- octet 3 bits 4321 Mobile Network Code 1st digit + -- bits 8765 Mobile Network Code 2nd digit + +-- data types for CAMEL + +CellGlobalIdOrServiceAreaIdOrLAI ::= CHOICE { + cellGlobalIdOrServiceAreaIdFixedLength [0] CellGlobalIdOrServiceAreaIdFixedLength, + laiFixedLength [1] LAIFixedLength} + +CellGlobalIdOrServiceAreaIdFixedLength ::= OCTET STRING (SIZE (7)) + -- Refers to Cell Global Identification or Service Are Identification + -- defined in 3GPP TS 23.003. + -- The internal structure is defined as follows: + -- octet 1 bits 4321 Mobile Country Code 1st digit + -- bits 8765 Mobile Country Code 2nd digit + -- octet 2 bits 4321 Mobile Country Code 3rd digit + -- bits 8765 Mobile Network Code 3rd digit + -- or filler (1111) for 2 digit MNCs + -- octet 3 bits 4321 Mobile Network Code 1st digit + -- bits 8765 Mobile Network Code 2nd digit + -- octets 4 and 5 Location Area Code according to 3GPP TS 24.008 + -- octets 6 and 7 Cell Identity (CI) value or + -- Service Area Code (SAC) value + -- according to 3GPP TS 23.003 + +LAIFixedLength ::= OCTET STRING (SIZE (5)) + -- Refers to Location Area Identification defined in 3GPP TS 23.003 [17]. + -- The internal structure is defined as follows: + -- octet 1 bits 4321 Mobile Country Code 1st digit + -- bits 8765 Mobile Country Code 2nd digit + -- octet 2 bits 4321 Mobile Country Code 3rd digit + -- bits 8765 Mobile Network Code 3rd digit + -- or filler (1111) for 2 digit MNCs + -- octet 3 bits 4321 Mobile Network Code 1st digit + -- bits 8765 Mobile Network Code 2nd digit + -- octets 4 and 5 Location Area Code according to 3GPP TS 24.008 [35] + +-- data types for subscriber management + +BasicServiceCode ::= CHOICE { + bearerService [2] BearerServiceCode, + teleservice [3] TeleserviceCode} + +Ext-BasicServiceCode ::= CHOICE { + ext-BearerService [2] Ext-BearerServiceCode, + ext-Teleservice [3] Ext-TeleserviceCode} + +EMLPP-Info ::= SEQUENCE { + maximumentitledPriority EMLPP-Priority, + defaultPriority EMLPP-Priority, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +EMLPP-Priority ::= INTEGER (0..15) + -- The mapping from the values A,B,0,1,2,3,4 to the integer-value is + -- specified as follows where A is the highest and 4 is the lowest + -- priority level + -- the integer values 7-15 are spare and shall be mapped to value 4 + +priorityLevelA EMLPP-Priority ::= 6 +priorityLevelB EMLPP-Priority ::= 5 +priorityLevel0 EMLPP-Priority ::= 0 +priorityLevel1 EMLPP-Priority ::= 1 +priorityLevel2 EMLPP-Priority ::= 2 +priorityLevel3 EMLPP-Priority ::= 3 +priorityLevel4 EMLPP-Priority ::= 4 + +MC-SS-Info ::= SEQUENCE { + ss-Code [0] SS-Code, + ss-Status [1] Ext-SS-Status, + nbrSB [2] MaxMC-Bearers, + nbrUser [3] MC-Bearers, + extensionContainer [4] ExtensionContainer OPTIONAL, + ...} + +MaxMC-Bearers ::= INTEGER (2..maxNumOfMC-Bearers) + +MC-Bearers ::= INTEGER (1..maxNumOfMC-Bearers) + +maxNumOfMC-Bearers INTEGER ::= 7 + +Ext-SS-Status ::= OCTET STRING (SIZE (1..5)) + + -- OCTET 1: + -- + -- bits 8765: 0000 (unused) + -- bits 4321: Used to convey the "P bit","R bit","A bit" and "Q bit", + -- representing supplementary service state information + -- as defined in TS 3GPP TS 23.011 [22] + + -- bit 4: "Q bit" + + -- bit 3: "P bit" + + -- bit 2: "R bit" + + -- bit 1: "A bit" + + -- OCTETS 2-5: reserved for future use. They shall be discarded if + -- received and not understood. + + + -- data types for geographic location + +AgeOfLocationInformation ::= INTEGER (0..32767) +-- the value represents the elapsed time in minutes since the last +-- network contact of the mobile station (i.e. the actuality of the +-- location information). +-- value "0" indicates that the MS is currently in contact with the +-- network +-- value "32767" indicates that the location information is at least +-- 32767 minutes old + +END + diff --git a/rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn new file mode 100644 index 000000000..d0b90fc78 --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn @@ -0,0 +1,415 @@ +-- $Id: MAP-ER-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.7 Error data types + +MAP-ER-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ER-DataTypes (17) version11 (11)} + +DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + RoamingNotAllowedParam, + CallBarredParam, + CUG-RejectParam, + SS-IncompatibilityCause, + PW-RegistrationFailureCause, + SM-DeliveryFailureCause, + SystemFailureParam, + DataMissingParam, + UnexpectedDataParam, + FacilityNotSupParam, + OR-NotAllowedParam, + UnknownSubscriberParam, + NumberChangedParam, + UnidentifiedSubParam, + IllegalSubscriberParam, + IllegalEquipmentParam, + BearerServNotProvParam, + TeleservNotProvParam, + TracingBufferFullParam, + NoRoamingNbParam, + AbsentSubscriberParam, + BusySubscriberParam, + NoSubscriberReplyParam, + ForwardingViolationParam, + ForwardingFailedParam, + ATI-NotAllowedParam, + SubBusyForMT-SMS-Param, + MessageWaitListFullParam, + AbsentSubscriberSM-Param, + AbsentSubscriberDiagnosticSM, + ResourceLimitationParam, + NoGroupCallNbParam, + IncompatibleTerminalParam, + ShortTermDenialParam, + LongTermDenialParam, + UnauthorizedRequestingNetwork-Param, + UnauthorizedLCSClient-Param, + PositionMethodFailure-Param, +UnknownOrUnreachableLCSClient-Param, + MM-EventNotSupported-Param, +ATSI-NotAllowedParam, +ATM-NotAllowedParam, +IllegalSS-OperationParam, +SS-NotAvailableParam, +SS-SubscriptionViolationParam, +InformationNotAvailableParam, +TargetCellOutsideGCA-Param, +OngoingGroupCallParam + +; + +IMPORTS + SS-Status +FROM MAP-SS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-DataTypes (14) version11 (11)} + + SignalInfo, + BasicServiceCode, + NetworkResource, + AdditionalNetworkResource +FROM MAP-CommonDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)} + + + SS-Code +FROM MAP-SS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)} + + ExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} +; + +RoamingNotAllowedParam ::= SEQUENCE { + roamingNotAllowedCause RoamingNotAllowedCause, + extensionContainer ExtensionContainer OPTIONAL, + ..., + additionalRoamingNotAllowedCause [0] AdditionalRoamingNotAllowedCause OPTIONAL } + +-- if the additionalRoamingNotallowedCause is received by the MSC/VLR or SGSN then the +-- roamingNotAllowedCause shall be discarded. + +AdditionalRoamingNotAllowedCause ::= ENUMERATED { + supportedRAT-TypesNotAllowed (0), + ...} + +RoamingNotAllowedCause ::= ENUMERATED { + plmnRoamingNotAllowed (0), + operatorDeterminedBarring (3)} + +CallBarredParam ::= CHOICE { + callBarringCause CallBarringCause, + -- call BarringCause must not be used in version 3 and higher + extensibleCallBarredParam ExtensibleCallBarredParam + -- extensibleCallBarredParam must not be used in version <3 + } + +CallBarringCause ::= ENUMERATED { + barringServiceActive (0), + operatorBarring (1)} + +ExtensibleCallBarredParam ::= SEQUENCE { + callBarringCause CallBarringCause OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ... , + unauthorisedMessageOriginator [1] NULL OPTIONAL } + +CUG-RejectParam ::= SEQUENCE { + cug-RejectCause CUG-RejectCause OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +CUG-RejectCause ::= ENUMERATED { + incomingCallsBarredWithinCUG (0), + subscriberNotMemberOfCUG (1), + requestedBasicServiceViolatesCUG-Constraints (5), + calledPartySS-InteractionViolation (7)} + +SS-IncompatibilityCause ::= SEQUENCE { + ss-Code [1] SS-Code OPTIONAL, + basicService BasicServiceCode OPTIONAL, + ss-Status [4] SS-Status OPTIONAL, + ...} + +PW-RegistrationFailureCause ::= ENUMERATED { + undetermined (0), + invalidFormat (1), + newPasswordsMismatch (2)} + +SM-EnumeratedDeliveryFailureCause ::= ENUMERATED { + memoryCapacityExceeded (0), + equipmentProtocolError (1), + equipmentNotSM-Equipped (2), + unknownServiceCentre (3), + sc-Congestion (4), + invalidSME-Address (5), + subscriberNotSC-Subscriber (6)} + +SM-DeliveryFailureCause ::= SEQUENCE { + sm-EnumeratedDeliveryFailureCause SM-EnumeratedDeliveryFailureCause, + diagnosticInfo SignalInfo OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +AbsentSubscriberSM-Param ::= SEQUENCE { + absentSubscriberDiagnosticSM AbsentSubscriberDiagnosticSM OPTIONAL, + -- AbsentSubscriberDiagnosticSM can be either for non-GPRS + -- or for GPRS + extensionContainer ExtensionContainer OPTIONAL, + ..., + additionalAbsentSubscriberDiagnosticSM [0] AbsentSubscriberDiagnosticSM OPTIONAL } + -- if received, additionalAbsentSubscriberDiagnosticSM + -- is for GPRS and absentSubscriberDiagnosticSM is + -- for non-GPRS + +AbsentSubscriberDiagnosticSM ::= INTEGER (0..255) + -- AbsentSubscriberDiagnosticSM values are defined in 3GPP TS 23.040 + +SystemFailureParam ::= CHOICE { + networkResource NetworkResource, + -- networkResource must not be used in version 3 + extensibleSystemFailureParam ExtensibleSystemFailureParam + -- extensibleSystemFailureParam must not be used in version <3 + } + +ExtensibleSystemFailureParam ::= SEQUENCE { + networkResource NetworkResource OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + additionalNetworkResource [0] AdditionalNetworkResource OPTIONAL, + failureCauseParam [1] FailureCauseParam OPTIONAL } + +FailureCauseParam ::= ENUMERATED { + limitReachedOnNumberOfConcurrentLocationRequests (0), + ... } + -- if unknown value is received in FailureCauseParam it shall be ignored + + +DataMissingParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +UnexpectedDataParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +FacilityNotSupParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ..., + shapeOfLocationEstimateNotSupported [0] NULL OPTIONAL, + neededLcsCapabilityNotSupportedInServingNode [1] NULL OPTIONAL } + +OR-NotAllowedParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +UnknownSubscriberParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ..., + unknownSubscriberDiagnostic UnknownSubscriberDiagnostic OPTIONAL} + +UnknownSubscriberDiagnostic ::= ENUMERATED { + imsiUnknown (0), + gprs-eps-SubscriptionUnknown (1), + ..., + npdbMismatch (2)} + -- if unknown values are received in + -- UnknownSubscriberDiagnostic they shall be discarded + +NumberChangedParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +UnidentifiedSubParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +IllegalSubscriberParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +IllegalEquipmentParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +BearerServNotProvParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +TeleservNotProvParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +TracingBufferFullParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +NoRoamingNbParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +AbsentSubscriberParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ..., + absentSubscriberReason [0] AbsentSubscriberReason OPTIONAL} + +AbsentSubscriberReason ::= ENUMERATED { + imsiDetach (0), + restrictedArea (1), + noPageResponse (2), + ... , + purgedMS (3)} +-- exception handling: at reception of other values than the ones listed the +-- AbsentSubscriberReason shall be ignored. +-- The AbsentSubscriberReason: purgedMS is defined for the Super-Charger feature +-- (see TS 23.116). If this value is received in a Provide Roaming Number response +-- it shall be mapped to the AbsentSubscriberReason: imsiDetach in the Send Routeing +-- Information response + +BusySubscriberParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ..., + ccbs-Possible [0] NULL OPTIONAL, + ccbs-Busy [1] NULL OPTIONAL} + +NoSubscriberReplyParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ForwardingViolationParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ForwardingFailedParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ATI-NotAllowedParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ATSI-NotAllowedParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ATM-NotAllowedParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +IllegalSS-OperationParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +SS-NotAvailableParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +SS-SubscriptionViolationParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +InformationNotAvailableParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +SubBusyForMT-SMS-Param ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ... , + gprsConnectionSuspended NULL OPTIONAL } + -- If GprsConnectionSuspended is not understood it shall + -- be discarded + +MessageWaitListFullParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ResourceLimitationParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +NoGroupCallNbParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +IncompatibleTerminalParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ShortTermDenialParam ::= SEQUENCE { + ...} + +LongTermDenialParam ::= SEQUENCE { + ...} + +UnauthorizedRequestingNetwork-Param ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +UnauthorizedLCSClient-Param ::= SEQUENCE { + unauthorizedLCSClient-Diagnostic [0] UnauthorizedLCSClient-Diagnostic OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ... } + +UnauthorizedLCSClient-Diagnostic ::= ENUMERATED { + noAdditionalInformation (0), + clientNotInMSPrivacyExceptionList (1), + callToClientNotSetup (2), + privacyOverrideNotApplicable (3), + disallowedByLocalRegulatoryRequirements (4), + ..., + unauthorizedPrivacyClass (5), + unauthorizedCallSessionUnrelatedExternalClient (6), + unauthorizedCallSessionRelatedExternalClient (7) } +-- exception handling: +-- any unrecognized value shall be ignored + +PositionMethodFailure-Param ::= SEQUENCE { + positionMethodFailure-Diagnostic [0] PositionMethodFailure-Diagnostic OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ... } + +PositionMethodFailure-Diagnostic ::= ENUMERATED { + congestion (0), + insufficientResources (1), + insufficientMeasurementData (2), + inconsistentMeasurementData (3), + locationProcedureNotCompleted (4), + locationProcedureNotSupportedByTargetMS (5), + qoSNotAttainable (6), + positionMethodNotAvailableInNetwork (7), + positionMethodNotAvailableInLocationArea (8), + ... } +-- exception handling: +-- any unrecognized value shall be ignored + +UnknownOrUnreachableLCSClient-Param ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +MM-EventNotSupported-Param ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +TargetCellOutsideGCA-Param ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +OngoingGroupCallParam ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + + +END + diff --git a/rrlp-ephemeris/asn1/MAP-ExtensionDataTypes.asn b/rrlp-ephemeris/asn1/MAP-ExtensionDataTypes.asn new file mode 100644 index 000000000..d94c057cc --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-ExtensionDataTypes.asn @@ -0,0 +1,74 @@ +-- $Id: MAP-ExtensionDataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- MAP-ExtensionDataTypes.asn +-- +-- Taken from 3GPP TS 29.002 V8.9.0 (2009-04) +-- +-- 17.7.11 Extension data types +-- + +MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} + +DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + + PrivateExtension, + ExtensionContainer, + SLR-ArgExtensionContainer; + + +-- IOC for private MAP extensions + + +MAP-EXTENSION ::= CLASS { + &ExtensionType OPTIONAL, + &extensionId OBJECT IDENTIFIER } + -- The length of the Object Identifier shall not exceed 16 octets and the + -- number of components of the Object Identifier shall not exceed 16 + +-- data types + +ExtensionContainer ::= SEQUENCE { + privateExtensionList [0]PrivateExtensionList OPTIONAL, + pcs-Extensions [1]PCS-Extensions OPTIONAL, + ...} + +SLR-ArgExtensionContainer ::= SEQUENCE { + privateExtensionList [0]PrivateExtensionList OPTIONAL, + slr-Arg-PCS-Extensions [1]SLR-Arg-PCS-Extensions OPTIONAL, + ...} + +PrivateExtensionList ::= SEQUENCE SIZE (1..maxNumOfPrivateExtensions) OF + PrivateExtension + +PrivateExtension ::= SEQUENCE { + extId MAP-EXTENSION.&extensionId + ({ExtensionSet}), + extType MAP-EXTENSION.&ExtensionType + ({ExtensionSet}{@extId}) OPTIONAL} + +maxNumOfPrivateExtensions INTEGER ::= 10 + +ExtensionSet MAP-EXTENSION ::= + {... + -- ExtensionSet is the set of all defined private extensions + } + -- Unsupported private extensions shall be discarded if received. + +PCS-Extensions ::= SEQUENCE { + ...} + +SLR-Arg-PCS-Extensions ::= SEQUENCE { + ..., + na-ESRK-Request [0] NULL OPTIONAL } + +END + diff --git a/rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn new file mode 100644 index 000000000..2434b89f9 --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn @@ -0,0 +1,657 @@ +-- $Id: MAP-LCS-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- MAP-LCS-DataTypes.asn +-- +-- Taken from 3GPP TS 29.002 V8.9.0 (2009-04) +-- +-- 17.7.13 Location service data types +-- + +MAP-LCS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-LCS-DataTypes (25) version11 (11)} + +DEFINITIONS +IMPLICIT TAGS +::= +BEGIN + +EXPORTS + RoutingInfoForLCS-Arg, + RoutingInfoForLCS-Res, + ProvideSubscriberLocation-Arg, + ProvideSubscriberLocation-Res, + SubscriberLocationReport-Arg, + SubscriberLocationReport-Res, +LocationType, +DeferredLocationEventType, +LCSClientName, +LCS-QoS, +Horizontal-Accuracy, +ResponseTime, +Ext-GeographicalInformation, +VelocityEstimate, +SupportedGADShapes, +Add-GeographicalInformation, +LCSRequestorID, +LCS-ReferenceNumber, +LCSCodeword, +AreaEventInfo, +ReportingPLMNList, +PeriodicLDRInfo, +SequenceNumber +; + +IMPORTS + AddressString, + ISDN-AddressString, + IMEI, + IMSI, + LMSI, + SubscriberIdentity, + AgeOfLocationInformation, + LCSClientExternalID, + LCSClientInternalID, +LCSServiceTypeID, +CellGlobalIdOrServiceAreaIdOrLAI, +PLMN-Id +FROM MAP-CommonDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)} + + ExtensionContainer, + SLR-ArgExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} + + USSD-DataCodingScheme, +USSD-String +FROM MAP-SS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) gsm-Network (1) modules (3) + map-SS-DataTypes (14) version11 (11)} + + APN, + GSN-Address, + SupportedLCS-CapabilitySets +FROM MAP-MS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-MS-DataTypes (11) version11 (11)} + + Additional-Number +FROM MAP-SM-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SM-DataTypes (16) version11 (11)} +; + + +RoutingInfoForLCS-Arg ::= SEQUENCE { + mlcNumber [0] ISDN-AddressString, + targetMS [1] SubscriberIdentity, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +RoutingInfoForLCS-Res ::= SEQUENCE { + targetMS [0] SubscriberIdentity, + lcsLocationInfo [1] LCSLocationInfo, + extensionContainer [2] ExtensionContainer OPTIONAL, + ..., + v-gmlc-Address [3] GSN-Address OPTIONAL, + h-gmlc-Address [4] GSN-Address OPTIONAL, + ppr-Address [5] GSN-Address OPTIONAL, + additional-v-gmlc-Address [6] GSN-Address OPTIONAL } + +LCSLocationInfo ::= SEQUENCE { + networkNode-Number ISDN-AddressString, + -- NetworkNode-number can be either msc-number or sgsn-number + lmsi [0] LMSI OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ... , + gprsNodeIndicator [2] NULL OPTIONAL, + -- gprsNodeIndicator is set only if the SGSN number is sent as the Network Node Number + additional-Number [3] Additional-Number OPTIONAL, + supportedLCS-CapabilitySets [4] SupportedLCS-CapabilitySets OPTIONAL, + additional-LCS-CapabilitySets [5] SupportedLCS-CapabilitySets OPTIONAL + } + +ProvideSubscriberLocation-Arg ::= SEQUENCE { + locationType LocationType, + mlc-Number ISDN-AddressString, + lcs-ClientID [0] LCS-ClientID OPTIONAL, + privacyOverride [1] NULL OPTIONAL, + imsi [2] IMSI OPTIONAL, + msisdn [3] ISDN-AddressString OPTIONAL, + lmsi [4] LMSI OPTIONAL, + imei [5] IMEI OPTIONAL, + lcs-Priority [6] LCS-Priority OPTIONAL, + lcs-QoS [7] LCS-QoS OPTIONAL, + extensionContainer [8] ExtensionContainer OPTIONAL, + ... , + supportedGADShapes [9] SupportedGADShapes OPTIONAL, + lcs-ReferenceNumber [10] LCS-ReferenceNumber OPTIONAL, + lcsServiceTypeID [11] LCSServiceTypeID OPTIONAL, + lcsCodeword [12] LCSCodeword OPTIONAL, + lcs-PrivacyCheck [13] LCS-PrivacyCheck OPTIONAL, + areaEventInfo [14] AreaEventInfo OPTIONAL, + h-gmlc-Address [15] GSN-Address OPTIONAL, + mo-lrShortCircuitIndicator [16] NULL OPTIONAL, + periodicLDRInfo [17] PeriodicLDRInfo OPTIONAL, + reportingPLMNList [18] ReportingPLMNList OPTIONAL } + + -- one of imsi or msisdn is mandatory + -- If a location estimate type indicates activate deferred location or cancel deferred + -- location, a lcs-Reference number shall be included. + +LocationType ::= SEQUENCE { + locationEstimateType [0] LocationEstimateType, + ..., + deferredLocationEventType [1] DeferredLocationEventType OPTIONAL } + +LocationEstimateType ::= ENUMERATED { + currentLocation (0), + currentOrLastKnownLocation (1), + initialLocation (2), + ..., + activateDeferredLocation (3), + cancelDeferredLocation (4) , + notificationVerificationOnly (5) } +-- exception handling: +-- a ProvideSubscriberLocation-Arg containing an unrecognized LocationEstimateType +-- shall be rejected by the receiver with a return error cause of unexpected data value + +DeferredLocationEventType ::= BIT STRING { + msAvailable (0) , + enteringIntoArea (1), + leavingFromArea (2), + beingInsideArea (3) , + periodicLDR (4) } (SIZE (1..16)) +-- beingInsideArea is always treated as oneTimeEvent regardless of the possible value +-- of occurrenceInfo inside areaEventInfo. +-- exception handling: +-- a ProvideSubscriberLocation-Arg containing other values than listed above in +-- DeferredLocationEventType shall be rejected by the receiver with a return error cause of +-- unexpected data value. + +LCS-ClientID ::= SEQUENCE { + lcsClientType [0] LCSClientType, + lcsClientExternalID [1] LCSClientExternalID OPTIONAL, + lcsClientDialedByMS [2] AddressString OPTIONAL, + lcsClientInternalID [3] LCSClientInternalID OPTIONAL, + lcsClientName [4] LCSClientName OPTIONAL, + ..., + lcsAPN [5] APN OPTIONAL, + lcsRequestorID [6] LCSRequestorID OPTIONAL } + +LCSClientType ::= ENUMERATED { + emergencyServices (0), + valueAddedServices (1), + plmnOperatorServices (2), + lawfulInterceptServices (3), + ... } + -- exception handling: + -- unrecognized values may be ignored if the LCS client uses the privacy override + -- otherwise, an unrecognized value shall be treated as unexpected data by a receiver + -- a return error shall then be returned if received in a MAP invoke + +LCSClientName ::= SEQUENCE { + dataCodingScheme [0] USSD-DataCodingScheme, + nameString [2] NameString, + ..., + lcs-FormatIndicator [3] LCS-FormatIndicator OPTIONAL } + +-- The USSD-DataCodingScheme shall indicate use of the default alphabet through the +-- following encoding +-- bit 7 6 5 4 3 2 1 0 +-- 0 0 0 0 1 1 1 1 + +NameString ::= USSD-String (SIZE (1..maxNameStringLength)) + +maxNameStringLength INTEGER ::= 63 + +LCSRequestorID ::= SEQUENCE { + dataCodingScheme [0] USSD-DataCodingScheme, + requestorIDString [1] RequestorIDString, + ..., + lcs-FormatIndicator [2] LCS-FormatIndicator OPTIONAL } + +RequestorIDString ::= USSD-String (SIZE (1..maxRequestorIDStringLength)) + +maxRequestorIDStringLength INTEGER ::= 63 + +LCS-FormatIndicator ::= ENUMERATED { + logicalName (0), + e-mailAddress (1), + msisdn (2), + url (3), + sipUrl (4), + ... } + +LCS-Priority ::= OCTET STRING (SIZE (1)) + -- 0 = highest priority + -- 1 = normal priority + -- all other values treated as 1 + +LCS-QoS ::= SEQUENCE { + horizontal-accuracy [0] Horizontal-Accuracy OPTIONAL, + verticalCoordinateRequest [1] NULL OPTIONAL, + vertical-accuracy [2] Vertical-Accuracy OPTIONAL, responseTime [3] ResponseTime OPTIONAL, + extensionContainer [4] ExtensionContainer OPTIONAL, + ..., + velocityRequest [5] NULL OPTIONAL +} + +Horizontal-Accuracy ::= OCTET STRING (SIZE (1)) + -- bit 8 = 0 + -- bits 7-1 = 7 bit Uncertainty Code defined in 3GPP TS 23.032. The horizontal location + -- error should be less than the error indicated by the uncertainty code with 67% + -- confidence. + +Vertical-Accuracy ::= OCTET STRING (SIZE (1)) + -- bit 8 = 0 + -- bits 7-1 = 7 bit Vertical Uncertainty Code defined in 3GPP TS 23.032. + -- The vertical location error should be less than the error indicated + -- by the uncertainty code with 67% confidence. + +ResponseTime ::= SEQUENCE { + responseTimeCategory ResponseTimeCategory, + ...} +-- note: an expandable SEQUENCE simplifies later addition of a numeric response time. + +ResponseTimeCategory ::= ENUMERATED { + lowdelay (0), + delaytolerant (1), + ... } +-- exception handling: +-- an unrecognized value shall be treated the same as value 1 (delaytolerant) + +SupportedGADShapes ::= BIT STRING { + ellipsoidPoint (0), + ellipsoidPointWithUncertaintyCircle (1), + ellipsoidPointWithUncertaintyEllipse (2), + polygon (3), + ellipsoidPointWithAltitude (4), + ellipsoidPointWithAltitudeAndUncertaintyElipsoid (5), + ellipsoidArc (6) } (SIZE (7..16)) +-- A node shall mark in the BIT STRING all Shapes defined in 3GPP TS 23.032 it supports. +-- exception handling: bits 7 to 15 shall be ignored if received. + +LCS-ReferenceNumber::= OCTET STRING (SIZE(1)) + +LCSCodeword ::= SEQUENCE { + dataCodingScheme [0] USSD-DataCodingScheme, + lcsCodewordString [1] LCSCodewordString, + ...} + +LCSCodewordString ::= USSD-String (SIZE (1..maxLCSCodewordStringLength)) + +maxLCSCodewordStringLength INTEGER ::= 20 + +LCS-PrivacyCheck ::= SEQUENCE { + callSessionUnrelated [0] PrivacyCheckRelatedAction, + callSessionRelated [1] PrivacyCheckRelatedAction OPTIONAL, + ...} + +PrivacyCheckRelatedAction ::= ENUMERATED { + allowedWithoutNotification (0), + allowedWithNotification (1), + allowedIfNoResponse (2), + restrictedIfNoResponse (3), + notAllowed (4), + ...} +-- exception handling: +-- a ProvideSubscriberLocation-Arg containing an unrecognized PrivacyCheckRelatedAction +-- shall be rejected by the receiver with a return error cause of unexpected data value + +AreaEventInfo ::= SEQUENCE { + areaDefinition [0] AreaDefinition, + occurrenceInfo [1] OccurrenceInfo OPTIONAL, + intervalTime [2] IntervalTime OPTIONAL, + ...} + +AreaDefinition ::= SEQUENCE { + areaList [0] AreaList, + ...} + +AreaList ::= SEQUENCE SIZE (1..maxNumOfAreas) OF Area + +maxNumOfAreas INTEGER ::= 10 + +Area ::= SEQUENCE { + areaType [0] AreaType, + areaIdentification [1] AreaIdentification, + ...} + +AreaType ::= ENUMERATED { + countryCode (0), + plmnId (1), + locationAreaId (2), + routingAreaId (3), + cellGlobalId (4), + ..., + utranCellId (5) } + +AreaIdentification ::= OCTET STRING (SIZE (2..7)) + -- The internal structure is defined as follows: + -- octet 1 bits 4321 Mobile Country Code 1st digit + -- bits 8765 Mobile Country Code 2nd digit + -- octet 2 bits 4321 Mobile Country Code 3rd digit + -- bits 8765 Mobile Network Code 3rd digit if 3 digit MNC included + -- or filler (1111) + -- octet 3 bits 4321 Mobile Network Code 1st digit + -- bits 8765 Mobile Network Code 2nd digit + -- octets 4 and 5 Location Area Code (LAC) for Local Area Id, + -- Routing Area Id and Cell Global Id + -- octet 6 Routing Area Code (RAC) for Routing Area Id + -- octets 6 and 7 Cell Identity (CI) for Cell Global Id + -- octets 4 until 7 Utran Cell Identity (UC-Id) for Utran Cell Id + +OccurrenceInfo ::= ENUMERATED { + oneTimeEvent (0), + multipleTimeEvent (1), + ...} + +IntervalTime ::= INTEGER (1..32767) + -- minimum interval time between area reports in seconds + +PeriodicLDRInfo ::= SEQUENCE { + reportingAmount ReportingAmount, + reportingInterval ReportingInterval, + ...} +-- reportingInterval x reportingAmount shall not exceed 8639999 (99 days, 23 hours, +-- 59 minutes and 59 seconds) for compatibility with OMA MLP and RLP + +ReportingAmount ::= INTEGER (1..maxReportingAmount) + +maxReportingAmount INTEGER ::= 8639999 + +ReportingInterval ::= INTEGER (1..maxReportingInterval) +-- ReportingInterval is in seconds + +maxReportingInterval INTEGER ::= 8639999 + +ReportingPLMNList::= SEQUENCE { + plmn-ListPrioritized [0] NULL OPTIONAL, + plmn-List [1] PLMNList, + ...} + +PLMNList::= SEQUENCE SIZE (1..maxNumOfReportingPLMN) OF + ReportingPLMN + +maxNumOfReportingPLMN INTEGER ::= 20 + +ReportingPLMN::= SEQUENCE { + plmn-Id [0] PLMN-Id, + ran-Technology [1] RAN-Technology OPTIONAL, + ran-PeriodicLocationSupport [2] NULL OPTIONAL, + ...} + +RAN-Technology ::= ENUMERATED { + gsm (0), + umts (1), + ...} + +ProvideSubscriberLocation-Res ::= SEQUENCE { + locationEstimate Ext-GeographicalInformation, + ageOfLocationEstimate [0] AgeOfLocationInformation OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ... , + add-LocationEstimate [2] Add-GeographicalInformation OPTIONAL, + deferredmt-lrResponseIndicator [3] NULL OPTIONAL, + geranPositioningData [4] PositioningDataInformation OPTIONAL, + utranPositioningData [5] UtranPositioningDataInfo OPTIONAL, + cellIdOrSai [6] CellGlobalIdOrServiceAreaIdOrLAI OPTIONAL, + sai-Present [7] NULL OPTIONAL, + accuracyFulfilmentIndicator [8] AccuracyFulfilmentIndicator OPTIONAL, + velocityEstimate [9] VelocityEstimate OPTIONAL, + mo-lrShortCircuitIndicator [10] NULL OPTIONAL } + +-- if deferredmt-lrResponseIndicator is set, locationEstimate is ignored. + +-- the add-LocationEstimate parameter shall not be sent to a node that did not indicate the +-- geographic shapes supported in the ProvideSubscriberLocation-Arg +-- The locationEstimate and the add-locationEstimate parameters shall not be sent if +-- the supportedGADShapes parameter has been received in ProvideSubscriberLocation-Arg +-- and the shape encoded in locationEstimate or add-LocationEstimate is not marked +-- as supported in supportedGADShapes. In such a case ProvideSubscriberLocation +-- shall be rejected with error FacilityNotSupported with additional indication +-- shapeOfLocationEstimateNotSupported. +-- sai-Present indicates that the cellIdOrSai parameter contains a Service Area Identity. + +AccuracyFulfilmentIndicator ::= ENUMERATED { + requestedAccuracyFulfilled (0), + requestedAccuracyNotFulfilled (1), + ... } + +Ext-GeographicalInformation ::= OCTET STRING (SIZE (1..maxExt-GeographicalInformation)) + -- Refers to geographical Information defined in 3GPP TS 23.032. + -- This is composed of 1 or more octets with an internal structure according to + -- 3GPP TS 23.032 + -- Octet 1: Type of shape, only the following shapes in 3GPP TS 23.032 are allowed: + -- (a) Ellipsoid point with uncertainty circle + -- (b) Ellipsoid point with uncertainty ellipse + -- (c) Ellipsoid point with altitude and uncertainty ellipsoid + -- (d) Ellipsoid Arc + -- (e) Ellipsoid Point + -- Any other value in octet 1 shall be treated as invalid + -- Octets 2 to 8 for case (a) – Ellipsoid point with uncertainty circle + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Uncertainty code 1 octet + -- Octets 2 to 11 for case (b) – Ellipsoid point with uncertainty ellipse: + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Uncertainty semi-major axis 1 octet + -- Uncertainty semi-minor axis 1 octet + -- Angle of major axis 1 octet + -- Confidence 1 octet + -- Octets 2 to 14 for case (c) – Ellipsoid point with altitude and uncertainty ellipsoid + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Altitude 2 octets + -- Uncertainty semi-major axis 1 octet + -- Uncertainty semi-minor axis 1 octet + -- Angle of major axis 1 octet + -- Uncertainty altitude 1 octet + -- Confidence 1 octet + -- Octets 2 to 13 for case (d) – Ellipsoid Arc + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Inner radius 2 octets + -- Uncertainty radius 1 octet + -- Offset angle 1 octet + -- Included angle 1 octet + -- Confidence 1 octet + -- Octets 2 to 7 for case (e) – Ellipsoid Point + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + + -- + -- An Ext-GeographicalInformation parameter comprising more than one octet and + -- containing any other shape or an incorrect number of octets or coding according + -- to 3GPP TS 23.032 shall be treated as invalid data by a receiver. + -- + -- An Ext-GeographicalInformation parameter comprising one octet shall be discarded + -- by the receiver if an Add-GeographicalInformation parameter is received + -- in the same message. + -- + -- An Ext-GeographicalInformation parameter comprising one octet shall be treated as + -- invalid data by the receiver if an Add-GeographicalInformation parameter is not + -- received in the same message. + +maxExt-GeographicalInformation INTEGER ::= 20 + -- the maximum length allows for further shapes in 3GPP TS 23.032 to be included in later + -- versions of 3GPP TS 29.002 + +VelocityEstimate ::= OCTET STRING (SIZE (4..7)) + -- Refers to Velocity description defined in 3GPP TS 23.032. + -- This is composed of 4 or more octets with an internal structure according to + -- 3GPP TS 23.032 + -- Octet 1: Type of velocity, only the following types in 3GPP TS 23.032 are allowed: + -- (a) Horizontal Velocity + -- (b) Horizontal with Vertical Velocity + -- (c) Horizontal Velocity with Uncertainty + -- (d) Horizontal with Vertical Velocity and Uncertainty + -- For types Horizontal with Vertical Velocity and Horizontal with Vertical Velocity + -- and Uncertainty, the direction of the Vertical Speed is also included in Octet 1 + -- Any other value in octet 1 shall be treated as invalid + -- Octets 2 to 4 for case (a) Horizontal velocity: + -- Bearing 1 octet + -- Horizontal Speed 2 octets + -- Octets 2 to 5 for case (b) – Horizontal with Vertical Velocity: + -- Bearing 1 octet + -- Horizontal Speed 2 octets + -- Vertical Speed 1 octet + -- Octets 2 to 5 for case (c) – Horizontal velocity with Uncertainty: + -- Bearing 1 octet + -- Horizontal Speed 2 octets + -- Uncertainty Speed 1 octet + -- Octets 2 to 7 for case (d) – Horizontal with Vertical Velocity and Uncertainty: + -- Bearing 1 octet + -- Horizontal Speed 2 octets + -- Vertical Speed 1 octet + -- Horizontal Uncertainty Speed 1 octet + -- Vertical Uncertainty Speed 1 octet + +PositioningDataInformation ::= OCTET STRING (SIZE (2..maxPositioningDataInformation)) + -- Refers to the Positioning Data defined in 3GPP TS 49.031. + -- This is composed of 2 or more octets with an internal structure according to + -- 3GPP TS 49.031. + +maxPositioningDataInformation INTEGER ::= 10 + -- + +UtranPositioningDataInfo ::= OCTET STRING (SIZE (3..maxUtranPositioningDataInfo)) + -- Refers to the Position Data defined in 3GPP TS 25.413. + -- This is composed of the positioningDataDiscriminator and the positioningDataSet + -- included in positionData as defined in 3GPP TS 25.413. + +maxUtranPositioningDataInfo INTEGER ::= 11 + -- + +Add-GeographicalInformation ::= OCTET STRING (SIZE (1..maxAdd-GeographicalInformation)) + -- Refers to geographical Information defined in 3GPP TS 23.032. + -- This is composed of 1 or more octets with an internal structure according to + -- 3GPP TS 23.032 + -- Octet 1: Type of shape, all the shapes defined in 3GPP TS 23.032 are allowed: + -- Octets 2 to n (where n is the total number of octets necessary to encode the shape + -- according to 3GPP TS 23.032) are used to encode the shape itself in accordance with the + -- encoding defined in 3GPP TS 23.032 + -- + -- An Add-GeographicalInformation parameter, whether valid or invalid, received + -- together with a valid Ext-GeographicalInformation parameter in the same message + -- shall be discarded. + -- + -- An Add-GeographicalInformation parameter containing any shape not defined in + -- 3GPP TS 23.032 or an incorrect number of octets or coding according to + -- 3GPP TS 23.032 shall be treated as invalid data by a receiver if not received + -- together with a valid Ext-GeographicalInformation parameter in the same message. + +maxAdd-GeographicalInformation INTEGER ::= 91 + -- the maximum length allows support for all the shapes currently defined in 3GPP TS 23.032 + +SubscriberLocationReport-Arg ::= SEQUENCE { + lcs-Event LCS-Event, + lcs-ClientID LCS-ClientID, + lcsLocationInfo LCSLocationInfo, + msisdn [0] ISDN-AddressString OPTIONAL, + imsi [1] IMSI OPTIONAL, + imei [2] IMEI OPTIONAL, + na-ESRD [3] ISDN-AddressString OPTIONAL, + na-ESRK [4] ISDN-AddressString OPTIONAL, + locationEstimate [5] Ext-GeographicalInformation OPTIONAL, + ageOfLocationEstimate [6] AgeOfLocationInformation OPTIONAL, + slr-ArgExtensionContainer [7] SLR-ArgExtensionContainer OPTIONAL, + ... , + add-LocationEstimate [8] Add-GeographicalInformation OPTIONAL, + deferredmt-lrData [9] Deferredmt-lrData OPTIONAL, + lcs-ReferenceNumber [10] LCS-ReferenceNumber OPTIONAL, + geranPositioningData [11] PositioningDataInformation OPTIONAL, + utranPositioningData [12] UtranPositioningDataInfo OPTIONAL, + cellIdOrSai [13] CellGlobalIdOrServiceAreaIdOrLAI OPTIONAL, + h-gmlc-Address [14] GSN-Address OPTIONAL, + lcsServiceTypeID [15] LCSServiceTypeID OPTIONAL, + sai-Present [17] NULL OPTIONAL, + pseudonymIndicator [18] NULL OPTIONAL, + accuracyFulfilmentIndicator [19] AccuracyFulfilmentIndicator OPTIONAL, + velocityEstimate [20] VelocityEstimate OPTIONAL, + sequenceNumber [21] SequenceNumber OPTIONAL, + periodicLDRInfo [22] PeriodicLDRInfo OPTIONAL, + mo-lrShortCircuitIndicator [23] NULL OPTIONAL } + + -- one of msisdn or imsi is mandatory + -- a location estimate that is valid for the locationEstimate parameter should + -- be transferred in this parameter in preference to the add-LocationEstimate. + -- the deferredmt-lrData parameter shall be included if and only if the lcs-Event + -- indicates a deferredmt-lrResponse. + -- if the lcs-Event indicates a deferredmt-lrResponse then the locationEstimate + -- and the add-locationEstimate parameters shall not be sent if the + -- supportedGADShapes parameter had been received in ProvideSubscriberLocation-Arg + -- and the shape encoded in locationEstimate or add-LocationEstimate was not marked + -- as supported in supportedGADShapes. In such a case terminationCause + -- in deferredmt-lrData shall be present with value + -- shapeOfLocationEstimateNotSupported. + -- If a lcs event indicates deferred mt-lr response, the lcs-Reference number shall be + -- included. + -- sai-Present indicates that the cellIdOrSai parameter contains a Service Area Identity. + +Deferredmt-lrData ::= SEQUENCE { + deferredLocationEventType DeferredLocationEventType, + terminationCause [0] TerminationCause OPTIONAL, + lcsLocationInfo [1] LCSLocationInfo OPTIONAL, + ...} + -- lcsLocationInfo may be included only if a terminationCause is present + -- indicating mt-lrRestart. + +LCS-Event ::= ENUMERATED { + emergencyCallOrigination (0), + emergencyCallRelease (1), + mo-lr (2), + ..., + deferredmt-lrResponse (3) , + deferredmo-lrTTTPInitiation (4) } + -- deferredmt-lrResponse is applicable to the delivery of a location estimate + -- for an LDR initiated earlier by either the network (via an MT-LR activate deferred + -- location) or the UE (via a deferred MO-LR TTTP initiation) + -- exception handling: + -- a SubscriberLocationReport-Arg containing an unrecognized LCS-Event + -- shall be rejected by a receiver with a return error cause of unexpected data value + +TerminationCause ::= ENUMERATED { + normal (0), + errorundefined (1), + internalTimeout (2), + congestion (3), + mt-lrRestart (4), + privacyViolation (5), + ..., + shapeOfLocationEstimateNotSupported (6) , + subscriberTermination (7), + uETermination (8), + networkTermination (9) } +-- mt-lrRestart shall be used to trigger the GMLC to restart the location procedure, +-- either because the sending node knows that the terminal has moved under coverage +-- of another MSC or SGSN (e.g. Send Identification received), or because the subscriber +-- has been deregistered due to a Cancel Location received from HLR. +-- +-- exception handling +-- an unrecognized value shall be treated the same as value 1 (errorundefined) + +SequenceNumber ::= INTEGER (1..maxReportingAmount) + +SubscriberLocationReport-Res ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ..., + na-ESRK [0] ISDN-AddressString OPTIONAL, + na-ESRD [1] ISDN-AddressString OPTIONAL, + h-gmlc-Address [2] GSN-Address OPTIONAL, + mo-lrShortCircuitIndicator [3] NULL OPTIONAL, + reportingPLMNList [4] ReportingPLMNList OPTIONAL, + lcs-ReferenceNumber [5] LCS-ReferenceNumber OPTIONAL } + +-- na-ESRK and na-ESRD are mutually exclusive +-- +-- exception handling +-- receipt of both na-ESRK and na-ESRD shall be treated the same as a return error + + +END + diff --git a/rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn new file mode 100644 index 000000000..9c12a028a --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn @@ -0,0 +1,2780 @@ +-- $Id: MAP-MS-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.1 Mobile Service data types + +MAP-MS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-MS-DataTypes (11) version11 (11)} + +DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + + -- location registration types + UpdateLocationArg, + UpdateLocationRes, + CancelLocationArg, + CancelLocationRes, + PurgeMS-Arg, + PurgeMS-Res, + SendIdentificationArg, + SendIdentificationRes, + UpdateGprsLocationArg, + UpdateGprsLocationRes, + IST-SupportIndicator, + SupportedLCS-CapabilitySets, + + -- gprs location registration types + GSN-Address, + + -- handover types + ForwardAccessSignalling-Arg, + PrepareHO-Arg, + PrepareHO-Res, + PrepareSubsequentHO-Arg, + PrepareSubsequentHO-Res, + ProcessAccessSignalling-Arg, + SendEndSignal-Arg, + SendEndSignal-Res, + + -- authentication management types + SendAuthenticationInfoArg, + SendAuthenticationInfoRes, + AuthenticationFailureReportArg, +AuthenticationFailureReportRes, + + -- security management types + Kc, + Cksn, + + -- equipment management types + CheckIMEI-Arg, + CheckIMEI-Res, + + -- subscriber management types + InsertSubscriberDataArg, + InsertSubscriberDataRes, + LSAIdentity, + DeleteSubscriberDataArg, + DeleteSubscriberDataRes, + Ext-QoS-Subscribed, + Ext2-QoS-Subscribed, + Ext3-QoS-Subscribed, + SubscriberData, + ODB-Data, + SubscriberStatus, + ZoneCodeList, + maxNumOfZoneCodes, + O-CSI, +D-CSI, + O-BcsmCamelTDPCriteriaList, + T-BCSM-CAMEL-TDP-CriteriaList, + SS-CSI, + ServiceKey, + DefaultCallHandling, + CamelCapabilityHandling, + BasicServiceCriteria, + SupportedCamelPhases, + OfferedCamel4CSIs, + OfferedCamel4Functionalities, + maxNumOfCamelTDPData, + CUG-Index, + CUG-Info, + CUG-Interlock, + InterCUG-Restrictions, + IntraCUG-Options, + NotificationToMSUser, + QoS-Subscribed, +IST-AlertTimerValue, + T-CSI, + T-BcsmTriggerDetectionPoint, +APN, +AdditionalInfo, + + -- fault recovery types + ResetArg, + RestoreDataArg, + RestoreDataRes, + +-- provide subscriber info types +GeographicalInformation, +MS-Classmark2, +GPRSMSClass, + + -- subscriber information enquiry types + ProvideSubscriberInfoArg, + ProvideSubscriberInfoRes, + SubscriberInfo, + LocationInformation, + LocationInformationGPRS, + RAIdentity, + SubscriberState, + GPRSChargingID, +MNPInfoRes, + RouteingNumber, + + -- any time information enquiry types + AnyTimeInterrogationArg, + AnyTimeInterrogationRes, + + -- any time information handling types + AnyTimeSubscriptionInterrogationArg, + AnyTimeSubscriptionInterrogationRes, + AnyTimeModificationArg, + AnyTimeModificationRes, + + -- subscriber data modification notification types + NoteSubscriberDataModifiedArg, + NoteSubscriberDataModifiedRes, + + -- gprs location information retrieval types + SendRoutingInfoForGprsArg, + SendRoutingInfoForGprsRes, + + -- failure reporting types + FailureReportArg, + FailureReportRes, + + -- gprs notification types + NoteMsPresentForGprsArg, + NoteMsPresentForGprsRes, + + -- Mobility Management types +NoteMM-EventArg, + NoteMM-EventRes, + NumberPortabilityStatus, + PagingArea, + + -- VGCS / VBS types types +GroupId, +Long-GroupId, +AdditionalSubscriptions + +; + +IMPORTS + maxNumOfSS, + SS-SubscriptionOption, + SS-List, + SS-ForBS-Code, + Password +FROM MAP-SS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-DataTypes (14) version11 (11)} + + SS-Code +FROM MAP-SS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)} + + Ext-BearerServiceCode +FROM MAP-BS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-BS-Code (20) version11 (11)} + + Ext-TeleserviceCode +FROM MAP-TS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-TS-Code (19) version11 (11)} + + AddressString, +ISDN-AddressString, + ISDN-SubaddressString, + FTN-AddressString, + AccessNetworkSignalInfo, + IMSI, + IMEI, + TMSI, + HLR-List, + LMSI, + Identity, + GlobalCellId, + CellGlobalIdOrServiceAreaIdOrLAI, + Ext-BasicServiceCode, + NAEA-PreferredCI, + EMLPP-Info, + MC-SS-Info, + SubscriberIdentity, + AgeOfLocationInformation, + LCSClientExternalID, + LCSClientInternalID, + Ext-SS-Status, + LCSServiceTypeID, + ASCI-CallReference, + TBCD-STRING, + LAIFixedLength, + PLMN-Id, +EMLPP-Priority +FROM MAP-CommonDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)} + + ExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} + + AbsentSubscriberDiagnosticSM +FROM MAP-ER-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ER-DataTypes (17) version11 (11)} + + TracePropagationList +FROM MAP-OM-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-OM-DataTypes (12) version11 (11)} + +; + +-- location registration types + +UpdateLocationArg ::= SEQUENCE { + imsi IMSI, + msc-Number [1] ISDN-AddressString, + vlr-Number ISDN-AddressString, + lmsi [10] LMSI OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ... , + vlr-Capability [6] VLR-Capability OPTIONAL, + informPreviousNetworkEntity [11] NULL OPTIONAL, + cs-LCS-NotSupportedByUE [12] NULL OPTIONAL, + v-gmlc-Address [2] GSN-Address OPTIONAL, + add-info [13] ADD-Info OPTIONAL, + pagingArea [14] PagingArea OPTIONAL, + skipSubscriberDataUpdate [15] NULL OPTIONAL + -- The skipSubscriberDataUpdate parameter in the UpdateLocationArg and the ADD-Info + -- structures carry the same semantic. + } + +VLR-Capability ::= SEQUENCE{ + supportedCamelPhases [0] SupportedCamelPhases OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ... , + solsaSupportIndicator [2] NULL OPTIONAL, + istSupportIndicator [1] IST-SupportIndicator OPTIONAL, + superChargerSupportedInServingNetworkEntity [3] SuperChargerInfo OPTIONAL, + longFTN-Supported [4] NULL OPTIONAL, + supportedLCS-CapabilitySets [5] SupportedLCS-CapabilitySets OPTIONAL, + offeredCamel4CSIs [6] OfferedCamel4CSIs OPTIONAL, + supportedRAT-TypesIndicator [7] SupportedRAT-Types OPTIONAL, + longGroupID-Supported [8] NULL OPTIONAL } + +SupportedRAT-Types::= BIT STRING { + utran (0), + geran (1), + gan (2), + i-hspa-evolution (3), + e-utran (4)} (SIZE (2..8)) + -- exception handling: bits 5 to 7 shall be ignored if received and not understood + + + +SuperChargerInfo ::= CHOICE { + sendSubscriberData [0] NULL, + subscriberDataStored [1] AgeIndicator } + +AgeIndicator ::= OCTET STRING (SIZE (1..6)) + -- The internal structure of this parameter is implementation specific. + +IST-SupportIndicator ::= ENUMERATED { + basicISTSupported (0), + istCommandSupported (1), + ...} +-- exception handling: +-- reception of values > 1 shall be mapped to ' istCommandSupported ' + +SupportedLCS-CapabilitySets ::= BIT STRING { + lcsCapabilitySet1 (0), + lcsCapabilitySet2 (1), + lcsCapabilitySet3 (2), + lcsCapabilitySet4 (3) , + lcsCapabilitySet5 (4) } (SIZE (2..16)) +-- Core network signalling capability set1 indicates LCS Release98 or Release99 version. +-- Core network signalling capability set2 indicates LCS Release4. +-- Core network signalling capability set3 indicates LCS Release5. +-- Core network signalling capability set4 indicates LCS Release6. +-- Core network signalling capability set5 indicates LCS Release7 or later version. +-- A node shall mark in the BIT STRING all LCS capability sets it supports. +-- If no bit is set then the sending node does not support LCS. +-- If the parameter is not sent by an VLR then the VLR may support at most capability set1. +-- If the parameter is not sent by an SGSN then no support for LCS is assumed. +-- An SGSN is not allowed to indicate support of capability set1. +-- Other bits than listed above shall be discarded. + +UpdateLocationRes ::= SEQUENCE { + hlr-Number ISDN-AddressString, + extensionContainer ExtensionContainer OPTIONAL, + ..., + add-Capability NULL OPTIONAL, + pagingArea-Capability [0]NULL OPTIONAL } + +ADD-Info ::= SEQUENCE { + imeisv [0] IMEI, + skipSubscriberDataUpdate [1] NULL OPTIONAL, + -- The skipSubscriberDataUpdate parameter in the UpdateLocationArg and the ADD-Info + -- structures carry the same semantic. + ...} + + +PagingArea ::= SEQUENCE SIZE (1..5) OF LocationArea + + +LocationArea ::= CHOICE { + laiFixedLength [0] LAIFixedLength, + lac [1] LAC} + + +LAC ::= OCTET STRING (SIZE (2)) + -- Refers to Location Area Code of the Location Area Identification defined in + -- 3GPP TS 23.003 [17]. + -- Location Area Code according to 3GPP TS 24.008 [35] + +CancelLocationArg ::= [3] SEQUENCE { + identity Identity, + cancellationType CancellationType OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + typeOfUpdate [0] TypeOfUpdate OPTIONAL } + +TypeOfUpdate ::= ENUMERATED { + sgsn-change (0), + mme-change (1), + ...} + -- TypeOfUpdate shall be absent if CancellationType is different from updateProcedure + +CancellationType ::= ENUMERATED { + updateProcedure (0), + subscriptionWithdraw (1), + ...} + -- The HLR shall not send values other than listed above + +CancelLocationRes ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +PurgeMS-Arg ::= [3] SEQUENCE { + imsi IMSI, + vlr-Number [0] ISDN-AddressString OPTIONAL, + sgsn-Number [1] ISDN-AddressString OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +PurgeMS-Res ::= SEQUENCE { + freezeTMSI [0] NULL OPTIONAL, + freezeP-TMSI [1] NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + freezeM-TMSI [2] NULL OPTIONAL } + +SendIdentificationArg ::= SEQUENCE { + tmsi TMSI, + numberOfRequestedVectors NumberOfRequestedVectors OPTIONAL, + -- within a dialogue numberOfRequestedVectors shall be present in + -- the first service request and shall not be present in subsequent service requests. + -- If received in a subsequent service request it shall be discarded. + segmentationProhibited NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + msc-Number ISDN-AddressString OPTIONAL, + previous-LAI [0] LAIFixedLength OPTIONAL, + hopCounter [1] HopCounter OPTIONAL } + +HopCounter ::= INTEGER (0..3) + +SendIdentificationRes ::= [3] SEQUENCE { + imsi IMSI OPTIONAL, + -- IMSI shall be present in the first (or only) service response of a dialogue. + -- If multiple service requests are present in a dialogue then IMSI + -- shall not be present in any service response other than the first one. + authenticationSetList AuthenticationSetList OPTIONAL, + currentSecurityContext [2]CurrentSecurityContext OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +-- authentication management types + +AuthenticationSetList ::= CHOICE { + tripletList [0] TripletList, + quintupletList [1] QuintupletList } + +TripletList ::= SEQUENCE SIZE (1..5) OF + AuthenticationTriplet + +QuintupletList ::= SEQUENCE SIZE (1..5) OF + AuthenticationQuintuplet + +AuthenticationTriplet ::= SEQUENCE { + rand RAND, + sres SRES, + kc Kc, + ...} + +AuthenticationQuintuplet ::= SEQUENCE { + rand RAND, + xres XRES, + ck CK, + ik IK, + autn AUTN, + ...} + +CurrentSecurityContext ::= CHOICE { + gsm-SecurityContextData [0] GSM-SecurityContextData, + umts-SecurityContextData [1] UMTS-SecurityContextData } + +GSM-SecurityContextData ::= SEQUENCE { + kc Kc, + cksn Cksn, + ... } + +UMTS-SecurityContextData ::= SEQUENCE { + ck CK, + ik IK, + ksi KSI, + ... } + +RAND ::= OCTET STRING (SIZE (16)) + +SRES ::= OCTET STRING (SIZE (4)) + +Kc ::= OCTET STRING (SIZE (8)) + +XRES ::= OCTET STRING (SIZE (4..16)) + +CK ::= OCTET STRING (SIZE (16)) + +IK ::= OCTET STRING (SIZE (16)) + +AUTN ::= OCTET STRING (SIZE (16)) + +AUTS ::= OCTET STRING (SIZE (14)) + +Cksn ::= OCTET STRING (SIZE (1)) + -- The internal structure is defined in 3GPP TS 24.008 + +KSI ::= OCTET STRING (SIZE (1)) + -- The internal structure is defined in 3GPP TS 24.008 + +AuthenticationFailureReportArg ::= SEQUENCE { + imsi IMSI, + failureCause FailureCause, + extensionContainer ExtensionContainer OPTIONAL, + ... , + re-attempt BOOLEAN OPTIONAL, + accessType AccessType OPTIONAL, + rand RAND OPTIONAL, + vlr-Number [0] ISDN-AddressString OPTIONAL, + sgsn-Number [1] ISDN-AddressString OPTIONAL } + +AccessType ::= ENUMERATED { + call (0), + emergencyCall (1), + locationUpdating (2), + supplementaryService (3), + shortMessage (4), + gprsAttach (5), + routingAreaUpdating (6), + serviceRequest (7), + pdpContextActivation (8), + pdpContextDeactivation (9), + ..., + gprsDetach (10)} + -- exception handling: + -- received values greater than 10 shall be ignored. + +AuthenticationFailureReportRes ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +FailureCause ::= ENUMERATED { + wrongUserResponse (0), + wrongNetworkSignature (1)} + +-- gprs location registration types + +UpdateGprsLocationArg ::= SEQUENCE { + imsi IMSI, + sgsn-Number ISDN-AddressString, + sgsn-Address GSN-Address, + extensionContainer ExtensionContainer OPTIONAL, + ... , + sgsn-Capability [0] SGSN-Capability OPTIONAL, + informPreviousNetworkEntity [1] NULL OPTIONAL, + ps-LCS-NotSupportedByUE [2] NULL OPTIONAL, + v-gmlc-Address [3] GSN-Address OPTIONAL, + add-info [4] ADD-Info OPTIONAL, + eps-info [5] EPS-Info OPTIONAL, + servingNodeTypeIndicator [6] NULL OPTIONAL, + skipSubscriberDataUpdate [7] NULL OPTIONAL, + usedRAT-Type [8] Used-RAT-Type OPTIONAL + } + +Used-RAT-Type::= ENUMERATED { + utran (0), + geran (1), + gan (2), + i-hspa-evolution (3), + e-utran (4), + ...} + +EPS-Info ::= CHOICE{ + pdn-gw-update [0] PDN-GW-Update, + isr-Information [1] ISR-Information } + +PDN-GW-Update ::= SEQUENCE{ + apn [0] APN OPTIONAL, + pdn-gw-Identity [1] PDN-GW-Identity OPTIONAL, + contextId [2] ContextId OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ... } + +ISR-Information::= BIT STRING { + updateMME (0), + cancelSGSN (1)} (SIZE (2..8)) + -- exception handling: reception of unknown bit assignments in the + -- ISR-Information data type shall be discarded by the receiver + +SGSN-Capability ::= SEQUENCE{ + solsaSupportIndicator NULL OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ... , + superChargerSupportedInServingNetworkEntity [2] SuperChargerInfo OPTIONAL , + gprsEnhancementsSupportIndicator [3] NULL OPTIONAL, + supportedCamelPhases [4] SupportedCamelPhases OPTIONAL, + supportedLCS-CapabilitySets [5] SupportedLCS-CapabilitySets OPTIONAL, + offeredCamel4CSIs [6] OfferedCamel4CSIs OPTIONAL, + smsCallBarringSupportIndicator [7] NULL OPTIONAL, supportedRAT-TypesIndicator [8] SupportedRAT-Types OPTIONAL, + supportedFeatures [9] SupportedFeatures OPTIONAL } + +SupportedFeatures::= BIT STRING { + odb-all (0), + odb-HPLMN-APN (1), + odb-VPLMN-APN (2), + regSub (3)} (SIZE (4..8)) + +GSN-Address ::= OCTET STRING (SIZE (5..17)) + -- Octets are coded according to TS 3GPP TS 23.003 [17] + +UpdateGprsLocationRes ::= SEQUENCE { + hlr-Number ISDN-AddressString, + extensionContainer ExtensionContainer OPTIONAL, + ..., + add-Capability NULL OPTIONAL, + sgsn-mmeSeparationSupported [0] NULL OPTIONAL } + +-- handover types + +ForwardAccessSignalling-Arg ::= [3] SEQUENCE { + an-APDU AccessNetworkSignalInfo, + integrityProtectionInfo [0] IntegrityProtectionInformation OPTIONAL, + encryptionInfo [1] EncryptionInformation OPTIONAL, + keyStatus [2] KeyStatus OPTIONAL, + allowedGSM-Algorithms [4] AllowedGSM-Algorithms OPTIONAL, + allowedUMTS-Algorithms [5] AllowedUMTS-Algorithms OPTIONAL, + radioResourceInformation [6] RadioResourceInformation OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ..., + radioResourceList [7] RadioResourceList OPTIONAL, + bssmap-ServiceHandover [9] BSSMAP-ServiceHandover OPTIONAL, + ranap-ServiceHandover [8] RANAP-ServiceHandover OPTIONAL, + bssmap-ServiceHandoverList [10] BSSMAP-ServiceHandoverList OPTIONAL, + currentlyUsedCodec [11] Codec OPTIONAL, + iuSupportedCodecsList [12] SupportedCodecsList OPTIONAL, + rab-ConfigurationIndicator [13] NULL OPTIONAL, + iuSelectedCodec [14] Codec OPTIONAL, + alternativeChannelType [15] RadioResourceInformation OPTIONAL, + tracePropagationList [17] TracePropagationList OPTIONAL } + +AllowedGSM-Algorithms ::= OCTET STRING (SIZE (1)) + -- internal structure is coded as Algorithm identifier octet from + -- Permitted Algorithms defined in 3GPP TS 48.008 + -- A node shall mark all GSM algorithms that are allowed in MSC-B + +AllowedUMTS-Algorithms ::= SEQUENCE { + integrityProtectionAlgorithms [0] PermittedIntegrityProtectionAlgorithms OPTIONAL, + encryptionAlgorithms [1] PermittedEncryptionAlgorithms OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +PermittedIntegrityProtectionAlgorithms ::= + OCTET STRING (SIZE (1..maxPermittedIntegrityProtectionAlgorithmsLength)) + -- Octets contain a complete PermittedIntegrityProtectionAlgorithms data type + -- as defined in 3GPP TS 25.413, encoded according to the encoding scheme + -- mandated by 3GPP TS 25.413. + -- Padding bits are included, if needed, in the least significant bits of the + -- last octet of the octet string. + + +maxPermittedIntegrityProtectionAlgorithmsLength INTEGER ::= 9 + +PermittedEncryptionAlgorithms ::= + OCTET STRING (SIZE (1..maxPermittedEncryptionAlgorithmsLength)) + -- Octets contain a complete PermittedEncryptionAlgorithms data type + -- as defined in 3GPP TS 25.413, encoded according to the encoding scheme + -- mandated by 3GPP TS 25.413 + -- Padding bits are included, if needed, in the least significant bits of the + -- last octet of the octet string. + + +maxPermittedEncryptionAlgorithmsLength INTEGER ::= 9 + +KeyStatus ::= ENUMERATED { + old (0), + new (1), + ...} + -- exception handling: + -- received values in range 2-31 shall be treated as "old" + -- received values greater than 31 shall be treated as "new" + +PrepareHO-Arg ::= [3] SEQUENCE { + targetCellId [0] GlobalCellId OPTIONAL, + ho-NumberNotRequired NULL OPTIONAL, + targetRNCId [1] RNCId OPTIONAL, + an-APDU [2] AccessNetworkSignalInfo OPTIONAL, + multipleBearerRequested [3] NULL OPTIONAL, + imsi [4] IMSI OPTIONAL, + integrityProtectionInfo [5] IntegrityProtectionInformation OPTIONAL, + encryptionInfo [6] EncryptionInformation OPTIONAL, + radioResourceInformation [7] RadioResourceInformation OPTIONAL, + allowedGSM-Algorithms [9] AllowedGSM-Algorithms OPTIONAL, + allowedUMTS-Algorithms [10] AllowedUMTS-Algorithms OPTIONAL, + radioResourceList [11] RadioResourceList OPTIONAL, + extensionContainer [8] ExtensionContainer OPTIONAL, + ... , + rab-Id [12] RAB-Id OPTIONAL, + bssmap-ServiceHandover [13] BSSMAP-ServiceHandover OPTIONAL, + ranap-ServiceHandover [14] RANAP-ServiceHandover OPTIONAL, + bssmap-ServiceHandoverList [15] BSSMAP-ServiceHandoverList OPTIONAL, + asciCallReference [20] ASCI-CallReference OPTIONAL, + geran-classmark [16] GERAN-Classmark OPTIONAL, + iuCurrentlyUsedCodec [17] Codec OPTIONAL, + iuSupportedCodecsList [18] SupportedCodecsList OPTIONAL, + rab-ConfigurationIndicator [19] NULL OPTIONAL, + uesbi-Iu [21] UESBI-Iu OPTIONAL, + imeisv [22] IMEI OPTIONAL, + alternativeChannelType [23] RadioResourceInformation OPTIONAL, + tracePropagationList [25] TracePropagationList OPTIONAL } + +BSSMAP-ServiceHandoverList ::= SEQUENCE SIZE (1.. maxNumOfServiceHandovers) OF + BSSMAP-ServiceHandoverInfo + +BSSMAP-ServiceHandoverInfo ::= SEQUENCE { + bssmap-ServiceHandover BSSMAP-ServiceHandover, + rab-Id RAB-Id, + -- RAB Identity is needed to relate the service handovers with the radio access bearers. + ...} + +maxNumOfServiceHandovers INTEGER ::= 7 + +BSSMAP-ServiceHandover ::= OCTET STRING (SIZE (1)) + -- Octets are coded according the Service Handover information element in + -- 3GPP TS 48.008. + +RANAP-ServiceHandover ::= OCTET STRING (SIZE (1)) + -- Octet contains a complete Service-Handover data type + -- as defined in 3GPP TS 25.413, encoded according to the encoding scheme + -- mandated by 3GPP TS 25.413 + -- Padding bits are included in the least significant bits. + + +RadioResourceList ::= SEQUENCE SIZE (1.. maxNumOfRadioResources) OF + RadioResource + +RadioResource ::= SEQUENCE { + radioResourceInformation RadioResourceInformation, + rab-Id RAB-Id, + -- RAB Identity is needed to relate the radio resources with the radio access bearers. + ...} + +maxNumOfRadioResources INTEGER ::= 7 + +PrepareHO-Res ::= [3] SEQUENCE { + handoverNumber [0] ISDN-AddressString OPTIONAL, + relocationNumberList [1] RelocationNumberList OPTIONAL, + an-APDU [2] AccessNetworkSignalInfo OPTIONAL, + multicallBearerInfo [3] MulticallBearerInfo OPTIONAL, + multipleBearerNotSupported NULL OPTIONAL, + selectedUMTS-Algorithms [5] SelectedUMTS-Algorithms OPTIONAL, + chosenRadioResourceInformation [6] ChosenRadioResourceInformation OPTIONAL, + extensionContainer [4] ExtensionContainer OPTIONAL, + ..., + iuSelectedCodec [7] Codec OPTIONAL, + iuAvailableCodecsList [8] CodecList OPTIONAL } + +SelectedUMTS-Algorithms ::= SEQUENCE { + integrityProtectionAlgorithm [0] ChosenIntegrityProtectionAlgorithm OPTIONAL, + encryptionAlgorithm [1] ChosenEncryptionAlgorithm OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +ChosenIntegrityProtectionAlgorithm ::= OCTET STRING (SIZE (1)) + -- Octet contains a complete IntegrityProtectionAlgorithm data type + -- as defined in 3GPP TS 25.413, encoded according to the encoding scheme + -- mandated by 3GPP TS 25.413 + -- Padding bits are included in the least significant bits. + +ChosenEncryptionAlgorithm ::= OCTET STRING (SIZE (1)) + -- Octet contains a complete EncryptionAlgorithm data type + -- as defined in 3GPP TS 25.413, encoded according to the encoding scheme + -- mandated by 3GPP TS 25.413 + -- Padding bits are included in the least significant bits. + +ChosenRadioResourceInformation ::= SEQUENCE { + chosenChannelInfo [0] ChosenChannelInfo OPTIONAL, + chosenSpeechVersion [1] ChosenSpeechVersion OPTIONAL, + ...} + +ChosenChannelInfo ::= OCTET STRING (SIZE (1)) + -- Octets are coded according the Chosen Channel information element in 3GPP TS 48.008 + +ChosenSpeechVersion ::= OCTET STRING (SIZE (1)) + -- Octets are coded according the Speech Version (chosen) information element in 3GPP TS + -- 48.008 + +PrepareSubsequentHO-Arg ::= [3] SEQUENCE { + targetCellId [0] GlobalCellId OPTIONAL, + targetMSC-Number [1] ISDN-AddressString, + targetRNCId [2] RNCId OPTIONAL, + an-APDU [3] AccessNetworkSignalInfo OPTIONAL, + selectedRab-Id [4] RAB-Id OPTIONAL, + extensionContainer [5] ExtensionContainer OPTIONAL, + ..., + geran-classmark [6] GERAN-Classmark OPTIONAL, + rab-ConfigurationIndicator [7] NULL OPTIONAL } + +PrepareSubsequentHO-Res ::= [3] SEQUENCE { + an-APDU AccessNetworkSignalInfo, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +ProcessAccessSignalling-Arg ::= [3] SEQUENCE { + an-APDU AccessNetworkSignalInfo, + selectedUMTS-Algorithms [1] SelectedUMTS-Algorithms OPTIONAL, + selectedGSM-Algorithm [2] SelectedGSM-Algorithm OPTIONAL, + chosenRadioResourceInformation [3] ChosenRadioResourceInformation OPTIONAL, + selectedRab-Id [4] RAB-Id OPTIONAL, + extensionContainer [0] ExtensionContainer OPTIONAL, + ..., + iUSelectedCodec [5] Codec OPTIONAL, + iuAvailableCodecsList [6] CodecList OPTIONAL } + +SupportedCodecsList ::= SEQUENCE { + utranCodecList [0] CodecList OPTIONAL, + geranCodecList [1] CodecList OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +CodecList ::= SEQUENCE { + codec1 [1] Codec, + codec2 [2] Codec OPTIONAL, + codec3 [3] Codec OPTIONAL, + codec4 [4] Codec OPTIONAL, + codec5 [5] Codec OPTIONAL, + codec6 [6] Codec OPTIONAL, + codec7 [7] Codec OPTIONAL, + codec8 [8] Codec OPTIONAL, + extensionContainer [9] ExtensionContainer OPTIONAL, + ...} + -- Codecs are sent in priority order where codec1 has highest priority + +Codec ::= OCTET STRING (SIZE (1..4)) + + -- The internal structure is defined as follows: + -- octet 1 Coded as Codec Identification code in 3GPP TS 26.103 + -- octets 2,3,4 Parameters for the Codec as defined in 3GPP TS + -- 26.103, if available, length depending on the codec + +GERAN-Classmark ::= OCTET STRING (SIZE (2..87)) + -- Octets are coded according the GERAN Classmark information element in 3GPP TS 48.008 + +SelectedGSM-Algorithm ::= OCTET STRING (SIZE (1)) + -- internal structure is coded as Algorithm identifier octet from Chosen Encryption + -- Algorithm defined in 3GPP TS 48.008 + -- A node shall mark only the selected GSM algorithm + +SendEndSignal-Arg ::= [3] SEQUENCE { + an-APDU AccessNetworkSignalInfo, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +SendEndSignal-Res ::= SEQUENCE { + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +RNCId ::= OCTET STRING (SIZE (7)) + -- The internal structure is defined as follows: + -- octet 1 bits 4321 Mobile Country Code 1st digit + -- bits 8765 Mobile Country Code 2nd digit + -- octet 2 bits 4321 Mobile Country Code 3rd digit + -- bits 8765 Mobile Network Code 3rd digit + -- or filler (1111) for 2 digit MNCs + -- octet 3 bits 4321 Mobile Network Code 1st digit + -- bits 8765 Mobile Network Code 2nd digit + -- octets 4 and 5 Location Area Code according to 3GPP TS 24.008 + -- octets 6 and 7 RNC Id value according to 3GPP TS 25.413 + +RelocationNumberList ::= SEQUENCE SIZE (1..maxNumOfRelocationNumber) OF + RelocationNumber + +MulticallBearerInfo ::= INTEGER (1..maxNumOfRelocationNumber) + +RelocationNumber ::= SEQUENCE { + handoverNumber ISDN-AddressString, + rab-Id RAB-Id, + -- RAB Identity is needed to relate the calls with the radio access bearers. + ...} + +RAB-Id ::= INTEGER (1..maxNrOfRABs) + +maxNrOfRABs INTEGER ::= 255 + +maxNumOfRelocationNumber INTEGER ::= 7 + +RadioResourceInformation ::= OCTET STRING (SIZE (3..13)) + -- Octets are coded according the Channel Type information element in 3GPP TS 48.008 + +IntegrityProtectionInformation ::= OCTET STRING (SIZE (18..maxNumOfIntegrityInfo)) + -- Octets contain a complete IntegrityProtectionInformation data type + -- as defined in 3GPP TS 25.413, encoded according to the encoding scheme + -- mandated by 3GPP TS 25.413 + -- Padding bits are included, if needed, in the least significant bits of the + -- last octet of the octet string. + +maxNumOfIntegrityInfo INTEGER ::= 100 + +EncryptionInformation ::= OCTET STRING (SIZE (18..maxNumOfEncryptionInfo)) + -- Octets contain a complete EncryptionInformation data type + -- as defined in 3GPP TS 25.413, encoded according to the encoding scheme + -- mandated by 3GPP TS 25.413 + -- Padding bits are included, if needed, in the least significant bits of the + -- last octet of the octet string. + +maxNumOfEncryptionInfo INTEGER ::= 100 + +-- authentication management types + +SendAuthenticationInfoArg ::= SEQUENCE { + imsi [0] IMSI, + numberOfRequestedVectors NumberOfRequestedVectors, + segmentationProhibited NULL OPTIONAL, + immediateResponsePreferred [1] NULL OPTIONAL, + re-synchronisationInfo Re-synchronisationInfo OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ..., + requestingNodeType [3] RequestingNodeType OPTIONAL, + requestingPLMN-Id [4] PLMN-Id OPTIONAL, + numberOfRequestedAdditional-Vectors [5] NumberOfRequestedVectors OPTIONAL, + additionalVectorsAreForEPS [6] NULL OPTIONAL } + + +NumberOfRequestedVectors ::= INTEGER (1..5) + +Re-synchronisationInfo ::= SEQUENCE { + rand RAND, + auts AUTS, + ...} + +SendAuthenticationInfoRes ::= [3] SEQUENCE { + authenticationSetList AuthenticationSetList OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + eps-AuthenticationSetList [2] EPS-AuthenticationSetList OPTIONAL } + +EPS-AuthenticationSetList ::= SEQUENCE SIZE (1..5) OF + EPC-AV + +EPC-AV ::= SEQUENCE { + rand RAND, + xres XRES, + autn AUTN, + kasme KASME, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +KASME ::= OCTET STRING (SIZE (16)) + +RequestingNodeType ::= ENUMERATED { + vlr (0), + sgsn (1), + ..., + s-cscf (2), + bsf (3), + gan-aaa-server (4), + wlan-aaa-server (5), + mme (16), + mme-sgsn (17) + } + -- the values 2, 3, 4 and 5 shall not be used on the MAP-D or Gr interfaces + -- exception handling: + -- received values in the range (6-15) shall be treated as "vlr" + -- received values greater than 17 shall be treated as "sgsn" + +-- equipment management types + +CheckIMEI-Arg ::= SEQUENCE { + imei IMEI, + requestedEquipmentInfo RequestedEquipmentInfo, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +CheckIMEI-Res ::= SEQUENCE { + equipmentStatus EquipmentStatus OPTIONAL, + bmuef UESBI-Iu OPTIONAL, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +RequestedEquipmentInfo::= BIT STRING { + equipmentStatus (0), + bmuef (1)} (SIZE (2..8)) + -- exception handling: reception of unknown bit assignments in the + -- RequestedEquipmentInfo data type shall be discarded by the receiver + +UESBI-Iu ::= SEQUENCE { + uesbi-IuA [0] UESBI-IuA OPTIONAL, + uesbi-IuB [1] UESBI-IuB OPTIONAL, + ...} + +UESBI-IuA ::= BIT STRING (SIZE(1..128)) +-- See 3GPP TS 25.413 + +UESBI-IuB ::= BIT STRING (SIZE(1..128)) +-- See 3GPP TS 25.413 + +EquipmentStatus ::= ENUMERATED { + whiteListed (0), + blackListed (1), + greyListed (2)} + +-- subscriber management types + +InsertSubscriberDataArg ::= SEQUENCE { + imsi [0] IMSI OPTIONAL, + COMPONENTS OF SubscriberData, + extensionContainer [14] ExtensionContainer OPTIONAL, + ... , + naea-PreferredCI [15] NAEA-PreferredCI OPTIONAL, + -- naea-PreferredCI is included at the discretion of the HLR operator. + gprsSubscriptionData [16] GPRSSubscriptionData OPTIONAL, + roamingRestrictedInSgsnDueToUnsupportedFeature [23] NULL + OPTIONAL, + networkAccessMode [24] NetworkAccessMode OPTIONAL, + lsaInformation [25] LSAInformation OPTIONAL, + lmu-Indicator [21] NULL OPTIONAL, + lcsInformation [22] LCSInformation OPTIONAL, + istAlertTimer [26] IST-AlertTimerValue OPTIONAL, + superChargerSupportedInHLR [27] AgeIndicator OPTIONAL, + mc-SS-Info [28] MC-SS-Info OPTIONAL, + cs-AllocationRetentionPriority [29] CS-AllocationRetentionPriority OPTIONAL, + sgsn-CAMEL-SubscriptionInfo [17] SGSN-CAMEL-SubscriptionInfo OPTIONAL, + chargingCharacteristics [18] ChargingCharacteristics OPTIONAL, + accessRestrictionData [19] AccessRestrictionData OPTIONAL, + ics-Indicator [20] BOOLEAN OPTIONAL, + eps-SubscriptionData [31] EPS-SubscriptionData OPTIONAL, + csg-SubscriptionDataList [32] CSG-SubscriptionDataList OPTIONAL } + -- If the Network Access Mode parameter is sent, it shall be present only in + -- the first sequence if seqmentation is used + +CSG-SubscriptionDataList ::= SEQUENCE SIZE (1..50) OF + CSG-SubscriptionData + +CSG-SubscriptionData ::= SEQUENCE { + csg-Id CSG-Id, + expirationDate Time OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +CSG-Id ::= BIT STRING (SIZE (27)) + -- coded according to 3GPP TS 23.003 [17]. + +Time ::= OCTET STRING (SIZE (4)) + -- Octets are coded according to IETF RFC 3588 [139] + + +EPS-SubscriptionData ::= SEQUENCE { + apn-oi-Replacement [0] APN-OI-Replacement OPTIONAL, + rfsp-id [2] RFSP-ID OPTIONAL, + ambr [3] AMBR OPTIONAL, + apn-ConfigurationProfile [4] APN-ConfigurationProfile OPTIONAL, + stn-sr [6] ISDN-AddressString OPTIONAL, + extensionContainer [5] ExtensionContainer OPTIONAL, + ... } + +APN-OI-Replacement ::= OCTET STRING (SIZE (9..100)) + -- Octets are coded as APN Operator Identifier according to TS 3GPP TS 23.003 [17] + +RFSP-ID ::= INTEGER (1..256) + +APN-ConfigurationProfile ::= SEQUENCE { + defaultContext ContextId, + completeDataListIncluded NULL OPTIONAL, + -- If segmentation is used, completeDataListIncluded may only be present in the + -- first segment of APN-ConfigurationProfile. + epsDataList [1] EPS-DataList, + extensionContainer [2] ExtensionContainer OPTIONAL, + ... } + +EPS-DataList ::= SEQUENCE SIZE (1..maxNumOfAPN-Configurations) OF + APN-Configuration + + +maxNumOfAPN-Configurations INTEGER ::= 50 + + +APN-Configuration ::= SEQUENCE { + contextId [0] ContextId, + servedPartyIP-Address [1] PDP-Address OPTIONAL, + apn [2] APN, + eps-qos-Subscribed [3] EPS-QoS-Subscribed, + pdn-gw-Identity [4] PDN-GW-Identity OPTIONAL, + pdn-gw-AllocationType [5] PDN-GW-AllocationType OPTIONAL, + vplmnAddressAllowed [6] NULL OPTIONAL, + chargingCharacteristics [7] ChargingCharacteristics OPTIONAL, + ambr [8] AMBR OPTIONAL, + specificAPNInfoList [9] SpecificAPNInfoList OPTIONAL, extensionContainer [10] ExtensionContainer OPTIONAL, + ... } + +EPS-QoS-Subscribed ::= SEQUENCE { + qos-Class-Identifier [0] QoS-Class-Identifier, + allocation-Retention-Priority [1] Allocation-Retention-Priority, + extensionContainer [2] ExtensionContainer OPTIONAL, + ... } + +AMBR ::= SEQUENCE { + max-RequestedBandwidth-UL [0] Bandwidth, + max-RequestedBandwidth-DL [1] Bandwidth, + extensionContainer [2] ExtensionContainer OPTIONAL, + ... } + + +SpecificAPNInfoList ::= SEQUENCE SIZE (1..maxNumOfSpecificAPNInfos) OF + SpecificAPNInfo + +maxNumOfSpecificAPNInfos INTEGER ::= 50 + +SpecificAPNInfo ::= SEQUENCE { + apn [0] APN, + pdn-gw-Identity [1] PDN-GW-Identity, + extensionContainer [2] ExtensionContainer OPTIONAL, + ... } + +Bandwidth ::= INTEGER + -- bits per second + +QoS-Class-Identifier ::= INTEGER (1..9) + -- values are defined in 3GPP TS 29.212 + + + +Allocation-Retention-Priority ::= SEQUENCE { + priority-level [0] INTEGER, + pre-emption-capability [1] BOOLEAN OPTIONAL, + pre-emption-vulnerability [2] BOOLEAN OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ... } + +PDN-GW-Identity ::= SEQUENCE { + pdn-gw-ipv4-Address [0] PDP-Address OPTIONAL, + pdn-gw-ipv6-Address [1] PDP-Address OPTIONAL, + pdn-gw-name [2] FQDN OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ... } + +FQDN ::= OCTET STRING (SIZE (9..100)) + + +PDN-GW-AllocationType ::= ENUMERATED { + static (0), + dynamic (1)} + + +AccessRestrictionData ::= BIT STRING { + utranNotAllowed (0), + geranNotAllowed (1), + ganNotAllowed (2), + i-hspa-evolutionNotAllowed (3), + e-utranNotAllowed (4), + ho-toNon3GPP-AccessNotAllowed (5) } (SIZE (2..8)) + -- exception handling: + -- access restriction data related to an access type not supported by a node + -- shall be ignored + -- bits 6 to 7 shall be ignored if received and not understood + + +CS-AllocationRetentionPriority ::= OCTET STRING (SIZE (1)) + -- This data type encodes each priority level defined in TS 23.107 as the binary value + -- of the priority level. + +IST-AlertTimerValue ::= INTEGER (15..255) + +LCSInformation ::= SEQUENCE { + gmlc-List [0] GMLC-List OPTIONAL, + lcs-PrivacyExceptionList [1] LCS-PrivacyExceptionList OPTIONAL, + molr-List [2] MOLR-List OPTIONAL, + ..., + add-lcs-PrivacyExceptionList [3] LCS-PrivacyExceptionList OPTIONAL } + -- add-lcs-PrivacyExceptionList may be sent only if lcs-PrivacyExceptionList is + -- present and contains four instances of LCS-PrivacyClass. If the mentioned condition + -- is not satisfied the receiving node shall discard add-lcs-PrivacyExceptionList. + -- If an LCS-PrivacyClass is received both in lcs-PrivacyExceptionList and in + -- add-lcs-PrivacyExceptionList with the same SS-Code, then the error unexpected + -- data value shall be returned. + +GMLC-List ::= SEQUENCE SIZE (1..maxNumOfGMLC) OF + ISDN-AddressString + -- if segmentation is used, the complete GMLC-List shall be sent in one segment + +maxNumOfGMLC INTEGER ::= 5 + +NetworkAccessMode ::= ENUMERATED { + packetAndCircuit (0), + onlyCircuit (1), + onlyPacket (2), + ...} + -- if unknown values are received in NetworkAccessMode + -- they shall be discarded. + +GPRSDataList ::= SEQUENCE SIZE (1..maxNumOfPDP-Contexts) OF + PDP-Context + +maxNumOfPDP-Contexts INTEGER ::= 50 + +PDP-Context ::= SEQUENCE { + pdp-ContextId ContextId, + pdp-Type [16] PDP-Type, + pdp-Address [17] PDP-Address OPTIONAL, + qos-Subscribed [18] QoS-Subscribed, + vplmnAddressAllowed [19] NULL OPTIONAL, + apn [20] APN, + extensionContainer [21] ExtensionContainer OPTIONAL, + ... , + ext-QoS-Subscribed [0] Ext-QoS-Subscribed OPTIONAL, + pdp-ChargingCharacteristics [1] ChargingCharacteristics OPTIONAL, + ext2-QoS-Subscribed [2] Ext2-QoS-Subscribed OPTIONAL, + -- ext2-QoS-Subscribed may be present only if ext-QoS-Subscribed is present. + ext3-QoS-Subscribed [3] Ext3-QoS-Subscribed OPTIONAL + -- ext3-QoS-Subscribed may be present only if ext2-QoS-Subscribed is present. + } + +ContextId ::= INTEGER (1..maxNumOfPDP-Contexts) + +GPRSSubscriptionData ::= SEQUENCE { + completeDataListIncluded NULL OPTIONAL, + -- If segmentation is used, completeDataListIncluded may only be present in the + -- first segment of GPRSSubscriptionData. + gprsDataList [1] GPRSDataList, + extensionContainer [2] ExtensionContainer OPTIONAL, + ... } + +SGSN-CAMEL-SubscriptionInfo ::= SEQUENCE { + gprs-CSI [0] GPRS-CSI OPTIONAL, + mo-sms-CSI [1] SMS-CSI OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ..., + mt-sms-CSI [3] SMS-CSI OPTIONAL, + mt-smsCAMELTDP-CriteriaList [4] MT-smsCAMELTDP-CriteriaList OPTIONAL, + mg-csi [5] MG-CSI OPTIONAL + } + +GPRS-CSI ::= SEQUENCE { + gprs-CamelTDPDataList [0] GPRS-CamelTDPDataList OPTIONAL, + camelCapabilityHandling [1] CamelCapabilityHandling OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + notificationToCSE [3] NULL OPTIONAL, + csi-Active [4] NULL OPTIONAL, + ...} +-- notificationToCSE and csi-Active shall not be present when GPRS-CSI is sent to SGSN. +-- They may only be included in ATSI/ATM ack/NSDC message. +-- GPRS-CamelTDPData and camelCapabilityHandling shall be present in +-- the GPRS-CSI sequence. +-- If GPRS-CSI is segmented, gprs-CamelTDPDataList and camelCapabilityHandling shall be +-- present in the first segment + +GPRS-CamelTDPDataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF + GPRS-CamelTDPData +-- GPRS-CamelTDPDataList shall not contain more than one instance of +-- GPRS-CamelTDPData containing the same value for gprs-TriggerDetectionPoint. + +GPRS-CamelTDPData ::= SEQUENCE { + gprs-TriggerDetectionPoint [0] GPRS-TriggerDetectionPoint, + serviceKey [1] ServiceKey, + gsmSCF-Address [2] ISDN-AddressString, + defaultSessionHandling [3] DefaultGPRS-Handling, + extensionContainer [4] ExtensionContainer OPTIONAL, + ... + } + +DefaultGPRS-Handling ::= ENUMERATED { + continueTransaction (0) , + releaseTransaction (1) , + ...} +-- exception handling: +-- reception of values in range 2-31 shall be treated as "continueTransaction" +-- reception of values greater than 31 shall be treated as "releaseTransaction" + +GPRS-TriggerDetectionPoint ::= ENUMERATED { + attach (1), + attachChangeOfPosition (2), + pdp-ContextEstablishment (11), + pdp-ContextEstablishmentAcknowledgement (12), + pdp-ContextChangeOfPosition (14), + ... } +-- exception handling: +-- For GPRS-CamelTDPData sequences containing this parameter with any +-- other value than the ones listed the receiver shall ignore the whole +-- GPRS-CamelTDPDatasequence. + +APN ::= OCTET STRING (SIZE (2..63)) + -- Octets are coded according to TS 3GPP TS 23.003 [17] + +PDP-Type ::= OCTET STRING (SIZE (2)) + -- Octets are coded according to TS 3GPP TS 29.060 [105] + +PDP-Address ::= OCTET STRING (SIZE (1..16)) + -- Octets are coded according to TS 3GPP TS 29.060 [105] + + -- The possible size values are: + -- 1-7 octets X.25 address type + -- 4 octets IPv4 address type + -- 16 octets Ipv6 address type + +QoS-Subscribed ::= OCTET STRING (SIZE (3)) + -- Octets are coded according to TS 3GPP TS 24.008 [35] Quality of Service Octets + -- 3-5. + +Ext-QoS-Subscribed ::= OCTET STRING (SIZE (1..9)) + -- OCTET 1: + -- Allocation/Retention Priority (This octet encodes each priority level defined in + -- 23.107 as the binary value of the priority level, declaration in 29.060) + -- Octets 2-9 are coded according to 3GPP TS 24.008 [35] Quality of Service Octets + -- 6-13. + +Ext2-QoS-Subscribed ::= OCTET STRING (SIZE (1..3)) + -- Octets 1-3 are coded according to 3GPP TS 24.008 [35] Quality of Service Octets 14-16. + -- If Quality of Service information is structured with 14 octet length, then + -- Octet 1 is coded according to 3GPP TS 24.008 [35] Quality of Service Octet 14. + +Ext3-QoS-Subscribed ::= OCTET STRING (SIZE (1..2)) + -- Octets 1-2 are coded according to 3GPP TS 24.008 [35] Quality of Service Octets 17-18. + +ChargingCharacteristics ::= OCTET STRING (SIZE (2)) + -- Octets are coded according to 3GPP TS 32.215. + +LSAOnlyAccessIndicator ::= ENUMERATED { + accessOutsideLSAsAllowed (0), + accessOutsideLSAsRestricted (1)} + +LSADataList ::= SEQUENCE SIZE (1..maxNumOfLSAs) OF + LSAData + +maxNumOfLSAs INTEGER ::= 20 + +LSAData ::= SEQUENCE { + lsaIdentity [0] LSAIdentity, + lsaAttributes [1] LSAAttributes, + lsaActiveModeIndicator [2] NULL OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +LSAInformation ::= SEQUENCE { + completeDataListIncluded NULL OPTIONAL, + + -- If segmentation is used, completeDataListIncluded may only be present in the + -- first segment. + lsaOnlyAccessIndicator [1] LSAOnlyAccessIndicator OPTIONAL, + lsaDataList [2] LSADataList OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +LSAIdentity ::= OCTET STRING (SIZE (3)) + -- Octets are coded according to TS 3GPP TS 23.003 [17] + +LSAAttributes ::= OCTET STRING (SIZE (1)) + -- Octets are coded according to TS 3GPP TS 48.008 [49] + +SubscriberData ::= SEQUENCE { + msisdn [1] ISDN-AddressString OPTIONAL, + category [2] Category OPTIONAL, + subscriberStatus [3] SubscriberStatus OPTIONAL, + bearerServiceList [4] BearerServiceList OPTIONAL, + -- The exception handling for reception of unsupported / not allocated + -- bearerServiceCodes is defined in section 8.8.1 + teleserviceList [6] TeleserviceList OPTIONAL, + -- The exception handling for reception of unsupported / not allocated + -- teleserviceCodes is defined in section 8.8.1 + provisionedSS [7] Ext-SS-InfoList OPTIONAL, + odb-Data [8] ODB-Data OPTIONAL, + roamingRestrictionDueToUnsupportedFeature [9] NULL OPTIONAL, + regionalSubscriptionData [10] ZoneCodeList OPTIONAL, + vbsSubscriptionData [11] VBSDataList OPTIONAL, + vgcsSubscriptionData [12] VGCSDataList OPTIONAL, + vlrCamelSubscriptionInfo [13] VlrCamelSubscriptionInfo OPTIONAL + } + +Category ::= OCTET STRING (SIZE (1)) + -- The internal structure is defined in ITU-T Rec Q.763. + +SubscriberStatus ::= ENUMERATED { + serviceGranted (0), + operatorDeterminedBarring (1)} + +BearerServiceList ::= SEQUENCE SIZE (1..maxNumOfBearerServices) OF + Ext-BearerServiceCode + +maxNumOfBearerServices INTEGER ::= 50 + +TeleserviceList ::= SEQUENCE SIZE (1..maxNumOfTeleservices) OF + Ext-TeleserviceCode + +maxNumOfTeleservices INTEGER ::= 20 + +ODB-Data ::= SEQUENCE { + odb-GeneralData ODB-GeneralData, + odb-HPLMN-Data ODB-HPLMN-Data OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +ODB-GeneralData ::= BIT STRING { + allOG-CallsBarred (0), + internationalOGCallsBarred (1), + internationalOGCallsNotToHPLMN-CountryBarred (2), + interzonalOGCallsBarred (6), + interzonalOGCallsNotToHPLMN-CountryBarred (7), + interzonalOGCallsAndInternationalOGCallsNotToHPLMN-CountryBarred (8), + premiumRateInformationOGCallsBarred (3), + premiumRateEntertainementOGCallsBarred (4), + ss-AccessBarred (5), + allECT-Barred (9), + chargeableECT-Barred (10), + internationalECT-Barred (11), + interzonalECT-Barred (12), + doublyChargeableECT-Barred (13), + multipleECT-Barred (14), + allPacketOrientedServicesBarred (15), + roamerAccessToHPLMN-AP-Barred (16), + roamerAccessToVPLMN-AP-Barred (17), + roamingOutsidePLMNOG-CallsBarred (18), + allIC-CallsBarred (19), + roamingOutsidePLMNIC-CallsBarred (20), + roamingOutsidePLMNICountryIC-CallsBarred (21), + roamingOutsidePLMN-Barred (22), + roamingOutsidePLMN-CountryBarred (23), + registrationAllCF-Barred (24), + registrationCFNotToHPLMN-Barred (25), + registrationInterzonalCF-Barred (26), + registrationInterzonalCFNotToHPLMN-Barred (27), + registrationInternationalCF-Barred (28)} (SIZE (15..32)) + -- exception handling: reception of unknown bit assignments in the + -- ODB-GeneralData type shall be treated like unsupported ODB-GeneralData + -- When the ODB-GeneralData type is removed from the HLR for a given subscriber, + -- in NoteSubscriberDataModified operation sent toward the gsmSCF + -- all bits shall be set to "O". + +ODB-HPLMN-Data ::= BIT STRING { + plmn-SpecificBarringType1 (0), + plmn-SpecificBarringType2 (1), + plmn-SpecificBarringType3 (2), + plmn-SpecificBarringType4 (3)} (SIZE (4..32)) + -- exception handling: reception of unknown bit assignments in the + -- ODB-HPLMN-Data type shall be treated like unsupported ODB-HPLMN-Data + -- When the ODB-HPLMN-Data type is removed from the HLR for a given subscriber, + -- in NoteSubscriberDataModified operation sent toward the gsmSCF + -- all bits shall be set to "O". + +Ext-SS-InfoList ::= SEQUENCE SIZE (1..maxNumOfSS) OF + Ext-SS-Info + +Ext-SS-Info ::= CHOICE { + forwardingInfo [0] Ext-ForwInfo, + callBarringInfo [1] Ext-CallBarInfo, + cug-Info [2] CUG-Info, + ss-Data [3] Ext-SS-Data, + emlpp-Info [4] EMLPP-Info} + +Ext-ForwInfo ::= SEQUENCE { + ss-Code SS-Code, + forwardingFeatureList Ext-ForwFeatureList, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +Ext-ForwFeatureList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF + Ext-ForwFeature + +Ext-ForwFeature ::= SEQUENCE { + basicService Ext-BasicServiceCode OPTIONAL, + ss-Status [4] Ext-SS-Status, + forwardedToNumber [5] ISDN-AddressString OPTIONAL, + -- When this data type is sent from an HLR which supports CAMEL Phase 2 + -- to a VLR that supports CAMEL Phase 2 the VLR shall not check the + -- format of the number + forwardedToSubaddress [8] ISDN-SubaddressString OPTIONAL, + forwardingOptions [6] Ext-ForwOptions OPTIONAL, + noReplyConditionTime [7] Ext-NoRepCondTime OPTIONAL, + extensionContainer [9] ExtensionContainer OPTIONAL, + ..., + longForwardedToNumber [10] FTN-AddressString OPTIONAL } + +Ext-ForwOptions ::= OCTET STRING (SIZE (1..5)) + + -- OCTET 1: + + -- bit 8: notification to forwarding party + -- 0 no notification + -- 1 notification + + -- bit 7: redirecting presentation + -- 0 no presentation + -- 1 presentation + + -- bit 6: notification to calling party + -- 0 no notification + -- 1 notification + + -- bit 5: 0 (unused) + + -- bits 43: forwarding reason + -- 00 ms not reachable + -- 01 ms busy + -- 10 no reply + -- 11 unconditional + + -- bits 21: 00 (unused) + + -- OCTETS 2-5: reserved for future use. They shall be discarded if + -- received and not understood. + +Ext-NoRepCondTime ::= INTEGER (1..100) + -- Only values 5-30 are used. + -- Values in the ranges 1-4 and 31-100 are reserved for future use + -- If received: + -- values 1-4 shall be mapped on to value 5 + -- values 31-100 shall be mapped on to value 30 + +Ext-CallBarInfo ::= SEQUENCE { + ss-Code SS-Code, + callBarringFeatureList Ext-CallBarFeatureList, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +Ext-CallBarFeatureList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF + Ext-CallBarringFeature + +Ext-CallBarringFeature ::= SEQUENCE { + basicService Ext-BasicServiceCode OPTIONAL, + ss-Status [4] Ext-SS-Status, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +CUG-Info ::= SEQUENCE { + cug-SubscriptionList CUG-SubscriptionList, + cug-FeatureList CUG-FeatureList OPTIONAL, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +CUG-SubscriptionList ::= SEQUENCE SIZE (0..maxNumOfCUG) OF + CUG-Subscription + +CUG-Subscription ::= SEQUENCE { + cug-Index CUG-Index, + cug-Interlock CUG-Interlock, + intraCUG-Options IntraCUG-Options, + basicServiceGroupList Ext-BasicServiceGroupList OPTIONAL, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +CUG-Index ::= INTEGER (0..32767) + -- The internal structure is defined in ETS 300 138. + +CUG-Interlock ::= OCTET STRING (SIZE (4)) + +IntraCUG-Options ::= ENUMERATED { + noCUG-Restrictions (0), + cugIC-CallBarred (1), + cugOG-CallBarred (2)} + +maxNumOfCUG INTEGER ::= 10 + +CUG-FeatureList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF + CUG-Feature + +Ext-BasicServiceGroupList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF + Ext-BasicServiceCode + +maxNumOfExt-BasicServiceGroups INTEGER ::= 32 + +CUG-Feature ::= SEQUENCE { + basicService Ext-BasicServiceCode OPTIONAL, + preferentialCUG-Indicator CUG-Index OPTIONAL, + interCUG-Restrictions InterCUG-Restrictions, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +InterCUG-Restrictions ::= OCTET STRING (SIZE (1)) + + -- bits 876543: 000000 (unused) + -- Exception handling: + -- bits 876543 shall be ignored if received and not understood + + -- bits 21 + -- 00 CUG only facilities + -- 01 CUG with outgoing access + -- 10 CUG with incoming access + -- 11 CUG with both outgoing and incoming access + +Ext-SS-Data ::= SEQUENCE { + ss-Code SS-Code, + ss-Status [4] Ext-SS-Status, + ss-SubscriptionOption SS-SubscriptionOption OPTIONAL, + basicServiceGroupList Ext-BasicServiceGroupList OPTIONAL, + extensionContainer [5] ExtensionContainer OPTIONAL, + ...} + +LCS-PrivacyExceptionList ::= SEQUENCE SIZE (1..maxNumOfPrivacyClass) OF + LCS-PrivacyClass + +maxNumOfPrivacyClass INTEGER ::= 4 + +LCS-PrivacyClass ::= SEQUENCE { + ss-Code SS-Code, + ss-Status Ext-SS-Status, + notificationToMSUser [0] NotificationToMSUser OPTIONAL, + -- notificationToMSUser may be sent only for SS-codes callSessionRelated + -- and callSessionUnrelated. If not received for SS-codes callSessionRelated + -- and callSessionUnrelated, + -- the default values according to 3GPP TS 23.271 shall be assumed. + externalClientList [1] ExternalClientList OPTIONAL, + -- externalClientList may be sent only for SS-code callSessionUnrelated to a + -- visited node that does not support LCS Release 4 or later versions. + -- externalClientList may be sent only for SS-codes callSessionUnrelated and + -- callSessionRelated to a visited node that supports LCS Release 4 or later versions. + plmnClientList [2] PLMNClientList OPTIONAL, + -- plmnClientList may be sent only for SS-code plmnoperator. + extensionContainer [3] ExtensionContainer OPTIONAL, + ..., + ext-externalClientList [4] Ext-ExternalClientList OPTIONAL, + -- Ext-externalClientList may be sent only if the visited node supports LCS Release 4 or + -- later versions, the user did specify more than 5 clients, and White Book SCCP is used. + serviceTypeList [5] ServiceTypeList OPTIONAL + -- serviceTypeList may be sent only for SS-code serviceType and if the visited node + -- supports LCS Release 5 or later versions. + -- + -- if segmentation is used, the complete LCS-PrivacyClass shall be sent in one segment +} + +ExternalClientList ::= SEQUENCE SIZE (0..maxNumOfExternalClient) OF + ExternalClient + +maxNumOfExternalClient INTEGER ::= 5 + +PLMNClientList ::= SEQUENCE SIZE (1..maxNumOfPLMNClient) OF + LCSClientInternalID + +maxNumOfPLMNClient INTEGER ::= 5 + +Ext-ExternalClientList ::= SEQUENCE SIZE (1..maxNumOfExt-ExternalClient) OF + ExternalClient + +maxNumOfExt-ExternalClient INTEGER ::= 35 + +ExternalClient ::= SEQUENCE { + clientIdentity LCSClientExternalID, + gmlc-Restriction [0] GMLC-Restriction OPTIONAL, + notificationToMSUser [1] NotificationToMSUser OPTIONAL, + -- If notificationToMSUser is not received, the default value according to + -- 3GPP TS 23.271 shall be assumed. + extensionContainer [2] ExtensionContainer OPTIONAL, + ... } + +GMLC-Restriction ::= ENUMERATED { + gmlc-List (0), + home-Country (1) , + ... } +-- exception handling: +-- At reception of any other value than the ones listed the receiver shall ignore +-- GMLC-Restriction. + +NotificationToMSUser ::= ENUMERATED { + notifyLocationAllowed (0), + notifyAndVerify-LocationAllowedIfNoResponse (1), + notifyAndVerify-LocationNotAllowedIfNoResponse (2), + ..., + locationNotAllowed (3) } +-- exception handling: +-- At reception of any other value than the ones listed the receiver shall ignore +-- NotificationToMSUser. + +ServiceTypeList ::= SEQUENCE SIZE (1..maxNumOfServiceType) OF + ServiceType + +maxNumOfServiceType INTEGER ::= 32 + +ServiceType ::= SEQUENCE { + serviceTypeIdentity LCSServiceTypeID, + gmlc-Restriction [0] GMLC-Restriction OPTIONAL, + notificationToMSUser [1] NotificationToMSUser OPTIONAL, + -- If notificationToMSUser is not received, the default value according to + -- 3GPP TS 23.271 shall be assumed. + extensionContainer [2] ExtensionContainer OPTIONAL, + ... } + +MOLR-List ::= SEQUENCE SIZE (1..maxNumOfMOLR-Class) OF + MOLR-Class + +maxNumOfMOLR-Class INTEGER ::= 3 + +MOLR-Class ::= SEQUENCE { + ss-Code SS-Code, + ss-Status Ext-SS-Status, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +ZoneCodeList ::= SEQUENCE SIZE (1..maxNumOfZoneCodes) + OF ZoneCode + +ZoneCode ::= OCTET STRING (SIZE (2)) + -- internal structure is defined in TS 3GPP TS 23.003 [17] + +maxNumOfZoneCodes INTEGER ::= 10 + +InsertSubscriberDataRes ::= SEQUENCE { + teleserviceList [1] TeleserviceList OPTIONAL, + bearerServiceList [2] BearerServiceList OPTIONAL, + ss-List [3] SS-List OPTIONAL, + odb-GeneralData [4] ODB-GeneralData OPTIONAL, + regionalSubscriptionResponse [5] RegionalSubscriptionResponse OPTIONAL, + supportedCamelPhases [6] SupportedCamelPhases OPTIONAL, + extensionContainer [7] ExtensionContainer OPTIONAL, + ... , + offeredCamel4CSIs [8] OfferedCamel4CSIs OPTIONAL, + supportedFeatures [9] SupportedFeatures OPTIONAL } + +RegionalSubscriptionResponse ::= ENUMERATED { + networkNode-AreaRestricted (0), + tooManyZoneCodes (1), + zoneCodesConflict (2), + regionalSubscNotSupported (3)} + +DeleteSubscriberDataArg ::= SEQUENCE { + imsi [0] IMSI, + basicServiceList [1] BasicServiceList OPTIONAL, + -- The exception handling for reception of unsupported/not allocated + -- basicServiceCodes is defined in section 6.8.2 + ss-List [2] SS-List OPTIONAL, + roamingRestrictionDueToUnsupportedFeature [4] NULL OPTIONAL, + regionalSubscriptionIdentifier [5] ZoneCode OPTIONAL, + vbsGroupIndication [7] NULL OPTIONAL, + vgcsGroupIndication [8] NULL OPTIONAL, + camelSubscriptionInfoWithdraw [9] NULL OPTIONAL, + extensionContainer [6] ExtensionContainer OPTIONAL, + ..., + gprsSubscriptionDataWithdraw [10] GPRSSubscriptionDataWithdraw OPTIONAL, + roamingRestrictedInSgsnDueToUnsuppportedFeature [11] NULL OPTIONAL, + lsaInformationWithdraw [12] LSAInformationWithdraw OPTIONAL, + gmlc-ListWithdraw [13] NULL OPTIONAL, + istInformationWithdraw [14] NULL OPTIONAL, + specificCSI-Withdraw [15] SpecificCSI-Withdraw OPTIONAL, + chargingCharacteristicsWithdraw [16] NULL OPTIONAL, + stn-srWithdraw [17] NULL OPTIONAL, + epsSubscriptionDataWithdraw [18] EPS-SubscriptionDataWithdraw OPTIONAL, + apn-oi-replacementWithdraw [19] NULL OPTIONAL, + csg-SubscriptionDeleted [20] NULL OPTIONAL } + +SpecificCSI-Withdraw ::= BIT STRING { + o-csi (0), + ss-csi (1), + tif-csi (2), + d-csi (3), + vt-csi (4), + mo-sms-csi (5), + m-csi (6), + gprs-csi (7), + t-csi (8), + mt-sms-csi (9), + mg-csi (10), + o-IM-CSI (11), + d-IM-CSI (12), + vt-IM-CSI (13) } (SIZE(8..32)) +-- exception handling: +-- bits 11 to 31 shall be ignored if received by a non-IP Multimedia Core Network entity. +-- bits 0-10 and 14-31 shall be ignored if received by an IP Multimedia Core Network entity. +-- bits 11-13 are only applicable in an IP Multimedia Core Network. +-- Bit 8 and bits 11-13 are only applicable for the NoteSubscriberDataModified operation. + +GPRSSubscriptionDataWithdraw ::= CHOICE { + allGPRSData NULL, + contextIdList ContextIdList} + +EPS-SubscriptionDataWithdraw ::= CHOICE { + allEPS-Data NULL, + contextIdList ContextIdList} + +ContextIdList ::= SEQUENCE SIZE (1..maxNumOfPDP-Contexts) OF + ContextId + +LSAInformationWithdraw ::= CHOICE { + allLSAData NULL, + lsaIdentityList LSAIdentityList } + +LSAIdentityList ::= SEQUENCE SIZE (1..maxNumOfLSAs) OF + LSAIdentity + +BasicServiceList ::= SEQUENCE SIZE (1..maxNumOfBasicServices) OF + Ext-BasicServiceCode + +maxNumOfBasicServices INTEGER ::= 70 + +DeleteSubscriberDataRes ::= SEQUENCE { + regionalSubscriptionResponse [0] RegionalSubscriptionResponse OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +VlrCamelSubscriptionInfo ::= SEQUENCE { + o-CSI [0] O-CSI OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ..., + ss-CSI [2] SS-CSI OPTIONAL, + o-BcsmCamelTDP-CriteriaList [4] O-BcsmCamelTDPCriteriaList OPTIONAL, + tif-CSI [3] NULL OPTIONAL, + m-CSI [5] M-CSI OPTIONAL, + mo-sms-CSI [6] SMS-CSI OPTIONAL, + vt-CSI [7] T-CSI OPTIONAL, + t-BCSM-CAMEL-TDP-CriteriaList [8] T-BCSM-CAMEL-TDP-CriteriaList OPTIONAL, + d-CSI [9] D-CSI OPTIONAL, + mt-sms-CSI [10] SMS-CSI OPTIONAL, + mt-smsCAMELTDP-CriteriaList [11] MT-smsCAMELTDP-CriteriaList OPTIONAL + } + +MT-smsCAMELTDP-CriteriaList ::= SEQUENCE SIZE (1.. maxNumOfCamelTDPData) OF + MT-smsCAMELTDP-Criteria + +MT-smsCAMELTDP-Criteria ::= SEQUENCE { + sms-TriggerDetectionPoint SMS-TriggerDetectionPoint, + tpdu-TypeCriterion [0] TPDU-TypeCriterion OPTIONAL, + ... } + +TPDU-TypeCriterion ::= SEQUENCE SIZE (1..maxNumOfTPDUTypes) OF + MT-SMS-TPDU-Type + + +maxNumOfTPDUTypes INTEGER ::= 5 + +MT-SMS-TPDU-Type ::= ENUMERATED { + sms-DELIVER (0), + sms-SUBMIT-REPORT (1), + sms-STATUS-REPORT (2), + ... } + +-- exception handling: +-- For TPDU-TypeCriterion sequences containing this parameter with any +-- other value than the ones listed above the receiver shall ignore +-- the whole TPDU-TypeCriterion sequence. +-- In CAMEL phase 4, sms-SUBMIT-REPORT shall not be used and a received TPDU-TypeCriterion +-- sequence containing sms-SUBMIT-REPORT shall be wholly ignored. + +D-CSI ::= SEQUENCE { + dp-AnalysedInfoCriteriaList [0] DP-AnalysedInfoCriteriaList OPTIONAL, + camelCapabilityHandling [1] CamelCapabilityHandling OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + notificationToCSE [3] NULL OPTIONAL, + csi-Active [4] NULL OPTIONAL, + ...} +-- notificationToCSE and csi-Active shall not be present when D-CSI is sent to VLR/GMSC. +-- They may only be included in ATSI/ATM ack/NSDC message. +-- DP-AnalysedInfoCriteria and camelCapabilityHandling shall be present in +-- the D-CSI sequence. +-- If D-CSI is segmented, then the first segment shall contain dp-AnalysedInfoCriteriaList +-- and camelCapabilityHandling. Subsequent segments shall not contain +-- camelCapabilityHandling, but may contain dp-AnalysedInfoCriteriaList. + +DP-AnalysedInfoCriteriaList ::= SEQUENCE SIZE (1..maxNumOfDP-AnalysedInfoCriteria) OF + DP-AnalysedInfoCriterium + +maxNumOfDP-AnalysedInfoCriteria INTEGER ::= 10 + +DP-AnalysedInfoCriterium ::= SEQUENCE { + dialledNumber ISDN-AddressString, + serviceKey ServiceKey, + gsmSCF-Address ISDN-AddressString, + defaultCallHandling DefaultCallHandling, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +SS-CSI ::= SEQUENCE { + ss-CamelData SS-CamelData, + extensionContainer ExtensionContainer OPTIONAL, + ..., + notificationToCSE [0] NULL OPTIONAL, + csi-Active [1] NULL OPTIONAL +-- notificationToCSE and csi-Active shall not be present when SS-CSI is sent to VLR. +-- They may only be included in ATSI/ATM ack/NSDC message. +} + +SS-CamelData ::= SEQUENCE { + ss-EventList SS-EventList, + gsmSCF-Address ISDN-AddressString, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +SS-EventList ::= SEQUENCE SIZE (1..maxNumOfCamelSSEvents) OF SS-Code + -- Actions for the following SS-Code values are defined in CAMEL Phase 3: + -- ect SS-Code ::= '00110001'B + -- multiPTY SS-Code ::= '01010001'B + -- cd SS-Code ::= '00100100'B + -- ccbs SS-Code ::= '01000100'B + -- all other SS codes shall be ignored + -- When SS-CSI is sent to the VLR, it shall not contain a marking for ccbs. + -- If the VLR receives SS-CSI containing a marking for ccbs, the VLR shall discard the + -- ccbs marking in SS-CSI. + +maxNumOfCamelSSEvents INTEGER ::= 10 + +O-CSI ::= SEQUENCE { + o-BcsmCamelTDPDataList O-BcsmCamelTDPDataList, + extensionContainer ExtensionContainer OPTIONAL, + ..., + camelCapabilityHandling [0] CamelCapabilityHandling OPTIONAL, + notificationToCSE [1] NULL OPTIONAL, + csiActive [2] NULL OPTIONAL} +-- notificationtoCSE and csiActive shall not be present when O-CSI is sent to VLR/GMSC. +-- They may only be included in ATSI/ATM ack/NSDC message. +-- O-CSI shall not be segmented. + +O-BcsmCamelTDPDataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF + O-BcsmCamelTDPData + -- O-BcsmCamelTDPDataList shall not contain more than one instance of + -- O-BcsmCamelTDPData containing the same value for o-BcsmTriggerDetectionPoint. + -- For CAMEL Phase 2, this means that only one instance of O-BcsmCamelTDPData is allowed + -- with o-BcsmTriggerDetectionPoint being equal to DP2. + +maxNumOfCamelTDPData INTEGER ::= 10 + +O-BcsmCamelTDPData ::= SEQUENCE { + o-BcsmTriggerDetectionPoint O-BcsmTriggerDetectionPoint, + serviceKey ServiceKey, + gsmSCF-Address [0] ISDN-AddressString, + defaultCallHandling [1] DefaultCallHandling, + extensionContainer [2] ExtensionContainer OPTIONAL, + ... + } + +ServiceKey ::= INTEGER (0..2147483647) + +O-BcsmTriggerDetectionPoint ::= ENUMERATED { + collectedInfo (2), + ..., + routeSelectFailure (4) } + -- exception handling: + -- For O-BcsmCamelTDPData sequences containing this parameter with any + -- other value than the ones listed the receiver shall ignore the whole + -- O-BcsmCamelTDPDatasequence. + -- For O-BcsmCamelTDP-Criteria sequences containing this parameter with any + -- other value than the ones listed the receiver shall ignore the whole + -- O-BcsmCamelTDP-Criteria sequence. + +O-BcsmCamelTDPCriteriaList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF + O-BcsmCamelTDP-Criteria + +T-BCSM-CAMEL-TDP-CriteriaList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF + T-BCSM-CAMEL-TDP-Criteria + +O-BcsmCamelTDP-Criteria ::= SEQUENCE { + o-BcsmTriggerDetectionPoint O-BcsmTriggerDetectionPoint, + destinationNumberCriteria [0] DestinationNumberCriteria OPTIONAL, + basicServiceCriteria [1] BasicServiceCriteria OPTIONAL, + callTypeCriteria [2] CallTypeCriteria OPTIONAL, + ..., + o-CauseValueCriteria [3] O-CauseValueCriteria OPTIONAL, + extensionContainer [4] ExtensionContainer OPTIONAL } + +T-BCSM-CAMEL-TDP-Criteria ::= SEQUENCE { + t-BCSM-TriggerDetectionPoint T-BcsmTriggerDetectionPoint, + basicServiceCriteria [0] BasicServiceCriteria OPTIONAL, + t-CauseValueCriteria [1] T-CauseValueCriteria OPTIONAL, + ... } + +DestinationNumberCriteria ::= SEQUENCE { + matchType [0] MatchType, + destinationNumberList [1] DestinationNumberList OPTIONAL, + destinationNumberLengthList [2] DestinationNumberLengthList OPTIONAL, + -- one or both of destinationNumberList and destinationNumberLengthList + -- shall be present + ...} + +DestinationNumberList ::= SEQUENCE SIZE (1..maxNumOfCamelDestinationNumbers) OF + ISDN-AddressString + -- The receiving entity shall not check the format of a number in + -- the dialled number list + +DestinationNumberLengthList ::= SEQUENCE SIZE (1..maxNumOfCamelDestinationNumberLengths) OF + INTEGER(1..maxNumOfISDN-AddressDigits) + +BasicServiceCriteria ::= SEQUENCE SIZE(1..maxNumOfCamelBasicServiceCriteria) OF + Ext-BasicServiceCode + +maxNumOfISDN-AddressDigits INTEGER ::= 15 + +maxNumOfCamelDestinationNumbers INTEGER ::= 10 + +maxNumOfCamelDestinationNumberLengths INTEGER ::= 3 + +maxNumOfCamelBasicServiceCriteria INTEGER ::= 5 + +CallTypeCriteria ::= ENUMERATED { + forwarded (0), + notForwarded (1)} + +MatchType ::= ENUMERATED { + inhibiting (0), + enabling (1)} + +O-CauseValueCriteria ::= SEQUENCE SIZE(1..maxNumOfCAMEL-O-CauseValueCriteria) OF + CauseValue + +T-CauseValueCriteria ::= SEQUENCE SIZE(1..maxNumOfCAMEL-T-CauseValueCriteria) OF + CauseValue + +maxNumOfCAMEL-O-CauseValueCriteria INTEGER ::= 5 + +maxNumOfCAMEL-T-CauseValueCriteria INTEGER ::= 5 + +CauseValue ::= OCTET STRING (SIZE(1)) +-- Type extracted from Cause parameter in ITU-T Recommendation Q.763. +-- For the use of cause value refer to ITU-T Recommendation Q.850. + +DefaultCallHandling ::= ENUMERATED { + continueCall (0) , + releaseCall (1) , + ...} + -- exception handling: + -- reception of values in range 2-31 shall be treated as "continueCall" + -- reception of values greater than 31 shall be treated as "releaseCall" + +CamelCapabilityHandling ::= INTEGER(1..16) + -- value 1 = CAMEL phase 1, + -- value 2 = CAMEL phase 2, + -- value 3 = CAMEL Phase 3, + -- value 4 = CAMEL phase 4: + -- reception of values greater than 4 shall be treated as CAMEL phase 4. + +SupportedCamelPhases ::= BIT STRING { + phase1 (0), + phase2 (1), + phase3 (2), + phase4 (3)} (SIZE (1..16)) +-- A node shall mark in the BIT STRING all CAMEL Phases it supports. +-- Other values than listed above shall be discarded. + +OfferedCamel4CSIs ::= BIT STRING { + o-csi (0), + d-csi (1), + vt-csi (2), + t-csi (3), + mt-sms-csi (4), + mg-csi (5), + psi-enhancements (6) +} (SIZE (7..16)) +-- A node supporting Camel phase 4 shall mark in the BIT STRING all Camel4 CSIs +-- it offers. +-- Other values than listed above shall be discarded. + +OfferedCamel4Functionalities ::= BIT STRING { + initiateCallAttempt (0), + splitLeg (1), + moveLeg (2), + disconnectLeg (3), + entityReleased (4), + dfc-WithArgument (5), + playTone (6), + dtmf-MidCall (7), + chargingIndicator (8), + alertingDP (9), + locationAtAlerting (10), + changeOfPositionDP (11), + or-Interactions (12), + warningToneEnhancements (13), + cf-Enhancements (14), + subscribedEnhancedDialledServices (15), + servingNetworkEnhancedDialledServices (16), + criteriaForChangeOfPositionDP (17), + serviceChangeDP (18), + collectInformation (19) +} (SIZE (15..64)) +-- A node supporting Camel phase 4 shall mark in the BIT STRING all CAMEL4 +-- functionalities it offers. +-- Other values than listed above shall be discarded. + +SMS-CSI ::= SEQUENCE { + sms-CAMEL-TDP-DataList [0] SMS-CAMEL-TDP-DataList OPTIONAL, + camelCapabilityHandling [1] CamelCapabilityHandling OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + notificationToCSE [3] NULL OPTIONAL, + csi-Active [4] NULL OPTIONAL, + ...} +-- notificationToCSE and csi-Active shall not be present +-- when MO-SMS-CSI or MT-SMS-CSI is sent to VLR or SGSN. +-- They may only be included in ATSI/ATM ack/NSDC message. +-- SMS-CAMEL-TDP-Data and camelCapabilityHandling shall be present in +-- the SMS-CSI sequence. +-- If SMS-CSI is segmented, sms-CAMEL-TDP-DataList and camelCapabilityHandling shall be +-- present in the first segment + +SMS-CAMEL-TDP-DataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF + SMS-CAMEL-TDP-Data +-- SMS-CAMEL-TDP-DataList shall not contain more than one instance of +-- SMS-CAMEL-TDP-Data containing the same value for sms-TriggerDetectionPoint. + +SMS-CAMEL-TDP-Data ::= SEQUENCE { + sms-TriggerDetectionPoint [0] SMS-TriggerDetectionPoint, + serviceKey [1] ServiceKey, + gsmSCF-Address [2] ISDN-AddressString, + defaultSMS-Handling [3] DefaultSMS-Handling, + extensionContainer [4] ExtensionContainer OPTIONAL, + ... + } + +SMS-TriggerDetectionPoint ::= ENUMERATED { + sms-CollectedInfo (1), + ..., + sms-DeliveryRequest (2) + } +-- exception handling: +-- For SMS-CAMEL-TDP-Data and MT-smsCAMELTDP-Criteria sequences containing this +-- parameter with any other value than the ones listed the receiver shall ignore +-- the whole sequence. +-- +-- If this parameter is received with any other value than sms-CollectedInfo +-- in an SMS-CAMEL-TDP-Data sequence contained in mo-sms-CSI, then the receiver shall +-- ignore the whole SMS-CAMEL-TDP-Data sequence. +-- +-- If this parameter is received with any other value than sms-DeliveryRequest +-- in an SMS-CAMEL-TDP-Data sequence contained in mt-sms-CSI then the receiver shall +-- ignore the whole SMS-CAMEL-TDP-Data sequence. +-- +-- If this parameter is received with any other value than sms-DeliveryRequest +-- in an MT-smsCAMELTDP-Criteria sequence then the receiver shall +-- ignore the whole MT-smsCAMELTDP-Criteria sequence. + +DefaultSMS-Handling ::= ENUMERATED { + continueTransaction (0) , + releaseTransaction (1) , + ...} +-- exception handling: +-- reception of values in range 2-31 shall be treated as "continueTransaction" +-- reception of values greater than 31 shall be treated as "releaseTransaction" + +M-CSI ::= SEQUENCE { + mobilityTriggers MobilityTriggers, + serviceKey ServiceKey, + gsmSCF-Address [0] ISDN-AddressString, + extensionContainer [1] ExtensionContainer OPTIONAL, + notificationToCSE [2] NULL OPTIONAL, + csi-Active [3] NULL OPTIONAL, + ...} +-- notificationToCSE and csi-Active shall not be present when M-CSI is sent to VLR. +-- They may only be included in ATSI/ATM ack/NSDC message. + +MG-CSI ::= SEQUENCE { + mobilityTriggers MobilityTriggers, + serviceKey ServiceKey, + gsmSCF-Address [0] ISDN-AddressString, + extensionContainer [1] ExtensionContainer OPTIONAL, + notificationToCSE [2] NULL OPTIONAL, + csi-Active [3] NULL OPTIONAL, + ...} +-- notificationToCSE and csi-Active shall not be present when MG-CSI is sent to SGSN. +-- They may only be included in ATSI/ATM ack/NSDC message. + +MobilityTriggers ::= SEQUENCE SIZE (1..maxNumOfMobilityTriggers) OF + MM-Code + +maxNumOfMobilityTriggers INTEGER ::= 10 + +MM-Code ::= OCTET STRING (SIZE (1)) +-- This type is used to indicate a Mobility Management event. +-- Actions for the following MM-Code values are defined in CAMEL Phase 4: +-- +-- CS domain MM events: +-- Location-update-in-same-VLR MM-Code ::= '00000000'B +-- Location-update-to-other-VLR MM-Code ::= '00000001'B +-- IMSI-Attach MM-Code ::= '00000010'B +-- MS-initiated-IMSI-Detach MM-Code ::= '00000011'B +-- Network-initiated-IMSI-Detach MM-Code ::= '00000100'B +-- +-- PS domain MM events: +-- Routeing-Area-update-in-same-SGSN MM-Code ::= '10000000'B +-- Routeing-Area-update-to-other-SGSN-update-from-new-SGSN +-- MM-Code ::= '10000001'B +-- Routeing-Area-update-to-other-SGSN-disconnect-by-detach +-- MM-Code ::= '10000010'B +-- GPRS-Attach MM-Code ::= '10000011'B +-- MS-initiated-GPRS-Detach MM-Code ::= '10000100'B +-- Network-initiated-GPRS-Detach MM-Code ::= '10000101'B +-- Network-initiated-transfer-to-MS-not-reachable-for-paging +-- MM-Code ::= '10000110'B +-- +-- If the MSC receives any other MM-code than the ones listed above for the +-- CS domain, then the MSC shall ignore that MM-code. +-- If the SGSN receives any other MM-code than the ones listed above for the +-- PS domain, then the SGSN shall ignore that MM-code. + +T-CSI ::= SEQUENCE { + t-BcsmCamelTDPDataList T-BcsmCamelTDPDataList, + extensionContainer ExtensionContainer OPTIONAL, + ..., + camelCapabilityHandling [0] CamelCapabilityHandling OPTIONAL, + notificationToCSE [1] NULL OPTIONAL, + csi-Active [2] NULL OPTIONAL} +-- notificationToCSE and csi-Active shall not be present when VT-CSI/T-CSI is sent +-- to VLR/GMSC. +-- They may only be included in ATSI/ATM ack/NSDC message. +-- T-CSI shall not be segmented. + +T-BcsmCamelTDPDataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF + T-BcsmCamelTDPData + --- T-BcsmCamelTDPDataList shall not contain more than one instance of + --- T-BcsmCamelTDPData containing the same value for t-BcsmTriggerDetectionPoint. + --- For CAMEL Phase 2, this means that only one instance of T-BcsmCamelTDPData is allowed + --- with t-BcsmTriggerDetectionPoint being equal to DP12. + --- For CAMEL Phase 3, more TDP’s are allowed. + +T-BcsmCamelTDPData ::= SEQUENCE { + t-BcsmTriggerDetectionPoint T-BcsmTriggerDetectionPoint, + serviceKey ServiceKey, + gsmSCF-Address [0] ISDN-AddressString, + defaultCallHandling [1] DefaultCallHandling, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +T-BcsmTriggerDetectionPoint ::= ENUMERATED { + termAttemptAuthorized (12), + ... , + tBusy (13), + tNoAnswer (14)} + -- exception handling: + -- For T-BcsmCamelTDPData sequences containing this parameter with any other + -- value than the ones listed above, the receiver shall ignore the whole + -- T-BcsmCamelTDPData sequence. + +-- gprs location information retrieval types + +SendRoutingInfoForGprsArg ::= SEQUENCE { + imsi [0] IMSI, + ggsn-Address [1] GSN-Address OPTIONAL, + ggsn-Number [2] ISDN-AddressString, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +SendRoutingInfoForGprsRes ::= SEQUENCE { + sgsn-Address [0] GSN-Address, + ggsn-Address [1] GSN-Address OPTIONAL, + mobileNotReachableReason [2] AbsentSubscriberDiagnosticSM OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +-- failure report types + +FailureReportArg ::= SEQUENCE { + imsi [0] IMSI, + ggsn-Number [1] ISDN-AddressString , + ggsn-Address [2] GSN-Address OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +FailureReportRes ::= SEQUENCE { + ggsn-Address [0] GSN-Address OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ...} + +-- gprs notification types + +NoteMsPresentForGprsArg ::= SEQUENCE { + imsi [0] IMSI, + sgsn-Address [1] GSN-Address, + ggsn-Address [2] GSN-Address OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +NoteMsPresentForGprsRes ::= SEQUENCE { + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +-- fault recovery types + +ResetArg ::= SEQUENCE { + hlr-Number ISDN-AddressString, + hlr-List HLR-List OPTIONAL, + ...} + +RestoreDataArg ::= SEQUENCE { + imsi IMSI, + lmsi LMSI OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ... , + vlr-Capability [6] VLR-Capability OPTIONAL } + +RestoreDataRes ::= SEQUENCE { + hlr-Number ISDN-AddressString, + msNotReachable NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +-- VBS/VGCS types +VBSDataList ::= SEQUENCE SIZE (1..maxNumOfVBSGroupIds) OF + VoiceBroadcastData + +VGCSDataList ::= SEQUENCE SIZE (1..maxNumOfVGCSGroupIds) OF + VoiceGroupCallData + +maxNumOfVBSGroupIds INTEGER ::= 50 + +maxNumOfVGCSGroupIds INTEGER ::= 50 + +VoiceGroupCallData ::= SEQUENCE { + groupId GroupId, + -- groupId shall be filled with six TBCD fillers (1111)if the longGroupId is present + extensionContainer ExtensionContainer OPTIONAL, + ..., + additionalSubscriptions AdditionalSubscriptions OPTIONAL, + additionalInfo [0] AdditionalInfo OPTIONAL, + longGroupId [1] Long-GroupId OPTIONAL } + + -- VoiceGroupCallData containing a longGroupId shall not be sent to VLRs that did not + -- indicate support of long Group IDs within the Update Location or Restore Data + -- request message + +AdditionalInfo ::= BIT STRING (SIZE (1..136)) +-- Refers to Additional Info as specified in 3GPP TS 43.068 + +AdditionalSubscriptions ::= BIT STRING { + privilegedUplinkRequest (0), + emergencyUplinkRequest (1), + emergencyReset (2)} (SIZE (3..8)) +-- Other bits than listed above shall be discarded. + +VoiceBroadcastData ::= SEQUENCE { + groupid GroupId, + -- groupId shall be filled with six TBCD fillers (1111)if the longGroupId is present + broadcastInitEntitlement NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + longGroupId [0] Long-GroupId OPTIONAL } + +-- VoiceBroadcastData containing a longGroupId shall not be sent to VLRs that did not +-- indicate support of long Group IDs within the Update Location or Restore Data + -- request message + +GroupId ::= TBCD-STRING (SIZE (3)) + -- When Group-Id is less than six characters in length, the TBCD filler (1111) + -- is used to fill unused half octets. + -- Refers to the Group Identification as specified in 3GPP TS 23.003 + -- and 3GPP TS 43.068/ 43.069 + +Long-GroupId ::= TBCD-STRING (SIZE (4)) + -- When Long-Group-Id is less than eight characters in length, the TBCD filler (1111) + -- is used to fill unused half octets. + -- Refers to the Group Identification as specified in 3GPP TS 23.003 + -- and 3GPP TS 43.068/ 43.069 + + +-- provide subscriber info types + +ProvideSubscriberInfoArg ::= SEQUENCE { + imsi [0] IMSI, + lmsi [1] LMSI OPTIONAL, + requestedInfo [2] RequestedInfo, + extensionContainer [3] ExtensionContainer OPTIONAL, + ..., + callPriority [4] EMLPP-Priority OPTIONAL + } + +ProvideSubscriberInfoRes ::= SEQUENCE { + subscriberInfo SubscriberInfo, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +SubscriberInfo ::= SEQUENCE { + locationInformation [0] LocationInformation OPTIONAL, + subscriberState [1] SubscriberState OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ... , + locationInformationGPRS [3] LocationInformationGPRS OPTIONAL, + ps-SubscriberState [4] PS-SubscriberState OPTIONAL, + imei [5] IMEI OPTIONAL, + ms-Classmark2 [6] MS-Classmark2 OPTIONAL, + gprs-MS-Class [7] GPRSMSClass OPTIONAL, + mnpInfoRes [8] MNPInfoRes OPTIONAL } + +-- If the HLR receives locationInformation, subscriberState or ms-Classmark2 from an SGSN +-- it shall discard them. +-- If the HLR receives locationInformationGPRS, ps-SubscriberState or gprs-MS-Class from +-- a VLR it shall discard them. +-- If the HLR receives parameters which it has not requested, it shall discard them. + +MNPInfoRes ::= SEQUENCE { + routeingNumber [0] RouteingNumber OPTIONAL, + imsi [1] IMSI OPTIONAL, + msisdn [2] ISDN-AddressString OPTIONAL, + numberPortabilityStatus [3] NumberPortabilityStatus OPTIONAL, + extensionContainer [4] ExtensionContainer OPTIONAL, + ... } +-- The IMSI parameter contains a generic IMSI, i.e. it is not tied necessarily to the +-- Subscriber. MCC and MNC values in this IMSI shall point to the Subscription Network of +-- the Subscriber. See 3GPP TS 23.066 [108]. + +RouteingNumber ::= TBCD-STRING (SIZE (1..5)) + + +NumberPortabilityStatus ::= ENUMERATED { + notKnownToBePorted (0), + ownNumberPortedOut (1), + foreignNumberPortedToForeignNetwork (2), + ..., + ownNumberNotPortedOut (4), + foreignNumberPortedIn (5) + } + -- exception handling: + -- reception of other values than the ones listed the receiver shall ignore the + -- whole NumberPortabilityStatus; + -- ownNumberNotPortedOut or foreignNumberPortedIn may only be included in Any Time + -- Interrogation message. + +MS-Classmark2 ::= OCTET STRING (SIZE (3)) + -- This parameter carries the value part of the MS Classmark 2 IE defined in + -- 3GPP TS 24.008 [35]. + +GPRSMSClass ::= SEQUENCE { + mSNetworkCapability [0] MSNetworkCapability, + mSRadioAccessCapability [1] MSRadioAccessCapability OPTIONAL + } + +MSNetworkCapability ::= OCTET STRING (SIZE (1..8)) + -- This parameter carries the value part of the MS Network Capability IE defined in + -- 3GPP TS 24.008 [35]. + +MSRadioAccessCapability ::= OCTET STRING (SIZE (1..50)) + -- This parameter carries the value part of the MS Radio Access Capability IE defined in + -- 3GPP TS 24.008 [35]. + +RequestedInfo ::= SEQUENCE { + locationInformation [0] NULL OPTIONAL, + subscriberState [1] NULL OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ..., + currentLocation [3] NULL OPTIONAL, + requestedDomain [4] DomainType OPTIONAL, + imei [6] NULL OPTIONAL, + ms-classmark [5] NULL OPTIONAL, + mnpRequestedInfo [7] NULL OPTIONAL } + +-- currentLocation shall be absent if locationInformation is absent + +DomainType ::= ENUMERATED { + cs-Domain (0), + ps-Domain (1), + ...} +-- exception handling: +-- reception of values > 1 shall be mapped to 'cs-Domain' + +LocationInformation ::= SEQUENCE { + ageOfLocationInformation AgeOfLocationInformation OPTIONAL, + geographicalInformation [0] GeographicalInformation OPTIONAL, + vlr-number [1] ISDN-AddressString OPTIONAL, + locationNumber [2] LocationNumber OPTIONAL, + cellGlobalIdOrServiceAreaIdOrLAI [3] CellGlobalIdOrServiceAreaIdOrLAI OPTIONAL, + extensionContainer [4] ExtensionContainer OPTIONAL, + ... , + selectedLSA-Id [5] LSAIdentity OPTIONAL, + msc-Number [6] ISDN-AddressString OPTIONAL, + geodeticInformation [7] GeodeticInformation OPTIONAL, + currentLocationRetrieved [8] NULL OPTIONAL, + sai-Present [9] NULL OPTIONAL } +-- sai-Present indicates that the cellGlobalIdOrServiceAreaIdOrLAI parameter contains +-- a Service Area Identity. +-- currentLocationRetrieved shall be present +-- if the location information were retrieved after a successfull paging. + +LocationInformationGPRS ::= SEQUENCE { + cellGlobalIdOrServiceAreaIdOrLAI [0] CellGlobalIdOrServiceAreaIdOrLAI OPTIONAL, + routeingAreaIdentity [1] RAIdentity OPTIONAL, + geographicalInformation [2] GeographicalInformation OPTIONAL, + sgsn-Number [3] ISDN-AddressString OPTIONAL, + selectedLSAIdentity [4] LSAIdentity OPTIONAL, + extensionContainer [5] ExtensionContainer OPTIONAL, + ..., + sai-Present [6] NULL OPTIONAL, + geodeticInformation [7] GeodeticInformation OPTIONAL, + currentLocationRetrieved [8] NULL OPTIONAL, + ageOfLocationInformation [9] AgeOfLocationInformation OPTIONAL } +-- sai-Present indicates that the cellGlobalIdOrServiceAreaIdOrLAI parameter contains +-- a Service Area Identity. +-- currentLocationRetrieved shall be present if the location information +-- was retrieved after successful paging. + +RAIdentity ::= OCTET STRING (SIZE (6)) +-- Routing Area Identity is coded in accordance with 3GPP TS 29.060 [105]. +-- It shall contain the value part defined in 3GPP TS 29.060 only. I.e. the 3GPP TS 29.060 +-- type identifier octet shall not be included. + + +GeographicalInformation ::= OCTET STRING (SIZE (8)) +-- Refers to geographical Information defined in 3GPP TS 23.032. +-- Only the description of an ellipsoid point with uncertainty circle +-- as specified in 3GPP TS 23.032 is allowed to be used +-- The internal structure according to 3GPP TS 23.032 is as follows: +-- Type of shape (ellipsoid point with uncertainty circle) 1 octet +-- Degrees of Latitude 3 octets +-- Degrees of Longitude 3 octets +-- Uncertainty code 1 octet + +GeodeticInformation ::= OCTET STRING (SIZE (10)) +-- Refers to Calling Geodetic Location defined in Q.763 (1999). +-- Only the description of an ellipsoid point with uncertainty circle +-- as specified in Q.763 (1999) is allowed to be used +-- The internal structure according to Q.763 (1999) is as follows: +-- Screening and presentation indicators 1 octet +-- Type of shape (ellipsoid point with uncertainty circle) 1 octet +-- Degrees of Latitude 3 octets +-- Degrees of Longitude 3 octets +-- Uncertainty code 1 octet +-- Confidence 1 octet + +LocationNumber ::= OCTET STRING (SIZE (2..10)) + -- the internal structure is defined in ITU-T Rec Q.763 + +SubscriberState ::= CHOICE { + assumedIdle [0] NULL, + camelBusy [1] NULL, + netDetNotReachable NotReachableReason, + notProvidedFromVLR [2] NULL} + +PS-SubscriberState ::= CHOICE { + notProvidedFromSGSN [0] NULL, + ps-Detached [1] NULL, + ps-AttachedNotReachableForPaging [2] NULL, + ps-AttachedReachableForPaging [3] NULL, + ps-PDP-ActiveNotReachableForPaging [4] PDP-ContextInfoList, + ps-PDP-ActiveReachableForPaging [5] PDP-ContextInfoList, + netDetNotReachable NotReachableReason } + +PDP-ContextInfoList ::= SEQUENCE SIZE (1..maxNumOfPDP-Contexts) OF + PDP-ContextInfo + +PDP-ContextInfo ::= SEQUENCE { + pdp-ContextIdentifier [0] ContextId, + pdp-ContextActive [1] NULL OPTIONAL, + pdp-Type [2] PDP-Type, + pdp-Address [3] PDP-Address OPTIONAL, + apn-Subscribed [4] APN OPTIONAL, + apn-InUse [5] APN OPTIONAL, + nsapi [6] NSAPI OPTIONAL, + transactionId [7] TransactionId OPTIONAL, + teid-ForGnAndGp [8] TEID OPTIONAL, + teid-ForIu [9] TEID OPTIONAL, + ggsn-Address [10] GSN-Address OPTIONAL, + qos-Subscribed [11] Ext-QoS-Subscribed OPTIONAL, + qos-Requested [12] Ext-QoS-Subscribed OPTIONAL, + qos-Negotiated [13] Ext-QoS-Subscribed OPTIONAL, + chargingId [14] GPRSChargingID OPTIONAL, + chargingCharacteristics [15] ChargingCharacteristics OPTIONAL, + rnc-Address [16] GSN-Address OPTIONAL, + extensionContainer [17] ExtensionContainer OPTIONAL, + ..., + qos2-Subscribed [18] Ext2-QoS-Subscribed OPTIONAL, + -- qos2-Subscribed may be present only if qos-Subscribed is present. + qos2-Requested [19] Ext2-QoS-Subscribed OPTIONAL, + -- qos2-Requested may be present only if qos-Requested is present. + qos2-Negotiated [20] Ext2-QoS-Subscribed OPTIONAL, + -- qos2-Negotiated may be present only if qos-Negotiated is present. + qos3-Subscribed [21] Ext3-QoS-Subscribed OPTIONAL, + -- qos3-Subscribed may be present only if qos2-Subscribed is present. + qos3-Requested [22] Ext3-QoS-Subscribed OPTIONAL, + -- qos3-Requested may be present only if qos2-Requested is present. + qos3-Negotiated [23] Ext3-QoS-Subscribed OPTIONAL + -- qos3-Negotiated may be present only if qos2-Negotiated is present. +} + +NSAPI ::= INTEGER (0..15) +-- This type is used to indicate the Network layer Service Access Point + +TransactionId ::= OCTET STRING (SIZE (1..2)) +-- This type carries the value part of the transaction identifier which is used in the +-- session management messages on the access interface. The encoding is defined in +-- 3GPP TS 24.008 + +TEID ::= OCTET STRING (SIZE (4)) +-- This type carries the value part of the Tunnel Endpoint Identifier which is used to +-- distinguish between different tunnels between the same pair of entities which communicate +-- using the GPRS Tunnelling Protocol The encoding is defined in 3GPP TS 29.060. + +GPRSChargingID ::= OCTET STRING (SIZE (4)) +-- The Charging ID is a unique four octet value generated by the GGSN when +-- a PDP Context is activated. A Charging ID is generated for each activated context. +-- The encoding is defined in 3GPP TS 29.060. + +NotReachableReason ::= ENUMERATED { + msPurged (0), + imsiDetached (1), + restrictedArea (2), + notRegistered (3)} + +-- any time interrogation info types + +AnyTimeInterrogationArg ::= SEQUENCE { + subscriberIdentity [0] SubscriberIdentity, + requestedInfo [1] RequestedInfo, + gsmSCF-Address [3] ISDN-AddressString, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +AnyTimeInterrogationRes ::= SEQUENCE { + subscriberInfo SubscriberInfo, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +-- any time information handling types + +AnyTimeSubscriptionInterrogationArg ::= SEQUENCE { + subscriberIdentity [0] SubscriberIdentity, + requestedSubscriptionInfo [1] RequestedSubscriptionInfo, + gsmSCF-Address [2] ISDN-AddressString, + extensionContainer [3] ExtensionContainer OPTIONAL, + longFTN-Supported [4] NULL OPTIONAL, + ...} + +AnyTimeSubscriptionInterrogationRes ::= SEQUENCE { + callForwardingData [1] CallForwardingData OPTIONAL, + callBarringData [2] CallBarringData OPTIONAL, + odb-Info [3] ODB-Info OPTIONAL, + camel-SubscriptionInfo [4] CAMEL-SubscriptionInfo OPTIONAL, + supportedVLR-CAMEL-Phases [5] SupportedCamelPhases OPTIONAL, + supportedSGSN-CAMEL-Phases [6] SupportedCamelPhases OPTIONAL, + extensionContainer [7] ExtensionContainer OPTIONAL, + ... , + offeredCamel4CSIsInVLR [8] OfferedCamel4CSIs OPTIONAL, + offeredCamel4CSIsInSGSN [9] OfferedCamel4CSIs OPTIONAL, + msisdn-BS-List [10] MSISDN-BS-List OPTIONAL } + +RequestedSubscriptionInfo ::= SEQUENCE { + requestedSS-Info [1] SS-ForBS-Code OPTIONAL, + odb [2] NULL OPTIONAL, + requestedCAMEL-SubscriptionInfo [3] RequestedCAMEL-SubscriptionInfo OPTIONAL, + supportedVLR-CAMEL-Phases [4] NULL OPTIONAL, + supportedSGSN-CAMEL-Phases [5] NULL OPTIONAL, + extensionContainer [6] ExtensionContainer OPTIONAL, + ..., + additionalRequestedCAMEL-SubscriptionInfo + [7] AdditionalRequestedCAMEL-SubscriptionInfo + OPTIONAL, + msisdn-BS-List [8] NULL OPTIONAL } + +MSISDN-BS-List ::= SEQUENCE SIZE (1..maxNumOfMSISDN) OF + MSISDN-BS + +maxNumOfMSISDN INTEGER ::= 50 + + +MSISDN-BS ::= SEQUENCE { + msisdn ISDN-AddressString, + basicServiceList [0] BasicServiceList OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ...} + +RequestedCAMEL-SubscriptionInfo ::= ENUMERATED { + o-CSI (0), + t-CSI (1), + vt-CSI (2), + tif-CSI (3), + gprs-CSI (4), + mo-sms-CSI (5), + ss-CSI (6), + m-CSI (7), + d-csi (8)} + +AdditionalRequestedCAMEL-SubscriptionInfo ::= ENUMERATED { + mt-sms-CSI (0), + mg-csi (1), + o-IM-CSI (2), + d-IM-CSI (3), + vt-IM-CSI (4), + ...} +-- exception handling: unknown values shall be discarded by the receiver. + +CallForwardingData ::= SEQUENCE { + forwardingFeatureList Ext-ForwFeatureList, + notificationToCSE NULL OPTIONAL, + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +CallBarringData ::= SEQUENCE { + callBarringFeatureList Ext-CallBarFeatureList, + password Password OPTIONAL, + wrongPasswordAttemptsCounter WrongPasswordAttemptsCounter OPTIONAL, + notificationToCSE NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +WrongPasswordAttemptsCounter ::= INTEGER (0..4) + +ODB-Info ::= SEQUENCE { + odb-Data ODB-Data, + notificationToCSE NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +CAMEL-SubscriptionInfo ::= SEQUENCE { + o-CSI [0] O-CSI OPTIONAL, + o-BcsmCamelTDP-CriteriaList [1] O-BcsmCamelTDPCriteriaList OPTIONAL, + d-CSI [2] D-CSI OPTIONAL, + t-CSI [3] T-CSI OPTIONAL, + t-BCSM-CAMEL-TDP-CriteriaList [4] T-BCSM-CAMEL-TDP-CriteriaList OPTIONAL, + vt-CSI [5] T-CSI OPTIONAL, + vt-BCSM-CAMEL-TDP-CriteriaList [6] T-BCSM-CAMEL-TDP-CriteriaList OPTIONAL, + tif-CSI [7] NULL OPTIONAL, + tif-CSI-NotificationToCSE [8] NULL OPTIONAL, + gprs-CSI [9] GPRS-CSI OPTIONAL, + mo-sms-CSI [10] SMS-CSI OPTIONAL, + ss-CSI [11] SS-CSI OPTIONAL, + m-CSI [12] M-CSI OPTIONAL, + extensionContainer [13] ExtensionContainer OPTIONAL, + ..., + specificCSIDeletedList [14] SpecificCSI-Withdraw OPTIONAL, + mt-sms-CSI [15] SMS-CSI OPTIONAL, + mt-smsCAMELTDP-CriteriaList [16] MT-smsCAMELTDP-CriteriaList OPTIONAL, + mg-csi [17] MG-CSI OPTIONAL, + o-IM-CSI [18] O-CSI OPTIONAL, + o-IM-BcsmCamelTDP-CriteriaList [19] O-BcsmCamelTDPCriteriaList OPTIONAL, + d-IM-CSI [20] D-CSI OPTIONAL, + vt-IM-CSI [21] T-CSI OPTIONAL, + vt-IM-BCSM-CAMEL-TDP-CriteriaList [22] T-BCSM-CAMEL-TDP-CriteriaList OPTIONAL + } + +AnyTimeModificationArg ::= SEQUENCE { + subscriberIdentity [0] SubscriberIdentity, + gsmSCF-Address [1] ISDN-AddressString, + modificationRequestFor-CF-Info [2] ModificationRequestFor-CF-Info OPTIONAL, + modificationRequestFor-CB-Info [3] ModificationRequestFor-CB-Info OPTIONAL, + modificationRequestFor-CSI [4] ModificationRequestFor-CSI OPTIONAL, + extensionContainer [5] ExtensionContainer OPTIONAL, + longFTN-Supported [6] NULL OPTIONAL, + ..., + modificationRequestFor-ODB-data [7] ModificationRequestFor-ODB-data OPTIONAL, + modificationRequestFor-IP-SM-GW-Data [8] ModificationRequestFor-IP-SM-GW-Data OPTIONAL } + +AnyTimeModificationRes ::= SEQUENCE { + ss-InfoFor-CSE [0] Ext-SS-InfoFor-CSE OPTIONAL, + camel-SubscriptionInfo [1] CAMEL-SubscriptionInfo OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ..., + odb-Info [3] ODB-Info OPTIONAL } + +ModificationRequestFor-CF-Info ::= SEQUENCE { + ss-Code [0] SS-Code, + basicService [1] Ext-BasicServiceCode OPTIONAL, + ss-Status [2] Ext-SS-Status OPTIONAL, + forwardedToNumber [3] AddressString OPTIONAL, + forwardedToSubaddress [4] ISDN-SubaddressString OPTIONAL, + noReplyConditionTime [5] Ext-NoRepCondTime OPTIONAL, + modifyNotificationToCSE [6] ModificationInstruction OPTIONAL, + extensionContainer [7] ExtensionContainer OPTIONAL, + ...} + +ModificationRequestFor-CB-Info ::= SEQUENCE { + ss-Code [0] SS-Code, + basicService [1] Ext-BasicServiceCode OPTIONAL, + ss-Status [2] Ext-SS-Status OPTIONAL, + password [3] Password OPTIONAL, + wrongPasswordAttemptsCounter [4] WrongPasswordAttemptsCounter OPTIONAL, + modifyNotificationToCSE [5] ModificationInstruction OPTIONAL, + extensionContainer [6] ExtensionContainer OPTIONAL, + ...} + +ModificationRequestFor-ODB-data ::= SEQUENCE { + odb-data [0] ODB-Data OPTIONAL, + modifyNotificationToCSE [1] ModificationInstruction OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +ModificationRequestFor-CSI ::= SEQUENCE { + requestedCamel-SubscriptionInfo [0] RequestedCAMEL-SubscriptionInfo, + modifyNotificationToCSE [1] ModificationInstruction OPTIONAL, + modifyCSI-State [2] ModificationInstruction OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ..., + additionalRequestedCAMEL-SubscriptionInfo + [4] AdditionalRequestedCAMEL-SubscriptionInfo + OPTIONAL } +-- requestedCamel-SubscriptionInfo shall be discarded if +-- additionalRequestedCAMEL-SubscriptionInfo is received + +ModificationRequestFor-IP-SM-GW-Data ::= SEQUENCE { + modifyRegistrationStatus [0] ModificationInstruction OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ...} + +ModificationInstruction ::= ENUMERATED { + deactivate (0), + activate (1)} + +-- subscriber data modification notification types + +NoteSubscriberDataModifiedArg ::= SEQUENCE { + imsi IMSI, + msisdn ISDN-AddressString, + forwardingInfoFor-CSE [0] Ext-ForwardingInfoFor-CSE OPTIONAL, + callBarringInfoFor-CSE [1] Ext-CallBarringInfoFor-CSE OPTIONAL, + odb-Info [2] ODB-Info OPTIONAL, + camel-SubscriptionInfo [3] CAMEL-SubscriptionInfo OPTIONAL, + allInformationSent [4] NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +NoteSubscriberDataModifiedRes ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +-- mobility management event notificatioon info types + +NoteMM-EventArg::= SEQUENCE { + serviceKey ServiceKey, + eventMet [0] MM-Code, + imsi [1] IMSI, + msisdn [2] ISDN-AddressString, + locationInformation [3] LocationInformation OPTIONAL, + supportedCAMELPhases [5] SupportedCamelPhases OPTIONAL, + extensionContainer [6] ExtensionContainer OPTIONAL, + ..., + locationInformationGPRS [7] LocationInformationGPRS OPTIONAL, + offeredCamel4Functionalities [8] OfferedCamel4Functionalities OPTIONAL +} + +NoteMM-EventRes ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +Ext-SS-InfoFor-CSE ::= CHOICE { + forwardingInfoFor-CSE [0] Ext-ForwardingInfoFor-CSE, + callBarringInfoFor-CSE [1] Ext-CallBarringInfoFor-CSE + } + +Ext-ForwardingInfoFor-CSE ::= SEQUENCE { + ss-Code [0] SS-Code, + forwardingFeatureList [1] Ext-ForwFeatureList, + notificationToCSE [2] NULL OPTIONAL, + extensionContainer [3] ExtensionContainer OPTIONAL, + ...} + +Ext-CallBarringInfoFor-CSE ::= SEQUENCE { + ss-Code [0] SS-Code, + callBarringFeatureList [1] Ext-CallBarFeatureList, + password [2] Password OPTIONAL, + wrongPasswordAttemptsCounter [3] WrongPasswordAttemptsCounter OPTIONAL, + notificationToCSE [4] NULL OPTIONAL, + extensionContainer [5] ExtensionContainer OPTIONAL, + ...} + +END + diff --git a/rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn new file mode 100644 index 000000000..024dd6f9b --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn @@ -0,0 +1,216 @@ +-- $Id: MAP-OM-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 17.7.2 Operation and maintenance data types +-- 3GPP TS 29.002 V8.9.0 (2009-04) + +MAP-OM-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-OM-DataTypes (12) version11 (11)} + +DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + ActivateTraceModeArg, + ActivateTraceModeRes, + DeactivateTraceModeArg, + DeactivateTraceModeRes, + TracePropagationList +; + +IMPORTS + AddressString, + IMSI +FROM MAP-CommonDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)} + + ExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} + +; + +ActivateTraceModeArg ::= SEQUENCE { + imsi [0] IMSI OPTIONAL, + traceReference [1] TraceReference, + traceType [2] TraceType, + omc-Id [3] AddressString OPTIONAL, + extensionContainer [4] ExtensionContainer OPTIONAL, + ..., + traceReference2 [5] TraceReference2 OPTIONAL, + traceDepthList [6] TraceDepthList OPTIONAL, + traceNE-TypeList [7] TraceNE-TypeList OPTIONAL, + traceInterfaceList [8] TraceInterfaceList OPTIONAL, + traceEventList [9] TraceEventList OPTIONAL + } + +TraceReference ::= OCTET STRING (SIZE (1..2)) + +TraceReference2 ::= OCTET STRING (SIZE (3)) + +TraceRecordingSessionReference ::= OCTET STRING (SIZE (2)) + +TraceType ::= INTEGER + (0..255) + -- Trace types are fully defined in 3GPP TS 52.008. [61] + +TraceDepthList ::= SEQUENCE { + msc-s-TraceDepth [0] TraceDepth OPTIONAL, + mgw-TraceDepth [1] TraceDepth OPTIONAL, + sgsn-TraceDepth [2] TraceDepth OPTIONAL, + ggsn-TraceDepth [3] TraceDepth OPTIONAL, + rnc-TraceDepth [4] TraceDepth OPTIONAL, + bmsc-TraceDepth [5] TraceDepth OPTIONAL, + ...} + +TraceDepth ::= ENUMERATED { + minimum (0), + medium (1), + maximum (2), + ...} +-- The value medium is applicable only for RNC. For other network elements, if value medium +-- is received, value minimum shall be applied. + +TraceNE-TypeList ::= BIT STRING { + msc-s (0), + mgw (1), + sgsn (2), + ggsn (3), + rnc (4), + bm-sc (5)} (SIZE (6..16)) +-- Other bits than listed above shall be discarded. + +TraceInterfaceList ::= SEQUENCE { + msc-s-List [0] MSC-S-InterfaceList OPTIONAL, + mgw-List [1] MGW-InterfaceList OPTIONAL, + sgsn-List [2] SGSN-InterfaceList OPTIONAL, + ggsn-List [3] GGSN-InterfaceList OPTIONAL, + rnc-List [4] RNC-InterfaceList OPTIONAL, + bmsc-List [5] BMSC-InterfaceList OPTIONAL, + ...} + +MSC-S-InterfaceList ::= BIT STRING { + a (0), + iu (1), + mc (2), + map-g (3), + map-b (4), + map-e (5), + map-f (6), + cap (7), + map-d (8), + map-c (9)} (SIZE (10..16)) +-- Other bits than listed above shall be discarded. + +MGW-InterfaceList ::= BIT STRING { + mc (0), + nb-up (1), + iu-up (2)} (SIZE (3..8)) +-- Other bits than listed above shall be discarded. + +SGSN-InterfaceList ::= BIT STRING { + gb (0), + iu (1), + gn (2), + map-gr (3), + map-gd (4), + map-gf (5), + gs (6), + ge (7)} (SIZE (8..16)) +-- Other bits than listed above shall be discarded. + +GGSN-InterfaceList ::= BIT STRING { + gn (0), + gi (1), + gmb (2)} (SIZE (3..8)) +-- Other bits than listed above shall be discarded. + +RNC-InterfaceList ::= BIT STRING { + iu (0), + iur (1), + iub (2), + uu (3)} (SIZE (4..8)) +-- Other bits than listed above shall be discarded. + +BMSC-InterfaceList ::= BIT STRING { + gmb (0)} (SIZE (1..8)) +-- Other bits than listed above shall be discarded. + +TraceEventList ::= SEQUENCE { + msc-s-List [0] MSC-S-EventList OPTIONAL, + mgw-List [1] MGW-EventList OPTIONAL, + sgsn-List [2] SGSN-EventList OPTIONAL, + ggsn-List [3] GGSN-EventList OPTIONAL, + bmsc-List [4] BMSC-EventList OPTIONAL, + ...} + +MSC-S-EventList ::= BIT STRING { + mo-mtCall (0), + mo-mt-sms (1), + lu-imsiAttach-imsiDetach (2), + handovers (3), + ss (4)} (SIZE (5..16)) +-- Other bits than listed above shall be discarded. + +MGW-EventList ::= BIT STRING { + context (0)} (SIZE (1..8)) +-- Other bits than listed above shall be discarded. + +SGSN-EventList ::= BIT STRING { + pdpContext (0), + mo-mt-sms (1), + rau-gprsAttach-gprsDetach (2), + mbmsContext (3)} (SIZE (4..16)) +-- Other bits than listed above shall be discarded. + +GGSN-EventList ::= BIT STRING { + pdpContext (0), + mbmsContext (1)} (SIZE (2..8)) +-- Other bits than listed above shall be discarded. + +BMSC-EventList ::= BIT STRING { + mbmsMulticastServiceActivation (0)} (SIZE (1..8)) +-- Other bits than listed above shall be discarded. + + +TracePropagationList ::= SEQUENCE { + traceReference [0] TraceReference OPTIONAL, + traceType [1] TraceType OPTIONAL, + traceReference2 [2] TraceReference2 OPTIONAL, + traceRecordingSessionReference [3] TraceRecordingSessionReference OPTIONAL, + rnc-TraceDepth [4] TraceDepth OPTIONAL, + rnc-InterfaceList [5] RNC-InterfaceList OPTIONAL, + msc-s-TraceDepth [6] TraceDepth OPTIONAL, + msc-s-InterfaceList [7] MSC-S-InterfaceList OPTIONAL, + msc-s-EventList [8] MSC-S-EventList OPTIONAL, + mgw-TraceDepth [9] TraceDepth OPTIONAL, + mgw-InterfaceList [10] MGW-InterfaceList OPTIONAL, + mgw-EventList [11] MGW-EventList OPTIONAL, + ...} + +ActivateTraceModeRes ::= SEQUENCE { + extensionContainer [0] ExtensionContainer OPTIONAL, + ..., + traceSupportIndicator [1] NULL OPTIONAL + } + +DeactivateTraceModeArg ::= SEQUENCE { + imsi [0] IMSI OPTIONAL, + traceReference [1] TraceReference, + extensionContainer [2] ExtensionContainer OPTIONAL, + ..., + traceReference2 [3] TraceReference2 OPTIONAL + } + +DeactivateTraceModeRes ::= SEQUENCE { + extensionContainer [0] ExtensionContainer OPTIONAL, + ...} + +END + diff --git a/rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn new file mode 100644 index 000000000..0ef941f2b --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn @@ -0,0 +1,270 @@ +-- $Id: MAP-SM-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.6 Short message data types + +MAP-SM-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SM-DataTypes (16) version11 (11)} + +DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + RoutingInfoForSM-Arg, + RoutingInfoForSM-Res, + MO-ForwardSM-Arg, + MO-ForwardSM-Res, + MT-ForwardSM-Arg, + MT-ForwardSM-Res, + ReportSM-DeliveryStatusArg, + ReportSM-DeliveryStatusRes, + AlertServiceCentreArg, + InformServiceCentreArg, + ReadyForSM-Arg, + ReadyForSM-Res, + SM-DeliveryOutcome, + AlertReason, + Additional-Number, + MT-ForwardSM-VGCS-Arg, + MT-ForwardSM-VGCS-Res +; + +IMPORTS + AddressString, + ISDN-AddressString, + SignalInfo, + IMSI, + LMSI, + ASCI-CallReference + +FROM MAP-CommonDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)} + + AbsentSubscriberDiagnosticSM +FROM MAP-ER-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ER-DataTypes (17) version11 (11)} + + ExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} +; + + +RoutingInfoForSM-Arg ::= SEQUENCE { + msisdn [0] ISDN-AddressString, + sm-RP-PRI [1] BOOLEAN, + serviceCentreAddress [2] AddressString, + extensionContainer [6] ExtensionContainer OPTIONAL, + ... , + gprsSupportIndicator [7] NULL OPTIONAL, + -- gprsSupportIndicator is set only if the SMS-GMSC supports + -- receiving of two numbers from the HLR + sm-RP-MTI [8] SM-RP-MTI OPTIONAL, + sm-RP-SMEA [9] SM-RP-SMEA OPTIONAL, + sm-deliveryNotIntended [10] SM-DeliveryNotIntended OPTIONAL } + +SM-DeliveryNotIntended ::= ENUMERATED { + onlyIMSI-requested (0), + onlyMCC-MNC-requested (1), + ...} + +SM-RP-MTI ::= INTEGER (0..10) + -- 0 SMS Deliver + -- 1 SMS Status Report + -- other values are reserved for future use and shall be discarded if + -- received + +SM-RP-SMEA ::= OCTET STRING (SIZE (1..12)) + -- this parameter contains an address field which is encoded + -- as defined in 3GPP TS 23.040. An address field contains 3 elements : + -- address-length + -- type-of-address + -- address-value + +RoutingInfoForSM-Res ::= SEQUENCE { + imsi IMSI, + locationInfoWithLMSI [0] LocationInfoWithLMSI, + extensionContainer [4] ExtensionContainer OPTIONAL, + ...} + +LocationInfoWithLMSI ::= SEQUENCE { + networkNode-Number [1] ISDN-AddressString, + lmsi LMSI OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + gprsNodeIndicator [5] NULL OPTIONAL, + -- gprsNodeIndicator is set only if the SGSN number is sent as the + -- Network Node Number + additional-Number [6] Additional-Number OPTIONAL + -- NetworkNode-number can be either msc-number or sgsn-number or IP-SM-GW + -- number or SMS Router number + } + +Additional-Number ::= CHOICE { + msc-Number [0] ISDN-AddressString, + sgsn-Number [1] ISDN-AddressString} + -- additional-number can be either msc-number or sgsn-number + -- if received networkNode-number is msc-number then the + -- additional number is sgsn-number + -- if received networkNode-number is sgsn-number then the + -- additional number is msc-number + +MO-ForwardSM-Arg ::= SEQUENCE { + sm-RP-DA SM-RP-DA, + sm-RP-OA SM-RP-OA, + sm-RP-UI SignalInfo, + extensionContainer ExtensionContainer OPTIONAL, + ... , + imsi IMSI OPTIONAL } + +MO-ForwardSM-Res ::= SEQUENCE { + sm-RP-UI SignalInfo OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +MT-ForwardSM-Arg ::= SEQUENCE { + sm-RP-DA SM-RP-DA, + sm-RP-OA SM-RP-OA, + sm-RP-UI SignalInfo, + moreMessagesToSend NULL OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +MT-ForwardSM-Res ::= SEQUENCE { + sm-RP-UI SignalInfo OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +SM-RP-DA ::= CHOICE { + imsi [0] IMSI, + lmsi [1] LMSI, + serviceCentreAddressDA [4] AddressString, + noSM-RP-DA [5] NULL} + +SM-RP-OA ::= CHOICE { + msisdn [2] ISDN-AddressString, + serviceCentreAddressOA [4] AddressString, + noSM-RP-OA [5] NULL} + +ReportSM-DeliveryStatusArg ::= SEQUENCE { + msisdn ISDN-AddressString, + serviceCentreAddress AddressString, + sm-DeliveryOutcome SM-DeliveryOutcome, + absentSubscriberDiagnosticSM [0] AbsentSubscriberDiagnosticSM + OPTIONAL, + extensionContainer [1] ExtensionContainer OPTIONAL, + ..., + gprsSupportIndicator [2] NULL OPTIONAL, + -- gprsSupportIndicator is set only if the SMS-GMSC supports + -- handling of two delivery outcomes + deliveryOutcomeIndicator [3] NULL OPTIONAL, + -- DeliveryOutcomeIndicator is set when the SM-DeliveryOutcome + -- is for GPRS + additionalSM-DeliveryOutcome [4] SM-DeliveryOutcome OPTIONAL, + -- If received, additionalSM-DeliveryOutcome is for GPRS + -- If DeliveryOutcomeIndicator is set, then AdditionalSM-DeliveryOutcome shall be absent + additionalAbsentSubscriberDiagnosticSM [5] AbsentSubscriberDiagnosticSM OPTIONAL, + -- If received additionalAbsentSubscriberDiagnosticSM is for GPRS + -- If DeliveryOutcomeIndicator is set, then AdditionalAbsentSubscriberDiagnosticSM + -- shall be absent + ip-sm-gw-Indicator [6] NULL OPTIONAL, + -- the ip-sm-gw indicator indicates by its presence that sm-deliveryOutcome + -- is for delivery via IMS + -- If present, deliveryOutcomeIndicator shall be absent. + ip-sm-gw-sm-deliveryOutcome [7] SM-DeliveryOutcome OPTIONAL, + -- If received ip-sm-gw-sm-deliveryOutcome is for delivery via IMS + -- If ip-sm-gw-Indicator is set, then ip-sm-gw-sm-deliveryOutcome shall be absent + ip-sm-gw-absentSubscriberDiagnosticSM [8] AbsentSubscriberDiagnosticSM OPTIONAL + -- If received ip-sm-gw-sm-absentSubscriberDiagnosticSM is for delivery via IMS + -- If ip-sm-gw-Indicator is set, then ip-sm-gw-sm-absentSubscriberDiagnosticSM + -- shall be absent +} + +SM-DeliveryOutcome ::= ENUMERATED { + memoryCapacityExceeded (0), + absentSubscriber (1), + successfulTransfer (2)} + +ReportSM-DeliveryStatusRes ::= SEQUENCE { + storedMSISDN ISDN-AddressString OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +AlertServiceCentreArg ::= SEQUENCE { + msisdn ISDN-AddressString, + serviceCentreAddress AddressString, + ...} + +InformServiceCentreArg ::= SEQUENCE { + storedMSISDN ISDN-AddressString OPTIONAL, + mw-Status MW-Status OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ... , + absentSubscriberDiagnosticSM AbsentSubscriberDiagnosticSM OPTIONAL, + additionalAbsentSubscriberDiagnosticSM [0] AbsentSubscriberDiagnosticSM OPTIONAL } + -- additionalAbsentSubscriberDiagnosticSM may be present only if + -- absentSubscriberDiagnosticSM is present. + -- if included, additionalAbsentSubscriberDiagnosticSM is for GPRS and + -- absentSubscriberDiagnosticSM is for non-GPRS + +MW-Status ::= BIT STRING { + sc-AddressNotIncluded (0), + mnrf-Set (1), + mcef-Set (2) , + mnrg-Set (3)} (SIZE (6..16)) + -- exception handling: + -- bits 4 to 15 shall be ignored if received and not understood + +ReadyForSM-Arg ::= SEQUENCE { + imsi [0] IMSI, + alertReason AlertReason, + alertReasonIndicator NULL OPTIONAL, + -- alertReasonIndicator is set only when the alertReason + -- sent to HLR is for GPRS + extensionContainer ExtensionContainer OPTIONAL, + ..., + additionalAlertReasonIndicator [1] NULL OPTIONAL + -- additionalAlertReasonIndicator is set only when the alertReason + -- sent to HLR is for IP-SM-GW + } + +ReadyForSM-Res ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ...} + +AlertReason ::= ENUMERATED { + ms-Present (0), + memoryAvailable (1)} + +MT-ForwardSM-VGCS-Arg ::= SEQUENCE { + asciCallReference ASCI-CallReference, + sm-RP-OA SM-RP-OA, + sm-RP-UI SignalInfo, + extensionContainer ExtensionContainer OPTIONAL, + ...} + +MT-ForwardSM-VGCS-Res ::= SEQUENCE { + sm-RP-UI [0] SignalInfo OPTIONAL, + dispatcherList [1] DispatcherList OPTIONAL, + ongoingCall NULL OPTIONAL, + extensionContainer [2] ExtensionContainer OPTIONAL, + ...} + +DispatcherList ::= + SEQUENCE SIZE (1..maxNumOfDispatchers) OF + ISDN-AddressString + +maxNumOfDispatchers INTEGER ::= 5 + + + +END + diff --git a/rrlp-ephemeris/asn1/MAP-SS-Code.asn b/rrlp-ephemeris/asn1/MAP-SS-Code.asn new file mode 100644 index 000000000..163f2dc3a --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-SS-Code.asn @@ -0,0 +1,190 @@ +-- $Id: MAP-SS-Code.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.5 Supplementary service codes + +MAP-SS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)} + +DEFINITIONS + +::= + +BEGIN + +SS-Code ::= OCTET STRING (SIZE (1)) + -- This type is used to represent the code identifying a single + -- supplementary service, a group of supplementary services, or + -- all supplementary services. The services and abbreviations + -- used are defined in TS 3GPP TS 22.004 [5]. The internal structure is + -- defined as follows: + -- + -- bits 87654321: group (bits 8765), and specific service + -- (bits 4321) + +allSS SS-Code ::= '00000000'B + -- reserved for possible future use + -- all SS + +allLineIdentificationSS SS-Code ::= '00010000'B + -- reserved for possible future use + -- all line identification SS +clip SS-Code ::= '00010001'B + -- calling line identification presentation +clir SS-Code ::= '00010010'B + -- calling line identification restriction +colp SS-Code ::= '00010011'B + -- connected line identification presentation +colr SS-Code ::= '00010100'B + -- connected line identification restriction +mci SS-Code ::= '00010101'B + -- reserved for possible future use + -- malicious call identification + +allNameIdentificationSS SS-Code ::= '00011000'B + -- all name identification SS +cnap SS-Code ::= '00011001'B + -- calling name presentation + + -- SS-Codes '00011010'B to '00011111'B are reserved for future + -- NameIdentification Supplementary Service use. + +allForwardingSS SS-Code ::= '00100000'B + -- all forwarding SS +cfu SS-Code ::= '00100001'B + -- call forwarding unconditional +allCondForwardingSS SS-Code ::= '00101000'B + -- all conditional forwarding SS +cfb SS-Code ::= '00101001'B + -- call forwarding on mobile subscriber busy +cfnry SS-Code ::= '00101010'B + -- call forwarding on no reply +cfnrc SS-Code ::= '00101011'B + -- call forwarding on mobile subscriber not reachable +cd SS-Code ::= '00100100'B + -- call deflection + +allCallOfferingSS SS-Code ::= '00110000'B + -- reserved for possible future use + -- all call offering SS includes also all forwarding SS +ect SS-Code ::= '00110001'B + -- explicit call transfer +mah SS-Code ::= '00110010'B + -- reserved for possible future use + -- mobile access hunting + +allCallCompletionSS SS-Code ::= '01000000'B + -- reserved for possible future use + -- all Call completion SS +cw SS-Code ::= '01000001'B + -- call waiting +hold SS-Code ::= '01000010'B + -- call hold +ccbs-A SS-Code ::= '01000011'B + -- completion of call to busy subscribers, originating side + -- this SS-Code is used only in InsertSubscriberData, DeleteSubscriberData + -- and InterrogateSS +ccbs-B SS-Code ::= '01000100'B + -- completion of call to busy subscribers, destination side + -- this SS-Code is used only in InsertSubscriberData and DeleteSubscriberData +mc SS-Code ::= '01000101'B + -- multicall + +allMultiPartySS SS-Code ::= '01010000'B + -- reserved for possible future use + -- all multiparty SS +multiPTY SS-Code ::= '01010001'B + -- multiparty + +allCommunityOfInterest-SS SS-Code ::= '01100000'B + -- reserved for possible future use + -- all community of interest SS +cug SS-Code ::= '01100001'B + -- closed user group + +allChargingSS SS-Code ::= '01110000'B + -- reserved for possible future use + -- all charging SS +aoci SS-Code ::= '01110001'B + -- advice of charge information +aocc SS-Code ::= '01110010'B + -- advice of charge charging + +allAdditionalInfoTransferSS SS-Code ::= '10000000'B + -- reserved for possible future use + -- all additional information transfer SS +uus1 SS-Code ::= '10000001'B + -- UUS1 user-to-user signalling +uus2 SS-Code ::= '10000010'B + -- UUS2 user-to-user signalling +uus3 SS-Code ::= '10000011'B + -- UUS3 user-to-user signalling + +allBarringSS SS-Code ::= '10010000'B + -- all barring SS +barringOfOutgoingCalls SS-Code ::= '10010001'B + -- barring of outgoing calls +baoc SS-Code ::= '10010010'B + -- barring of all outgoing calls +boic SS-Code ::= '10010011'B + -- barring of outgoing international calls +boicExHC SS-Code ::= '10010100'B + -- barring of outgoing international calls except those directed + -- to the home PLMN Country +barringOfIncomingCalls SS-Code ::= '10011001'B + -- barring of incoming calls +baic SS-Code ::= '10011010'B + -- barring of all incoming calls +bicRoam SS-Code ::= '10011011'B + -- barring of incoming calls when roaming outside home PLMN + -- Country + +allPLMN-specificSS SS-Code ::= '11110000'B +plmn-specificSS-1 SS-Code ::= '11110001'B +plmn-specificSS-2 SS-Code ::= '11110010'B +plmn-specificSS-3 SS-Code ::= '11110011'B +plmn-specificSS-4 SS-Code ::= '11110100'B +plmn-specificSS-5 SS-Code ::= '11110101'B +plmn-specificSS-6 SS-Code ::= '11110110'B +plmn-specificSS-7 SS-Code ::= '11110111'B +plmn-specificSS-8 SS-Code ::= '11111000'B +plmn-specificSS-9 SS-Code ::= '11111001'B +plmn-specificSS-A SS-Code ::= '11111010'B +plmn-specificSS-B SS-Code ::= '11111011'B +plmn-specificSS-C SS-Code ::= '11111100'B +plmn-specificSS-D SS-Code ::= '11111101'B +plmn-specificSS-E SS-Code ::= '11111110'B +plmn-specificSS-F SS-Code ::= '11111111'B + +allCallPrioritySS SS-Code ::= '10100000'B + -- reserved for possible future use + -- all call priority SS +emlpp SS-Code ::= '10100001'B + -- enhanced Multilevel Precedence Pre-emption (EMLPP) service + +allLCSPrivacyException SS-Code ::= '10110000'B + -- all LCS Privacy Exception Classes +universal SS-Code ::= '10110001'B + -- allow location by any LCS client +callSessionRelated SS-Code ::= '10110010'B + -- allow location by any value added LCS client to which a call/session + -- is established from the target MS +callSessionUnrelated SS-Code ::= '10110011'B + -- allow location by designated external value added LCS clients +plmnoperator SS-Code ::= '10110100'B + -- allow location by designated PLMN operator LCS clients +serviceType SS-Code ::= '10110101'B + -- allow location by LCS clients of a designated LCS service type + +allMOLR-SS SS-Code ::= '11000000'B + -- all Mobile Originating Location Request Classes +basicSelfLocation SS-Code ::= '11000001'B + -- allow an MS to request its own location +autonomousSelfLocation SS-Code ::= '11000010'B + -- allow an MS to perform self location without interaction + -- with the PLMN for a predetermined period of time +transferToThirdParty SS-Code ::= '11000011'B + -- allow an MS to request transfer of its location to another LCS client + +END + diff --git a/rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn new file mode 100644 index 000000000..253f7f01a --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn @@ -0,0 +1,342 @@ +-- $Id: MAP-SS-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.4 Supplementary service data types + +MAP-SS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-DataTypes (14) version11 (11)} + +DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + RegisterSS-Arg, + SS-Info, + SS-Status, + SS-SubscriptionOption, + SS-ForBS-Code, + InterrogateSS-Res, + USSD-Arg, + USSD-Res, + USSD-DataCodingScheme, + USSD-String, + Password, + GuidanceInfo, + SS-List, + SS-InfoList, + OverrideCategory, + CliRestrictionOption, + NoReplyConditionTime, + ForwardingOptions, + maxNumOfSS, + SS-Data, + SS-InvocationNotificationArg, + SS-InvocationNotificationRes, + CCBS-Feature, + RegisterCC-EntryArg, + RegisterCC-EntryRes, + EraseCC-EntryArg, + EraseCC-EntryRes +; + +IMPORTS + AddressString, + ISDN-AddressString, + ISDN-SubaddressString, + FTN-AddressString, + IMSI, + BasicServiceCode, + AlertingPattern, + EMLPP-Priority, + MaxMC-Bearers, + MC-Bearers, + ExternalSignalInfo +FROM MAP-CommonDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)} + + ExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} + + SS-Code +FROM MAP-SS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)} +; + + +RegisterSS-Arg ::= SEQUENCE { + ss-Code SS-Code, + basicService BasicServiceCode OPTIONAL, + forwardedToNumber [4] AddressString OPTIONAL, + forwardedToSubaddress [6] ISDN-SubaddressString OPTIONAL, + noReplyConditionTime [5] NoReplyConditionTime OPTIONAL, + ..., + defaultPriority [7] EMLPP-Priority OPTIONAL, + nbrUser [8] MC-Bearers OPTIONAL, + longFTN-Supported [9] NULL OPTIONAL } + +NoReplyConditionTime ::= INTEGER (5..30) + +SS-Info ::= CHOICE { + forwardingInfo [0] ForwardingInfo, + callBarringInfo [1] CallBarringInfo, + ss-Data [3] SS-Data} + +ForwardingInfo ::= SEQUENCE { + ss-Code SS-Code OPTIONAL, + forwardingFeatureList ForwardingFeatureList, + ...} + +ForwardingFeatureList ::= + SEQUENCE SIZE (1..maxNumOfBasicServiceGroups) OF + ForwardingFeature + +ForwardingFeature ::= SEQUENCE { + basicService BasicServiceCode OPTIONAL, + ss-Status [4] SS-Status OPTIONAL, + forwardedToNumber [5] ISDN-AddressString OPTIONAL, + forwardedToSubaddress [8] ISDN-SubaddressString OPTIONAL, + forwardingOptions [6] ForwardingOptions OPTIONAL, + noReplyConditionTime [7] NoReplyConditionTime OPTIONAL, + ..., + longForwardedToNumber [9] FTN-AddressString OPTIONAL } + +SS-Status ::= OCTET STRING (SIZE (1)) + + -- bits 8765: 0000 (unused) + -- bits 4321: Used to convey the "P bit","R bit","A bit" and "Q bit", + -- representing supplementary service state information + -- as defined in TS 3GPP TS 23.011 [22] + + -- bit 4: "Q bit" + + -- bit 3: "P bit" + + -- bit 2: "R bit" + + -- bit 1: "A bit" + +ForwardingOptions ::= OCTET STRING (SIZE (1)) + + -- bit 8: notification to forwarding party + -- 0 no notification + -- 1 notification + + -- bit 7: redirecting presentation + -- 0 no presentation + -- 1 presentation + + -- bit 6: notification to calling party + -- 0 no notification + -- 1 notification + + -- bit 5: 0 (unused) + + -- bits 43: forwarding reason + -- 00 ms not reachable + -- 01 ms busy + -- 10 no reply + -- 11 unconditional when used in a SRI Result, + -- or call deflection when used in a RCH Argument + -- bits 21: 00 (unused) + +CallBarringInfo ::= SEQUENCE { + ss-Code SS-Code OPTIONAL, + callBarringFeatureList CallBarringFeatureList, + ...} + +CallBarringFeatureList ::= SEQUENCE SIZE (1..maxNumOfBasicServiceGroups) OF + CallBarringFeature + +CallBarringFeature ::= SEQUENCE { + basicService BasicServiceCode OPTIONAL, + ss-Status [4] SS-Status OPTIONAL, + ...} + +SS-Data ::= SEQUENCE { + ss-Code SS-Code OPTIONAL, + ss-Status [4] SS-Status OPTIONAL, + ss-SubscriptionOption SS-SubscriptionOption OPTIONAL, + basicServiceGroupList BasicServiceGroupList OPTIONAL, + ..., + defaultPriority EMLPP-Priority OPTIONAL, + nbrUser [5] MC-Bearers OPTIONAL + } + +SS-SubscriptionOption ::= CHOICE { + cliRestrictionOption [2] CliRestrictionOption, + overrideCategory [1] OverrideCategory} + +CliRestrictionOption ::= ENUMERATED { + permanent (0), + temporaryDefaultRestricted (1), + temporaryDefaultAllowed (2)} + +OverrideCategory ::= ENUMERATED { + overrideEnabled (0), + overrideDisabled (1)} + +SS-ForBS-Code ::= SEQUENCE { + ss-Code SS-Code, + basicService BasicServiceCode OPTIONAL, + ..., + longFTN-Supported [4] NULL OPTIONAL } + +GenericServiceInfo ::= SEQUENCE { + ss-Status SS-Status, + cliRestrictionOption CliRestrictionOption OPTIONAL, + ..., + maximumEntitledPriority [0] EMLPP-Priority OPTIONAL, + defaultPriority [1] EMLPP-Priority OPTIONAL, + ccbs-FeatureList [2] CCBS-FeatureList OPTIONAL, + nbrSB [3] MaxMC-Bearers OPTIONAL, + nbrUser [4] MC-Bearers OPTIONAL, + nbrSN [5] MC-Bearers OPTIONAL } + +CCBS-FeatureList ::= SEQUENCE SIZE (1..maxNumOfCCBS-Requests) OF + CCBS-Feature + +maxNumOfCCBS-Requests INTEGER ::= 5 + +CCBS-Feature ::= SEQUENCE { + ccbs-Index [0] CCBS-Index OPTIONAL, + b-subscriberNumber [1] ISDN-AddressString OPTIONAL, + b-subscriberSubaddress [2] ISDN-SubaddressString OPTIONAL, + basicServiceGroup [3] BasicServiceCode OPTIONAL, + ...} + +CCBS-Index ::= INTEGER (1..maxNumOfCCBS-Requests) + +InterrogateSS-Res ::= CHOICE { + ss-Status [0] SS-Status, + basicServiceGroupList [2] BasicServiceGroupList, + forwardingFeatureList [3] ForwardingFeatureList, + genericServiceInfo [4] GenericServiceInfo } + +USSD-Arg ::= SEQUENCE { + ussd-DataCodingScheme USSD-DataCodingScheme, + ussd-String USSD-String, + ... , + alertingPattern AlertingPattern OPTIONAL, + msisdn [0] ISDN-AddressString OPTIONAL } + +USSD-Res ::= SEQUENCE { + ussd-DataCodingScheme USSD-DataCodingScheme, + ussd-String USSD-String, + ...} + +USSD-DataCodingScheme ::= OCTET STRING (SIZE (1)) + -- The structure of the USSD-DataCodingScheme is defined by + -- the Cell Broadcast Data Coding Scheme as described in + -- TS 3GPP TS 23.038 [25] + +USSD-String ::= OCTET STRING (SIZE (1..maxUSSD-StringLength)) + -- The structure of the contents of the USSD-String is dependent + -- on the USSD-DataCodingScheme as described in TS 3GPP TS 23.038 [25]. + +maxUSSD-StringLength INTEGER ::= 160 + +Password ::= NumericString + (FROM ("0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9")) + (SIZE (4)) + +GuidanceInfo ::= ENUMERATED { + enterPW (0), + enterNewPW (1), + enterNewPW-Again (2)} + -- How this information is really delivered to the subscriber + -- (display, announcement, ...) is not part of this + -- specification. + +SS-List ::= SEQUENCE SIZE (1..maxNumOfSS) OF + SS-Code + +maxNumOfSS INTEGER ::= 30 + +SS-InfoList ::= SEQUENCE SIZE (1..maxNumOfSS) OF + SS-Info + +BasicServiceGroupList ::= SEQUENCE SIZE (1..maxNumOfBasicServiceGroups) OF + BasicServiceCode + +maxNumOfBasicServiceGroups INTEGER ::= 13 + +SS-InvocationNotificationArg ::= SEQUENCE { + imsi [0] IMSI, + msisdn [1] ISDN-AddressString, + ss-Event [2] SS-Code, + -- The following SS-Code values are allowed : + -- ect SS-Code ::= '00110001'B + -- multiPTY SS-Code ::= '01010001'B + -- cd SS-Code ::= '00100100'B + -- ccbs SS-Code ::= '01000100'B + ss-EventSpecification [3] SS-EventSpecification OPTIONAL, + extensionContainer [4] ExtensionContainer OPTIONAL, + ..., + b-subscriberNumber [5] ISDN-AddressString OPTIONAL, + ccbs-RequestState [6] CCBS-RequestState OPTIONAL + } + +CCBS-RequestState ::= ENUMERATED { + request (0), + recall (1), + active (2), + completed (3), + suspended (4), + frozen (5), + deleted (6) + } + +SS-InvocationNotificationRes ::= SEQUENCE { + extensionContainer ExtensionContainer OPTIONAL, + ... + } + +SS-EventSpecification ::= SEQUENCE SIZE (1..maxEventSpecification) OF + AddressString + +maxEventSpecification INTEGER ::= 2 + +RegisterCC-EntryArg ::= SEQUENCE { + ss-Code [0] SS-Code, + ccbs-Data [1] CCBS-Data OPTIONAL, + ...} + +CCBS-Data ::= SEQUENCE { + ccbs-Feature [0] CCBS-Feature, + translatedB-Number [1] ISDN-AddressString, + serviceIndicator [2] ServiceIndicator OPTIONAL, + callInfo [3] ExternalSignalInfo, + networkSignalInfo [4] ExternalSignalInfo, + ...} + +ServiceIndicator ::= BIT STRING { + clir-invoked (0), + camel-invoked (1)} (SIZE(2..32)) + -- exception handling: + -- bits 2 to 31 shall be ignored if received and not understood + +RegisterCC-EntryRes ::= SEQUENCE { + ccbs-Feature [0] CCBS-Feature OPTIONAL, + ...} + +EraseCC-EntryArg ::= SEQUENCE { + ss-Code [0] SS-Code, + ccbs-Index [1] CCBS-Index OPTIONAL, + ...} + +EraseCC-EntryRes ::= SEQUENCE { + ss-Code [0] SS-Code, + ss-Status [1] SS-Status OPTIONAL, + ...} + +END + diff --git a/rrlp-ephemeris/asn1/MAP-TS-Code.asn b/rrlp-ephemeris/asn1/MAP-TS-Code.asn new file mode 100644 index 000000000..5ac00bff2 --- /dev/null +++ b/rrlp-ephemeris/asn1/MAP-TS-Code.asn @@ -0,0 +1,92 @@ +-- $Id: MAP-TS-Code.asn 28149 2009-04-25 17:45:34Z etxrab $ +-- 3GPP TS 29.002 V8.9.0 (2009-04) +-- 17.7.9 Teleservice Codes + +MAP-TS-Code { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-TS-Code (19) version11 (11)} + +DEFINITIONS + +::= + +BEGIN + +TeleserviceCode ::= OCTET STRING (SIZE (1)) + -- This type is used to represent the code identifying a single + -- teleservice, a group of teleservices, or all teleservices. The + -- services are defined in TS GSM 22.003 [4]. + -- The internal structure is defined as follows: + + -- bits 87654321: group (bits 8765) and specific service + -- (bits 4321) + +Ext-TeleserviceCode ::= OCTET STRING (SIZE (1..5)) + -- This type is used to represent the code identifying a single + -- teleservice, a group of teleservices, or all teleservices. The + -- services are defined in TS GSM 22.003 [4]. + -- The internal structure is defined as follows: + + -- OCTET 1: + -- bits 87654321: group (bits 8765) and specific service + -- (bits 4321) + + -- OCTETS 2-5: reserved for future use. If received the + -- Ext-TeleserviceCode shall be + -- treated according to the exception handling defined for the + -- operation that uses this type. + + -- Ext-TeleserviceCode includes all values defined for TeleserviceCode. + +allTeleservices TeleserviceCode ::= '00000000'B + +allSpeechTransmissionServices TeleserviceCode ::= '00010000'B +telephony TeleserviceCode ::= '00010001'B +emergencyCalls TeleserviceCode ::= '00010010'B + +allShortMessageServices TeleserviceCode ::= '00100000'B +shortMessageMT-PP TeleserviceCode ::= '00100001'B +shortMessageMO-PP TeleserviceCode ::= '00100010'B + +allFacsimileTransmissionServices TeleserviceCode ::= '01100000'B +facsimileGroup3AndAlterSpeech TeleserviceCode ::= '01100001'B +automaticFacsimileGroup3 TeleserviceCode ::= '01100010'B +facsimileGroup4 TeleserviceCode ::= '01100011'B + +-- The following non-hierarchical Compound Teleservice Groups +-- are defined in TS 3GPP TS 22.030: +allDataTeleservices TeleserviceCode ::= '01110000'B + -- covers Teleservice Groups 'allFacsimileTransmissionServices' + -- and 'allShortMessageServices' +allTeleservices-ExeptSMS TeleserviceCode ::= '10000000'B + -- covers Teleservice Groups 'allSpeechTransmissionServices' and + -- 'allFacsimileTransmissionServices' +-- +-- Compound Teleservice Group Codes are only used in call +-- independent supplementary service operations, i.e. they +-- are not used in InsertSubscriberData or in +-- DeleteSubscriberData messages. + +allVoiceGroupCallServices TeleserviceCode ::= '10010000'B +voiceGroupCall TeleserviceCode ::= '10010001'B +voiceBroadcastCall TeleserviceCode ::= '10010010'B + +allPLMN-specificTS TeleserviceCode ::= '11010000'B +plmn-specificTS-1 TeleserviceCode ::= '11010001'B +plmn-specificTS-2 TeleserviceCode ::= '11010010'B +plmn-specificTS-3 TeleserviceCode ::= '11010011'B +plmn-specificTS-4 TeleserviceCode ::= '11010100'B +plmn-specificTS-5 TeleserviceCode ::= '11010101'B +plmn-specificTS-6 TeleserviceCode ::= '11010110'B +plmn-specificTS-7 TeleserviceCode ::= '11010111'B +plmn-specificTS-8 TeleserviceCode ::= '11011000'B +plmn-specificTS-9 TeleserviceCode ::= '11011001'B +plmn-specificTS-A TeleserviceCode ::= '11011010'B +plmn-specificTS-B TeleserviceCode ::= '11011011'B +plmn-specificTS-C TeleserviceCode ::= '11011100'B +plmn-specificTS-D TeleserviceCode ::= '11011101'B +plmn-specificTS-E TeleserviceCode ::= '11011110'B +plmn-specificTS-F TeleserviceCode ::= '11011111'B + +END + diff --git a/rrlp-ephemeris/asn1/RRLP-Components.asn b/rrlp-ephemeris/asn1/RRLP-Components.asn new file mode 100644 index 000000000..3bade6a6a --- /dev/null +++ b/rrlp-ephemeris/asn1/RRLP-Components.asn @@ -0,0 +1,1488 @@ +-- RRLP-Components.asn +-- $Id$ +-- Taken from 3GPP TS 44.031 V7.4.0 (2007-03) +-- http://www.3gpp.org/ftp/Specs/archive/44_series/44.031/44031-740.zip/44031-740.doc +-- +-- 4 Components +-- 5 Elements of Components +-- + +RRLP-Components +-- { RRLP-Components } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + Ext-GeographicalInformation, VelocityEstimate +FROM + MAP-LCS-DataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-LCS-DataTypes (25) version11 (11)} + + ExtensionContainer +FROM MAP-ExtensionDataTypes { + itu-t identified-organization (4) etsi (0) mobileDomain (0) + gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} +; + + +-- Add here other ASN.1 definitions presented below +-- in chapters 4 and 5. + +-- Measurement Position request component +MsrPosition-Req ::= SEQUENCE { + positionInstruct PositionInstruct, + referenceAssistData ReferenceAssistData OPTIONAL, + msrAssistData MsrAssistData OPTIONAL, + systemInfoAssistData SystemInfoAssistData OPTIONAL, + gps-AssistData GPS-AssistData OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + -- Release 98 extension element +rel98-MsrPosition-Req-extension Rel98-MsrPosition-Req-Extension OPTIONAL, + -- Release 5 extension element +rel5-MsrPosition-Req-extension Rel5-MsrPosition-Req-Extension OPTIONAL, + -- Release 7 extension element +rel7-MsrPosition-Req-extension Rel7-MsrPosition-Req-Extension OPTIONAL +} + +-- Measurement Position response component +MsrPosition-Rsp ::= SEQUENCE { + multipleSets MultipleSets OPTIONAL, + referenceIdentity ReferenceIdentity OPTIONAL, + otd-MeasureInfo OTD-MeasureInfo OPTIONAL, + locationInfo LocationInfo OPTIONAL, + gps-MeasureInfo GPS-MeasureInfo OPTIONAL, + locationError LocationError OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + -- Release extension here + rel-98-MsrPosition-Rsp-Extension + Rel-98-MsrPosition-Rsp-Extension OPTIONAL, + rel-5-MsrPosition-Rsp-Extension + Rel-5-MsrPosition-Rsp-Extension OPTIONAL, + -- rel-5-MsrPosition-Rsp-Extension and other possible future extensions + -- are the only information elements that may be included in the 2nd + -- MsrPosition-Rsp component when RRLP pseudo-segmentation is used + rel-7-MsrPosition-Rsp-Extension + Rel-7-MsrPosition-Rsp-Extension OPTIONAL +} + +-- Assistance Data component +AssistanceData ::= SEQUENCE { + referenceAssistData ReferenceAssistData OPTIONAL, + msrAssistData MsrAssistData OPTIONAL, + systemInfoAssistData SystemInfoAssistData OPTIONAL, + gps-AssistData GPS-AssistData OPTIONAL, + moreAssDataToBeSent MoreAssDataToBeSent OPTIONAL, -- If not present, interpret as only + -- Assistance Data component used to + -- deliver entire set of assistance + -- data. + extensionContainer ExtensionContainer OPTIONAL, + ..., + -- Release extension here + rel98-AssistanceData-Extension Rel98-AssistanceData-Extension OPTIONAL, + rel5-AssistanceData-Extension Rel5-AssistanceData-Extension OPTIONAL, + rel7-AssistanceData-Extension Rel7-AssistanceData-Extension OPTIONAL +} + +-- Protocol Error component +ProtocolError ::= SEQUENCE { + errorCause ErrorCodes, + extensionContainer ExtensionContainer OPTIONAL, + ..., + -- Release extensions here + rel-5-ProtocolError-Extension Rel-5-ProtocolError-Extension OPTIONAL +} + +-- Position instructions +PositionInstruct ::= SEQUENCE { + -- Method type + methodType MethodType, + positionMethod PositionMethod, + measureResponseTime MeasureResponseTime, + useMultipleSets UseMultipleSets, + environmentCharacter EnvironmentCharacter OPTIONAL +} + +-- +MethodType ::= CHOICE { + msAssisted AccuracyOpt, -- accuracy is optional + msBased Accuracy, -- accuracy is mandatory + msBasedPref Accuracy, -- accuracy is mandatory + msAssistedPref Accuracy -- accuracy is mandatory +} + +-- Accuracy of the location estimation +AccuracyOpt ::= SEQUENCE { + accuracy Accuracy OPTIONAL +} + +-- The values of this field are defined in 3GPP TS 23.032 (Uncertainty code) +Accuracy ::= INTEGER (0..127) + + +-- Position Method +PositionMethod ::= ENUMERATED { + eotd (0), + gps (1), + gpsOrEOTD (2) +} + +-- Measurement request response time +MeasureResponseTime ::= INTEGER (0..7) + +-- useMultiple Sets, FFS! +UseMultipleSets ::= ENUMERATED { + multipleSets (0), -- multiple sets are allowed + oneSet (1) -- sending of multiple is not allowed +} + +-- Environment characterization +EnvironmentCharacter ::= ENUMERATED { + badArea (0), -- bad urban or suburban, heavy multipath and NLOS + notBadArea (1), -- light multipath and NLOS + mixedArea (2), -- not defined or mixed environment + ... +} + +-- E-OTD reference BTS for Assitance data IE +ReferenceAssistData ::= SEQUENCE { + bcchCarrier BCCHCarrier, -- BCCH carrier + bsic BSIC, -- BSIC + timeSlotScheme TimeSlotScheme, -- Timeslot scheme + btsPosition BTSPosition OPTIONAL +} + +-- ellipsoid point and +-- ellipsoid point with altitude and uncertainty ellipsoid shapes are supported +BTSPosition ::= Ext-GeographicalInformation + +-- RF channel number of BCCH +BCCHCarrier ::= INTEGER (0..1023) + +-- Base station Identity Code +BSIC ::= INTEGER (0..63) + +-- Timeslot scheme +TimeSlotScheme ::= ENUMERATED { + equalLength (0), + variousLength (1) +} + +-- Time slot (modulo) +ModuloTimeSlot ::= INTEGER (0..3) + +-- E-OTD measurement assistance data IE +-- The total number of neighbors in this element (MsrAssistData) +-- and in SystemInfoAssistData element (presented neighbors +-- can be at a maximum 15!) +MsrAssistData ::= SEQUENCE { + msrAssistList SeqOfMsrAssistBTS +} +SeqOfMsrAssistBTS ::= SEQUENCE (SIZE(1..15)) OF MsrAssistBTS + +MsrAssistBTS ::= SEQUENCE { + bcchCarrier BCCHCarrier, -- BCCH carrier + bsic BSIC, -- BSIC + multiFrameOffset MultiFrameOffset, -- multiframe offset + timeSlotScheme TimeSlotScheme, -- Timeslot scheme + roughRTD RoughRTD, -- rough RTD value + + -- Location Calculation Assistance data is moved here + calcAssistanceBTS CalcAssistanceBTS OPTIONAL +} + +-- Multiframe offset +MultiFrameOffset ::= INTEGER (0..51) +-- The Multiframe Offset value 51 shall not be encoded by the transmitting entity and +-- shall be treated by the receiving entity as 0. + +-- Rough RTD value between one base station and reference BTS +RoughRTD ::= INTEGER (0..1250) +-- The RoughRTD value 1250 shall not be encoded by the transmitting entity and shall +-- be treated by the receiving entity as 0. + +-- E-OTD Measurement assistance data for system information List IE +-- The total number of base stations in this element (SystemInfoAssistData +-- presented neighbors) and in MsrAssistData element can be at a maximum 15. +SystemInfoAssistData ::= SEQUENCE { + systemInfoAssistList SeqOfSystemInfoAssistBTS +} +SeqOfSystemInfoAssistBTS::= SEQUENCE (SIZE(1..32)) OF SystemInfoAssistBTS + +-- whether n.th is present or not ? +SystemInfoAssistBTS ::= CHOICE { + notPresent NULL, + present AssistBTSData +} + +-- Actual assistance data for system information base station +AssistBTSData ::= SEQUENCE { + bsic BSIC, -- BSIC + multiFrameOffset MultiFrameOffset, -- multiframe offset + timeSlotScheme TimeSlotScheme, -- Timeslot scheme + roughRTD RoughRTD, -- rough RTD value + + -- Location Calculation Assistance data + calcAssistanceBTS CalcAssistanceBTS OPTIONAL +} + +-- E-OTD Location calculation assistance data, +-- CalcAssistanceBTS element is optional not subfields +CalcAssistanceBTS ::= SEQUENCE { + fineRTD FineRTD, -- fine RTD value between base stations + referenceWGS84 ReferenceWGS84 -- reference coordinates +} + +-- Coordinates of neighbour BTS, WGS-84 ellipsoid +ReferenceWGS84 ::= SEQUENCE { + relativeNorth RelDistance, -- relative distance (south negative) + relativeEast RelDistance, -- relative distance (west negative) + -- Relative Altitude is not always known + relativeAlt RelativeAlt OPTIONAL -- relative altitude +} + +-- Fine RTD value between this BTS and the reference BTS +FineRTD ::= INTEGER (0..255) + +-- Relative north/east distance +RelDistance ::= INTEGER (-200000..200000) + +-- Relative altitude +RelativeAlt ::= INTEGER (-4000..4000) + +-- Measure position response IEs +-- Reference Identity +-- Multiple sets +MultipleSets ::= SEQUENCE { + -- number of reference sets + nbrOfSets INTEGER (2..3), + + -- This field actually tells the number of reference BTSs + nbrOfReferenceBTSs INTEGER (1..3), + + -- This field is conditional and included optionally only if + -- nbrOfSets is 3 and number of reference BTSs is 2. + referenceRelation ReferenceRelation OPTIONAL +} + +-- Relation between refence BTSs and sets +ReferenceRelation ::= ENUMERATED { + secondBTSThirdSet (0), -- 1st BTS related to 1st and 2nd sets + secondBTSSecondSet (1), -- 1st BTS related to 1st and 3rd sets + firstBTSFirstSet (2) -- 1st BTS related to 1st set +} + +-- Reference BTS Identity, this element contains number of +-- BTSs told nbrOfReferenceBTSs field in Multiple sets element) +ReferenceIdentity ::= SEQUENCE { + -- Reference BTS list + refBTSList SeqOfReferenceIdentityType +} +SeqOfReferenceIdentityType ::= SEQUENCE (SIZE(1..3)) OF ReferenceIdentityType + +-- Cell identity +ReferenceIdentityType ::= CHOICE { + bsicAndCarrier BSICAndCarrier, -- BSIC and Carrier + ci CellID, -- Cell ID, LAC not needed + requestIndex RequestIndex, -- Index to Requested Neighbor List + systemInfoIndex SystemInfoIndex, -- Index to System info list, this type of ref. identity + -- shall not be used by the MS unless it has received + -- the SystemInfoAssistData from the SMLC for this cell. + ciAndLAC CellIDAndLAC -- CI and LAC +} + +BSICAndCarrier ::= SEQUENCE { + carrier BCCHCarrier, + bsic BSIC +} + +RequestIndex ::= INTEGER (1..16) + +SystemInfoIndex ::= INTEGER (1..32) + +CellIDAndLAC ::= SEQUENCE { + referenceLAC LACID, -- Location area code + referenceCI CellID -- Cell identity +} +CellID ::= INTEGER (0..65535) +LACID ::= INTEGER (0..65535) + +-- OTD-MeasureInfo +OTD-MeasureInfo ::= SEQUENCE { + -- Measurement info elements, OTD-MsrElement is repeated number of times + -- told in nbrOfReferenceBTSs in MultipleSets, default value is 1 + otdMsrFirstSets OTD-MsrElementFirst, + + -- if more than one sets are present this element is repeated + -- NumberOfSets - 1 (-1 = first set) + otdMsrRestSets SeqOfOTD-MsrElementRest OPTIONAL +} + +SeqOfOTD-MsrElementRest ::= SEQUENCE (SIZE(1..2)) OF OTD-MsrElementRest + +-- OTD measurent information for 1 set +OTD-MsrElementFirst ::= SEQUENCE { + refFrameNumber INTEGER (0..42431), -- Frame number modulo 42432 + referenceTimeSlot ModuloTimeSlot, + toaMeasurementsOfRef TOA-MeasurementsOfRef OPTIONAL, + stdResolution StdResolution, + taCorrection INTEGER (0..960) OPTIONAL, -- TA correction + + -- measured neighbors in OTD measurements + otd-FirstSetMsrs SeqOfOTD-FirstSetMsrs OPTIONAL +} +SeqOfOTD-FirstSetMsrs ::= SEQUENCE (SIZE(1..10)) OF OTD-FirstSetMsrs + +-- OTD measurent information 2 and 3 sets if exist +OTD-MsrElementRest ::= SEQUENCE { + refFrameNumber INTEGER (0..42431), -- Frame number modulo 42432 + referenceTimeSlot ModuloTimeSlot, + toaMeasurementsOfRef TOA-MeasurementsOfRef OPTIONAL, + stdResolution StdResolution, + taCorrection INTEGER (0..960) OPTIONAL, -- TA correction + + -- measured neighbors in OTD measurements + otd-MsrsOfOtherSets SeqOfOTD-MsrsOfOtherSets OPTIONAL +} +SeqOfOTD-MsrsOfOtherSets ::= SEQUENCE (SIZE(1..10)) OF OTD-MsrsOfOtherSets + +-- Standard deviation of the TOA measurements from the reference BTS +TOA-MeasurementsOfRef ::= SEQUENCE { + refQuality RefQuality, + numOfMeasurements NumOfMeasurements +} + +RefQuality ::= INTEGER (0..31) -- St Dev of TOA of reference as defined in annex +NumOfMeasurements ::= INTEGER (0..7) -- No. of measurements for RefQuality as defined in annex +StdResolution ::= INTEGER (0..3) -- Values of resolution are defined in annex + +OTD-FirstSetMsrs ::= OTD-MeasurementWithID + +-- Neighbour info in OTD measurements 0-10 times in TD measurement info +OTD-MsrsOfOtherSets ::= CHOICE { + identityNotPresent OTD-Measurement, + identityPresent OTD-MeasurementWithID +} + +-- For this OTD measurement identity is same as the identity of BTS +-- in the first set with same sequence number +OTD-Measurement ::= SEQUENCE { + nborTimeSlot ModuloTimeSlot, + eotdQuality EOTDQuality, + otdValue OTDValue +} + +-- This measurement contains the BTS identity and measurement +OTD-MeasurementWithID ::=SEQUENCE { + neighborIdentity NeighborIdentity, + nborTimeSlot ModuloTimeSlot, + eotdQuality EOTDQuality, + otdValue OTDValue +} + +EOTDQuality ::= SEQUENCE { + nbrOfMeasurements INTEGER (0..7), + stdOfEOTD INTEGER (0..31) +} + +NeighborIdentity ::= CHOICE { + bsicAndCarrier BSICAndCarrier, -- BSIC and Carrier + ci CellID, -- Cell ID, LAC not needed + multiFrameCarrier MultiFrameCarrier, -- MultiFrameOffest and BSIC + requestIndex RequestIndex, -- Index to Requested Neighbor List + systemInfoIndex SystemInfoIndex, -- Index to System info list, this type of neighbour + -- identity shall not be used by the MS unless it has + -- received the SystemInfoAssistData from the SMLC for + -- this cell. + ciAndLAC CellIDAndLAC -- CI and LAC +} + +-- Multiframe and carrier +MultiFrameCarrier ::= SEQUENCE { + bcchCarrier BCCHCarrier, + multiFrameOffset MultiFrameOffset +} + +-- OTD measurement value for neighbour +OTDValue ::= INTEGER (0..39999) + +-- Location information IE +LocationInfo ::= SEQUENCE { + refFrame INTEGER (0..65535), -- Reference Frame number + -- If refFrame is within (42432..65535), it shall be ignored by the receiver + -- in that case the MS should provide GPS TOW if available + gpsTOW INTEGER (0..14399999) OPTIONAL, -- GPS TOW + fixType FixType, + -- Note that applicable range for refFrame is 0 - 42431 + -- Possible shapes carried in posEstimate are + -- ellipsoid point, + -- ellipsoid point with uncertainty circle + -- ellipsoid point with uncertainty ellipse + -- ellipsoid point with altitude and uncertainty ellipsoid + posEstimate Ext-GeographicalInformation +} + +FixType ::= INTEGER { + twoDFix (0), + threeDFix (1) +} (0..1) + +-- GPS-Measurement information +GPS-MeasureInfo ::= SEQUENCE { + -- Measurement info elements + -- user has to make sure that in this element is number of elements + -- defined in reference BTS identity + gpsMsrSetList SeqOfGPS-MsrSetElement +} +SeqOfGPS-MsrSetElement ::= SEQUENCE (SIZE(1..3)) OF GPS-MsrSetElement + +-- OTD measurent information 1-3 times in message +GPS-MsrSetElement ::= SEQUENCE { + refFrame INTEGER (0..65535) OPTIONAL, -- Reference Frame number + gpsTOW GPSTOW24b, -- GPS TOW + -- Note that applicable range for refFrame is 0 - 42431 + +--N_SAT can be read from number of elements of gps-msrList + + gps-msrList SeqOfGPS-MsrElement +} + +-- 24 bit presentation for GPSTOW +GPSTOW24b ::= INTEGER (0..14399999) + +-- measured elements in measurement parameters field +SeqOfGPS-MsrElement ::= SEQUENCE (SIZE(1..16)) OF GPS-MsrElement + +GPS-MsrElement ::= SEQUENCE { + satelliteID SatelliteID, -- Satellite identifier + cNo INTEGER (0..63), -- carrier noise ratio + doppler INTEGER (-32768..32767), -- doppler, mulltiply by 0.2 + wholeChips INTEGER (0..1022), -- whole value of the code phase measurement + fracChips INTEGER (0..1024), -- fractional value of the code phase measurement + -- a value of 1024 shall not be encoded by the sender + -- the receiver shall consider a value of 1024 to be + -- invalid data + mpathIndic MpathIndic, -- multipath indicator + pseuRangeRMSErr INTEGER (0..63) -- index +} + +-- Multipath indicator +MpathIndic ::= ENUMERATED { + notMeasured (0), + low (1), + medium (2), + high (3) +} + +-- Location error IE +LocationError ::= SEQUENCE { + locErrorReason LocErrorReason, + additionalAssistanceData AdditionalAssistanceData OPTIONAL, + ... +} + +LocErrorReason ::= ENUMERATED { + unDefined (0), + notEnoughBTSs (1), + notEnoughSats (2), + eotdLocCalAssDataMissing (3), + eotdAssDataMissing (4), + gpsLocCalAssDataMissing (5), + gpsAssDataMissing (6), + methodNotSupported (7), + notProcessed (8), + refBTSForGPSNotServingBTS (9), + refBTSForEOTDNotServingBTS (10), + ..., + notEnoughGANSSSats (11), + ganssAssDataMissing (12), + refBTSForGANSSNotServingBTS (13) +} + +-- exception handling: +-- an unrecognized value shall be treated the same as value 0 + + +-- defines additional assistance data needed for any new location attempt +-- MS shall retain any assistance data already received +AdditionalAssistanceData ::= SEQUENCE { + gpsAssistanceData GPSAssistanceData OPTIONAL, + extensionContainer ExtensionContainer OPTIONAL, + ..., + ganssAssistanceData GANSSAssistanceData OPTIONAL +} + +GPSAssistanceData ::= OCTET STRING (SIZE (1..maxGPSAssistanceData)) +-- GPSAssistanceData has identical structure and encoding to octets 3 to n of the +-- GPS Assistance Data IE in 3GPP TS 49.031 + +maxGPSAssistanceData INTEGER ::= 40 + +GANSSAssistanceData ::= OCTET STRING (SIZE (1..maxGANSSAssistanceData)) +-- GANSSAssistanceData has identical structure and encoding to octets 3 to n of the +-- GANSS Assistance Data IE in 3GPP TS 49.031 + +maxGANSSAssistanceData INTEGER ::= 40 + + +-- Protocol Error Causes +ErrorCodes ::= ENUMERATED { + unDefined (0), +missingComponet (1), +incorrectData (2), +missingIEorComponentElement (3), +messageTooShort (4), +unknowReferenceNumber (5), +... +} + +-- exception handling: +-- an unrecognized value shall be treated the same as value 0 + +-- GPS assistance data IE +GPS-AssistData ::= SEQUENCE { + controlHeader ControlHeader +} + +-- More Assistance Data To Be Sent IE +-- More Assistance Data Components On the Way indication for delivery of an entire set of assistance +-- data in multiple Assistance Data components. + +MoreAssDataToBeSent ::= ENUMERATED { + noMoreMessages (0), -- This is the only or last Assistance Data message used to deliver + -- the entire set of assistance data. + moreMessagesOnTheWay (1) -- The SMLC will send more Assistance Data messages or a final RRLP + -- Measure Position Request message to deliver the + -- the entire set of assistance data. +} + +-- Control header of the GPS assistance data +ControlHeader ::= SEQUENCE { + + -- Field type Present information + referenceTime ReferenceTime OPTIONAL, + refLocation RefLocation OPTIONAL, + dgpsCorrections DGPSCorrections OPTIONAL, + navigationModel NavigationModel OPTIONAL, + ionosphericModel IonosphericModel OPTIONAL, + utcModel UTCModel OPTIONAL, + almanac Almanac OPTIONAL, + acquisAssist AcquisAssist OPTIONAL, + realTimeIntegrity SeqOf-BadSatelliteSet OPTIONAL +} + +ReferenceTime ::= SEQUENCE { + gpsTime GPSTime, + gsmTime GSMTime OPTIONAL, + gpsTowAssist GPSTOWAssist OPTIONAL +} + +-- GPS Time includes week number and time-of-week (TOW) +GPSTime ::= SEQUENCE { + gpsTOW23b GPSTOW23b, + gpsWeek GPSWeek +} + +-- GPSTOW, range 0-604799.92, resolution 0.08 sec, 23-bit presentation +GPSTOW23b ::= INTEGER (0..7559999) + +-- GPS week number +GPSWeek ::= INTEGER (0..1023) + +-- GPSTOWAssist consists of TLM message, Anti-spoof flag, Alert flag, and 2 reserved bits in TLM Word +-- for each visible satellite. +-- N_SAT can be read from number of elements in GPSTOWAssist +GPSTOWAssist ::= SEQUENCE (SIZE(1..12)) OF GPSTOWAssistElement + +GPSTOWAssistElement ::= SEQUENCE { + satelliteID SatelliteID, + tlmWord TLMWord, + antiSpoof AntiSpoofFlag, + alert AlertFlag, + tlmRsvdBits TLMReservedBits +} + +-- TLM Word, 14 bits +TLMWord ::= INTEGER (0..16383) + +-- Anti-Spoof flag +AntiSpoofFlag ::= INTEGER (0..1) + +-- Alert flag +AlertFlag ::= INTEGER (0..1) + +-- Reserved bits in TLM word, MSB occurs earlier in TLM Word transmitted by satellite +TLMReservedBits ::= INTEGER (0..3) + +GSMTime ::= SEQUENCE { + bcchCarrier BCCHCarrier, -- BCCH carrier + bsic BSIC, -- BSIC + frameNumber FrameNumber, + timeSlot TimeSlot, + bitNumber BitNumber +} + +-- Frame number +FrameNumber ::= INTEGER (0..2097151) + +-- Time slot number +TimeSlot ::= INTEGER (0..7) + +-- Bit number +BitNumber ::= INTEGER (0..156) + + +-- Reference Location IE +RefLocation ::= SEQUENCE { + threeDLocation Ext-GeographicalInformation +} + +-- DGPS Corrections IE +DGPSCorrections ::= SEQUENCE { + + gpsTOW INTEGER (0..604799), -- DGPS reference time + status INTEGER (0..7), + -- N_SAT can be read from number of elements of satList + satList SeqOfSatElement +} +SeqOfSatElement ::= SEQUENCE (SIZE (1..16)) OF SatElement + +-- number of correction for satellites +SatElement ::= SEQUENCE { + satelliteID SatelliteID, + + +--- Sequence number for ephemeris + iode INTEGER (0..239), + -- User Differential Range Error + udre INTEGER (0..3), + + -- Pseudo Range Correction, range is + -- -655.04 - +655.04, + pseudoRangeCor INTEGER (-2047..2047), + + -- Pseudo Range Rate Correction, range is + -- -4.064 - +4.064, + rangeRateCor INTEGER (-127..127), + +-- Delta Pseudo Range Correction 2 + deltaPseudoRangeCor2 INTEGER (-127..127), -- This IE shall be ignored by the receiver and + -- set to zero by the sender + -- Delta Pseudo Range Correction 2 + deltaRangeRateCor2 INTEGER (-7..7), -- This IE shall be ignored by the receiver and + -- set to zero by the sender + -- Delta Pseudo Range Correction 3 + deltaPseudoRangeCor3 INTEGER (-127..127), -- This IE shall be ignored by the receiver and + -- set to zero by the sender + -- Delta Pseudo Range Correction 3 + deltaRangeRateCor3 INTEGER (-7..7) -- This IE shall be ignored by the receiver and + -- set to zero by the sender +} + +SatelliteID ::= INTEGER (0..63) -- identifies satellite + +-- Navigation Model IE +NavigationModel ::= SEQUENCE { + navModelList SeqOfNavModelElement +} + +-- navigation model satellite list +SeqOfNavModelElement ::= SEQUENCE (SIZE(1..16)) OF NavModelElement + +NavModelElement ::= SEQUENCE { + satelliteID SatelliteID, + satStatus SatStatus -- satellite status +} + +-- the Status of the navigation model +SatStatus ::= CHOICE { + -- New satellite, new Navigation Model + newSatelliteAndModelUC UncompressedEphemeris, + + -- Existing satellite, Existing Navigation Model + oldSatelliteAndModel NULL, + + -- Existing satellite, new Navigation Model + newNaviModelUC UncompressedEphemeris, + ... +} + +-- Uncompressed satellite emhemeris and clock corrections +UncompressedEphemeris ::= SEQUENCE { + ephemCodeOnL2 INTEGER (0..3), + ephemURA INTEGER (0..15), + ephemSVhealth INTEGER (0..63), + ephemIODC INTEGER (0..1023), + ephemL2Pflag INTEGER (0..1), + ephemSF1Rsvd EphemerisSubframe1Reserved, + ephemTgd INTEGER (-128..127), + ephemToc INTEGER (0..37799), + ephemAF2 INTEGER (-128..127), + ephemAF1 INTEGER (-32768..32767), + ephemAF0 INTEGER (-2097152..2097151), + ephemCrs INTEGER (-32768..32767), + ephemDeltaN INTEGER (-32768..32767), + ephemM0 INTEGER (-2147483648..2147483647), + ephemCuc INTEGER (-32768..32767), + ephemE INTEGER (0..4294967295), + ephemCus INTEGER (-32768..32767), + ephemAPowerHalf INTEGER (0..4294967295), + ephemToe INTEGER (0..37799), + ephemFitFlag INTEGER (0..1), + ephemAODA INTEGER (0..31), + ephemCic INTEGER (-32768..32767), + ephemOmegaA0 INTEGER (-2147483648..2147483647), + ephemCis INTEGER (-32768..32767), + ephemI0 INTEGER (-2147483648..2147483647), + ephemCrc INTEGER (-32768..32767), + ephemW INTEGER (-2147483648..2147483647), + ephemOmegaADot INTEGER (-8388608..8388607), + ephemIDot INTEGER (-8192..8191) +} + +-- Reserved bits in subframe 1 of navigation message +EphemerisSubframe1Reserved ::= SEQUENCE { + reserved1 INTEGER (0..8388607), -- 23-bit field + reserved2 INTEGER (0..16777215), -- 24-bit field + reserved3 INTEGER (0..16777215), -- 24-bit field + reserved4 INTEGER (0..65535) -- 16-bit field +} + +-- Ionospheric Model IE +IonosphericModel ::= SEQUENCE { + alfa0 INTEGER (-128..127), + alfa1 INTEGER (-128..127), + alfa2 INTEGER (-128..127), + alfa3 INTEGER (-128..127), + beta0 INTEGER (-128..127), + beta1 INTEGER (-128..127), + beta2 INTEGER (-128..127), + beta3 INTEGER (-128..127) +} + +-- Universal Time Coordinate Model +UTCModel ::= SEQUENCE { + utcA1 INTEGER (-8388608..8388607), + utcA0 INTEGER (-2147483648..2147483647), + utcTot INTEGER (0..255), + utcWNt INTEGER (0..255), + utcDeltaTls INTEGER (-128..127), + utcWNlsf INTEGER (0..255), + utcDN INTEGER (-128..127), + utcDeltaTlsf INTEGER (-128..127) +} + +-- Almanac, Long term model +-- NOTE: These are parameters are subset of the ephemeris +-- NOTE: But with reduced resolution and accuracy +Almanac ::= SEQUENCE { + alamanacWNa INTEGER (0..255), -- Once per message + + -- navigation model satellite list. + -- The size of almanacList is actually Nums_Sats_Total field + almanacList SeqOfAlmanacElement +} +SeqOfAlmanacElement ::= SEQUENCE (SIZE(1..64)) OF AlmanacElement + +-- Almanac info once per satellite +AlmanacElement ::= SEQUENCE { + satelliteID SatelliteID, + almanacE INTEGER (0..65535), + alamanacToa INTEGER (0..255), + almanacKsii INTEGER (-32768..32767), + almanacOmegaDot INTEGER (-32768..32767), + almanacSVhealth INTEGER (0..255), + almanacAPowerHalf INTEGER (0..16777215), + almanacOmega0 INTEGER (-8388608..8388607), + almanacW INTEGER (-8388608..8388607), + almanacM0 INTEGER (-8388608..8388607), + almanacAF0 INTEGER (-1024..1023), + almanacAF1 INTEGER (-1024..1023) +} + +-- Acquisition Assistance +AcquisAssist ::= SEQUENCE { + + -- Number of Satellites can be read from acquistList + timeRelation TimeRelation, + + -- Acquisition assistance list + -- The size of Number of Satellites is actually Number of Satellites field + acquisList SeqOfAcquisElement +} +SeqOfAcquisElement ::= SEQUENCE (SIZE(1..16)) OF AcquisElement + +-- the relationship between GPS time and air-interface timing +TimeRelation ::= SEQUENCE { + -- + gpsTOW GPSTOW23b, -- 23b presentation + gsmTime GSMTime OPTIONAL +} + +-- data occuring per number of satellites +AcquisElement ::= SEQUENCE { + svid SatelliteID, + + -- Doppler 0th order term, + -- -5120.0 - 5117.5 Hz (= -2048 - 2047 with 2.5 Hz resolution) + doppler0 INTEGER (-2048..2047), + addionalDoppler AddionalDopplerFields OPTIONAL, + codePhase INTEGER (0..1022), -- Code Phase + intCodePhase INTEGER (0..19), -- Integer Code Phase + gpsBitNumber INTEGER (0..3), -- GPS bit number + codePhaseSearchWindow INTEGER (0..15), -- Code Phase Search Window + addionalAngle AddionalAngleFields OPTIONAL +} + +AddionalDopplerFields ::= SEQUENCE { + -- Doppler 1st order term, -1.0 - +0.5 Hz/sec + -- (= -42 + (0 to 63) with 1/42 Hz/sec. resolution) + doppler1 INTEGER (0..63), + dopplerUncertainty INTEGER (0..7) + -- a sender shall not encode any DopplerUncertainty value in the range 5 to 7 + -- a receiver shall ignore any value between 5 and 7. +} + +AddionalAngleFields ::= SEQUENCE { + -- azimuth angle, 0 - 348.75 deg (= 0 - 31 with 11.25 deg resolution) + azimuth INTEGER (0..31), + -- elevation angle, 0 - 78.75 deg (= 0 - 7 with 11.25 deg resolution) + elevation INTEGER (0..7) +} + +-- Real-Time Integrity +-- number of bad satellites can be read from this element +SeqOf-BadSatelliteSet ::= SEQUENCE (SIZE(1..16)) OF SatelliteID + +-- Extension Elements + +-- Release 98 Extensions here +Rel98-MsrPosition-Req-Extension ::= SEQUENCE { + rel98-Ext-ExpOTD Rel98-Ext-ExpOTD OPTIONAL, -- ExpectedOTD extension + ..., + gpsTimeAssistanceMeasurementRequest NULL OPTIONAL, + gpsReferenceTimeUncertainty GPSReferenceTimeUncertainty OPTIONAL + +-- Further R98 extensions here +} +Rel98-AssistanceData-Extension ::= SEQUENCE { + rel98-Ext-ExpOTD Rel98-Ext-ExpOTD OPTIONAL, -- ExpectedOTD extension + ..., + gpsTimeAssistanceMeasurementRequest NULL OPTIONAL, + gpsReferenceTimeUncertainty GPSReferenceTimeUncertainty OPTIONAL + +-- Further R98 extensions here +} + +-- Release 98 ExpOTD extension +Rel98-Ext-ExpOTD ::= SEQUENCE { +-- If MsrAssistBTS is included in message, msrAssistData-R98-ExpOTD shall be included. + msrAssistData-R98-ExpOTD MsrAssistData-R98-ExpOTD OPTIONAL, + +-- If SystemInfoAssistaData is included in message, systemInfoAssistData-R98-ExpOTD shall be +-- included. + systemInfoAssistData-R98-ExpOTD SystemInfoAssistData-R98-ExpOTD OPTIONAL +} + +-- MsrAssistData R98 extension +MsrAssistData-R98-ExpOTD ::= SEQUENCE { + msrAssistList-R98-ExpOTD SeqOfMsrAssistBTS-R98-ExpOTD +} + +-- Indexes in SeqOfMsrAssistBTS-R98-ExpOTD refer to SeqOfMsrAssistBTS +-- If the index exceeds the SegOfMsrAssistBTS range or if there is other +-- inconsistencies between the BTS indices, the MS shall apply protocol +-- error cause incorrectData +SeqOfMsrAssistBTS-R98-ExpOTD ::= SEQUENCE (SIZE(1..15)) OF MsrAssistBTS-R98-ExpOTD + +-- This element completes MsrAssistBTS IE +MsrAssistBTS-R98-ExpOTD ::= SEQUENCE { + expectedOTD ExpectedOTD, + expOTDUncertainty ExpOTDUncertainty +} + +-- SystemInfoAssistData R98 extension +SystemInfoAssistData-R98-ExpOTD ::= SEQUENCE { + systemInfoAssistListR98-ExpOTD SeqOfSystemInfoAssistBTS-R98-ExpOTD +} + +-- SeqOfSystemInfoAssistBTS-R98-ExpOTD index refer to SeqOfSystemInfoAssistBTS +-- If the index exceeds the SegOfSystemInfoAssistBTS range or if there is other +-- inconsistencies between the BTS indices, the MS shall apply protocol +-- error cause incorrectData +SeqOfSystemInfoAssistBTS-R98-ExpOTD ::= SEQUENCE (SIZE(1..32)) OF SystemInfoAssistBTS-R98-ExpOTD + +-- whether n.th is present or not ? +SystemInfoAssistBTS-R98-ExpOTD ::= CHOICE { + notPresent NULL, + present AssistBTSData-R98-ExpOTD +} + +-- This element completes AssistBTSData IE +AssistBTSData-R98-ExpOTD ::= SEQUENCE { + expectedOTD ExpectedOTD, + expOTDuncertainty ExpOTDUncertainty -- Uncertainty of expected OTD +} + +-- Expected OTD value between nbor base station and reference BTS +-- at MS's current estimated location. +ExpectedOTD ::= INTEGER (0..1250) +-- The ExpectedOTD value 1250 shall not be encoded by the transmitting entity and +-- shall be treated by the receiving entity as 0. +-- Uncertainty of Exptected OTD in bits +ExpOTDUncertainty ::= INTEGER(0..7) + +-- Release 98 extensions + +GPSReferenceTimeUncertainty ::= INTEGER (0 .. 127) -- Coding according to Annex + +GPSTimeAssistanceMeasurements ::= SEQUENCE { + referenceFrameMSB INTEGER (0 .. 63), -- MSB of frame number + gpsTowSubms INTEGER (0 .. 9999) OPTIONAL, -- in units of 100ns, for MS based AGPS + deltaTow INTEGER (0 .. 127) OPTIONAL, -- for MS assisted AGPS + gpsReferenceTimeUncertainty GPSReferenceTimeUncertainty OPTIONAL +} + +Rel-98-MsrPosition-Rsp-Extension ::= SEQUENCE { + + -- First extension to Release 98 + rel-98-Ext-MeasureInfo SEQUENCE { + otd-MeasureInfo-R98-Ext OTD-MeasureInfo-R98-Ext OPTIONAL + }, + ..., + timeAssistanceMeasurements GPSTimeAssistanceMeasurements OPTIONAL + -- Further R98 extensions here +} + +-- This is an addition to OTD-MeasureInfo element defined in original message, +-- If OTD-MeasureInfo is absent, or if one or more OTD-MsrElementRest are present +-- OTD-MeasureInfo-R98-Ext shall be absent. +-- OTD-MeasureInfo-R98-Ext +OTD-MeasureInfo-R98-Ext ::= SEQUENCE { + -- Measurement info elements + otdMsrFirstSets-R98-Ext OTD-MsrElementFirst-R98-Ext +} + +-- OTD measurement information Ext for the first set only +OTD-MsrElementFirst-R98-Ext ::= SEQUENCE { + -- additional measured neighbors in OTD measurements + otd-FirstSetMsrs-R98-Ext SeqOfOTD-FirstSetMsrs-R98-Ext OPTIONAL +} +SeqOfOTD-FirstSetMsrs-R98-Ext ::= SEQUENCE (SIZE(1..5)) OF OTD-FirstSetMsrs + +Rel-5-MsrPosition-Rsp-Extension ::= SEQUENCE { + + extended-reference Extended-reference OPTIONAL, + -- The extended-reference shall be included by the MS if and only if previously + -- received from the SMLC in a Measure Position Request. When included, the value sent + -- by the MS shall equal the value received from the SMLC. + + -- extension to Release 5, for RRLP pseudo-segmentation here + otd-MeasureInfo-5-Ext OTD-MeasureInfo-5-Ext OPTIONAL, + ulPseudoSegInd UlPseudoSegInd OPTIONAL, -- Included when uplink RRLP + -- Pseudo-segmentation is used, not included when no uplink pseudo-segmentation is used + ... + -- Possibly more extensions for Release 5 here later +} + +Extended-reference ::= SEQUENCE { + smlc-code INTEGER (0..63), + transaction-ID INTEGER (0..262143) +} + +OTD-MeasureInfo-5-Ext ::= SeqOfOTD-MsrElementRest + -- if more than one measurement sets are present this element is repeated + -- NumberOfSets - 1 (-1 = first set) combined in OTD-MeasureInfo-5-Ext and + -- OTD-MeasureInfo (e.g. if NumberOfSets is 3, then one otdMsrRestSets may + -- be sent in OTD-MeasureInfo-5-Ext and one in OTD-MeasureInfo) + +-- First part of Uplink RRLP Pseudo-segmentation indication, possibly more may be defined +-- in the future for segmentation with more than two segments. +UlPseudoSegInd ::= ENUMERATED { + firstOfMany (0), + secondOfMany(1) +} + +Rel5-MsrPosition-Req-Extension ::= SEQUENCE { + extended-reference Extended-reference, + ... + -- Possibly more extensions for Release 5 here later +} + +Rel5-AssistanceData-Extension ::= SEQUENCE { + extended-reference Extended-reference, + ... + +-- Possibly more extensions for Release 5 here later +} + +Rel-5-ProtocolError-Extension::= SEQUENCE { + extended-reference Extended-reference OPTIONAL, + -- The extended-reference shall be included by the MS if and only if previously + -- received from the SMLC. + -- When included, the value sent by the MS shall equal the value received from the SMLC. + ... + + -- Possibly more extensions for Release 5 here later +} + +-- Release 7 Extensions here + +Rel7-MsrPosition-Req-Extension ::= SEQUENCE { +velocityRequested NULL OPTIONAL, + ganssPositionMethod GANSSPositioningMethod OPTIONAL, + ganss-AssistData GANSS-AssistData OPTIONAL, + ganssCarrierPhaseMeasurementRequest NULL OPTIONAL, + ganssTODGSMTimeAssociationMeasurementRequest NULL OPTIONAL, +requiredResponseTime RequiredResponseTime OPTIONAL, + ... + -- Further Release 7 extentions here +} + +-- additional satellite systems may be added in future versions of the protocol +GANSSPositioningMethod ::= BIT STRING { + gps (0), + galileo (1)} (SIZE (2..16)) + +GANSS-AssistData ::= SEQUENCE { + ganss-controlHeader GANSS-ControlHeader +} + +GANSS-ControlHeader ::= SEQUENCE { + ganssCommonAssistData GANSSCommonAssistData OPTIONAL, + ganssGenericAssistDataList SeqOfGANSSGenericAssistDataElement OPTIONAL +} + +-- GANSS Common Assistance Data Elements +GANSSCommonAssistData ::= SEQUENCE { + ganssReferenceTime GANSSReferenceTime OPTIONAL, + ganssRefLocation GANSSRefLocation OPTIONAL, + ganssIonosphericModel GANSSIonosphericModel OPTIONAL, + ... +} + +-- List of GANSS Generic Assistance Data Elements, up to 8 GANSS +SeqOfGANSSGenericAssistDataElement ::= SEQUENCE (SIZE (1..8)) OF GANSSGenericAssistDataElement + +-- GANSS Generic Assistance Data Elements +GANSSGenericAssistDataElement ::= SEQUENCE { + ganssID INTEGER (0..7) OPTIONAL, -- Coding according to Annex + ganssTimeModel SeqOfGANSSTimeModel OPTIONAL, + ganssDiffCorrections GANSSDiffCorrections OPTIONAL, + ganssNavigationModel GANSSNavModel OPTIONAL, + ganssRealTimeIntegrity GANSSRealTimeIntegrity OPTIONAL, + ganssDataBitAssist GANSSDataBitAssist OPTIONAL, + ganssRefMeasurementAssist GANSSRefMeasurementAssist OPTIONAL, + ganssAlmanacModel GANSSAlmanacModel OPTIONAL, + ganssUTCModel GANSSUTCModel OPTIONAL, + ... +} + +-- GANSS COMMON ASSISTANCE DATA ELEMENTS + +-- GANSS Reference Time IE +GANSSReferenceTime ::= SEQUENCE { + ganssRefTimeInfo GANSSRefTimeInfo, + ganssTOD-GSMTimeAssociation GANSSTOD-GSMTimeAssociation OPTIONAL +} + +-- GANSS Reference Time includes GANSS TOD, GANSS Day, uncertainty +GANSSRefTimeInfo ::= SEQUENCE { + ganssDay INTEGER(0 .. 8191) OPTIONAL, + ganssTOD GANSSTOD, + ganssTODUncertainty GANSSTODUncertainty OPTIONAL, + ganssTimeID INTEGER (0 .. 7) OPTIONAL +} + +-- GANSS TOD integer seconds +GANSSTOD ::= INTEGER (0 .. 86399) + +-- GANSS TOD uncertainty +GANSSTODUncertainty ::= INTEGER (0 .. 127) -- Coding according to Annex + +-- GANSS TOD-GSM Time association +GANSSTOD-GSMTimeAssociation ::= SEQUENCE { + bcchCarrier BCCHCarrier, -- BCCH carrier + bsic BSIC, -- BSIC + frameNumber FrameNumber, + timeSlot TimeSlot, + bitNumber BitNumber, + frameDrift FrameDrift OPTIONAL +} + +-- Frame drift +FrameDrift ::= INTEGER(-64 .. 63) + +-- GANSS Reference Location IE +GANSSRefLocation ::= SEQUENCE { + threeDLocation Ext-GeographicalInformation +} + +-- GANSS Ionospheric Model IE +-- GANSS Ionospheric Model consists of NeQuick model parameters and storm flags + +GANSSIonosphericModel ::= SEQUENCE { + ganssIonoModel GANSSIonosphereModel, + ganssIonoStormFlags GANSSIonoStormFlags OPTIONAL, + ... +} + +-- GANSS ionosphere model. Coding according to Annex +GANSSIonosphereModel ::= SEQUENCE { + ai0 INTEGER (0 .. 4095), + ai1 INTEGER (0 .. 4095), + ai2 INTEGER (0 .. 4095) +} + +-- GANSS ionosphere storm flags +GANSSIonoStormFlags ::= SEQUENCE { + ionoStormFlag1 INTEGER (0 .. 1), + ionoStormFlag2 INTEGER (0 .. 1), + ionoStormFlag3 INTEGER (0 .. 1), + ionoStormFlag4 INTEGER (0 .. 1), + ionoStormFlag5 INTEGER (0 .. 1) +} + +-- GANSS GENERIC ASSISTANCE DATA ELEMENTS + +-- GANSS Time Model IE consists of time offset and first and second order parameters to relate GNSS +-- specific system time to selected time reference +SeqOfGANSSTimeModel ::= SEQUENCE (SIZE(1..7)) OF GANSSTimeModelElement + +GANSSTimeModelElement ::= SEQUENCE { + ganssTimeModelRefTime INTEGER(0 .. 65535), + tA0 TA0, + tA1 TA1 OPTIONAL, + tA2 TA2 OPTIONAL, + gnssTOID INTEGER (0 .. 7), + weekNumber INTEGER (0 .. 8191) OPTIONAL +} + +-- GANSS time model parameter A0 +TA0 ::= INTEGER (-2147483648 .. 2147483647) + +-- GANSS time model parameter A1 +TA1 ::= INTEGER (-8388608 .. 8388607) + +-- GANSS time model parameter A2 +TA2 ::= INTEGER (-64 .. 63) + +-- DGANSS Corrections IE +GANSSDiffCorrections ::= SEQUENCE { + dganssRefTime INTEGER (0 .. 119), -- DGANSS reference time + + -- N_SGN_TYPE can be read from number of elements of sgnTypeList + sgnTypeList SeqOfSgnTypeElement +} + +SeqOfSgnTypeElement ::= SEQUENCE (SIZE (1..3)) OF SgnTypeElement -- max three signals per GNSS + +-- DGANSS signal type element, once per GNSS signal type included in DGANSS +SgnTypeElement ::= SEQUENCE { + ganssSignalID GANSSSignalID OPTIONAL, -- signal type identity + ganssStatusHealth INTEGER (0 .. 7), + -- N_SGN can be read from number of elements of dganssSgnList + dganssSgnList SeqOfDGANSSSgnElement +} + +GANSSSignalID ::= INTEGER (0 .. 3) -- Coding according to Annex +SeqOfDGANSSSgnElement ::= SEQUENCE (SIZE (1..16)) OF DGANSSSgnElement + +-- number of correction for signals +DGANSSSgnElement ::= SEQUENCE { + svID SVID, -- Satellite identity + +--- Sequence number for GANSS Navigation Model that matches the DGANSS correction set + iod INTEGER (0 .. 1023), + + -- User Differential Range Error + udre INTEGER (0..3), + + -- Pseudo Range Correction, range is + -- -655.04 - +655.04, + pseudoRangeCor INTEGER (-2047..2047), + + -- Pseudo Range Rate Correction, range is + -- -4.064 - +4.064, + rangeRateCor INTEGER (-127..127) +} + +SVID ::= INTEGER (0 .. 63) -- Coding according to Annex + +-- GANSS Navigation Model IE +GANSSNavModel ::= SEQUENCE { + nonBroadcastIndFlag INTEGER (0 .. 1), + toeMSB INTEGER (0 .. 31) OPTIONAL, -- 5 MSB of toe and toc + eMSB INTEGER (0 .. 127) OPTIONAL, + sqrtAMBS INTEGER (0 .. 63) OPTIONAL, + ganssSatelliteList SeqOfGANSSSatelliteElement +} + +SeqOfGANSSSatelliteElement ::= SEQUENCE (SIZE(1..32)) OF GANSSSatelliteElement + +GANSSSatelliteElement ::= SEQUENCE { + svID SVID, + svHealth INTEGER (-7 .. 13), -- Coding according to Annex + iod INTEGER (0 .. 1023), -- Coding according to Annex + ganssClockModel GANSSClockModel, + ganssOrbitModel GANSSOrbitModel, + ... +} + +-- GANSS orbit model for the GNSS satellite according to the choice +GANSSOrbitModel ::= CHOICE { + keplerianSet NavModel-KeplerianSet, + ... +} + +-- Navigation model in Keplerian parameters +NavModel-KeplerianSet ::= SEQUENCE { + keplerToeLSB INTEGER (0 .. 511), -- 9LSB are given in GANSSNavigationModel + keplerW INTEGER (-2147483648..2147483647), + keplerDeltaN INTEGER (-32768..32767), + keplerM0 INTEGER (-2147483648..2147483647), + keplerOmegaDot INTEGER (-8388608..8388607), + keplerELSB INTEGER (0..33554431), + keplerIDot INTEGER (-8192..8191), + keplerAPowerHalfLSB INTEGER (0.. 67108863), + keplerI0 INTEGER (-2147483648..2147483647), + keplerOmega0 INTEGER (-2147483648..2147483647), + keplerCrs INTEGER (-32768..32767), + keplerCis INTEGER (-32768..32767), + keplerCus INTEGER (-32768..32767), + keplerCrc INTEGER (-32768..32767), + keplerCic INTEGER (-32768..32767), + keplerCuc INTEGER (-32768..32767) +} + +-- GANSS clock model for the GNSS satellite according to the choice +GANSSClockModel ::= CHOICE { + standardClockModelList SeqOfStandardClockModelElement, + ... +} + +SeqOfStandardClockModelElement ::= SEQUENCE (SIZE(1..2)) OF StandardClockModelElement + +StandardClockModelElement ::= SEQUENCE { + stanClockTocLSB INTEGER (0 .. 511), -- 9LSB of time of clock + stanClockAF2 INTEGER (-2048 .. 2047), + stanClockAF1 INTEGER (-131072 .. 131071), + stanClockAF0 INTEGER (-134217728 .. 134217727), + stanClockTgd INTEGER (-512 .. 511) OPTIONAL, + stanModelID INTEGER (0 .. 1) OPTIONAL, + ... +} + +-- GANSS Real-Time Integrity IE +GANSSRealTimeIntegrity ::= SEQUENCE { + -- list of bad signals + -- NBS can be read from number of elements in SeqOf-BadSignalSet + ganssBadSignalList SeqOfBadSignalElement +} + +SeqOfBadSignalElement ::= SEQUENCE (SIZE(1..16)) OF BadSignalElement + +BadSignalElement ::= SEQUENCE { + badSVID SVID, -- Coding according to Annex + badSignalID INTEGER (0 .. 3) OPTIONAL -- Coding according to Annex +} + + +-- GANSS Data Bit Assistance IE +GANSSDataBitAssist ::= SEQUENCE { + ganssTOD INTEGER (0 .. 59), + svID SVID, + ganssDataTypeID INTEGER (0 .. 2), -- Coding according to Annex + -- list of navigation data bits + -- N_BIT can be read from number of elements in SeqOf-DataBits + ganssDataBits SeqOf-GANSSDataBits +} + +SeqOf-GANSSDataBits ::= SEQUENCE (SIZE(1 .. 1024)) OF GANSSDataBit +GANSSDataBit ::= INTEGER(0 .. 1) + +-- GANSS Reference Measurement Assistance IE +-- Code and Doppler assistance from the network. +GANSSRefMeasurementAssist ::= SEQUENCE { + ganssSignalID INTEGER (0 .. 3) OPTIONAL, -- Coding according to Annex + ganssRefMeasAssitList SeqOfGANSSRefMeasurementElement +} + +SeqOfGANSSRefMeasurementElement ::= SEQUENCE (SIZE(1 .. 16)) OF GANSSRefMeasurementElement + +GANSSRefMeasurementElement ::= SEQUENCE { + svID SVID, + -- Doppler 0th order term, + -- -1024 m/s to 1023.5 m/s with 0.5 m/s resolution) + doppler0 INTEGER (-2048 .. 2047), -- Coding according to Annex + additionalDoppler AdditionalDopplerFields OPTIONAL, + codePhase INTEGER (0 .. 1022), -- Code Phase in ms + intCodePhase INTEGER (0 .. 127), -- Integer Code Phase in ms + codePhaseSearchWindow INTEGER (0 .. 31), -- Code Phase Search Window, see Annex + additionalAngle AddionalAngleFields OPTIONAL, + ... +} + +AdditionalDopplerFields ::= SEQUENCE { + -- Doppler 1st order term, -0.2 - +0.1 m/s2 + doppler1 INTEGER (0..63), + dopplerUncertainty INTEGER (0..4) +} + +-- GANSS Almanac Model IE +GANSSAlmanacModel ::= SEQUENCE { + weekNumber INTEGER (0 .. 255), + svIDMask SVIDMASK, + toa INTEGER (0 .. 255) OPTIONAL, + ioda INTEGER (0 .. 3) OPTIONAL, + ganssAlmanacList SeqOfGANSSAlmanacElement +} + +-- SV ID Mask, LSB for ID 1 and MSB for ID 36 +SVIDMASK ::= BIT STRING (SIZE (1..36)) + +SeqOfGANSSAlmanacElement ::= SEQUENCE (SIZE(1 .. 36)) OF GANSSAlmanacElement + +-- GANSS Almanac Model +GANSSAlmanacElement ::= CHOICE { + keplerianAlmanacSet Almanac-KeplerianSet, + ... +} + +-- Almanac parameters according to Keplerian parameters +Almanac-KeplerianSet ::= SEQUENCE { + kepAlmanacE INTEGER (0 .. 2047), + kepAlmanacDeltaI INTEGER (-1024 .. 1023), + kepAlmanacOmegaDot INTEGER (-1024 .. 1023), + kepSVHealth INTEGER (0 .. 15), -- Coding according to Annex + kepAlmanacAPowerHalf INTEGER (-65536 .. 65535), + kepAlmanacOmega0 INTEGER (-32768 .. 32767), + kepAlmanacW INTEGER (-32768 .. 32767), + kepAlmanacM0 INTEGER (-32768 .. 32767), + kepAlmanacAF0 INTEGER (-8192 .. 8191), + kepAlmanacAF1 INTEGER (-1024..1023) +} + +-- GANSS Universal Time Coordinate Model +GANSSUTCModel ::= SEQUENCE { + ganssUtcA1 INTEGER (-8388608..8388607), + ganssUtcA0 INTEGER (-2147483648..2147483647), + ganssUtcTot INTEGER (0..255), + ganssUtcWNt INTEGER (0..255), + ganssUtcDeltaTls INTEGER (-128..127), + ganssUtcWNlsf INTEGER (0..255), + ganssUtcDN INTEGER (-128..127), + ganssUtcDeltaTlsf INTEGER (-128..127) +} + +--Required Measurement Request Response Time, range is 1 to 128 seconds. +RequiredResponseTime ::= INTEGER (1..128) + +Rel-7-MsrPosition-Rsp-Extension ::= SEQUENCE { + + velEstimate VelocityEstimate OPTIONAL, + -- Horizontal Velocity + -- Horizontal with Vertical Velocity + -- Horizontal Velocity with Uncertainty + -- Horizontal with Vertical Velocity and Uncertainty + ganssLocationInfo GANSSLocationInfo OPTIONAL, + ganssMeasureInfo GANSSMeasureInfo OPTIONAL, + ... +-- Further Release 7 extensions here +} + +-- GANSS Location Information contains location estimate, time stamp with uncertainty +-- and optionally Reference Frame field +GANSSLocationInfo ::= SEQUENCE { + referenceFrame ReferenceFrame OPTIONAL, -- Reference Frame Number + ganssTODm GANSSTODm OPTIONAL, -- GNSS TOD modulo + ganssTODFrac INTEGER (0 .. 16384) OPTIONAL, -- Coding according to Annex + ganssTODUncertainty GANSSTODUncertainty OPTIONAL, -- Coding according to Annex + ganssTimeID INTEGER (0 .. 3) OPTIONAL, -- Coding according to Annex + fixType FixType, + posData PositionData, + stationaryIndication INTEGER(0 .. 1) OPTIONAL, -- '0' if moving or motion not known + -- Possible shapes carried in posEstimate are + -- ellipsoid point, + -- ellipsoid point with uncertainty circle + -- ellipsoid point with uncertainty ellipse + -- ellipsoid point with altitude and uncertainty ellipsoid + posEstimate Ext-GeographicalInformation, + ... +} + +PositionData ::= BIT STRING { + e-otd(0), + gps (1), + galileo (2) } (SIZE (3..16)) + + +-- GANSS TOD modulo 1 hour +GANSSTODm ::= INTEGER (0 .. 3599999) + +ReferenceFrame ::= SEQUENCE { + referenceFN INTEGER (0 .. 65535), + -- Note that applicable range for referenceFN is 0 - 42431 + referenceFNMSB INTEGER (0 .. 63) OPTIONAL -- MSB of Reference Frame Number +} + + + +-- GANSS Measurement Information +GANSSMeasureInfo ::= SEQUENCE { + -- Measurement info elements + -- user has to make sure that in this element is number of elements + -- defined in reference BTS identity + ganssMsrSetList SeqOfGANSS-MsrSetElement +} +SeqOfGANSS-MsrSetElement ::= SEQUENCE (SIZE(1..3)) OF GANSS-MsrSetElement + +-- GANSS measurement information 1-3 times in a message +GANSS-MsrSetElement ::= SEQUENCE { + referenceFrame ReferenceFrame OPTIONAL, -- Reference Frame Number + ganssTODm GANSSTODm OPTIONAL, -- GANSS TOD modulo + deltaGNASSTOD INTEGER (0 .. 127) OPTIONAL, + ganssTODUncertainty GANSSTODUncertainty OPTIONAL, -- Coding accoring to Annex + + --N_SGN_TYPE can be read from number of elements of SeqOfGANSS-SgnTypeElement + ganss-SgnTypeList SeqOfGANSS-SgnTypeElement +} + +-- Measurements can be returned up to 6 different signal types +SeqOfGANSS-SgnTypeElement ::= SEQUENCE (SIZE(1..6)) OF GANSS-SgnTypeElement + +GANSS-SgnTypeElement ::= SEQUENCE { + ganssSignalID INTEGER (0 .. 15), -- Coding accroding to Annex + --N_SGN can be read from number of elements of SeqOfGANSS-SgnElement + ganss-SgnList SeqOfGANSS-SgnElement +} + +-- Measurements can be returned up to 16 per signal types +SeqOfGANSS-SgnElement ::= SEQUENCE (SIZE(1..16)) OF GANSS-SgnElement + + +GANSS-SgnElement ::= SEQUENCE { + svID SVID, + cNo INTEGER (0 .. 63), + mpathDet MpathIndic, -- Coding according to Annex + carrierQualityInd INTEGER (0 .. 3) OPTIONAL, -- Coding according to Annex + codePhase INTEGER (0 .. 2097151), + integerCodePhase INTEGER (0 .. 63) OPTIONAL, + codePhaseRMSError INTEGER (0..63), -- Coding accoring to Annex + doppler INTEGER (-32768 .. 32767) OPTIONAL, + adr INTEGER (0 .. 33554431) OPTIONAL +} + +Rel7-AssistanceData-Extension ::= SEQUENCE { + ganss-AssistData GANSS-AssistData OPTIONAL, + ganssCarrierPhaseMeasurementRequest NULL OPTIONAL, + ganssTODGSMTimeAssociationMeasurementRequest NULL OPTIONAL, + ... +-- Possibly more extensions for Release 7 here +} + +END diff --git a/rrlp-ephemeris/asn1/RRLP-Messages.asn b/rrlp-ephemeris/asn1/RRLP-Messages.asn new file mode 100644 index 000000000..79140e2a2 --- /dev/null +++ b/rrlp-ephemeris/asn1/RRLP-Messages.asn @@ -0,0 +1,38 @@ +-- RRLP-Messages.asn +-- $Id$ +-- Taken from 3GPP TS 44.031 V7.4.0 (2007-03) +-- http://www.3gpp.org/ftp/Specs/archive/44_series/44.031/44031-740.zip/44031-740.doc +-- +-- 3.1 General Format of RRLP Message +-- + +RRLP-Messages +-- { RRLP-messages } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + MsrPosition-Req, MsrPosition-Rsp, AssistanceData, + ProtocolError +FROM + RRLP-Components -- { RRLP-Components } +; + +PDU ::= SEQUENCE { + referenceNumber INTEGER (0..7), + component RRLP-Component +} + +RRLP-Component ::= CHOICE { + msrPositionReq MsrPosition-Req, + msrPositionRsp MsrPosition-Rsp, + assistanceData AssistanceData, + assistanceDataAck NULL, + protocolError ProtocolError, + ... + +} + +END diff --git a/rrlp-ephemeris/asn1/patch-rrlp-components.diff b/rrlp-ephemeris/asn1/patch-rrlp-components.diff new file mode 100644 index 000000000..a5e55ae06 --- /dev/null +++ b/rrlp-ephemeris/asn1/patch-rrlp-components.diff @@ -0,0 +1,36 @@ +--- RRLP-Components.asn 2009-10-26 22:10:44.000000000 +0100 ++++ RRLP-Components.asn 2009-10-26 22:10:44.000000000 +0100 +@@ -18,16 +18,16 @@ + Ext-GeographicalInformation, VelocityEstimate + FROM + MAP-LCS-DataTypes { +- ccitt identified-organization (4) etsi (0) mobileDomain (0) +- gsm-Network (1) modules (3) map-LCS-DataTypes (25) version5 (5)} ++ itu-t identified-organization (4) etsi (0) mobileDomain (0) ++ gsm-Network (1) modules (3) map-LCS-DataTypes (25) version11 (11)} + + ExtensionContainer + FROM MAP-ExtensionDataTypes { +- ccitt identified-organization (4) etsi (0) mobileDomain (0) +- gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version4 (4)} ++ itu-t identified-organization (4) etsi (0) mobileDomain (0) ++ gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)} + ; + + -- Add here other ASN.1 definitions presented below + -- in chapters 4 and 5. + +@@ -305,11 +305,11 @@ + SystemInfoIndex ::= INTEGER (1..32) + + CellIDAndLAC ::= SEQUENCE { +- referenceLAC LAC, -- Location area code ++ referenceLAC LACID, -- Location area code + referenceCI CellID -- Cell identity + } + CellID ::= INTEGER (0..65535) +-LAC ::= INTEGER (0..65535) ++LACID ::= INTEGER (0..65535) + + -- OTD-MeasureInfo + OTD-MeasureInfo ::= SEQUENCE { diff --git a/rrlp-ephemeris/data.ubx b/rrlp-ephemeris/data.ubx new file mode 100644 index 0000000000000000000000000000000000000000..07cdddcd90e067c4f6aa42a02790e8ab41247056 GIT binary patch literal 2872 zcmZvedr;KZ7018(K)_{rgvdicP?3eKA`lQ+H9mO11bK>r7@84q%9!yDDxg(Ur^aY% zLrv0{HBy%lhg38gCSnucp*0#rYvZFG(J{tWvBHY*+tYLRZvQFy&FuU*zu)I~zu$ZA zx%Y6aLZ^y?>9nWcK2x7+!Ih+-KdAu~yhph_?bE_>h4Q_8m`KHU9smA4{aA%gorZd9 zAc=UNl=qpP*sbBOJ@CLu3lBWz$GI`$-GR?w^+3tZkxUd1olUtU>whkhuwlHZt0OyDQ4#`MZp|0z$j| zN9g~@u5UsG&%R{nDos|KP`oYy&CW(>pR17E+(hOM4>YWIv+Fl(BbsyY3kv%O(I}nGms3>N`2~(|u(;$`NM-OFtr4lX^$``O)qt3oqDDvQdTmN*4Z* zG8Ob}9#pT|=**##x?Vh(1;VjTUb~7b*j>n3)R!12V*)SncLCkdm_*+R4&voQR3sps{-`Ck$B9B6kV>iMBv zFB8H1Wb*+xY_Vm+V|EPw5?2IuvyFaJRs*w-H&TY>{0n)b>@Pb)h9tnfZY=h8`eWRX z7Ks+3DqSXy_Q?6ZWLE%+8f5J4h>PEne#DOYx%GHr_Y;8UJpXPFS9ECtkgbWwrWbWk z1!>T6fXJNhfl4QLdp)&0;(g^2h_G8k4ZAWCn;MA769aUM>pN;70DIR-{V@*xk|r7Z zIO0Y7r5|68!>l9MqsQ(i8bjl;XrpnvJ`%n!^^s;kgV_a1Fc0XF5Fq{Z@IvdI zBVqWO=)2VosMCd@d8HoZoS)Of(U@>V>iaqLOWUMASEkIz|E-VAM>W>+d)Ji(cy6o4 z!i!T-`b`X+f{D8RcACt;cE#u8<@yX&1IJFDBSQcm9Ur|%mu`gOMtmdP<$5UKZ><4R zpJ!^nmYk9?(^yG&JkDK5pk8henKyg++V%+{3Sx1C$T+N zT1|;)vQ5FBqF&OxM`SpDl+0&c(Ov9@dT~C?1+M|?k0M%xDHRJJF^EB)ZvmB=eyuj z7NucZFz2&ep?8?y7N*8WhK(3n{x52?4b$0sk{9Q{;2&GkvBHM0`%7N*2f^D?GH}O*dCpJUXfxdiX{A(yKfYSO0bUrUmO#mi{vr6Tyi6>< z#k{vdemr0Enzbmd9fzuNHJ;Ki{o;b;MSl^zn|~I%Jef~c=#kD$rd6*%zw`mUIZuZW z+^6pkN?!CI!KZ~}!!n-v8imfV|N3Rusj4**8}2WI7U2l|R`Q~M2!3_Md@KrLzEU9@ z^Gy@I=DIPyD%!navKLt;<&Yysx#m@ii7eIDQV$3irz z_R{%+TA1L5SMnt<&VRxGsw5AqM14jo^a+n&IJcEvZ`)6;k)P89Xi!%qdC?yP?;n+q zGp=&{KIRubEXLMpR@&KJ#`y<)S4m#<55aqd6d+rSZ&YXt`*HVZp_%=$NUl9j8n|Mg zPV(aX7rd^q5DP^;$0=0De06vu9rgS@)fE1dtfWx>8Oe+OAozEUMR+{S{A7hLv!9IG zR+_M`oxHQQ(-_{r(>6+8^bf%&#TMgjkovgQ{V~9T6dWrVLe?$9F0RPMX1z@3|w*UYD literal 0 HcmV?d00001 diff --git a/rrlp-ephemeris/gpl-2.0.txt b/rrlp-ephemeris/gpl-2.0.txt new file mode 100644 index 000000000..d511905c1 --- /dev/null +++ b/rrlp-ephemeris/gpl-2.0.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/rrlp-ephemeris/gpl-3.0.txt b/rrlp-ephemeris/gpl-3.0.txt new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/rrlp-ephemeris/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/rrlp-ephemeris/gps.c b/rrlp-ephemeris/gps.c new file mode 100644 index 000000000..c23574840 --- /dev/null +++ b/rrlp-ephemeris/gps.c @@ -0,0 +1,126 @@ +/* + * gps.c + * + * A few utility functions to deal with low level GPS data + * + * + * Copyright (C) 2009 Sylvain Munaut + * + * 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, see . + */ + +#include "gps.h" + + +#define GET_FIELD_U(w, nb, pos) (((w) >> (pos)) & ((1<<(nb))-1)) +#define GET_FIELD_S(w, nb, pos) (((int)((w) << (32-(nb)-(pos)))) >> (32-(nb))) + +/* + * Unpacks GPS Subframe 1,2,3 payloads (3 * 8 words) + * + * Note: eph->sv_id is not filled here since not present in those subframes + * + * (no parity bit checking is done, only the lower 24 bits of each word + * are used) + */ +int +gps_unpack_sf123(uint32_t *sf, struct gps_ephemeris_sv *eph) +{ + uint32_t *sf1 = &sf[0]; + uint32_t *sf2 = &sf[8]; + uint32_t *sf3 = &sf[16]; + + int iode1, iode2; + + eph->week_no = GET_FIELD_U(sf1[0], 10, 14); + eph->code_on_l2 = GET_FIELD_U(sf1[0], 2, 12); + eph->sv_ura = GET_FIELD_U(sf1[0], 4, 8); + eph->sv_health = GET_FIELD_U(sf1[0], 6, 2); + eph->l2_p_flag = GET_FIELD_U(sf1[1], 1, 23); + eph->t_gd = GET_FIELD_S(sf1[4], 8, 0); + eph->iodc = (GET_FIELD_U(sf1[0], 2, 0) << 8) | \ + GET_FIELD_U(sf1[5], 8, 16); + eph->t_oc = GET_FIELD_U(sf1[5], 16, 0); + eph->a_f2 = GET_FIELD_S(sf1[6], 8, 16); + eph->a_f1 = GET_FIELD_S(sf1[6], 16, 0); + eph->a_f0 = GET_FIELD_S(sf1[7], 22, 2); + + iode1 = GET_FIELD_U(sf2[0], 8, 16); + eph->c_rs = GET_FIELD_S(sf2[0], 16, 0); + eph->delta_n = GET_FIELD_S(sf2[1], 16, 8); + eph->m_0 = (GET_FIELD_S(sf2[1], 8, 0) << 24) | \ + GET_FIELD_U(sf2[2], 24, 0); + eph->c_uc = GET_FIELD_S(sf2[3], 16, 8); + eph->e = (GET_FIELD_U(sf2[3], 8, 0) << 24) | \ + GET_FIELD_U(sf2[4], 24, 0); + eph->c_us = GET_FIELD_S(sf2[5], 16, 8); + eph->a_powhalf = (GET_FIELD_U(sf2[5], 8, 0) << 24) | \ + GET_FIELD_U(sf2[6], 24, 0); + eph->t_oe = GET_FIELD_U(sf2[7], 16, 8); + eph->fit_flag = GET_FIELD_U(sf2[7], 1, 7); + + eph->c_ic = GET_FIELD_S(sf3[0], 16, 8); + eph->omega_0 = (GET_FIELD_S(sf3[0], 8, 0) << 24) | \ + GET_FIELD_U(sf3[1], 24, 0); + eph->c_is = GET_FIELD_S(sf3[2], 16, 8); + eph->i_0 = (GET_FIELD_S(sf3[2], 8, 0) << 24) | \ + GET_FIELD_U(sf3[3], 24, 0); + eph->c_rc = GET_FIELD_S(sf3[4], 16, 8); + eph->w = (GET_FIELD_S(sf3[4], 8, 0) << 24) | \ + GET_FIELD_U(sf3[5], 24, 0); + eph->omega_dot = GET_FIELD_S(sf3[6], 24, 0); + iode2 = GET_FIELD_U(sf3[7], 8, 16); + eph->idot = GET_FIELD_S(sf3[7], 14, 2); + + eph->_rsvd1 = GET_FIELD_U(sf1[1], 23, 0); + eph->_rsvd2 = GET_FIELD_U(sf1[2], 24, 0); + eph->_rsvd3 = GET_FIELD_U(sf1[3], 24, 0); + eph->_rsvd4 = GET_FIELD_U(sf1[4], 16, 8); + eph->aodo = GET_FIELD_U(sf2[7], 5, 2); + + /* Check & cross-validate iodc[7:0], iode1, iode2 */ + if ((iode1 != iode2) || (iode1 != (eph->iodc & 0xff))) + return -1; + + return 0; +} + + +/* + * Unpacks GPS Subframe 4 or 5 Almanac pages payload (8 words) + * + * (no parity bit checking is done, only the lower 24 bits of each word + * are used) + */ +int +gps_unpack_sf45_almanac(uint32_t *sf, struct gps_almanac_sv *alm) +{ + alm->sv_id = GET_FIELD_U(sf[0], 6, 16); + + alm->e = GET_FIELD_U(sf[0], 16, 0); + alm->t_oa = GET_FIELD_U(sf[1], 8, 16); + alm->ksii = GET_FIELD_S(sf[1], 16, 0); + alm->omega_dot = GET_FIELD_S(sf[2], 16, 8); + alm->sv_health = GET_FIELD_U(sf[2], 8, 0); + alm->a_powhalf = GET_FIELD_U(sf[3], 24, 0); + alm->omega_0 = GET_FIELD_S(sf[4], 24, 0); + alm->w = GET_FIELD_S(sf[5], 24, 0); + alm->m_0 = GET_FIELD_S(sf[6], 24, 0); + alm->a_f0 = (GET_FIELD_S(sf[7], 8, 16) << 3) | \ + GET_FIELD_U(sf[7], 3, 2); + alm->a_f1 = GET_FIELD_S(sf[7], 11, 5); + + return 0; +} + diff --git a/rrlp-ephemeris/gps.h b/rrlp-ephemeris/gps.h new file mode 100644 index 000000000..f6f7cc07b --- /dev/null +++ b/rrlp-ephemeris/gps.h @@ -0,0 +1,171 @@ +/* + * gps.h + * + * Header to deal with low level GPS data + * + * + * Copyright (C) 2009 Sylvain Munaut + * + * 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, see . + */ + +#ifndef __GPS_H__ +#define __GPS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + +#define MAX_SV 64 + + +/* Ionosperic model data */ +struct gps_ionosphere_model { + /* #bits Scale factor Effective Units */ + /* (LSB) range */ + + int alpha_0; /* s 8 2^-30 seconds */ + int alpha_1; /* s 8 2^-27 s / semi-circles */ + int alpha_2; /* s 8 2^-24 s / (semi-circles)^2 */ + int alpha_3; /* s 8 2^-24 s / (semi-circles)^3 */ + int beta_0; /* s 8 2^11 seconds */ + int beta_1; /* s 8 2^14 s / semi-circles */ + int beta_2; /* s 8 2^16 s / (semi-circles)^2 */ + int beta_3; /* s 8 2^16 s / (semi-circles)^3 */ +}; + + +/* UTC model data */ +struct gps_utc_model { + /* #bits Scale factor Effective Units */ + /* (LSB) range */ + + int a0; /* s 32 2^-30 seconds */ + int a1; /* s 24 2^-50 seconds / seconds */ + int delta_t_ls; /* s 8 1 seconds */ + int t_ot; /* u 8 2^12 602,112 seconds */ + int wn_t; /* u 8 1 weeks */ + int wn_lsf; /* u 8 1 weeks */ + int dn; /* u 8 1 7 days */ + int delta_t_lsf;/* s 8 1 seconds */ +}; + + +/* Almanach data */ +struct gps_almanac_sv { + int sv_id; + int sv_health; + + /* #bits Scale factor Effective Units */ + /* (LSB) range */ + + int e; /* u 16 2^-21 */ + int t_oa; /* u 8 2^12 602,112 seconds */ + int ksii; /* s 16 2^-19 semi-circles */ + int omega_dot; /* s 16 2^-38 semi-circles / s */ + int a_powhalf; /* u 24 2^-11 meters */ + int omega_0; /* s 24 2^-23 semi-circles */ + int w; /* s 24 2^-23 semi-circles */ + int m_0; /* s 24 2^-23 semi-circles */ + int a_f0; /* s 11 2^-20 seconds */ + int a_f1; /* s 11 2^-38 seconds / seconds */ +}; + +struct gps_almanac { + int wna; + int n_sv; + struct gps_almanac_sv svs[MAX_SV]; +}; + + +/* Ephemeris data */ +struct gps_ephemeris_sv { + int sv_id; + + /* #bits Scale factor Effective Units */ + /* (LSB) range */ + + int code_on_l2; /* u 2 1 / */ + int week_no; /* u 10 1 week */ + int l2_p_flag; /* u 1 1 / */ + int sv_ura; /* u 4 / / */ + int sv_health; /* u 6 / / */ + int t_gd; /* s 8 2^-31 seconds */ + int iodc; /* u 10 / / */ + int t_oc; /* u 16 2^4 604,784 seconds */ + int a_f2; /* s 8 2^-55 sec / sec^2 */ + int a_f1; /* s 16 2^-43 sec / sec */ + int a_f0; /* s 22 2^-31 seconds */ + + int c_rs; /* s 16 2^-5 meters */ + int delta_n; /* s 16 2^-43 semi-circles / s */ + int m_0; /* s 32 2^-31 semi-circles */ + int c_uc; /* s 16 2^-29 radians */ + unsigned int e; /* u 32 2^-33 0.03 / */ + int c_us; /* s 16 2^-29 radians */ + unsigned int a_powhalf; /* u 32 2^-19 meters^(1/2) */ + int t_oe; /* u 16 2^4 604,784 seconds */ + int fit_flag; /* u 1 / / */ + + int c_ic; /* s 16 2^-29 radians */ + int omega_0; /* s 32 2^-31 semi-circles */ + int c_is; /* s 16 2^-29 radians */ + int i_0; /* s 32 2^-31 semi-circles */ + int c_rc; /* s 16 2^-5 meters */ + int w; /* s 32 2^-31 semi-circles */ + int omega_dot; /* s 24 2^-43 semi-circles / s */ + int idot; /* s 14 2^-43 semi-circles / s */ + + int _rsvd1; /* 23 bits */ + int _rsvd2; /* 24 bits */ + int _rsvd3; /* 24 bits */ + int _rsvd4; /* 16 bits */ + int aodo; /* 8 bits Not sure it needs to be here ... */ +}; + +struct gps_ephemeris { + int n_sv; + struct gps_ephemeris_sv svs[MAX_SV]; +}; + + +/* All assist data */ +#define GPS_FIELD_IONOSPHERE (1<<0) +#define GPS_FIELD_UTC (1<<1) +#define GPS_FIELD_ALMANAC (1<<2) +#define GPS_FIELD_EPHEMERIS (1<<3) + +struct gps_assist_data { + int fields; + struct gps_ionosphere_model ionosphere; + struct gps_utc_model utc; + struct gps_almanac almanac; + struct gps_ephemeris ephemeris; +}; + + +/* GPS Subframe utility methods (see gps.c for details) */ +int gps_unpack_sf123(uint32_t *sf, struct gps_ephemeris_sv *eph); +int gps_unpack_sf45_almanac(uint32_t *sf, struct gps_almanac_sv *alm); + + +#ifdef __cplusplus +} +#endif + +#endif /* __GPS_H__ */ + diff --git a/rrlp-ephemeris/main.c b/rrlp-ephemeris/main.c new file mode 100644 index 000000000..bb025a2ba --- /dev/null +++ b/rrlp-ephemeris/main.c @@ -0,0 +1,99 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include "gps.h" +#include "ubx.h" +#include "ubx-parse.h" +#include "rrlp.h" + +static int +do_ubx_read(struct gps_assist_data *gps, const char *filename) +{ + int rv, fd, i; + struct stat st; + void *buf; + + /* Load file */ + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + + rv = fstat(fd, &st); + if (rv < 0) { + close(fd); + return -1; + } + + buf = malloc(st.st_size); + if (!buf) { + close(fd); + return -1; + } + + rv = read(fd, buf, st.st_size); + if (rv != st.st_size) { + free(buf); + close(fd); + return -1; + } + + /* Parse each message */ + for (i=0; i + * + * 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, see . + */ + + +#include + +#include "gps.h" +#include "rrlp.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* ------------------------------------------------------------------------ */ +/* RRLP Assistance request decoding */ +/* ---------------------------------------------------------------------{{{ */ +/* Decode and validate the assistance data request messages. + * See section 10.10 of + * . ETSI TS 149 031 V8.1.0 (2009-01) + * . 3GPP TS 49.031 version 8.1.0 Release 8 + */ + +/* Packed structure from 49.031 spec (RGA = Request GPS Assistance) */ + +#define RRLP_RGA0_ALMANAC (1<<0) +#define RRLP_RGA0_UTC_MODEL (1<<1) +#define RRLP_RGA0_IONO_MODEL (1<<2) +#define RRLP_RGA0_NAV_MODEL (1<<3) +#define RRLP_RGA0_DGPS (1<<4) +#define RRLP_RGA0_REF_LOC (1<<5) +#define RRLP_RGA0_REF_TIME (1<<6) +#define RRLP_RGA0_ACQ_ASSIST (1<<7) + +#define RRLP_RGA1_REALTIME_INT (1<<0) +#define RRLP_RGA1_EPH_EXT (1<<1) +#define RRLP_RGA1_EPH_EXT_CHECK (1<<2) + +struct rrlp_rga_hdr { + uint8_t items0; + uint8_t items1; +} __attribute__((packed)); + +struct rrlp_rga_eph_sv { + uint8_t sv_id; /* [7:6] reserved, [5:0] sv_id */ + uint8_t iode; /* latest eph in the MS memory in hours */ +} __attribute__((packed)); + +struct rrlp_rga_eph { + uint8_t wn_hi; /* [7:6] = wn[9:8] */ + uint8_t wn_lo; /* wn[7:0] */ + uint8_t toe; /* latest eph in the MS memory in hours */ + uint8_t nsat_tmtoe; /* [7:4] nstat, [3:0] T-Toe limit */ + struct rrlp_rga_eph_sv svs[0]; +} __attribute__((packed)); + +struct rrlp_rga_eph_ext { + uint8_t validity; /* in 4 hours units */ +} __attribute__((packed)); + +struct rrlp_rga_eph_ext_check { + /* weeks are in gps week modulo 4 */ + uint8_t wn_begin_end; /* [7:4] begin, [3:0] end */ + uint8_t tow_begin; + uint8_t tow_end; +} __attribute__((packed)); + + +/* Parsing function */ + +int +rrlp_decode_assistance_request( + struct rrlp_assist_req *ar, + void *req, int req_len) +{ + struct rrlp_rga_hdr *hdr = NULL; + struct rrlp_rga_eph *eph = NULL; + struct rrlp_rga_eph_ext *eph_ext = NULL; + struct rrlp_rga_eph_ext_check *eph_ext_check = NULL; + int p = 0; + + /* Reset */ + ar->req_elems = 0; + ar->eph_svs = 0; + + /* Parse message */ + hdr = req; + p += sizeof(struct rrlp_rga_hdr); + if (p > req_len) + return -1; + + if (hdr->items0 & RRLP_RGA0_NAV_MODEL) { + eph = req + p; + p += sizeof(struct rrlp_rga_eph); + if (p > req_len) + return -1; + p += (eph->nsat_tmtoe >> 4) * sizeof(struct rrlp_rga_eph_sv); + if (p > req_len) + return -1; + } + + if (hdr->items1 & RRLP_RGA1_EPH_EXT) { + eph_ext = req + p; + p += sizeof(struct rrlp_rga_eph_ext); + if (p > req_len) + return -1; + } + + if (hdr->items1 & RRLP_RGA1_EPH_EXT_CHECK) { + eph_ext_check = req + p; + p += sizeof(struct rrlp_rga_eph_ext_check); + if (p > req_len) + return -1; + } + + if (p != req_len) + return -2; /* not all bytes consumed ??? */ + + /* Print a warning for unsupported requests */ + if ((eph_ext != NULL) || + (eph_ext_check != NULL) || + (hdr->items0 & (RRLP_RGA0_DGPS | RRLP_RGA0_ACQ_ASSIST)) || + (hdr->items1 & RRLP_RGA1_REALTIME_INT)) { + fprintf(stderr, "[w] Unsupported assistance data requested, ignored ...\n"); + } + + /* Copy the request */ + if (hdr->items0 & RRLP_RGA0_ALMANAC) + ar->req_elems |= RRLP_AR_ALMANAC; + + if (hdr->items0 & RRLP_RGA0_UTC_MODEL) + ar->req_elems |= RRLP_AR_UTC_MODEL; + + if (hdr->items0 & RRLP_RGA0_IONO_MODEL) + ar->req_elems |= RRLP_AR_IONO_MODEL; + + if (hdr->items0 & RRLP_RGA0_REF_LOC) + ar->req_elems |= RRLP_AR_REF_LOC; + + if (hdr->items0 & RRLP_RGA0_REF_TIME) + ar->req_elems |= RRLP_AR_REF_TIME; + + if (hdr->items0 & RRLP_RGA0_NAV_MODEL) { + int i, n_svs = eph->nsat_tmtoe >> 4; + ar->req_elems |= RRLP_AR_EPHEMERIS; + for (i=0; ieph_svs |= (1ULL << (eph->svs[i].sv_id - 1)); + } + + return 0; +} + +/* }}} */ + + +/* ------------------------------------------------------------------------ */ +/* RRLP elements fill */ +/* ---------------------------------------------------------------------{{{ */ + +static void +_rrlp_fill_navigation_model_element( + struct NavModelElement *rrlp_nme, + struct gps_ephemeris_sv *gps_eph_sv) +{ + struct UncompressedEphemeris *rrlp_eph; + + rrlp_nme->satStatus.present = SatStatus_PR_newSatelliteAndModelUC; + rrlp_nme->satelliteID = gps_eph_sv->sv_id; + + rrlp_eph = &rrlp_nme->satStatus.choice.newSatelliteAndModelUC; + + rrlp_eph->ephemCodeOnL2 = gps_eph_sv->code_on_l2; + rrlp_eph->ephemURA = gps_eph_sv->sv_ura; + rrlp_eph->ephemSVhealth = gps_eph_sv->sv_health; + rrlp_eph->ephemIODC = gps_eph_sv->iodc; + rrlp_eph->ephemL2Pflag = gps_eph_sv->l2_p_flag; + rrlp_eph->ephemTgd = gps_eph_sv->t_gd; + rrlp_eph->ephemToc = gps_eph_sv->t_oc; + rrlp_eph->ephemAF2 = gps_eph_sv->a_f2; + rrlp_eph->ephemAF1 = gps_eph_sv->a_f1; + rrlp_eph->ephemAF0 = gps_eph_sv->a_f0; + rrlp_eph->ephemCrs = gps_eph_sv->c_rs; + rrlp_eph->ephemDeltaN = gps_eph_sv->delta_n; + rrlp_eph->ephemM0 = gps_eph_sv->m_0; + rrlp_eph->ephemCuc = gps_eph_sv->c_uc; + rrlp_eph->ephemE = gps_eph_sv->e; + rrlp_eph->ephemCus = gps_eph_sv->c_us; + rrlp_eph->ephemAPowerHalf = gps_eph_sv->a_powhalf; + rrlp_eph->ephemToe = gps_eph_sv->t_oe; + rrlp_eph->ephemFitFlag = gps_eph_sv->fit_flag; + rrlp_eph->ephemAODA = gps_eph_sv->aodo; + rrlp_eph->ephemCic = gps_eph_sv->c_ic; + rrlp_eph->ephemOmegaA0 = gps_eph_sv->omega_0; + rrlp_eph->ephemCis = gps_eph_sv->c_is; + rrlp_eph->ephemI0 = gps_eph_sv->i_0; + rrlp_eph->ephemCrc = gps_eph_sv->c_rc; + rrlp_eph->ephemW = gps_eph_sv->w; + rrlp_eph->ephemOmegaADot = gps_eph_sv->omega_dot; + rrlp_eph->ephemIDot = gps_eph_sv->idot; + + rrlp_eph->ephemSF1Rsvd.reserved1 = gps_eph_sv->_rsvd1; + rrlp_eph->ephemSF1Rsvd.reserved2 = gps_eph_sv->_rsvd2; + rrlp_eph->ephemSF1Rsvd.reserved3 = gps_eph_sv->_rsvd3; + rrlp_eph->ephemSF1Rsvd.reserved4 = gps_eph_sv->_rsvd4; +} + +static void +_rrlp_fill_almanac_element( + struct AlmanacElement *rrlp_ae, + struct gps_almanac_sv *gps_alm_sv) +{ + rrlp_ae->satelliteID = gps_alm_sv->sv_id; + + rrlp_ae->almanacE = gps_alm_sv->e; + rrlp_ae->alamanacToa = gps_alm_sv->t_oa; + rrlp_ae->almanacKsii = gps_alm_sv->ksii; + rrlp_ae->almanacOmegaDot = gps_alm_sv->omega_dot; + rrlp_ae->almanacSVhealth = gps_alm_sv->sv_health; + rrlp_ae->almanacAPowerHalf = gps_alm_sv->a_powhalf; + rrlp_ae->almanacOmega0 = gps_alm_sv->omega_0; + rrlp_ae->almanacW = gps_alm_sv->w; + rrlp_ae->almanacM0 = gps_alm_sv->m_0; + rrlp_ae->almanacAF0 = gps_alm_sv->a_f0; + rrlp_ae->almanacAF1 = gps_alm_sv->a_f1; + +} + +static void +_rrlp_fill_ionospheric_model( + struct IonosphericModel *rrlp_iono, + struct gps_ionosphere_model *gps_iono) +{ + rrlp_iono->alfa0 = gps_iono->alpha_0; + rrlp_iono->alfa1 = gps_iono->alpha_1; + rrlp_iono->alfa2 = gps_iono->alpha_2; + rrlp_iono->alfa3 = gps_iono->alpha_3; + rrlp_iono->beta0 = gps_iono->beta_0; + rrlp_iono->beta1 = gps_iono->beta_1; + rrlp_iono->beta2 = gps_iono->beta_2; + rrlp_iono->beta3 = gps_iono->beta_3; +} + +static void +_rrlp_fill_utc_model( + struct UTCModel *rrlp_utc, + struct gps_utc_model *gps_utc) +{ + rrlp_utc->utcA1 = gps_utc->a1; + rrlp_utc->utcA0 = gps_utc->a0; + rrlp_utc->utcTot = gps_utc->t_ot; + rrlp_utc->utcWNt = gps_utc->wn_t & 0xff; + rrlp_utc->utcDeltaTls = gps_utc->delta_t_ls; + rrlp_utc->utcWNlsf = gps_utc->wn_lsf & 0xff; + rrlp_utc->utcDN = gps_utc->dn; + rrlp_utc->utcDeltaTlsf = gps_utc->delta_t_lsf; +} + +/* }}} */ + + +/* ------------------------------------------------------------------------ */ +/* RRLP Assistance PDU Generation */ +/* ---------------------------------------------------------------------{{{ */ + +struct PDU * +_rrlp_create_gps_assist_pdu(int refnum, struct GPS_AssistData **o_gps_ad) +{ + struct PDU *pdu; + struct GPS_AssistData *gps_ad; + + pdu = calloc(1, sizeof(*pdu)); + if (!pdu) + return NULL; + + gps_ad = calloc(1, sizeof(*gps_ad)); + if (!gps_ad) { + free(pdu); + return NULL; + } + + if (o_gps_ad) + *o_gps_ad = gps_ad; + + pdu->referenceNumber = refnum; + pdu->component.present = RRLP_Component_PR_assistanceData; + pdu->component.choice.assistanceData.gps_AssistData = gps_ad; + + return pdu; +} + +static int +_rrlp_add_ionospheric_model( + struct GPS_AssistData *rrlp_gps_ad, + struct gps_assist_data *gps_ad) +{ + struct IonosphericModel *rrlp_iono; + + if (!(gps_ad->fields & GPS_FIELD_IONOSPHERE)) + return -EINVAL; + + rrlp_iono = calloc(1, sizeof(*rrlp_iono)); + if (!rrlp_iono) + return -ENOMEM; + rrlp_gps_ad->controlHeader.ionosphericModel = rrlp_iono; + + _rrlp_fill_ionospheric_model(rrlp_iono, &gps_ad->ionosphere); + + return 0; +} + +static int +_rrlp_add_utc_model( + struct GPS_AssistData *rrlp_gps_ad, + struct gps_assist_data *gps_ad) +{ + struct UTCModel *rrlp_utc; + + if (!(gps_ad->fields & GPS_FIELD_UTC)) + return -EINVAL; + + rrlp_utc = calloc(1, sizeof(*rrlp_utc)); + if (!rrlp_utc) + return -ENOMEM; + rrlp_gps_ad->controlHeader.utcModel = rrlp_utc; + + _rrlp_fill_utc_model(rrlp_utc, &gps_ad->utc); + + return 0; +} + +static int +_rrlp_add_reference_location( + struct GPS_AssistData *rrlp_gps_ad, + struct gps_assist_data *gps_ad) +{ + struct RefLocation *rrlp_refloc; + + /* FIXME: Check if info is in gps_ad */ + + rrlp_refloc = calloc(1, sizeof(*rrlp_refloc)); + if (!rrlp_refloc) + return -ENOMEM; + rrlp_gps_ad->controlHeader.refLocation = rrlp_refloc; + + /* FIXME */ + { + uint8_t gps_loc[] = { + 0x80, /* Ellipsoid Point with altitude */ + 0x48, 0x0f, 0x93, /* 50.667778 N */ + 0x03, 0x47, 0x87, /* 4.611667 E */ + 0x00, 0x72, /* 114m */ + }; + uint8_t *b = malloc(sizeof(gps_loc)); + memcpy(b, gps_loc, sizeof(gps_loc)); + rrlp_refloc->threeDLocation.buf = b; + rrlp_refloc->threeDLocation.size = sizeof(gps_loc); + } + + return 0; +} + +static int +_rrlp_add_reference_time( + struct GPS_AssistData *rrlp_gps_ad, + struct gps_assist_data *gps_ad) +{ + struct ReferenceTime *rrlp_reftime; + + /* FIXME: Check if info is in gps_ad */ + + rrlp_reftime = calloc(1, sizeof(*rrlp_reftime)); + if (!rrlp_reftime) + return -ENOMEM; + rrlp_gps_ad->controlHeader.referenceTime = rrlp_reftime; + + /* FIXME */ +// rrlp_reftime.gpsTime.gpsTOW23b = g_gps_tow / 80; /* 23 bits */ +// rrlp_reftime.gpsTime.gpsWeek = g_gps_week & 0x3ff; /* 10 bits */ + + return 0; +} + +static int +_rrlp_add_almanac( + struct GPS_AssistData *rrlp_gps_ad, + struct gps_assist_data *gps_ad, int *start, int count) +{ + int i; + struct Almanac *rrlp_alm; + struct gps_almanac *gps_alm = &gps_ad->almanac; + + if (!(gps_ad->fields & GPS_FIELD_ALMANAC)) + return -EINVAL; + + rrlp_alm = calloc(1, sizeof(*rrlp_alm)); + if (!rrlp_alm) + return -ENOMEM; + rrlp_gps_ad->controlHeader.almanac = rrlp_alm; + + rrlp_alm->alamanacWNa = gps_alm->wna; + if (count == -1) + count = gps_alm->n_sv - *start; + for (i=*start; (i<*start+count) && (in_sv); i++) { + struct AlmanacElement *ae; + ae = calloc(1, sizeof(*ae)); + if (!ae) + return -ENOMEM; + _rrlp_fill_almanac_element(ae, &gps_alm->svs[i]); + ASN_SEQUENCE_ADD(&rrlp_alm->almanacList.list, ae); + } + + *start = i; + + return i < gps_alm->n_sv; +} + +static int +_rrlp_add_ephemeris( + struct GPS_AssistData *rrlp_gps_ad, + struct gps_assist_data *gps_ad, int *start, int count, uint64_t mask) +{ + int i, j; + struct NavigationModel *rrlp_nav; + struct gps_ephemeris *gps_eph = &gps_ad->ephemeris; + + if (!(gps_ad->fields & GPS_FIELD_EPHEMERIS)) + return -EINVAL; + + rrlp_nav = calloc(1, sizeof(*rrlp_nav)); + if (!rrlp_nav) + return -ENOMEM; + rrlp_gps_ad->controlHeader.navigationModel = rrlp_nav; + + if (count == -1) + count = gps_eph->n_sv - *start; + for (i=*start,j=0; (jn_sv); i++) { + if (!(mask & (1ULL<<(gps_eph->svs[i].sv_id-1)))) + continue; + struct NavModelElement *nme; + nme = calloc(1, sizeof(*nme)); + if (!nme) + return -ENOMEM; + _rrlp_fill_navigation_model_element(nme, &gps_eph->svs[i]); + ASN_SEQUENCE_ADD(&rrlp_nav->navModelList.list, nme); + j++; + } + + *start = i; + + return i < gps_eph->n_sv; +} + + +#define MAX_PDUS 64 + +int +rrlp_gps_assist_pdus( + struct gps_assist_data *gps_ad, struct rrlp_assist_req *req, + void **o_pdu, int *o_len, int o_max_pdus) +{ + struct PDU *lst_pdu[MAX_PDUS]; + int lst_cnt = 0; + + struct PDU *rrlp_pdu = NULL; + struct GPS_AssistData *rrlp_gps_ad = NULL; + uint32_t re = req->req_elems; + int i, rv = 0; + + /* IonosphericModel, UTCModel, RefLocation, ReferenceTime */ + if (re & (RRLP_AR_IONO_MODEL | + RRLP_AR_UTC_MODEL | + RRLP_AR_REF_TIME | + RRLP_AR_REF_LOC)) + { + int pdu_has_data = 0; + + rrlp_pdu = _rrlp_create_gps_assist_pdu(1, &rrlp_gps_ad); + if (!rrlp_pdu) { + rv = -ENOMEM; + goto error; + } + + if (re & RRLP_AR_IONO_MODEL) + if (!_rrlp_add_ionospheric_model(rrlp_gps_ad, gps_ad)) + pdu_has_data = 1; + + if (re & RRLP_AR_UTC_MODEL) + if (!_rrlp_add_utc_model(rrlp_gps_ad, gps_ad)) + pdu_has_data = 1; + + if (re & RRLP_AR_REF_TIME) + if (!_rrlp_add_reference_time(rrlp_gps_ad, gps_ad)) + pdu_has_data = 1; + + if (re & RRLP_AR_REF_LOC) + if (!_rrlp_add_reference_location(rrlp_gps_ad, gps_ad)) + pdu_has_data = 1; + + if (pdu_has_data) { + lst_pdu[lst_cnt++] = rrlp_pdu; + rrlp_pdu = NULL; + } + } + + /* Almanac */ + if (re & RRLP_AR_ALMANAC) { + i = 0; + do { + if (!(gps_ad->fields & GPS_FIELD_ALMANAC)) + break; + + if (!rrlp_pdu) { + rrlp_pdu = _rrlp_create_gps_assist_pdu(1, &rrlp_gps_ad); + if (!rrlp_pdu) { + rv = -ENOMEM; + goto error; + } + } + + rv = _rrlp_add_almanac(rrlp_gps_ad, gps_ad, &i, 10); + if (rv < 0) + goto error; + + lst_pdu[lst_cnt++] = rrlp_pdu; + rrlp_pdu = NULL; + } while (rv); + } + + /* Ephemeris */ + if (re & RRLP_AR_EPHEMERIS) { + i = 0; + do { + if (!(gps_ad->fields & GPS_FIELD_EPHEMERIS)) + break; + + if (!rrlp_pdu) { + rrlp_pdu = _rrlp_create_gps_assist_pdu(1, &rrlp_gps_ad); + if (!rrlp_pdu) { + rv = -ENOMEM; + goto error; + } + } + + rv = _rrlp_add_ephemeris(rrlp_gps_ad, gps_ad, &i, 2, req->eph_svs); + + lst_pdu[lst_cnt++] = rrlp_pdu; + rrlp_pdu = NULL; + + } while (rv); + } + + /* Serialize & Release all PDUs */ + for (i=0; i + * + * 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, see . + */ + +#ifndef __RRLP_H__ +#define __RRLP_H__ + +#include + +#include "gps.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Our internal simplified structure for requests */ + +#define RRLP_AR_REF_LOC (1<<0) +#define RRLP_AR_REF_TIME (1<<1) +#define RRLP_AR_UTC_MODEL (1<<2) +#define RRLP_AR_IONO_MODEL (1<<3) +#define RRLP_AR_ALMANAC (1<<4) +#define RRLP_AR_EPHEMERIS (1<<5) + +struct rrlp_assist_req { + uint32_t req_elems; + uint64_t eph_svs; +}; + + +/* Methods */ +int rrlp_decode_assistance_request(struct rrlp_assist_req *ar, + void *req, int req_len); + +int rrlp_gps_assist_pdus( + struct gps_assist_data *gps_ad, struct rrlp_assist_req *req, + void **o_pdu, int *o_len, int o_max_pdus); + + +#ifdef __cplusplus +} +#endif + +#endif /* __RRLP_H__ */ + diff --git a/rrlp-ephemeris/ubx-parse.c b/rrlp-ephemeris/ubx-parse.c new file mode 100644 index 000000000..cb8c22e83 --- /dev/null +++ b/rrlp-ephemeris/ubx-parse.c @@ -0,0 +1,165 @@ +/* + * ubx-parse.c + * + * Implementation of parsing code converting UBX messages to GPS assist + * data + * + * + * Copyright (C) 2009 Sylvain Munaut + * + * 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, see . + */ + +#include + +#include "gps.h" +#include "ubx.h" +#include "ubx-parse.h" + + +/* Helpers */ + +static int +float_to_fixedpoint(float f, int sf) +{ + if (sf < 0) { + while (sf++ < 0) + f *= 2.0f; + } else { + while (sf-- > 0) + f *= 0.5f; + } + + return (int)f; +} + +static inline int +double_to_fixedpoint(double d, int sf) +{ + if (sf < 0) { + while (sf++ < 0) + d *= 2.0; + } else { + while (sf-- > 0) + d *= 0.5; + } + + return (int)d; +} + + +/* UBX message parsing to fill gps assist data */ + +static void +_ubx_msg_parse_nav_posllh(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) +{ + struct ubx_nav_posllh *nav_posllh = pl; + struct gps_assist_data *gps = ud; + + //printf("[.] NAV_POSLLH\n"); + + // FIXME: Extract info for "Reference Position" +} + +static void +_ubx_msg_parse_aid_ini(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) +{ + struct ubx_aid_ini *aid_ini = pl; + struct gps_assist_data *gps = ud; + + //printf("[.] AID_INI\n"); + + // FIXME: Extract info for "Reference Time" +} + +static void +_ubx_msg_parse_aid_hui(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) +{ + struct ubx_aid_hui *aid_hui = pl; + struct gps_assist_data *gps = ud; + + //printf("[.] AID_HUI\n"); + + if (aid_hui->flags & 0x2) { /* UTC parameters valid */ + struct gps_utc_model *utc = &gps->utc; + + gps->fields |= GPS_FIELD_UTC; + + utc->a0 = double_to_fixedpoint(aid_hui->utc_a0, -30); + utc->a1 = double_to_fixedpoint(aid_hui->utc_a1, -50); + utc->delta_t_ls = aid_hui->utc_ls; + utc->t_ot = aid_hui->utc_tot >> 12; + utc->wn_t = aid_hui->utc_wnt; + utc->wn_lsf = aid_hui->utc_wnf; + utc->dn = aid_hui->utc_dn; + utc->delta_t_lsf = aid_hui->utc_lsf; + } + + if (aid_hui->flags & 0x04) { /* Klobuchar parameters valid */ + struct gps_ionosphere_model *iono = &gps->ionosphere; + + gps->fields |= GPS_FIELD_IONOSPHERE; + + iono->alpha_0 = float_to_fixedpoint(aid_hui->klob_a0, -30); + iono->alpha_1 = float_to_fixedpoint(aid_hui->klob_a1, -27); + iono->alpha_2 = float_to_fixedpoint(aid_hui->klob_a2, -24); + iono->alpha_3 = float_to_fixedpoint(aid_hui->klob_a3, -24); + iono->beta_0 = float_to_fixedpoint(aid_hui->klob_b0, 11); + iono->beta_1 = float_to_fixedpoint(aid_hui->klob_b1, 14); + iono->beta_2 = float_to_fixedpoint(aid_hui->klob_b2, 16); + iono->beta_3 = float_to_fixedpoint(aid_hui->klob_b3, 16); + } +} + +static void +_ubx_msg_parse_aid_alm(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) +{ + struct ubx_aid_alm *aid_alm = pl; + struct gps_assist_data *gps = ud; + + //printf("[.] AID_ALM %d - %d\n", aid_alm->sv_id, aid_alm->gps_week); + + if (aid_alm->gps_week) { + gps->fields |= GPS_FIELD_ALMANAC; + gps->almanac.wna = aid_alm->gps_week & 0xff; + gps_unpack_sf45_almanac(aid_alm->alm_words, &gps->almanac.svs[gps->almanac.n_sv++]); + } +} + +static void +_ubx_msg_parse_aid_eph(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) +{ + struct ubx_aid_eph *aid_eph = pl; + struct gps_assist_data *gps = ud; + + //printf("[.] AID_EPH %d - %s\n", aid_eph->sv_id, aid_eph->present ? "present" : "not present"); + + if (aid_eph->present) { + int i = gps->ephemeris.n_sv++; + gps->fields |= GPS_FIELD_EPHEMERIS; + gps->ephemeris.svs[i].sv_id = aid_eph->sv_id; + gps_unpack_sf123(aid_eph->eph_words, &gps->ephemeris.svs[i]); + } +} + + +/* Dispatch table */ +struct ubx_dispatch_entry ubx_parse_dt[] = { + UBX_DISPATCH(NAV, POSLLH, _ubx_msg_parse_nav_posllh), + UBX_DISPATCH(AID, INI, _ubx_msg_parse_aid_ini), + UBX_DISPATCH(AID, HUI, _ubx_msg_parse_aid_hui), + UBX_DISPATCH(AID, ALM, _ubx_msg_parse_aid_alm), + UBX_DISPATCH(AID, EPH, _ubx_msg_parse_aid_eph), +}; + diff --git a/rrlp-ephemeris/ubx-parse.h b/rrlp-ephemeris/ubx-parse.h new file mode 100644 index 000000000..621475d65 --- /dev/null +++ b/rrlp-ephemeris/ubx-parse.h @@ -0,0 +1,45 @@ +/* + * ubx-parse.h + * + * Header for parsing code converting UBX messages to GPS assist data + * + * + * Copyright (C) 2009 Sylvain Munaut + * + * 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, see . + */ + +#ifndef __UBX_PARSE_H__ +#define __UBX_PARSE_H__ + + +#include "gps.h" +#include "ubx.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Dispatch table */ +extern struct ubx_dispatch_entry ubx_parse_dt[]; + + +#ifdef __cplusplus +} +#endif + +#endif /* __UBX_PARSE_H__ */ + diff --git a/rrlp-ephemeris/ubx.c b/rrlp-ephemeris/ubx.c new file mode 100644 index 000000000..83dd1f055 --- /dev/null +++ b/rrlp-ephemeris/ubx.c @@ -0,0 +1,81 @@ +/* + * ubx.c + * + * Implementation of generic UBX helpers + * + * + * Copyright (C) 2009 Sylvain Munaut + * + * 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, see . + */ + +#include +#include + +#include "ubx.h" + + +static void +ubx_checksum(uint8_t *data, int len, uint8_t *cksum) +{ + int i; + uint8_t ck0 = 0, ck1 = 0; + for (i=0; ihandler) { + if ((dt->msg_class == msg_class) && (dt->msg_id == msg_id)) + return dt->handler; + dt++; + } + return NULL; +} + + +int +ubx_msg_dispatch(struct ubx_dispatch_entry *dt, + void *msg, int len, void *userdata) +{ + struct ubx_hdr *hdr = msg; + uint8_t cksum[2], *cksum_ptr; + ubx_msg_handler_t h; + + if ((hdr->sync[0] != UBX_SYNC0) || (hdr->sync[1] != UBX_SYNC1)) { + fprintf(stderr, "[!] Invalid sync bytes\n"); + return -1; + } + + ubx_checksum(msg + 2, sizeof(struct ubx_hdr) + hdr->payload_len - 2, cksum); + cksum_ptr = msg + (sizeof(struct ubx_hdr) + hdr->payload_len); + if ((cksum_ptr[0] != cksum[0]) || (cksum_ptr[1] != cksum[1])) { + fprintf(stderr, "[!] Invalid checksum\n"); + return -1; + } + + h = ubx_find_handler(dt, hdr->msg_class, hdr->msg_id); + if (h) + h(hdr, msg + sizeof(struct ubx_hdr), hdr->payload_len, userdata); + + return sizeof(struct ubx_hdr) + hdr->payload_len + 2; +} + diff --git a/rrlp-ephemeris/ubx.h b/rrlp-ephemeris/ubx.h new file mode 100644 index 000000000..826438658 --- /dev/null +++ b/rrlp-ephemeris/ubx.h @@ -0,0 +1,232 @@ +/* + * ubx.h + * + * Header for UBX related stuff + * + * + * Copyright (C) 2009 Sylvain Munaut + * + * 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, see . + */ + +#ifndef __UBX_H__ +#define __UBX_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Constants used in UBX */ + + /* Sync bytes (two first bytes of each message) */ +#define UBX_SYNC0 0xb5 +#define UBX_SYNC1 0x62 + + /* UBX messages classes */ +#define UBX_CLASS_NAV 0x01 +#define UBX_CLASS_RXM 0x02 +#define UBX_CLASS_INF 0x04 +#define UBX_CLASS_ACK 0x05 +#define UBX_CLASS_CFG 0x06 +#define UBX_CLASS_UPD 0x09 +#define UBX_CLASS_MON 0x0a +#define UBX_CLASS_AID 0x0b +#define UBX_CLASS_TIM 0x0d + + /* UBX messages type ID (by class) */ +#define UBX_NAV_POSECEF 0x01 +#define UBX_NAV_POSLLH 0x02 +#define UBX_NAV_STATUS 0x03 +#define UBX_NAV_DOP 0x04 +#define UBX_NAV_SOL 0x06 +#define UBX_NAV_POSUTM 0x08 +#define UBX_NAV_VELECEF 0x11 +#define UBX_NAV_VELNED 0x12 +#define UBX_NAV_TIMEGPS 0x20 +#define UBX_NAV_TIMEUTC 0x21 +#define UBX_NAV_CLOCK 0x22 +#define UBX_NAV_SVINFO 0x30 +#define UBX_NAV_DGPS 0x31 +#define UBX_NAV_SBAS 0x32 +#define UBX_NAV_EKFSTATUS 0x40 + +#define UBX_RXM_RAW 0x10 +#define UBX_RXM_SFRB 0x11 +#define UBX_RXM_SVSI 0x20 +#define UBX_RXM_SVSI_GPS 0x20 +#define UBX_RXM_ALM 0x30 +#define UBX_RXM_EPH 0x31 +#define UBX_RXM_POSREQ 0x40 + +#define UBX_INF_ERROR 0x00 +#define UBX_INF_WARNING 0x01 +#define UBX_INF_NOTICE 0x02 +#define UBX_INF_TEST 0x03 +#define UBX_INF_DEBUG 0x04 +#define UBX_INF_USER 0x07 + +#define UBX_ACK_NAK 0x00 +#define UBX_ACK_ACK 0x01 + +#define UBX_CFG_PRT 0x00 +#define UBX_CFG_USB 0x1b +#define UBX_CFG_MSG 0x01 +#define UBX_CFG_NMEA 0x17 +#define UBX_CFG_RATE 0x08 +#define UBX_CFG_CFG 0x09 +#define UBX_CFG_TP 0x07 +#define UBX_CFG_NAV2 0x1a +#define UBX_CFG_DAT 0x06 +#define UBX_CFG_INF 0x02 +#define UBX_CFG_RST 0x04 +#define UBX_CFG_RXM 0x11 +#define UBX_CFG_ANT 0x13 +#define UBX_CFG_FXN 0x0e +#define UBX_CFG_SBAS 0x16 +#define UBX_CFG_LIC 0x80 +#define UBX_CFG_TM 0x10 +#define UBX_CFG_TM2 0x19 +#define UBX_CFG_TMODE 0x1d +#define UBX_CFG_EKF 0x12 + +#define UBX_UPD_DOWNL 0x01 +#define UBX_UPD_UPLOAD 0x02 +#define UBX_UPD_EXEC 0x03 +#define UBX_UPD_MEMCPY 0x04 + +#define UBX_MON_SCHD 0x01 +#define UBX_MON_IO 0x02 +#define UBX_MON_IPC 0x03 +#define UBX_MON_VER 0x04 +#define UBX_MON_EXCEPT 0x05 +#define UBX_MON_MSGPP 0x06 +#define UBX_MON_RXBUF 0x07 +#define UBX_MON_TXBUF 0x08 +#define UBX_MON_HW 0x09 +#define UBX_MON_USB 0x0a + +#define UBX_AID_REQ 0x00 +#define UBX_AID_INI 0x01 +#define UBX_AID_HUI 0x02 +#define UBX_AID_DATA 0x10 +#define UBX_AID_ALM 0x30 +#define UBX_AID_EPH 0x31 + +#define UBX_TIM_TP 0x01 +#define UBX_TIM_TM 0x02 +#define UBX_TIM_TM2 0x03 +#define UBX_TIM_SVIN 0x04 + + +/* Header */ +struct ubx_hdr { + uint8_t sync[2]; + uint8_t msg_class; + uint8_t msg_id; + uint16_t payload_len; +} __attribute__((packed)); + + +/* Payload formats (some of them) */ +struct ubx_nav_posllh { + uint32_t itow; + int32_t lon; /* scaling 1e-7 */ + int32_t lat; /* scaling 1e-7 */ + int32_t height;/* mm */ + int32_t hsl; /* mm */ + uint32_t hacc; /* mm */ + uint32_t vacc; /* mm */ +} __attribute__((packed)); + +struct ubx_aid_ini { + int32_t x; + int32_t y; + int32_t z; + uint32_t posacc; + uint16_t tm_cfg; + uint16_t wn; + uint32_t tow; + int32_t tow_ns; + uint32_t tacc_ms; + uint32_t tacc_ns; + int32_t clkd; + uint32_t clkdacc; + uint32_t flags; +} __attribute__((packed)); + +struct ubx_aid_hui { + uint32_t health; + double utc_a1; + double utc_a0; + int32_t utc_tot; + int16_t utc_wnt; + int16_t utc_ls; + int16_t utc_wnf; + int16_t utc_dn; + int16_t utc_lsf; + int16_t utc_spare; + float klob_a0; + float klob_a1; + float klob_a2; + float klob_a3; + float klob_b0; + float klob_b1; + float klob_b2; + float klob_b3; + uint32_t flags; +} __attribute__((packed)); + +struct ubx_aid_alm { + uint32_t sv_id; + uint32_t gps_week; + uint32_t alm_words[8]; /* Present only if 'gps_week' != 0 */ +} __attribute__((packed)); + +struct ubx_aid_eph { + uint32_t sv_id; + uint32_t present; + uint32_t eph_words[24]; /* Present only if 'present' != 0 */ +} __attribute__((packed)); + + +/* Message handler */ +typedef void (*ubx_msg_handler_t)( + struct ubx_hdr *hdr, void *payload, int payload_len, void *userdata); + +struct ubx_dispatch_entry { + uint8_t msg_class; + uint8_t msg_id; + ubx_msg_handler_t handler; +}; + +#define UBX_DISPATCH(kls,id,hdl) { \ + .msg_class = UBX_CLASS_ ## kls , \ + .msg_id = UBX_ ## kls ## _ ## id, \ + .handler = (hdl), \ +} + + +/* Methods */ +int ubx_msg_dispatch(struct ubx_dispatch_entry *dt, + void *msg, int len, void *userdata); + + +#ifdef __cplusplus +} +#endif + +#endif /* __UBX_H__ */ + From b61e3b21580afc6381a6c72618d51697c7ce9771 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 22 Dec 2009 22:32:51 +0100 Subject: [PATCH 156/365] Import the new logging architecture This is the new logging architecture, including * support for multiuple logging targets like stderr and vty * log levels in addition to categories/subsystems * filtering based on imsi, i.e. only see events for one subscriber * dynamically change log level for each category for each vty --- openbsc/include/openbsc/debug.h | 129 ++++++--- openbsc/include/openbsc/telnet_interface.h | 3 +- openbsc/src/abis_rsl.c | 2 + openbsc/src/bs11_config.c | 8 +- openbsc/src/bsc_hack.c | 14 +- openbsc/src/bsc_mgcp.c | 7 + openbsc/src/debug.c | 296 ++++++++++++++++++--- openbsc/src/e1_input.c | 2 + openbsc/src/ipaccess-config.c | 6 + openbsc/src/telnet_interface.c | 6 + openbsc/src/vty_interface.c | 173 ++++++++++++ openbsc/tests/debug/Makefile.am | 2 +- 12 files changed, 571 insertions(+), 77 deletions(-) diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index fc387cec3..129956d8e 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -1,52 +1,51 @@ #ifndef _DEBUG_H #define _DEBUG_H +#include +#include "linuxlist.h" + #define DEBUG -#define DRLL 0x0001 -#define DCC 0x0002 -#define DMM 0x0004 -#define DRR 0x0008 -#define DRSL 0x0010 -#define DNM 0x0020 - -#define DMNCC 0x0080 -#define DSMS 0x0100 -#define DPAG 0x0200 -#define DMEAS 0x0400 - -#define DMI 0x1000 -#define DMIB 0x2000 -#define DMUX 0x4000 -#define DINP 0x8000 - -#define DSCCP 0x10000 -#define DMSC 0x20000 - -#define DMGCP 0x40000 - -#define DHO 0x80000 +/* Debug Areas of the code */ +enum { + DRLL, + DCC, + DMM, + DRR, + DRSL, + DNM, + DMNCC, + DSMS, + DPAG, + DMEAS, + DMI, + DMIB, + DMUX, + DINP, + DSCCP, + DMSC, + DMGCP, + DHO, + Debug_LastEntry, +}; #ifdef DEBUG #define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args) #define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args) #else -#define DEBUGP(xss, fmt, args...) +#define DEBUGP(xss, fmt, args...) #define DEBUGPC(ss, fmt, args...) #endif + #define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1]; char *hexdump(const unsigned char *buf, int len); void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6))); -void debug_parse_category_mask(const char* mask); -void debug_use_color(int use_color); -void debug_timestamp(int enable); -extern unsigned int debug_mask; /* new logging interface */ -#define LOGP(ss, level, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ##args) -#define LOGPC(ss, level, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ##args) +#define LOGP(ss, level, fmt, args...) debugp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args) +#define LOGPC(ss, level, fmt, args...) debugp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args) /* different levels */ #define LOGL_DEBUG 1 /* debugging information */ @@ -55,4 +54,74 @@ extern unsigned int debug_mask; #define LOGL_ERROR 7 /* error condition, requires user action */ #define LOGL_FATAL 8 /* fatal, program aborted */ +/* context */ +#define BSC_CTX_LCHAN 0 +#define BSC_CTX_SUBSCR 1 +#define BSC_CTX_BTS 2 +#define BSC_CTX_SCCP 3 + +/* target */ + +enum { + DEBUG_FILTER_IMSI = 1 << 0, + DEBUG_FILTER_ALL = 1 << 1, +}; + +struct debug_category { + int enabled; + int loglevel; +}; + +struct debug_target { + int filter_map; + char *imsi_filter; + + + struct debug_category categories[Debug_LastEntry]; + int use_color; + int print_timestamp; + int loglevel; + + union { + struct { + FILE *out; + } tgt_stdout; + + struct { + int priority; + } tgt_syslog; + + struct { + void *vty; + } tgt_vty; + }; + + void (*output) (struct debug_target *target, const char *string); + + struct llist_head entry; +}; + +/* use the above macros */ +void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 6, 7))); +void debug_init(void); + +/* context management */ +void debug_reset_context(void); +void debug_set_context(int ctx, void *value); + +/* filter on the targets */ +void debug_set_imsi_filter(struct debug_target *target, const char *imsi); +void debug_set_all_filter(struct debug_target *target, int); +void debug_set_use_color(struct debug_target *target, int); +void debug_set_print_timestamp(struct debug_target *target, int); +void debug_set_log_level(struct debug_target *target, int log_level); +void debug_parse_category_mask(struct debug_target *target, const char* mask); +void debug_set_category_filter(struct debug_target *target, int category, int enable, int level); + + +/* management of the targets */ +struct debug_target *debug_target_create(void); +struct debug_target *debug_target_create_stderr(void); +void debug_add_target(struct debug_target *target); +void debug_del_target(struct debug_target *target); #endif /* _DEBUG_H */ diff --git a/openbsc/include/openbsc/telnet_interface.h b/openbsc/include/openbsc/telnet_interface.h index d3381e0a4..f4e976f77 100644 --- a/openbsc/include/openbsc/telnet_interface.h +++ b/openbsc/include/openbsc/telnet_interface.h @@ -22,7 +22,7 @@ #define TELNET_INTERFACE_H #include "gsm_data.h" -#include "linuxlist.h" +#include "debug.h" #include "select.h" #include @@ -35,6 +35,7 @@ struct telnet_connection { struct gsm_network *network; struct bsc_fd fd; struct vty *vty; + struct debug_target *dbg; }; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 787a8038b..d669ba06d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -237,6 +237,8 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) } lchan = &ts->lchan[lch_idx]; + debug_set_context(BSC_CTX_LCHAN, lchan); + debug_set_context(BSC_CTX_SUBSCR, lchan->subscr); return lchan; } diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index 2a80a49ad..b2470a9fc 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -71,6 +71,8 @@ static const char *trx1_password = "1111111111"; static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 }; +static struct debug_target *stderr_target; + /* dummy function to keep gsm_data.c happy */ struct counter *counter_alloc(const char *name) { @@ -759,7 +761,7 @@ static void handle_options(int argc, char **argv) serial_port = optarg; break; case 'b': - debug_parse_category_mask(optarg); + debug_parse_category_mask(stderr_target, optarg); break; case 's': fname_software = optarg; @@ -812,6 +814,10 @@ int main(int argc, char **argv) struct gsm_network *gsmnet; int rc; + debug_init(); + stderr_target = debug_target_create_stderr(); + debug_add_target(stderr_target); + debug_set_all_filter(stderr_target, 1); handle_options(argc, argv); gsmnet = gsm_network_init(1, 1, NULL); diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index a9a5d372f..0d20d43d3 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -38,6 +38,7 @@ #include /* MCC and MNC for the Location Area Identifier */ +static struct debug_target *stderr_target; struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; @@ -105,10 +106,10 @@ static void handle_options(int argc, char** argv) print_help(); exit(0); case 's': - debug_use_color(0); + debug_set_use_color(stderr_target, 0); break; case 'd': - debug_parse_category_mask(optarg); + debug_parse_category_mask(stderr_target, optarg); break; case 'l': database_name = strdup(optarg); @@ -120,7 +121,7 @@ static void handle_options(int argc, char** argv) create_pcap_file(optarg); break; case 'T': - debug_timestamp(1); + debug_set_print_timestamp(stderr_target, 1); break; case 'P': ipacc_rtp_direct = 0; @@ -158,11 +159,17 @@ int main(int argc, char **argv) { int rc; + debug_init(); tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); talloc_ctx_init(); on_dso_load_token(); on_dso_load_rrlp(); on_dso_load_ho_dec(); + stderr_target = debug_target_create_stderr(); + debug_add_target(stderr_target); + + /* enable filters */ + debug_set_all_filter(stderr_target, 1); /* parse options */ handle_options(argc, argv); @@ -193,6 +200,7 @@ int main(int argc, char **argv) while (1) { bsc_upqueue(bsc_gsmnet); + debug_reset_context(); bsc_select_main(0); } } diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 6d5e6b154..fff6d6039 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -1084,8 +1084,15 @@ int main(int argc, char** argv) struct gsm_network dummy_network; struct sockaddr_in addr; int on = 1, i, rc; + struct debug_target *stderr_target; tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent"); + + debug_init(); + stderr_target = debug_target_create_stderr(); + debug_add_target(stderr_target); + debug_set_all_filter(stderr_target, 1); + handle_options(argc, argv); telnet_init(&dummy_network, 4243); diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 6e99d4144..d3d58f3fb 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -27,21 +27,53 @@ #include #include +#include +#include +#include -unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB|DMEAS); +/* default categories */ +static struct debug_category default_categories[Debug_LastEntry] = { + [DRLL] = { .enabled = 1, .loglevel = 0}, + [DCC] = { .enabled = 1, .loglevel = 0}, + [DMM] = { .enabled = 1, .loglevel = 0}, + [DRR] = { .enabled = 1, .loglevel = 0}, + [DRSL] = { .enabled = 1, .loglevel = 0}, + [DMM] = { .enabled = 1, .loglevel = 0}, + [DMNCC] = { .enabled = 1, .loglevel = 0}, + [DSMS] = { .enabled = 1, .loglevel = 0}, + [DPAG] = { .enabled = 1, .loglevel = 0}, + [DMEAS] = { .enabled = 0, .loglevel = 0}, + [DMI] = { .enabled = 0, .loglevel = 0}, + [DMIB] = { .enabled = 0, .loglevel = 0}, + [DMUX] = { .enabled = 1, .loglevel = 0}, + [DINP] = { .enabled = 1, .loglevel = 0}, + [DSCCP] = { .enabled = 1, .loglevel = 0}, + [DMSC] = { .enabled = 1, .loglevel = 0}, + [DMGCP] = { .enabled = 1, .loglevel = 0}, + [DHO] = { .enabled = 1, .loglevel = 0}, +}; struct debug_info { const char *name; const char *color; const char *description; int number; + int position; }; +struct debug_context { + struct gsm_lchan *lchan; + struct gsm_subscriber *subscr; + struct gsm_bts *bts; +}; + +static struct debug_context debug_context; +static void *tall_dbg_ctx = NULL; +static LLIST_HEAD(target_list); + #define DEBUG_CATEGORY(NUMBER, NAME, COLOR, DESCRIPTION) \ { .name = NAME, .color = COLOR, .description = DESCRIPTION, .number = NUMBER }, -#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) - static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DRLL, "DRLL", "\033[1;31m", "") DEBUG_CATEGORY(DCC, "DCC", "\033[1;32m", "") @@ -63,50 +95,51 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DHO, "DHO", "", "") }; -static int use_color = 1; - -void debug_use_color(int color) -{ - use_color = color; -} - -static int print_timestamp = 0; - -void debug_timestamp(int enable) -{ - print_timestamp = enable; -} - - /* * Parse the category mask. - * category1:category2:category3 + * The format can be this: category1:category2:category3 + * or category1,2:category2,3:... */ -void debug_parse_category_mask(const char *_mask) +void debug_parse_category_mask(struct debug_target* target, const char *_mask) { - unsigned int new_mask = 0; int i = 0; char *mask = strdup(_mask); char *category_token = NULL; + /* Disable everything to enable it afterwards */ + for (i = 0; i < ARRAY_SIZE(target->categories); ++i) + target->categories[i].enabled = 0; + category_token = strtok(mask, ":"); do { for (i = 0; i < ARRAY_SIZE(debug_info); ++i) { - if (strcasecmp(debug_info[i].name, category_token) == 0) - new_mask |= debug_info[i].number; + char* colon = strstr(category_token, ","); + int length = strlen(category_token); + + if (colon) + length = colon - category_token; + + if (strncasecmp(debug_info[i].name, category_token, length) == 0) { + int number = debug_info[i].number; + int level = 0; + + if (colon) + level = atoi(colon+1); + + target->categories[number].enabled = 1; + target->categories[number].loglevel = level; + } } } while ((category_token = strtok(NULL, ":"))); - free(mask); - debug_mask = new_mask; } -const char* color(int subsys) +static const char* color(int subsys) { int i = 0; - for (i = 0; use_color && i < ARRAY_SIZE(debug_info); ++i) { + for (i = 0; i < ARRAY_SIZE(debug_info); ++i) { if (debug_info[i].number == subsys) return debug_info[i].color; } @@ -114,35 +147,97 @@ const char* color(int subsys) return ""; } -void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) +static void _output(struct debug_target *target, unsigned int subsys, char *file, int line, + int cont, const char *format, va_list ap) { - va_list ap; - FILE *outfd = stderr; + char col[30]; + char sub[30]; + char tim[30]; + char buf[4096]; + char final[4096]; - if (!(debug_mask & subsys)) - return; + /* prepare the data */ + col[0] = '\0'; + sub[0] = '\0'; + tim[0] = '\0'; + buf[0] = '\0'; - va_start(ap, format); - - fprintf(outfd, "%s", color(subsys)); + /* are we using color */ + if (target->use_color) + snprintf(col, sizeof(col), "%s", color(subsys)); + vsnprintf(buf, sizeof(buf), format, ap); if (!cont) { - if (print_timestamp) { + if (target->print_timestamp) { char *timestr; time_t tm; tm = time(NULL); timestr = ctime(&tm); timestr[strlen(timestr)-1] = '\0'; - fprintf(outfd, "%s ", timestr); + snprintf(tim, sizeof(tim), "%s ", timestr); } - fprintf(outfd, "<%4.4x> %s:%d ", subsys, file, line); + snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line); } - vfprintf(outfd, format, ap); - fprintf(outfd, "\033[0;m"); + snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf); + target->output(target, final); +} + + +static void _debugp(unsigned int subsys, int level, char *file, int line, + int cont, const char *format, va_list ap) +{ + struct debug_target *tar; + + llist_for_each_entry(tar, &target_list, entry) { + struct debug_category *category; + int output = 0; + + category = &tar->categories[subsys]; + /* subsystem is not supposed to be debugged */ + if (!category->enabled) + continue; + + /* Check the global log level */ + if (tar->loglevel != 0 && level < tar->loglevel) + continue; + + /* Check the category log level */ + if (category->loglevel != 0 && level < category->loglevel) + continue; + + /* + * Apply filters here... if that becomes messy we will need to put + * filters in a list and each filter will say stop, continue, output + */ + if ((tar->filter_map & DEBUG_FILTER_ALL) != 0) { + output = 1; + } else if ((tar->filter_map & DEBUG_FILTER_IMSI) != 0 + && debug_context.subscr && strcmp(debug_context.subscr->imsi, tar->imsi_filter) == 0) { + output = 1; + } + + if (output) + _output(tar, subsys, file, line, cont, format, ap); + } +} + +void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + _debugp(subsys, LOGL_DEBUG, file, line, cont, format, ap); va_end(ap); +} - fflush(outfd); +void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + _debugp(subsys, level, file, line, cont, format, ap); + va_end(ap); } static char hexd_buff[4096]; @@ -164,3 +259,122 @@ char *hexdump(const unsigned char *buf, int len) return hexd_buff; } + + +void debug_add_target(struct debug_target *target) +{ + llist_add_tail(&target->entry, &target_list); +} + +void debug_del_target(struct debug_target *target) +{ + llist_del(&target->entry); +} + +void debug_reset_context(void) +{ + memset(&debug_context, 0, sizeof(debug_context)); +} + +/* currently we are not reffing these */ +void debug_set_context(int ctx, void *value) +{ + switch (ctx) { + case BSC_CTX_LCHAN: + debug_context.lchan = (struct gsm_lchan *) value; + break; + case BSC_CTX_SUBSCR: + debug_context.subscr = (struct gsm_subscriber *) value; + break; + case BSC_CTX_BTS: + debug_context.bts = (struct gsm_bts *) value; + break; + case BSC_CTX_SCCP: + break; + default: + break; + } +} + +void debug_set_imsi_filter(struct debug_target *target, const char *imsi) +{ + if (imsi) { + target->filter_map |= DEBUG_FILTER_IMSI; + target->imsi_filter = talloc_strdup(target, imsi); + } else if (target->imsi_filter) { + target->filter_map &= ~DEBUG_FILTER_IMSI; + talloc_free(target->imsi_filter); + target->imsi_filter = NULL; + } +} + +void debug_set_all_filter(struct debug_target *target, int all) +{ + if (all) + target->filter_map |= DEBUG_FILTER_ALL; + else + target->filter_map &= ~DEBUG_FILTER_ALL; +} + +void debug_set_use_color(struct debug_target *target, int use_color) +{ + target->use_color = use_color; +} + +void debug_set_print_timestamp(struct debug_target *target, int print_timestamp) +{ + target->print_timestamp = print_timestamp; +} + +void debug_set_log_level(struct debug_target *target, int log_level) +{ + target->loglevel = log_level; +} + +void debug_set_category_filter(struct debug_target *target, int category, int enable, int level) +{ + if (category >= Debug_LastEntry) + return; + target->categories[category].enabled = !!enable; + target->categories[category].loglevel = level; +} + +static void _stderr_output(struct debug_target *target, const char *log) +{ + fprintf(target->tgt_stdout.out, "%s", log); + fflush(target->tgt_stdout.out); +} + +struct debug_target *debug_target_create(void) +{ + struct debug_target *target; + + target = talloc_zero(tall_dbg_ctx, struct debug_target); + if (!target) + return NULL; + + INIT_LLIST_HEAD(&target->entry); + memcpy(target->categories, default_categories, sizeof(default_categories)); + target->use_color = 1; + target->print_timestamp = 0; + target->loglevel = 0; + return target; +} + +struct debug_target *debug_target_create_stderr(void) +{ + struct debug_target *target; + + target = debug_target_create(); + if (!target) + return NULL; + + target->tgt_stdout.out = stderr; + target->output = _stderr_output; + return target; +} + +void debug_init(void) +{ + tall_dbg_ctx = talloc_named_const(NULL, 1, "debug"); +} diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index 083d8f8de..0a0cc8d7e 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -435,6 +435,8 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, "tei %d, sapi %d\n", tei, sapi); return -EINVAL; } + + debug_set_context(BSC_CTX_BTS, link->trx->bts); switch (link->type) { case E1INP_SIGN_OML: msg->trx = link->trx; diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index c50a46581..005c93dd5 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -289,6 +289,12 @@ int main(int argc, char **argv) struct gsm_bts *bts; struct sockaddr_in sin; int rc, option_index = 0, stream_id = 0xff; + struct debug_target *stderr_target; + + debug_init(); + stderr_target = debug_target_create_stderr(); + debug_add_target(stderr_target); + debug_set_all_filter(stderr_target, 1); printf("ipaccess-config (C) 2009 by Harald Welte\n"); printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index bc91ca333..ebddaf57a 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -120,6 +120,12 @@ int telnet_close_client(struct bsc_fd *fd) { close(fd->fd); bsc_unregister_fd(fd); + + if (conn->dbg) { + debug_del_target(conn->dbg); + talloc_free(conn->dbg); + } + llist_del(&conn->entry); talloc_free(conn); return 0; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 62eee7a80..9645af23a 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -37,6 +37,7 @@ #include #include #include +#include static struct gsm_network *gsmnet; @@ -845,6 +846,170 @@ DEFUN(show_paging, return CMD_SUCCESS; } +static void _vty_output(struct debug_target *tgt, const char *line) +{ + struct vty *vty = tgt->tgt_vty.vty; + vty_out(vty, "%s", line); + /* This is an ugly hack, but there is no easy way... */ + if (strchr(line, '\n')) + vty_out(vty, "\r"); +} + +struct debug_target *debug_target_create_vty(struct vty *vty) +{ + struct debug_target *target; + + target = debug_target_create(); + if (!target) + return NULL; + + target->tgt_vty.vty = vty; + target->output = _vty_output; + return target; +} + +DEFUN(enable_logging, + enable_logging_cmd, + "logging enable", + "Enables logging to this vty\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (conn->dbg) { + vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + conn->dbg = debug_target_create_vty(vty); + if (!conn->dbg) + return CMD_WARNING; + + debug_add_target(conn->dbg); + return CMD_SUCCESS; +} + +DEFUN(logging_fltr_imsi, + logging_fltr_imsi_cmd, + "logging filter imsi IMSI", + "Print all messages related to a IMSI\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + debug_set_imsi_filter(conn->dbg, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(logging_fltr_all, + logging_fltr_all_cmd, + "logging filter all <0-1>", + "Print all messages to the console\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + debug_set_all_filter(conn->dbg, atoi(argv[0])); + return CMD_SUCCESS; +} + +DEFUN(logging_use_clr, + logging_use_clr_cmd, + "logging use color <0-1>", + "Use color for printing messages\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + debug_set_use_color(conn->dbg, atoi(argv[0])); + return CMD_SUCCESS; +} + +DEFUN(logging_prnt_timestamp, + logging_prnt_timestamp_cmd, + "logging print timestamp <0-1>", + "Print the timestamp of each message\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + debug_set_print_timestamp(conn->dbg, atoi(argv[0])); + return CMD_SUCCESS; +} + +DEFUN(logging_set_category_mask, + logging_set_category_mask_cmd, + "logging set debug mask MASK", + "Decide which categories to output.\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + debug_parse_category_mask(conn->dbg, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(logging_set_log_level, + logging_set_log_level_cmd, + "logging set log level <0-8>", + "Set the global log level. The value 0 implies no filtering.\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + debug_set_log_level(conn->dbg, atoi(argv[0])); + return CMD_SUCCESS; +} + +DEFUN(diable_logging, + disable_logging_cmd, + "logging disable", + "Disables logging to this vty\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + debug_del_target(conn->dbg); + talloc_free(conn->dbg); + conn->dbg = NULL; + return CMD_SUCCESS; +} + DEFUN(show_stats, show_stats_cmd, "show statistics", @@ -1581,6 +1746,14 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &show_paging_cmd); install_element(VIEW_NODE, &show_stats_cmd); + install_element(VIEW_NODE, &enable_logging_cmd); + install_element(VIEW_NODE, &disable_logging_cmd); + install_element(VIEW_NODE, &logging_fltr_imsi_cmd); + install_element(VIEW_NODE, &logging_fltr_all_cmd); + install_element(VIEW_NODE, &logging_use_clr_cmd); + install_element(VIEW_NODE, &logging_prnt_timestamp_cmd); + install_element(VIEW_NODE, &logging_set_category_mask_cmd); + install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net); install_default(GSMNET_NODE); diff --git a/openbsc/tests/debug/Makefile.am b/openbsc/tests/debug/Makefile.am index 0cdf46ad5..62c906e72 100644 --- a/openbsc/tests/debug/Makefile.am +++ b/openbsc/tests/debug/Makefile.am @@ -1,4 +1,4 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include noinst_PROGRAMS = debug_test -debug_test_SOURCES = debug_test.c $(top_srcdir)/src/debug.c +debug_test_SOURCES = debug_test.c $(top_srcdir)/src/debug.c $(top_srcdir)/src/talloc.c From f9b1f30558c7c9aca1225a98c64a8f9c345cf7f9 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 05:08:12 +0100 Subject: [PATCH 157/365] [debug] Make the test case compile and it is still passing --- openbsc/tests/debug/debug_test.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/openbsc/tests/debug/debug_test.c b/openbsc/tests/debug/debug_test.c index 77ac01532..0f0c284ab 100644 --- a/openbsc/tests/debug/debug_test.c +++ b/openbsc/tests/debug/debug_test.c @@ -1,6 +1,6 @@ /* simple test for the debug interface */ /* - * (C) 2008 by Holger Hans Peter Freyther + * (C) 2008, 2009 by Holger Hans Peter Freyther * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -24,11 +24,18 @@ int main(int argc, char** argv) { - debug_parse_category_mask("DRLL"); - DEBUGP(DCC, "You should not see this\n"); + struct debug_target *stderr_target; - debug_parse_category_mask("DRLL:DCC"); - DEBUGP(DRLL, "You should see this\n"); - DEBUGP(DCC, "You should see this\n"); - DEBUGP(DMM, "You should not see this\n"); + debug_init(); + stderr_target = debug_target_create_stderr(); + debug_add_target(stderr_target); + debug_set_all_filter(stderr_target, 1); + + debug_parse_category_mask(stderr_target, "DRLL"); + DEBUGP(DCC, "You should not see this\n"); + + debug_parse_category_mask(stderr_target, "DRLL:DCC"); + DEBUGP(DRLL, "You should see this\n"); + DEBUGP(DCC, "You should see this\n"); + DEBUGP(DMM, "You should not see this\n"); } From 3b05a7affab6846a7327a68b6e79f66ee7f8c3cd Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 05:13:29 +0100 Subject: [PATCH 158/365] [channel] Compile statistics.c into the test. --- openbsc/tests/channel/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am index 50fadc582..564cbafe2 100644 --- a/openbsc/tests/channel/Makefile.am +++ b/openbsc/tests/channel/Makefile.am @@ -12,6 +12,7 @@ channel_test_SOURCES = channel_test.c \ $(top_srcdir)/src/select.c \ $(top_srcdir)/src/talloc.c \ $(top_srcdir)/src/gsm_data.c \ - $(top_srcdir)/src/signal.c + $(top_srcdir)/src/signal.c \ + $(top_srcdir)/src/statistics.c channel_test_LDADD = -ldl -ldbi From 5dbd71e31d08e883db6549b6dcca6560e786c764 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 05:13:48 +0100 Subject: [PATCH 159/365] [sccp] Provide dummy db_store_counter... --- openbsc/tests/sccp/sccp_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/tests/sccp/sccp_test.c b/openbsc/tests/sccp/sccp_test.c index bd28ed179..37615e0e2 100644 --- a/openbsc/tests/sccp/sccp_test.c +++ b/openbsc/tests/sccp/sccp_test.c @@ -722,3 +722,5 @@ int main(int argc, char **argv) test_sccp_system_crash(); return 0; } + +void db_store_counter() {} From 6fced2fd0a0065249265b6f4a53acd925c2e0f09 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 05:16:13 +0100 Subject: [PATCH 160/365] [statistics] Make counter_db_store internal Do not expose DB functionality on this level --- openbsc/include/openbsc/statistics.h | 1 - openbsc/src/statistics.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/statistics.h b/openbsc/include/openbsc/statistics.h index 9291a8c25..9d761c62b 100644 --- a/openbsc/include/openbsc/statistics.h +++ b/openbsc/include/openbsc/statistics.h @@ -25,6 +25,5 @@ static inline void counter_reset(struct counter *ctr) struct counter *counter_alloc(const char *name); void counter_free(struct counter *ctr); -int counters_store_db(void); #endif /* _STATISTICS_H */ diff --git a/openbsc/src/statistics.c b/openbsc/src/statistics.c index 3429d6ec6..4cc281d5a 100644 --- a/openbsc/src/statistics.c +++ b/openbsc/src/statistics.c @@ -56,7 +56,7 @@ void counter_free(struct counter *ctr) talloc_free(ctr); } -int counters_store_db(void) +static int counters_store_db(void) { struct counter *ctr; int rc = 0; From 079353ad1f894853b80cda4db8ee0ce08d682b28 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 05:29:04 +0100 Subject: [PATCH 161/365] [statistics] Do the syncing to db from within the bsc_hack Change the counters_store_db function to be a generic for_each function taking a function pointer and data. Use that in bsc_hack to store it to the DB. This is removing the DB requirement and will allow to handle the counter values in different ways without making the counter list public. I verified that the syncing is still taking place. --- openbsc/include/openbsc/statistics.h | 2 ++ openbsc/src/bsc_hack.c | 23 +++++++++++++++++++++++ openbsc/src/statistics.c | 21 ++------------------- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/openbsc/include/openbsc/statistics.h b/openbsc/include/openbsc/statistics.h index 9d761c62b..1d56054ab 100644 --- a/openbsc/include/openbsc/statistics.h +++ b/openbsc/include/openbsc/statistics.h @@ -26,4 +26,6 @@ static inline void counter_reset(struct counter *ctr) struct counter *counter_alloc(const char *name); void counter_free(struct counter *ctr); +int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data); + #endif /* _STATISTICS_H */ diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 0d20d43d3..8792cc36c 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -43,6 +43,11 @@ struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; + +/* timer to store statistics */ +#define DB_SYNC_INTERVAL 60, 0 +static struct timer_list db_sync_timer; + extern int bsc_bootstrap_network(int (*mmc_rev)(struct gsm_network *, int, void *), const char *cfg_file); extern int bsc_shutdown_net(struct gsm_network *net); @@ -155,6 +160,19 @@ static void signal_handler(int signal) } } +/* timer handling */ +static int _db_store_counter(struct counter *counter, void *data) +{ + return db_store_counter(counter); +} + +static void db_sync_timer_cb(void *data) +{ + /* store counters to database and re-schedule */ + counters_for_each(_db_store_counter, NULL); + bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); +} + int main(int argc, char **argv) { int rc; @@ -189,6 +207,11 @@ int main(int argc, char **argv) } printf("DB: Database prepared.\n"); + /* setup the timer */ + db_sync_timer.cb = db_sync_timer_cb; + db_sync_timer.data = NULL; + bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); + rc = bsc_bootstrap_network(mncc_recv, config_file); if (rc < 0) exit(1); diff --git a/openbsc/src/statistics.c b/openbsc/src/statistics.c index 4cc281d5a..9bd44f3d4 100644 --- a/openbsc/src/statistics.c +++ b/openbsc/src/statistics.c @@ -33,10 +33,6 @@ static LLIST_HEAD(counters); -static struct timer_list db_sync_timer; - -#define DB_SYNC_INTERVAL 60, 0 - struct counter *counter_alloc(const char *name) { struct counter *ctr = talloc_zero(tall_bsc_ctx, struct counter); @@ -56,13 +52,13 @@ void counter_free(struct counter *ctr) talloc_free(ctr); } -static int counters_store_db(void) +int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data) { struct counter *ctr; int rc = 0; llist_for_each_entry(ctr, &counters, list) { - rc = db_store_counter(ctr); + rc = handle_counter(ctr, data); if (rc < 0) return rc; } @@ -70,16 +66,3 @@ static int counters_store_db(void) return rc; } -static void db_sync_timer_cb(void *data) -{ - /* store counters to database and re-schedule */ - counters_store_db(); - bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); -} - -static __attribute__((constructor)) void on_dso_load_stat(void) -{ - db_sync_timer.cb = db_sync_timer_cb; - db_sync_timer.data = NULL; - bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); -} From 004e055cfd9cd49fe4fb2b71aa16d08fecf189c8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 05:31:36 +0100 Subject: [PATCH 162/365] [ipacess-config] Remove one of my bogus debugging statements --- openbsc/src/ipaccess-config.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index 005c93dd5..7df4cefeb 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -342,7 +342,6 @@ int main(int argc, char **argv) break; case 's': stream_id = atoi(optarg); - printf("foo: %d\n", stream_id); break; case 'h': print_usage(); From e7ff91342e02cd1cd5af9dfbf7c822f55b228b4b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 07:26:57 +0100 Subject: [PATCH 163/365] [sw_load] For the nanoBTS just open the firmware * The two version strings are not in an easy to parse header and from my trace it appears like the whole file is sent to the BTS. So just open the firmware file.. --- openbsc/src/abis_nm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index bb7248be7..64b87b570 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1372,6 +1372,17 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname) /* rewind to start of file */ rewind(sw->stream); break; + case GSM_BTS_TYPE_NANOBTS: + sw->stream = fdopen(sw->fd, "r"); + if (!sw->stream) { + perror("fdopen"); + return -1; + } + + /* TODO: extract that from the filename or content */ + sw->file_id_len = 0; + sw->file_version_len = 0; + break; default: /* We don't know how to treat them yet */ close(sw->fd); From 66e8219f962d22d96d1c1645280649d507ca2ae4 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 08:06:31 +0100 Subject: [PATCH 164/365] [sw_load] It turns out there is a header that needs to be read The magic " SDP" is occuring twice in the file. The first time seems to be the file header and the second time it is with the payload. We will need to parse this somehow... --- openbsc/src/abis_nm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 64b87b570..98683d380 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1341,6 +1341,11 @@ static int sw_activate(struct abis_nm_sw *sw) return abis_nm_sendmsg(sw->bts, msg); } +static int parse_sdp_header(struct abis_nm_sw *sw) +{ + return -1; +} + static int sw_open_file(struct abis_nm_sw *sw, const char *fname) { char file_id[12+1]; @@ -1380,8 +1385,11 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname) } /* TODO: extract that from the filename or content */ - sw->file_id_len = 0; - sw->file_version_len = 0; + rc = parse_sdp_header(sw); + if (rc < 0) { + fprintf(stderr, "Could not parse the ipaccess SDP header\n"); + return -1; + } break; default: /* We don't know how to treat them yet */ From 65d67dc222c8508c0e98ef37b2ef17aea1eee73f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 12:52:30 +0100 Subject: [PATCH 165/365] [ipaccess] Start adding a tool that analyzes the ipaccess header So far I have not much idea about the format. It is starting with the magic byte and the header is spanning until the next occurence of the " SDP" marker. --- openbsc/src/Makefile.am | 4 +- .../src/ipaccess-firmware/ipaccess-firmware.c | 67 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/ipaccess-firmware/ipaccess-firmware.c diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index de413d5ed..3f98bdad9 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp + isdnsync bsc_mgcp ipaccess_firmware noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h @@ -38,3 +38,5 @@ isdnsync_SOURCES = isdnsync.c bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a + +ipaccess_firmware_SOURCES = ipaccess-firmware/ipaccess-firmware.c diff --git a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c new file mode 100644 index 000000000..0f9362941 --- /dev/null +++ b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c @@ -0,0 +1,67 @@ +/* Routines for parsing an ipacces SDP firmware file */ + +/* (C) 2009 by Holger Hans Peter Freyther + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + + +static void analyze_file(int fd) +{ + char buf[4096]; + int rc; + + rc = read(fd, buf, 4); + if (rc <= 0) { + fprintf(stderr, "Not enough space for the header.\n"); + return; + } + + if (strcmp(buf, " SDP") != 0) { + fprintf(stderr, "Wrong magic number at the beginning of the file.\n"); + return; + } + + printf("Printing header information:\n"); +} + +int main(int argc, char** argv) +{ + int i, fd; + + for (i = 1; i < argc; ++i) { + printf("Opening possible firmware '%s'\n", argv[i]); + fd = open(argv[i], O_RDONLY); + if (!fd) { + perror("nada"); + continue; + } + + analyze_file(fd); + } + + return EXIT_SUCCESS; +} From e0d2ff4c2e60549ebb82488d1e8457b26810d8bd Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 13:03:12 +0100 Subject: [PATCH 166/365] [ipaccess] The second four bytes appear to be always the same --- openbsc/src/ipaccess-firmware/ipaccess-firmware.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c index 0f9362941..413f84511 100644 --- a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c +++ b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c @@ -28,6 +28,9 @@ #include +/* more magic, the second "int" in the header */ +static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; + static void analyze_file(int fd) { @@ -45,6 +48,17 @@ static void analyze_file(int fd) return; } + rc = read(fd, buf, 4); + if (rc <= 0) { + fprintf(stderr, "Not enough space for the more_magic.\n"); + return; + } + + if (strncmp(buf, more_magic, 4) != 0) { + fprintf(stderr, "The more magic is not right.\n"); + return; + } + printf("Printing header information:\n"); } From bf2bdc6e840035ccd7481b2b362c583fb498d5fe Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 23 Dec 2009 13:09:27 +0100 Subject: [PATCH 167/365] [ipaccess] The next byte appears to be size... Using okteta to display the size in bigendian and then selecting from the start to the " SDP" I get the same number... --- openbsc/src/ipaccess-firmware/ipaccess-firmware.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c index 413f84511..e2e5008c0 100644 --- a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c +++ b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c @@ -19,6 +19,7 @@ * */ +#include #include #include #include @@ -36,6 +37,7 @@ static void analyze_file(int fd) { char buf[4096]; int rc; + unsigned int absolute_size; rc = read(fd, buf, 4); if (rc <= 0) { @@ -59,7 +61,17 @@ static void analyze_file(int fd) return; } + rc = read(fd, buf, 4); + if (rc <= 0) { + fprintf(stderr, "Trying to read the header length failed.\n"); + return; + } + + memcpy(&absolute_size, &buf[0], 4); + absolute_size = ntohl(absolute_size); + printf("Printing header information:\n"); + printf("The header is %u bytes long\n", absolute_size); } int main(int argc, char** argv) From b7bcb79bea2b8b6afaf91ed253bcacffaedc3719 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 23 Dec 2009 18:24:31 +0100 Subject: [PATCH 168/365] Fix segfault in case BTS has more TRX than we have configured --- openbsc/src/bsc_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 1a70230fc..58cdafe7b 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -408,6 +408,8 @@ static int sw_activ_rep(struct msgb *mb) struct gsm_bts *bts = mb->trx->bts; struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr); + if (!trx) + return -EINVAL; switch (foh->obj_class) { case NM_OC_BASEB_TRANSC: From 2ca7c3142989606590b45f661224a5b175f85dd4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 23 Dec 2009 22:44:04 +0100 Subject: [PATCH 169/365] Add ipaccess-proxy, a proxy for ip.access A-bis over IP This proxy allows us to restart OpenBSC while the BTS's are kept running with their CCCH/BCCH alive. This is very useful to make sure the phones don't roam to other networks while restarting OpenBSC. The proxy also intrduces UDP sockets for injecting UDP packets into the A-bis data stream. --- openbsc/src/Makefile.am | 4 +- openbsc/src/ipaccess-proxy.c | 1126 ++++++++++++++++++++++++++++++++++ 2 files changed, 1129 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/ipaccess-proxy.c diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 3f98bdad9..54a8cde2d 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess_firmware + isdnsync bsc_mgcp ipaccess_firmware ipaccess-proxy noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h @@ -40,3 +40,5 @@ bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_in bsc_mgcp_LDADD = libvty.a ipaccess_firmware_SOURCES = ipaccess-firmware/ipaccess-firmware.c + +ipaccess_proxy_SOURCES = ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/ipaccess-proxy.c b/openbsc/src/ipaccess-proxy.c new file mode 100644 index 000000000..00b634052 --- /dev/null +++ b/openbsc/src/ipaccess-proxy.c @@ -0,0 +1,1126 @@ +/* OpenBSC Abis/IP proxy ip.access nanoBTS */ + +/* (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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static struct debug_target *stderr_target; + +/* one instance of an ip.access protocol proxy */ +struct ipa_proxy { + /* socket where we listen for incoming OML from BTS */ + struct bsc_fd oml_listen_fd; + /* socket where we listen for incoming RSL from BTS */ + struct bsc_fd rsl_listen_fd; + /* list of BTS's (struct ipa_bts_conn */ + struct llist_head bts_list; + /* the BSC reconnect timer */ + struct timer_list reconn_timer; +}; + +/* global pointer to the proxy structure */ +static struct ipa_proxy *ipp; + +struct ipa_proxy_conn { + struct bsc_fd fd; + struct llist_head tx_queue; + struct ipa_bts_conn *bts_conn; +}; + +#define MAX_TRX 4 + +/* represents a particular BTS in our proxy */ +struct ipa_bts_conn { + /* list of BTS's (ipa_proxy->bts_list) */ + struct llist_head list; + /* back pointer to the proxy which we belong to */ + struct ipa_proxy *ipp; + /* the unit ID as determined by CCM */ + struct { + u_int16_t site_id; + u_int16_t bts_id; + } unit_id; + + /* incoming connections from BTS */ + struct ipa_proxy_conn *oml_conn; + struct ipa_proxy_conn *rsl_conn[MAX_TRX]; + + /* outgoing connections to BSC */ + struct ipa_proxy_conn *bsc_oml_conn; + struct ipa_proxy_conn *bsc_rsl_conn[MAX_TRX]; + + /* UDP sockets for BTS and BSC injection */ + struct bsc_fd udp_bts_fd; + struct bsc_fd udp_bsc_fd; + + char *id_tags[0xff]; + u_int8_t *id_resp; + unsigned int id_resp_len; +}; + +enum ipp_fd_type { + OML_FROM_BTS = 1, + RSL_FROM_BTS = 2, + OML_TO_BSC = 3, + RSL_TO_BSC = 4, + UDP_TO_BTS = 5, + UDP_TO_BSC = 6, +}; + +/* some of the code against we link from OpenBSC needs this */ +void *tall_bsc_ctx; + +static char *listen_ipaddr; +static char *bsc_ipaddr; + +#define PROXY_ALLOC_SIZE 300 + +static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG }; +static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK }; +static const u_int8_t id_req[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET, + 0x01, IPAC_IDTAG_UNIT, + 0x01, IPAC_IDTAG_MACADDR, + 0x01, IPAC_IDTAG_LOCATION1, + 0x01, IPAC_IDTAG_LOCATION2, + 0x01, IPAC_IDTAG_EQUIPVERS, + 0x01, IPAC_IDTAG_SWVERSION, + 0x01, IPAC_IDTAG_UNITNAME, + 0x01, IPAC_IDTAG_SERNR, + }; + +static const char *idtag_names[] = { + [IPAC_IDTAG_SERNR] = "Serial_Number", + [IPAC_IDTAG_UNITNAME] = "Unit_Name", + [IPAC_IDTAG_LOCATION1] = "Location_1", + [IPAC_IDTAG_LOCATION2] = "Location_2", + [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version", + [IPAC_IDTAG_SWVERSION] = "Software_Version", + [IPAC_IDTAG_IPADDR] = "IP_Address", + [IPAC_IDTAG_MACADDR] = "MAC_Address", + [IPAC_IDTAG_UNIT] = "Unit_ID", +}; + +static const char *ipac_idtag_name(int tag) +{ + if (tag >= ARRAY_SIZE(idtag_names)) + return "unknown"; + + return idtag_names[tag]; +} + +static int ipac_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len) +{ + u_int8_t t_len; + u_int8_t t_tag; + u_int8_t *cur = buf; + + while (cur < buf + len) { + t_len = *cur++; + t_tag = *cur++; + + DEBUGPC(DMI, "%s='%s' ", ipac_idtag_name(t_tag), cur); + + dec->lv[t_tag].len = t_len; + dec->lv[t_tag].val = cur; + + cur += t_len; + } + return 0; +} + +static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id, + u_int16_t *trx_id) +{ + unsigned long ul; + char *endptr; + const char *nptr; + + nptr = str; + ul = strtoul(nptr, &endptr, 10); + if (endptr <= nptr) + return -EINVAL; + if (site_id) + *site_id = ul & 0xffff; + + if (*endptr++ != '/') + return -EINVAL; + + nptr = endptr; + ul = strtoul(nptr, &endptr, 10); + if (endptr <= nptr) + return -EINVAL; + if (bts_id) + *bts_id = ul & 0xffff; + + if (*endptr++ != '/') + return -EINVAL; + + nptr = endptr; + ul = strtoul(nptr, &endptr, 10); + if (endptr <= nptr) + return -EINVAL; + if (trx_id) + *trx_id = ul & 0xffff; + + return 0; +} + +static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp, + u_int16_t site_id, + u_int16_t bts_id) +{ + struct ipa_bts_conn *ipbc; + + llist_for_each_entry(ipbc, &ipp->bts_list, list) { + if (ipbc->unit_id.site_id == site_id && + ipbc->unit_id.bts_id == bts_id) + return ipbc; + } + + return NULL; +} + +struct ipa_proxy_conn *alloc_conn(void) +{ + struct ipa_proxy_conn *ipc; + + ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn); + if (!ipc) + return NULL; + + INIT_LLIST_HEAD(&ipc->tx_queue); + + return ipc; +} + +static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp) +{ + unsigned int i, len; + + for (i = 0; i <= 0xff; i++) { + if (!TLVP_PRESENT(tlvp, i)) + continue; + + len = TLVP_LEN(tlvp, i); +#if 0 + if (!ipbc->id_tags[i]) + ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len); + else +#endif + ipbc->id_tags[i] = talloc_realloc_size(tall_bsc_ctx, + ipbc->id_tags[i], len); + if (!ipbc->id_tags[i]) + return -ENOMEM; + + memset(ipbc->id_tags[i], 0, len); + //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len); + } + return 0; +} + + +static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data); + +#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id) + +static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line, + struct ipa_bts_conn *ipbc, u_int8_t trx_id) +{ + if (ipbc) + debugp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id, + ipbc->unit_id.bts_id, trx_id); + else + debugp2(ss, lvl, file, line, 0, "unknown "); +} + +/* UDP socket handling */ + +static int make_sock(struct bsc_fd *bfd, u_int16_t port, int proto, int priv_nr, + int (*cb)(struct bsc_fd *fd, unsigned int what), + void *data) +{ + struct sockaddr_in addr; + int ret, on = 1; + + bfd->fd = socket(AF_INET, SOCK_DGRAM, proto); + bfd->cb = cb; + bfd->when = BSC_FD_READ; + bfd->data = data; + bfd->priv_nr = priv_nr; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "could not bind socket: %s\n", + strerror(errno)); + return -EIO; + } + + ret = bsc_register_fd(bfd); + if (ret < 0) { + perror("register UDP fd"); + return ret; + } + return 0; +} + +static int handle_udp_read(struct bsc_fd *bfd) +{ + struct ipa_bts_conn *ipbc = bfd->data; + struct ipa_proxy_conn *other_conn = NULL; + struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP"); + struct ipaccess_head *hh; + int ret; + + /* with UDP sockets, we cannot read partial packets but have to read + * all of it in one go */ + hh = (struct ipaccess_head *) msg->data; + ret = recv(bfd->fd, msg->data, msg->data_len, 0); + if (ret < 0) { + DEBUGP(DINP, "recv error %s\n", strerror(errno)); + msgb_free(msg); + return ret; + } + if (ret == 0) { + DEBUGP(DINP, "UDP peer disappeared, dead socket\n"); + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + msgb_free(msg); + return -EIO; + } + if (ret < sizeof(*hh)) { + DEBUGP(DINP, "could not even read header!?!\n"); + msgb_free(msg); + return -EIO; + } + msgb_put(msg, ret); + msg->l2h = msg->data + sizeof(*hh); + DEBUGP(DMI, "UDP RX: %s\n", hexdump(msg->data, msg->len)); + + if (hh->len != msg->len - sizeof(*hh)) { + DEBUGP(DINP, "length (%u/%u) disagrees with header(%u)\n", + msg->len, msg->len - 3, hh->len); + msgb_free(msg); + return -EIO; + } + + switch (bfd->priv_nr & 0xff) { + case UDP_TO_BTS: + /* injection towards BTS */ + switch (hh->proto) { + case IPAC_PROTO_RSL: + /* FIXME: what to do about TRX > 0 */ + other_conn = ipbc->rsl_conn[0]; + break; + default: + DEBUGP(DINP, "Unknown protocol 0x%02x, sending to " + "OML FD\n", hh->proto); + /* fall through */ + case IPAC_PROTO_IPACCESS: + case IPAC_PROTO_OML: + other_conn = ipbc->oml_conn; + break; + } + break; + case UDP_TO_BSC: + /* injection towards BSC */ + switch (hh->proto) { + case IPAC_PROTO_RSL: + /* FIXME: what to do about TRX > 0 */ + other_conn = ipbc->bsc_rsl_conn[0]; + break; + default: + DEBUGP(DINP, "Unknown protocol 0x%02x, sending to " + "OML FD\n", hh->proto); + case IPAC_PROTO_IPACCESS: + case IPAC_PROTO_OML: + other_conn = ipbc->bsc_oml_conn; + break; + } + break; + default: + DEBUGP(DINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr); + break; + } + + if (other_conn) { + /* enqueue the message for TX on the respective FD */ + msgb_enqueue(&other_conn->tx_queue, msg); + other_conn->fd.when |= BSC_FD_WRITE; + } else + msgb_free(msg); + + return 0; +} + +static int handle_udp_write(struct bsc_fd *bfd) +{ + /* not implemented yet */ + bfd->when &= ~BSC_FD_WRITE; + + return -EIO; +} + +/* callback from select.c in case one of the fd's can be read/written */ +static int udp_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) + rc = handle_udp_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_udp_write(bfd); + + return rc; +} + + +static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd, + u_int16_t site_id, u_int16_t bts_id, + u_int16_t trx_id, struct tlv_parsed *tlvp, + struct msgb *msg) +{ + struct ipa_bts_conn *ipbc; + u_int16_t udp_port; + int ret = 0; + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + inet_aton(bsc_ipaddr, &sin.sin_addr); + + DEBUGP(DINP, "(%u/%u/%u) New BTS connection: ", + site_id, bts_id, trx_id); + + /* OML needs to be established before RSL */ + if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) { + DEBUGPC(DINP, "Not a OML connection ?!?\n"); + return -EIO; + } + + /* allocate new BTS connection data structure */ + ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn); + if (!ipbc) { + ret = -ENOMEM; + goto err_out; + } + + DEBUGPC(DINP, "Created BTS Conn data structure\n"); + ipbc->ipp = ipp; + ipbc->unit_id.site_id = site_id; + ipbc->unit_id.bts_id = bts_id; + ipbc->oml_conn = ipc; + ipc->bts_conn = ipbc; + + /* store the content of the ID TAGS for later reference */ + store_idtags(ipbc, tlvp); + ipbc->id_resp_len = msg->len; + ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len); + memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len); + + /* Create OML TCP connection towards BSC */ + sin.sin_port = htons(3002); + ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc); + if (!ipbc->bsc_oml_conn) { + ret = -EIO; + goto err_bsc_conn; + } + + DEBUGP(DINP, "(%u/%u/%u) OML Connected to BSC\n", + site_id, bts_id, trx_id); + + /* Create UDP socket for BTS packet injection */ + udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100); + ret = make_sock(&ipbc->udp_bts_fd, udp_port, IPPROTO_UDP, + UDP_TO_BTS, udp_fd_cb, ipbc); + if (ret < 0) + goto err_udp_bts; + DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection " + "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port); + + /* Create UDP socket for BSC packet injection */ + udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100); + ret = make_sock(&ipbc->udp_bsc_fd, udp_port, IPPROTO_UDP, + UDP_TO_BSC, udp_fd_cb, ipbc); + if (ret < 0) + goto err_udp_bsc; + DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection " + "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port); + llist_add(&ipbc->list, &ipp->bts_list); + + return 0; + +err_udp_bsc: + bsc_unregister_fd(&ipbc->udp_bts_fd); +err_udp_bts: + bsc_unregister_fd(&ipbc->bsc_oml_conn->fd); + close(ipbc->bsc_oml_conn->fd.fd); + talloc_free(ipbc->bsc_oml_conn); + ipbc->bsc_oml_conn = NULL; +err_bsc_conn: + talloc_free(ipbc->id_resp); + talloc_free(ipbc); +#if 0 + bsc_unregister_fd(bfd); + close(bfd->fd); + talloc_free(bfd); +#endif +err_out: + return ret; +} + +static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg, + struct bsc_fd *bfd) +{ + struct tlv_parsed tlvp; + u_int8_t msg_type = *(msg->l2h); + u_int16_t site_id, bts_id, trx_id; + struct ipa_bts_conn *ipbc; + int ret = 0; + + switch (msg_type) { + case IPAC_MSGT_PING: + ret = write(bfd->fd, pong, sizeof(pong)); + if (ret < 0) + return ret; + if (ret < sizeof(pong)) { + DEBUGP(DINP, "short write\n"); + return -EIO; + } + break; + case IPAC_MSGT_PONG: + DEBUGP(DMI, "PONG!\n"); + break; + case IPAC_MSGT_ID_RESP: + DEBUGP(DMI, "ID_RESP "); + /* parse tags, search for Unit ID */ + ipac_idtag_parse(&tlvp, (u_int8_t *)msg->l2h + 2, + msgb_l2len(msg)-2); + DEBUGP(DMI, "\n"); + + if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) { + LOGP(DINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n"); + return -EIO; + } + + /* lookup BTS, create sign_link, ... */ + parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT), + &site_id, &bts_id, &trx_id); + ipbc = find_bts_by_unitid(ipp, site_id, bts_id); + if (!ipbc) { + /* We have not found an ipbc (per-bts proxy instance) + * for this BTS yet. The first connection of a new BTS must + * be a OML connection. We allocate the associated data structures, + * and try to connect to the remote end */ + + return ipbc_alloc_connect(ipc, bfd, site_id, bts_id, + trx_id, &tlvp, msg); + /* if this fails, the caller will clean up bfd */ + } else { + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + inet_aton(bsc_ipaddr, &sin.sin_addr); + + DEBUGP(DINP, "Identified BTS %u/%u/%u\n", + site_id, bts_id, trx_id); + + if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) { + LOGP(DINP, LOGL_ERROR, "Second OML connection from " + "same BTS ?!?\n"); + return 0; + } + + if (trx_id > MAX_TRX) { + LOGP(DINP, LOGL_ERROR, "We don't support more " + "than %u TRX\n", MAX_TRX); + return -EINVAL; + } + + ipc->bts_conn = ipbc; + /* store TRX number in higher 8 bit of the bfd private number */ + bfd->priv_nr |= trx_id << 8; + ipbc->rsl_conn[trx_id] = ipc; + + /* Create RSL TCP connection towards BSC */ + sin.sin_port = htons(3003); + ipbc->bsc_rsl_conn[trx_id] = + connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc); + if (!ipbc->bsc_oml_conn) + return -EIO; + DEBUGP(DINP, "(%u/%u/%u) Connected RSL to BSC\n", + site_id, bts_id, trx_id); + } + break; + case IPAC_MSGT_ID_GET: + DEBUGP(DMI, "ID_GET\n"); + if ((bfd->priv_nr & 0xff) != OML_TO_BSC && + (bfd->priv_nr & 0xff) != RSL_TO_BSC) { + DEBUGP(DINP, "IDentity REQuest from BTS ?!?\n"); + return -EIO; + } + ipbc = ipc->bts_conn; + if (!ipbc) { + DEBUGP(DINP, "ID_GET from BSC before we have ID_RESP from BTS\n"); + return -EIO; + } + ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len); + break; + case IPAC_MSGT_ID_ACK: + DEBUGP(DMI, "ID_ACK? -> ACK!\n"); + ret = write(bfd->fd, id_ack, sizeof(id_ack)); + break; + } + return 0; +} + +struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) +{ + struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP"); + struct ipaccess_head *hh; + int len, ret = 0; + + if (!msg) { + *error = -ENOMEM; + return NULL; + } + + /* first read our 3-byte header */ + hh = (struct ipaccess_head *) msg->data; + ret = recv(bfd->fd, msg->data, 3, 0); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno)); + msgb_free(msg); + *error = ret; + return NULL; + } else if (ret == 0) { + msgb_free(msg); + *error = ret; + return NULL; + } + + msgb_put(msg, ret); + + /* then read te length as specified in header */ + msg->l2h = msg->data + sizeof(*hh); + len = ntohs(hh->len); + ret = recv(bfd->fd, msg->l2h, len, 0); + if (ret < len) { + LOGP(DINP, LOGL_ERROR, "short read!\n"); + msgb_free(msg); + *error = -EIO; + return NULL; + } + msgb_put(msg, ret); + + return msg; +} + +static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc, + unsigned int priv_nr) +{ + struct ipa_proxy_conn *bsc_conn; + unsigned int trx_id = priv_nr >> 8; + + switch (priv_nr & 0xff) { + case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */ + bsc_conn = ipbc->bsc_oml_conn; + break; + case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */ + bsc_conn = ipbc->bsc_rsl_conn[trx_id]; + break; + case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */ + bsc_conn = ipbc->oml_conn; + break; + case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */ + bsc_conn = ipbc->rsl_conn[trx_id]; + break; + default: + bsc_conn = NULL; + break; + } + return bsc_conn; +} + +static void reconn_tmr_cb(void *data) +{ + struct ipa_proxy *ipp = data; + struct ipa_bts_conn *ipbc; + struct sockaddr_in sin; + int i; + + DEBUGP(DINP, "Running reconnect timer\n"); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + inet_aton(bsc_ipaddr, &sin.sin_addr); + + llist_for_each_entry(ipbc, &ipp->bts_list, list) { + /* if OML to BSC is dead, try to restore it */ + if (ipbc->oml_conn && !ipbc->bsc_oml_conn) { + sin.sin_port = htons(3002); + logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0); + LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n"); + ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc); + if (!ipbc->bsc_oml_conn) + goto reschedule; + logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0); + LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n"); + } + /* if we (still) don't have a OML connection, skip RSL */ + if (!ipbc->oml_conn || !ipbc->bsc_oml_conn) + continue; + + for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) { + unsigned int priv_nr; + /* don't establish RSL links which we don't have */ + if (!ipbc->rsl_conn[i]) + continue; + if (ipbc->bsc_rsl_conn[i]) + continue; + priv_nr = ipbc->rsl_conn[i]->fd.priv_nr; + priv_nr &= ~0xff; + priv_nr |= RSL_TO_BSC; + sin.sin_port = htons(3003); + logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8); + LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n"); + ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc); + if (!ipbc->bsc_rsl_conn) + goto reschedule; + logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8); + LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n"); + } + } + return; + +reschedule: + bsc_schedule_timer(&ipp->reconn_timer, 5, 0); +} + +static void handle_dead_socket(struct bsc_fd *bfd) +{ + struct ipa_proxy_conn *ipc = bfd->data; /* local conn */ + struct ipa_proxy_conn *bsc_conn; /* remote conn */ + struct ipa_bts_conn *ipbc = ipc->bts_conn; + unsigned int trx_id = bfd->priv_nr >> 8; + struct msgb *msg, *msg2; + + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + + /* FIXME: clear tx_queue, remove all references, etc. */ + llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list) + msgb_free(msg); + + switch (bfd->priv_nr & 0xff) { + case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */ + ipbc->oml_conn = NULL; + bsc_conn = ipbc->bsc_oml_conn; + /* close the connection to the BSC */ + bsc_unregister_fd(&bsc_conn->fd); + close(bsc_conn->fd.fd); + llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list) + msgb_free(msg); + talloc_free(bsc_conn); + ipbc->bsc_oml_conn = NULL; + /* FIXME: do we need to delete the entire ipbc ? */ + break; + case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */ + ipbc->rsl_conn[trx_id] = NULL; + bsc_conn = ipbc->bsc_rsl_conn[trx_id]; + /* close the connection to the BSC */ + bsc_unregister_fd(&bsc_conn->fd); + close(bsc_conn->fd.fd); + llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list) + msgb_free(msg); + talloc_free(bsc_conn); + ipbc->bsc_rsl_conn[trx_id] = NULL; + break; + case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */ + ipbc->bsc_oml_conn = NULL; + bsc_conn = ipbc->oml_conn; + /* start reconnect timer */ + bsc_schedule_timer(&ipp->reconn_timer, 5, 0); + break; + case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */ + ipbc->bsc_rsl_conn[trx_id] = NULL; + bsc_conn = ipbc->rsl_conn[trx_id]; + /* start reconnect timer */ + bsc_schedule_timer(&ipp->reconn_timer, 5, 0); + break; + default: + bsc_conn = NULL; + break; + } + + talloc_free(ipc); +} + +static int handle_tcp_read(struct bsc_fd *bfd) +{ + struct ipa_proxy_conn *ipc = bfd->data; + struct ipa_bts_conn *ipbc = ipc->bts_conn; + struct ipa_proxy_conn *bsc_conn; + struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP"); + struct ipaccess_head *hh; + int ret = 0; + char *btsbsc; + + if (!msg) + return -ENOMEM; + + if ((bfd->priv_nr & 0xff) <= 2) + btsbsc = "BTS"; + else + btsbsc = "BSC"; + + msg = ipaccess_read_msg(bfd, &ret); + if (!msg) { + if (ret == 0) { + logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8); + LOGPC(DINP, LOGL_NOTICE, "%s disappeared, " + "dead socket\n", btsbsc); + handle_dead_socket(bfd); + } + return ret; + } + + msgb_put(msg, ret); + logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8); + DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, hexdump(msg->data, msg->len)); + + hh = (struct ipaccess_head *) msg->data; + if (hh->proto == IPAC_PROTO_IPACCESS) { + ret = ipaccess_rcvmsg(ipc, msg, bfd); + if (ret < 0) { + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + talloc_free(bfd); + } + /* we do not forward the CCM protocol through the + * proxy but rather terminate it ourselves */ + msgb_free(msg); + return ret; + } + + if (!ipbc) { + LOGP(DINP, LOGL_ERROR, + "received %s packet but no ipc->bts_conn?!?\n", btsbsc); + msgb_free(msg); + return -EIO; + } + + bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr); + if (bsc_conn) { + /* enqueue packet towards BSC */ + msgb_enqueue(&bsc_conn->tx_queue, msg); + /* mark respective filedescriptor as 'we want to write' */ + bsc_conn->fd.when |= BSC_FD_WRITE; + } else { + logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8); + LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, " + "since remote connection is dead\n", btsbsc); + msgb_free(msg); + } + + return ret; +} + +/* a TCP socket is ready to be written to */ +static int handle_tcp_write(struct bsc_fd *bfd) +{ + struct ipa_proxy_conn *ipc = bfd->data; + struct ipa_bts_conn *ipbc = ipc->bts_conn; + struct llist_head *lh; + struct msgb *msg; + char *btsbsc; + int ret; + + if ((bfd->priv_nr & 0xff) <= 2) + btsbsc = "BTS"; + else + btsbsc = "BSC"; + + + /* get the next msg for this timeslot */ + if (llist_empty(&ipc->tx_queue)) { + bfd->when &= ~BSC_FD_WRITE; + return 0; + } + lh = ipc->tx_queue.next; + llist_del(lh); + msg = llist_entry(lh, struct msgb, list); + + logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8); + DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr, + hexdump(msg->data, msg->len)); + + ret = send(bfd->fd, msg->data, msg->len, 0); + msgb_free(msg); + + if (ret == 0) { + logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8); + LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc); + handle_dead_socket(bfd); + } + + return ret; +} + +/* callback from select.c in case one of the fd's can be read/written */ +static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) { + rc = handle_tcp_read(bfd); + if (rc < 0) + return rc; + } + if (what & BSC_FD_WRITE) + rc = handle_tcp_write(bfd); + + return rc; +} + +/* callback of the listening filedescriptor */ +static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) +{ + int ret; + struct ipa_proxy_conn *ipc; + struct bsc_fd *bfd; + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + if (!(what & BSC_FD_READ)) + return 0; + + ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len); + if (ret < 0) { + perror("accept"); + return ret; + } + DEBUGP(DINP, "accept()ed new %s link from %s\n", + (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL", + inet_ntoa(sa.sin_addr)); + + ipc = alloc_conn(); + if (!ipc) { + close(ret); + return -ENOMEM; + } + + bfd = &ipc->fd; + bfd->fd = ret; + bfd->data = ipc; + bfd->priv_nr = listen_bfd->priv_nr; + bfd->cb = ipaccess_fd_cb; + bfd->when = BSC_FD_READ; + ret = bsc_register_fd(bfd); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "could not register FD\n"); + close(bfd->fd); + talloc_free(ipc); + return ret; + } + + /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */ + ret = write(bfd->fd, id_req, sizeof(id_req)); + + return 0; +} + +static int make_listen_sock(struct bsc_fd *bfd, u_int16_t port, int priv_nr, + int (*cb)(struct bsc_fd *fd, unsigned int what)) +{ + struct sockaddr_in addr; + int ret, on = 1; + + bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + bfd->cb = cb; + bfd->when = BSC_FD_READ; + bfd->priv_nr = priv_nr; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (!listen_ipaddr) + addr.sin_addr.s_addr = INADDR_ANY; + else + inet_aton(listen_ipaddr, &addr.sin_addr); + + setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "could not bind listen socket %s\n", + strerror(errno)); + return -EIO; + } + + ret = listen(bfd->fd, 1); + if (ret < 0) { + perror("listen"); + return ret; + } + + ret = bsc_register_fd(bfd); + if (ret < 0) { + perror("register_listen_fd"); + return ret; + } + return 0; +} + +/* Actively connect to a BSC. */ +static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data) +{ + struct ipa_proxy_conn *ipc; + struct bsc_fd *bfd; + int ret, on = 1; + + ipc = alloc_conn(); + if (!ipc) + return NULL; + + ipc->bts_conn = data; + + bfd = &ipc->fd; + bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + bfd->cb = ipaccess_fd_cb; + bfd->when = BSC_FD_READ | BSC_FD_WRITE; + bfd->data = ipc; + bfd->priv_nr = priv_nr; + + setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa)); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "could not connect socket\n"); + close(bfd->fd); + talloc_free(ipc); + return NULL; + } + + /* pre-fill tx_queue with identity request */ + ret = bsc_register_fd(bfd); + if (ret < 0) { + close(bfd->fd); + talloc_free(ipc); + return NULL; + } + + return ipc; +} + +static int ipaccess_proxy_setup(void) +{ + int ret; + + ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy); + if (!ipp) + return -ENOMEM; + INIT_LLIST_HEAD(&ipp->bts_list); + ipp->reconn_timer.cb = reconn_tmr_cb; + ipp->reconn_timer.data = ipp; + + /* Listen for OML connections */ + ret = make_listen_sock(&ipp->oml_listen_fd, 3002, OML_FROM_BTS, listen_fd_cb); + if (ret < 0) + return ret; + + /* Listen for RSL connections */ + ret = make_listen_sock(&ipp->rsl_listen_fd, 3003, RSL_FROM_BTS, listen_fd_cb); + + return ret; +} + +static void signal_handler(int signal) +{ + fprintf(stdout, "signal %u received\n", signal); + + switch (signal) { + case SIGABRT: + /* in case of abort, we want to obtain a talloc report + * and then return to the caller, who will abort the process */ + case SIGUSR1: + talloc_report_full(tall_bsc_ctx, stderr); + break; + default: + break; + } +} + +int main(int argc, char **argv) +{ + int rc; + + listen_ipaddr = "192.168.100.11"; + bsc_ipaddr = "192.168.100.239"; + + tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy"); + + debug_init(); + stderr_target = debug_target_create_stderr(); + debug_add_target(stderr_target); + debug_set_all_filter(stderr_target, 1); + debug_parse_category_mask(stderr_target, "DINP:DMI"); + + rc = ipaccess_proxy_setup(); + if (rc < 0) + exit(1); + + signal(SIGUSR1, &signal_handler); + signal(SIGABRT, &signal_handler); + + while (1) { + bsc_select_main(0); + } +} From 87ed5cd4ad0795d6d63b017e8811cc4bef646ec4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 23 Dec 2009 22:47:53 +0100 Subject: [PATCH 170/365] introduce #defines for ip.access RSL and OML UDP ports --- openbsc/include/openbsc/ipaccess.h | 3 +++ openbsc/src/input/ipaccess.c | 4 ++-- openbsc/src/ipaccess-proxy.c | 14 ++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index 395687764..21a5c1759 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -3,6 +3,9 @@ #include "e1_input.h" +#define IPA_TCP_PORT_OML 3002 +#define IPA_TCP_PORT_RSL 3003 + struct ipaccess_head { u_int16_t len; /* network byte order */ u_int8_t proto; diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 6bd501df1..bbfb091e7 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -657,12 +657,12 @@ int ipaccess_setup(struct gsm_network *gsmnet) e1h->gsmnet = gsmnet; /* Listen for OML connections */ - ret = make_sock(&e1h->listen_fd, 3002, listen_fd_cb); + ret = make_sock(&e1h->listen_fd, IPA_TCP_PORT_OML, listen_fd_cb); if (ret < 0) return ret; /* Listen for RSL connections */ - ret = make_sock(&e1h->rsl_listen_fd, 3003, rsl_listen_fd_cb); + ret = make_sock(&e1h->rsl_listen_fd, IPA_TCP_PORT_RSL, rsl_listen_fd_cb); return ret; } diff --git a/openbsc/src/ipaccess-proxy.c b/openbsc/src/ipaccess-proxy.c index 00b634052..6e0ce6ae4 100644 --- a/openbsc/src/ipaccess-proxy.c +++ b/openbsc/src/ipaccess-proxy.c @@ -464,7 +464,7 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd, memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len); /* Create OML TCP connection towards BSC */ - sin.sin_port = htons(3002); + sin.sin_port = htons(IPA_TCP_PORT_OML); ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc); if (!ipbc->bsc_oml_conn) { ret = -EIO; @@ -588,7 +588,7 @@ static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg, ipbc->rsl_conn[trx_id] = ipc; /* Create RSL TCP connection towards BSC */ - sin.sin_port = htons(3003); + sin.sin_port = htons(IPA_TCP_PORT_RSL); ipbc->bsc_rsl_conn[trx_id] = connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc); if (!ipbc->bsc_oml_conn) @@ -703,7 +703,7 @@ static void reconn_tmr_cb(void *data) llist_for_each_entry(ipbc, &ipp->bts_list, list) { /* if OML to BSC is dead, try to restore it */ if (ipbc->oml_conn && !ipbc->bsc_oml_conn) { - sin.sin_port = htons(3002); + sin.sin_port = htons(IPA_TCP_PORT_OML); logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0); LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n"); ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc); @@ -726,7 +726,7 @@ static void reconn_tmr_cb(void *data) priv_nr = ipbc->rsl_conn[i]->fd.priv_nr; priv_nr &= ~0xff; priv_nr |= RSL_TO_BSC; - sin.sin_port = htons(3003); + sin.sin_port = htons(IPA_TCP_PORT_RSL); logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8); LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n"); ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc); @@ -1072,12 +1072,14 @@ static int ipaccess_proxy_setup(void) ipp->reconn_timer.data = ipp; /* Listen for OML connections */ - ret = make_listen_sock(&ipp->oml_listen_fd, 3002, OML_FROM_BTS, listen_fd_cb); + ret = make_listen_sock(&ipp->oml_listen_fd, IPA_TCP_PORT_OML, + OML_FROM_BTS, listen_fd_cb); if (ret < 0) return ret; /* Listen for RSL connections */ - ret = make_listen_sock(&ipp->rsl_listen_fd, 3003, RSL_FROM_BTS, listen_fd_cb); + ret = make_listen_sock(&ipp->rsl_listen_fd, IPA_TCP_PORT_RSL, + RSL_FROM_BTS, listen_fd_cb); return ret; } From afdca0f3dfd3247e1c6de35fecdef3950db1fea9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 23 Dec 2009 23:01:04 +0100 Subject: [PATCH 171/365] input/ipaccess: Differentiate between LOGL_ERROR and DEBUG also: make sure we properly reset the OML/RSL UP flags on a dead socket. --- openbsc/src/input/ipaccess.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 6bd501df1..3e1d43acc 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -213,7 +213,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, &site_id, &bts_id, &trx_id); bts = find_bts_by_unitid(e1h->gsmnet, site_id, bts_id); if (!bts) { - DEBUGP(DINP, "Unable to find BTS configuration for " + LOGP(DINP, LOGL_ERROR, "Unable to find BTS configuration for " " %u/%u/%u, disconnecting\n", site_id, bts_id, trx_id); return -EIO; @@ -270,7 +270,7 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) hh = (struct ipaccess_head *) msg->data; ret = recv(bfd->fd, msg->data, 3, 0); if (ret < 0) { - fprintf(stderr, "recv error %s\n", strerror(errno)); + LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno)); msgb_free(msg); *error = ret; return NULL; @@ -287,7 +287,7 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) len = ntohs(hh->len); ret = recv(bfd->fd, msg->l2h, len, 0); if (ret < len) { - fprintf(stderr, "short read!\n"); + LOGP(DINP, LOGL_ERROR, "short read!\n"); msgb_free(msg); *error = -EIO; return NULL; @@ -310,9 +310,12 @@ static int handle_ts1_read(struct bsc_fd *bfd) msg = ipaccess_read_msg(bfd, &error); if (!msg) { if (error == 0) { - fprintf(stderr, "BTS disappeared, dead socket\n"); + LOGP(DINP, LOGL_NOTICE, "BTS disappeared, dead socket\n"); e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL); e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML); + link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0); + if (link) + link->trx->bts->ip_access.flags = 0; bsc_unregister_fd(bfd); close(bfd->fd); bfd->fd = -1; @@ -340,7 +343,8 @@ static int handle_ts1_read(struct bsc_fd *bfd) link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0); if (!link) { - printf("no matching signalling link for hh->proto=0x%02x\n", hh->proto); + LOGP(DINP, LOGL_ERROR, "no matching signalling link for " + "hh->proto=0x%02x\n", hh->proto); msgb_free(msg); return -EIO; } @@ -362,7 +366,7 @@ static int handle_ts1_read(struct bsc_fd *bfd) ret = abis_nm_rcvmsg(msg); break; default: - DEBUGP(DMI, "Unknown IP.access protocol proto=0x%02x\n", hh->proto); + LOGP(DINP, LOGL_NOTICE, "Unknown IP.access protocol proto=0x%02x\n", hh->proto); msgb_free(msg); break; } @@ -462,7 +466,7 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what) if (what & BSC_FD_WRITE) rc = handle_ts1_write(bfd); } else - fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type); + LOGP(DINP, LOGL_ERROR, "unknown E1 TS type %u\n", e1i_ts->type); return rc; } @@ -492,7 +496,8 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) perror("accept"); return ret; } - DEBUGP(DINP, "accept()ed new OML link from %s\n", inet_ntoa(sa.sin_addr)); + LOGP(DINP, LOGL_NOTICE, "accept()ed new OML link from %s\n", + inet_ntoa(sa.sin_addr)); line = talloc_zero(tall_bsc_ctx, struct e1inp_line); if (!line) { @@ -514,7 +519,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) bfd->when = BSC_FD_READ; ret = bsc_register_fd(bfd); if (ret < 0) { - fprintf(stderr, "could not register FD\n"); + LOGP(DINP, LOGL_ERROR, "could not register FD\n"); close(bfd->fd); talloc_free(line); return ret; @@ -550,13 +555,13 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) perror("accept"); return bfd->fd; } - DEBUGP(DINP, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr)); + LOGP(DINP, LOGL_NOTICE, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr)); bfd->priv_nr = 2; bfd->cb = ipaccess_fd_cb; bfd->when = BSC_FD_READ; ret = bsc_register_fd(bfd); if (ret < 0) { - fprintf(stderr, "could not register FD\n"); + LOGP(DINP, LOGL_ERROR, "could not register FD\n"); close(bfd->fd); talloc_free(bfd); return ret; @@ -587,7 +592,7 @@ static int make_sock(struct bsc_fd *bfd, u_int16_t port, ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); if (ret < 0) { - fprintf(stderr, "could not bind l2 socket %s\n", + LOGP(DINP, LOGL_ERROR, "could not bind l2 socket %s\n", strerror(errno)); return -EIO; } @@ -623,7 +628,7 @@ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa) ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa)); if (ret < 0) { - fprintf(stderr, "could not connect socket\n"); + LOGP(DINP, LOGL_ERROR, "could not connect socket\n"); close(bfd->fd); return ret; } From 61cc306a55bdcbf543ce5c3e74a4d30cdbba5984 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 23 Dec 2009 23:03:57 +0100 Subject: [PATCH 172/365] debug: Fix typo DMM -> DNM (we don't need DMM twice) This prevented NM related log messages from showing up at stderr --- openbsc/src/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index d3d58f3fb..c02c086bb 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -35,7 +35,7 @@ static struct debug_category default_categories[Debug_LastEntry] = { [DRLL] = { .enabled = 1, .loglevel = 0}, [DCC] = { .enabled = 1, .loglevel = 0}, - [DMM] = { .enabled = 1, .loglevel = 0}, + [DNM] = { .enabled = 1, .loglevel = 0}, [DRR] = { .enabled = 1, .loglevel = 0}, [DRSL] = { .enabled = 1, .loglevel = 0}, [DMM] = { .enabled = 1, .loglevel = 0}, From a16ef3d23f31369399dd28b23a0c95648248cbf1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 23 Dec 2009 23:35:51 +0100 Subject: [PATCH 173/365] ipaccess-proxy: Fix two memory leaks --- openbsc/src/ipaccess-proxy.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openbsc/src/ipaccess-proxy.c b/openbsc/src/ipaccess-proxy.c index 6e0ce6ae4..dd9d6b1b5 100644 --- a/openbsc/src/ipaccess-proxy.c +++ b/openbsc/src/ipaccess-proxy.c @@ -245,7 +245,7 @@ static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp) ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len); else #endif - ipbc->id_tags[i] = talloc_realloc_size(tall_bsc_ctx, + ipbc->id_tags[i] = talloc_realloc_size(ipbc, ipbc->id_tags[i], len); if (!ipbc->id_tags[i]) return -ENOMEM; @@ -807,14 +807,11 @@ static int handle_tcp_read(struct bsc_fd *bfd) struct ipa_proxy_conn *ipc = bfd->data; struct ipa_bts_conn *ipbc = ipc->bts_conn; struct ipa_proxy_conn *bsc_conn; - struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP"); + struct msgb *msg; struct ipaccess_head *hh; int ret = 0; char *btsbsc; - if (!msg) - return -ENOMEM; - if ((bfd->priv_nr & 0xff) <= 2) btsbsc = "BTS"; else From 3606cc576502b95d4973fac2af76d1b9bdc4705b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 5 Dec 2009 15:13:22 +0530 Subject: [PATCH 174/365] [authentication] Code for retrieving authentication data from SQL DB This is the first step towards supporting actual A3/A8 authentication. --- openbsc/include/openbsc/gsm_data.h | 19 ++++++ openbsc/src/db.c | 92 ++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index c2eec4156..ff01d7287 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -589,6 +589,25 @@ struct gsm_sms { char text[SMS_TEXT_SIZE]; }; +enum gsm_auth_algo { + AUTH_ALGO_NONE, + AUTH_ALGO_XOR, + AUTH_ALGO_COMP128v1, +}; + +/* Real authentication information containing Ki */ +struct gsm_auth_info { + enum gsm_auth_algo auth_algo; + unsigned int a3a8_ki_len; + u_int8_t a3a8_ki[16]; +}; + +struct gsm_auth_tuple { + u_int8_t rand[16]; + u_int8_t sres[8]; + u_int8_t kc[8]; +}; + struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_code, int (*mncc_recv)(struct gsm_network *, int, void *)); struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 7b864fb43..cf9df11ad 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -123,6 +123,18 @@ static char *create_stmts[] = { "timestamp TIMESTAMP NOT NULL, " "value INTEGER NOT NULL, " "name TEXT NOT NULL " + "CREATE TABLE IF NOT EXISTS AuthKeys (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "subscriber_id NUMERIC UNIQUE NOT NULL, " + "algorithm_id NUMERIC NOT NULL, " + "a3a8_ki BLOB " + ")", + "CREATE TABLE IF NOT EXISTS AuthTuples (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "subscriber_id NUMERIC UNIQUE NOT NULL, " + "rand BLOB" + "sres BLOB" + "kc BLOB" ")", }; @@ -314,6 +326,86 @@ static int get_equipment_by_subscr(struct gsm_subscriber *subscr) return 0; } + +int get_authinfo_by_subscr(struct gsm_auth_info *ainfo, + struct gsm_subscriber *subscr) +{ + dbi_result result; + const unsigned char *a3a8_ki; + + result = dbi_conn_queryf(conn, + "SELECT * FROM AuthKeys WHERE subscriber_id=%u", + subscr->id); + if (!result) + return -EIO; + + if (!dbi_result_next_row(result)) { + dbi_result_free(result); + return -ENOENT; + } + + ainfo->auth_algo = dbi_result_get_ulonglong(result, "algorithm_id"); + ainfo->a3a8_ki_len = dbi_result_get_field_length(result, "a3a8_ki"); + a3a8_ki = dbi_result_get_binary(result, "a3a8_ki"); + if (ainfo->a3a8_ki_len > sizeof(ainfo->a3a8_ki_len)) + ainfo->a3a8_ki_len = sizeof(ainfo->a3a8_ki_len); + memcpy(ainfo->a3a8_ki, a3a8_ki, ainfo->a3a8_ki_len); + + dbi_result_free(result); + + return 0; +} + +int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr) +{ + dbi_result result; + int len; + const unsigned char *blob; + + result = dbi_conn_queryf(conn, + "SELECT * FROM AuthTuples WHERE subscriber_id=%u", + subscr->id); + if (!result) + return -EIO; + + if (!dbi_result_next_row(result)) { + dbi_result_free(result); + return -ENOENT; + } + + memset(atuple, 0, sizeof(atuple)); + + len = dbi_result_get_field_length(result, "rand"); + if (len != sizeof(atuple->rand)) + goto err_size; + + blob = dbi_result_get_binary(result, "rand"); + memcpy(atuple->rand, blob, len); + + len = dbi_result_get_field_length(result, "sres"); + if (len != sizeof(atuple->sres)) + goto err_size; + + blob = dbi_result_get_binary(result, "sres"); + memcpy(atuple->sres, blob, len); + + len = dbi_result_get_field_length(result, "kc"); + if (len != sizeof(atuple->kc)) + goto err_size; + + blob = dbi_result_get_binary(result, "kc"); + memcpy(atuple->kc, blob, len); + + dbi_result_free(result); + + return 0; + +err_size: + dbi_result_free(result); + return -EIO; +} + #define BASE_QUERY "SELECT * FROM Subscriber " struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, enum gsm_subscriber_field field, From 09f7ad0ff7961b713264629dae790db9453c8116 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 09:42:07 +0100 Subject: [PATCH 175/365] fix merge artefact from db.c --- openbsc/src/db.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index cf9df11ad..11fb4dd4e 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -123,6 +123,7 @@ static char *create_stmts[] = { "timestamp TIMESTAMP NOT NULL, " "value INTEGER NOT NULL, " "name TEXT NOT NULL " + ")", "CREATE TABLE IF NOT EXISTS AuthKeys (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "subscriber_id NUMERIC UNIQUE NOT NULL, " From 30d2ebddd6eb1fd62deff137aa2c8eab55f2efc3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 09:43:25 +0100 Subject: [PATCH 176/365] move msgb talloc context into talloc_ctx.c This keeps the ordering right, independent of link ordering, it will ensure that the talloc dump will also catch msgb related memory leaks. --- openbsc/src/msgb.c | 7 +------ openbsc/src/talloc_ctx.c | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/openbsc/src/msgb.c b/openbsc/src/msgb.c index 48a5a7b03..9f2fcfa96 100644 --- a/openbsc/src/msgb.c +++ b/openbsc/src/msgb.c @@ -28,7 +28,7 @@ #include #include -static void *tall_msgb_ctx; +void *tall_msgb_ctx; struct msgb *msgb_alloc(u_int16_t size, const char *name) { @@ -96,8 +96,3 @@ void msgb_reset(struct msgb *msg) msg->l3h = NULL; msg->smsh = NULL; } - -static __attribute__((constructor)) void on_dso_load_trau_msgb(void) -{ - tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 1, "msgb"); -} diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c index aa9f0b4d7..e90677b7e 100644 --- a/openbsc/src/talloc_ctx.c +++ b/openbsc/src/talloc_ctx.c @@ -1,6 +1,7 @@ #include #include +extern void *tall_msgb_ctx; extern void *tall_fle_ctx; extern void *tall_locop_ctx; extern void *tall_gsms_ctx; @@ -16,6 +17,7 @@ extern void *tall_upq_ctx; void talloc_ctx_init(void) { + tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb"); tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0, "bs11_file_list_entry"); tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 0, "loc_updating_oper"); From 026a6c33895bd13a8561b6f933b67abd005bccee Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 10:04:09 +0100 Subject: [PATCH 177/365] counter: create their own talloc context for better readability --- openbsc/src/statistics.c | 4 +++- openbsc/src/talloc_ctx.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/src/statistics.c b/openbsc/src/statistics.c index 9bd44f3d4..9452b16e1 100644 --- a/openbsc/src/statistics.c +++ b/openbsc/src/statistics.c @@ -33,9 +33,11 @@ static LLIST_HEAD(counters); +void *tall_ctr_ctx; + struct counter *counter_alloc(const char *name) { - struct counter *ctr = talloc_zero(tall_bsc_ctx, struct counter); + struct counter *ctr = talloc_zero(tall_ctr_ctx, struct counter); if (!ctr) return NULL; diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c index e90677b7e..13ec77530 100644 --- a/openbsc/src/talloc_ctx.c +++ b/openbsc/src/talloc_ctx.c @@ -14,6 +14,7 @@ extern void *tall_tqe_ctx; extern void *tall_trans_ctx; extern void *tall_map_ctx; extern void *tall_upq_ctx; +extern void *tall_ctr_ctx; void talloc_ctx_init(void) { @@ -31,4 +32,5 @@ void talloc_ctx_init(void) tall_trans_ctx = talloc_named_const(tall_bsc_ctx, 0, "transaction"); tall_map_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_map_entry"); tall_upq_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_upq_entry"); + tall_ctr_ctx = talloc_named_const(tall_ctr_ctx, 0, "counter"); } From d6847a940a15ba9a66f3a53d1377a127256eb363 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 10:06:33 +0100 Subject: [PATCH 178/365] use enum for operational state --- openbsc/include/openbsc/abis_nm.h | 6 ++++++ openbsc/src/abis_nm.c | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 00697a384..c237613c8 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -485,6 +485,12 @@ enum abis_nm_avail_state { NM_AVSTATE_OK = 0xff, }; +enum abis_nm_op_state { + NM_OPSTATE_DISABLED = 1, + NM_OPSTATE_ENABLED = 2, + NM_OPSTATE_NULL = 0xff, +}; + /* Section 9.4.13: Channel Combination */ enum abis_nm_chan_comb { NM_CHANC_TCHFull = 0x00, /* TCH/F + TCH/H + SACCH/TF */ diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 98683d380..c99ffcfbb 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -540,11 +540,11 @@ static const char *obj_class_name(u_int8_t oc) const char *nm_opstate_name(u_int8_t os) { switch (os) { - case 1: + case NM_OPSTATE_DISABLED: return "Disabled"; - case 2: + case NM_OPSTATE_ENABLED: return "Enabled"; - case 0xff: + case NM_OPSTATE_NULL: return "NULL"; default: return "RFU"; From 02cbff09df44715abf671d10a351092b9c8cf61b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 10:07:36 +0100 Subject: [PATCH 179/365] fix typo in talloc_ctx causing counters not to show up in talloc report --- openbsc/src/talloc_ctx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c index 13ec77530..5f0ee4de8 100644 --- a/openbsc/src/talloc_ctx.c +++ b/openbsc/src/talloc_ctx.c @@ -32,5 +32,5 @@ void talloc_ctx_init(void) tall_trans_ctx = talloc_named_const(tall_bsc_ctx, 0, "transaction"); tall_map_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_map_entry"); tall_upq_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_upq_entry"); - tall_ctr_ctx = talloc_named_const(tall_ctr_ctx, 0, "counter"); + tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter"); } From 4c70454bae4122b0c72c37fdaad0caa117c93888 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 10:10:16 +0100 Subject: [PATCH 180/365] channel allocator: don't allocate channels of unavalable TRXs In case we have multiple TRX configured, but not all of them are actually active/operational, we should not try to allocate channels from such transceivers. --- openbsc/src/chan_alloc.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 632860814..4bdf722b0 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -35,6 +35,32 @@ static void auto_release_channel(void *_lchan); +static int ts_is_usable(struct gsm_bts_trx_ts *ts) +{ + /* FIXME: How does this behave for BS-11 ? */ + if (is_ipaccess_bts(ts->trx->bts)) { + if (ts->nm_state.operational != NM_OPSTATE_ENABLED || + ts->nm_state.availability != NM_AVSTATE_OK) + return 0; + } + + return 1; +} + +static int trx_is_usable(struct gsm_bts_trx *trx) +{ + /* FIXME: How does this behave for BS-11 ? */ + if (is_ipaccess_bts(trx->bts)) { + if (trx->nm_state.operational != NM_OPSTATE_ENABLED || + trx->nm_state.availability != NM_AVSTATE_OK || + trx->bb_transc.nm_state.operational != NM_OPSTATE_ENABLED || + trx->bb_transc.nm_state.availability != NM_AVSTATE_OK) + return 0; + } + + return 1; +} + struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, enum gsm_phys_chan_config pchan) { @@ -63,6 +89,9 @@ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts, llist_for_each_entry(trx, &bts->trx_list, list) { int from, to; + if (!trx_is_usable(trx)) + continue; + /* the following constraints are pure policy, * no requirement to put this restriction in place */ if (trx == bts->c0) { @@ -97,6 +126,10 @@ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts, for (j = from; j <= to; j++) { struct gsm_bts_trx_ts *ts = &trx->ts[j]; + + if (!ts_is_usable(ts)) + continue; + if (ts->pchan == GSM_PCHAN_NONE) { ts->pchan = pchan; /* set channel attribute on OML */ @@ -130,8 +163,13 @@ _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan) struct gsm_bts_trx_ts *ts; int j, ss; + if (!trx_is_usable(trx)) + return NULL; + for (j = 0; j < 8; j++) { ts = &trx->ts[j]; + if (!ts_is_usable(ts)) + continue; if (ts->pchan != pchan) continue; /* check if all sub-slots are allocated yet */ From 28f811c87f939fc9d3523f85baa2b62a2629796d Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 23 Dec 2009 18:15:09 +0100 Subject: [PATCH 181/365] db: Fix compile warning, declare db_sms_get_unsent_by_subscr Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/db.h | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index fca736493..8059668ed 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -46,6 +46,7 @@ int db_sync_equipment(struct gsm_equipment *equip); /* SMS store-and-forward */ int db_sms_store(struct gsm_sms *sms); struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id); +struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id); struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr); int db_sms_mark_sent(struct gsm_sms *sms); From 3cefa9aaa0832b9cf99f3599f7cc1c0499e78cbb Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 10:51:56 +0100 Subject: [PATCH 182/365] vty: sub-divide talloc contexts and include them in talloc report The VTY code makes so many allocations that a full report is simply too long to provide any useful information. So we sub-divide it in multiple contexts, and report only one level deep at SIGURS1. We also introduce SIGUSR2 for the full detailed VTY report. --- openbsc/include/vty/command.h | 2 ++ openbsc/include/vty/vector.h | 2 ++ openbsc/src/bsc_hack.c | 6 +++++ openbsc/src/vty/command.c | 44 ++++++++++++++++++----------------- openbsc/src/vty/vector.c | 12 ++++++---- openbsc/src/vty/vty.c | 2 ++ 6 files changed, 42 insertions(+), 26 deletions(-) diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 10a60add5..03b071f70 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -356,4 +356,6 @@ void host_config_set(const char *); void print_version(const char *); +extern void *tall_vty_cmd_ctx; + #endif /* _ZEBRA_COMMAND_H */ diff --git a/openbsc/include/vty/vector.h b/openbsc/include/vty/vector.h index 00f0079f3..22a184d61 100644 --- a/openbsc/include/vty/vector.h +++ b/openbsc/include/vty/vector.h @@ -59,4 +59,6 @@ vector vector_copy(vector v); void *vector_lookup(vector, unsigned int); void *vector_lookup_ensure(vector, unsigned int); +extern void *tall_vty_vec_ctx; + #endif /* _ZEBRA_VECTOR_H */ diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 8792cc36c..3122fae9c 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -138,6 +138,7 @@ static void handle_options(int argc, char** argv) } } +extern void *tall_vty_ctx; static void signal_handler(int signal) { fprintf(stdout, "signal %u received\n", signal); @@ -153,8 +154,12 @@ static void signal_handler(int signal) /* in case of abort, we want to obtain a talloc report * and then return to the caller, who will abort the process */ case SIGUSR1: + talloc_report(tall_vty_ctx, stderr); talloc_report_full(tall_bsc_ctx, stderr); break; + case SIGUSR2: + talloc_report_full(tall_vty_ctx, stderr); + break; default: break; } @@ -219,6 +224,7 @@ int main(int argc, char **argv) signal(SIGINT, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); + signal(SIGUSR2, &signal_handler); signal(SIGPIPE, SIG_IGN); while (1) { diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c index 6372fb13b..5b1dcb977 100644 --- a/openbsc/src/vty/command.c +++ b/openbsc/src/vty/command.c @@ -49,6 +49,8 @@ Boston, MA 02111-1307, USA. */ #include #include +void *tall_vty_cmd_ctx; + /* Command vector which includes some level of command lists. Normally each daemon maintains each own cmdvec. */ vector cmdvec; @@ -173,7 +175,7 @@ char *argv_concat(const char **argv, int argc, int shift) len += strlen(argv[i]) + 1; if (!len) return NULL; - p = str = _talloc_zero(tall_vty_ctx, len, "arvg_concat"); + p = str = _talloc_zero(tall_vty_cmd_ctx, len, "arvg_concat"); for (i = shift; i < argc; i++) { size_t arglen; memcpy(p, argv[i], (arglen = strlen(argv[i]))); @@ -275,7 +277,7 @@ vector cmd_make_strvec(const char *string) *cp != '\0') cp++; strlen = cp - start; - token = _talloc_zero(tall_vty_ctx, strlen + 1, "make_strvec"); + token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "make_strvec"); memcpy(token, start, strlen); *(token + strlen) = '\0'; vector_set(strvec, token); @@ -331,7 +333,7 @@ static char *cmd_desc_str(const char **string) cp++; strlen = cp - start; - token = _talloc_zero(tall_vty_ctx, strlen + 1, "cmd_desc_str"); + token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "cmd_desc_str"); memcpy(token, start, strlen); *(token + strlen) = '\0'; @@ -402,11 +404,11 @@ static vector cmd_make_descvec(const char *string, const char *descstr) len = cp - sp; - token = _talloc_zero(tall_vty_ctx, len + 1, "cmd_make_descvec"); + token = _talloc_zero(tall_vty_cmd_ctx, len + 1, "cmd_make_descvec"); memcpy(token, sp, len); *(token + len) = '\0'; - desc = talloc_zero(tall_vty_ctx, struct desc); + desc = talloc_zero(tall_vty_cmd_ctx, struct desc); desc->cmd = token; desc->str = cmd_desc_str(&dp); @@ -1804,7 +1806,7 @@ static char **cmd_complete_command_real(vector vline, struct vty *vty, if ((desc = vector_slot(descvec, j))) { if ((string = cmd_entry_function(vector_slot(vline, index), desc->cmd))) if (cmd_unique_string (matchvec, string)) - vector_set (matchvec, talloc_strdup(tall_vty_ctx, string)); + vector_set (matchvec, talloc_strdup(tall_vty_cmd_ctx, string)); } } } @@ -1845,7 +1847,7 @@ static char **cmd_complete_command_real(vector vline, struct vty *vty, if (len < lcd) { char *lcdstr; - lcdstr = _talloc_zero(tall_vty_ctx, lcd + 1, + lcdstr = _talloc_zero(tall_vty_cmd_ctx, lcd + 1, "complete-lcdstr"); memcpy(lcdstr, matchvec->index[0], lcd); lcdstr[lcd] = '\0'; @@ -2463,13 +2465,13 @@ DEFUN(config_write_file, config_file = host.config; config_file_sav = - _talloc_zero(tall_vty_ctx, + _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1, "config_file_sav"); strcpy(config_file_sav, config_file); strcat(config_file_sav, CONF_BACKUP_EXT); - config_file_tmp = _talloc_zero(tall_vty_ctx, strlen(config_file) + 8, + config_file_tmp = _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + 8, "config_file_tmp"); sprintf(config_file_tmp, "%s.XXXXXX", config_file); @@ -2650,7 +2652,7 @@ DEFUN(config_hostname, if (host.name) talloc_free(host.name); - host.name = talloc_strdup(tall_vty_ctx, argv[0]); + host.name = talloc_strdup(tall_vty_cmd_ctx, argv[0]); return CMD_SUCCESS; } @@ -2685,7 +2687,7 @@ DEFUN(config_password, password_cmd, host.password = NULL; if (host.password_encrypt) talloc_free(host.password_encrypt); - host.password_encrypt = talloc_strdup(tall_vty_ctx, argv[1]); + host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]); return CMD_SUCCESS; } else { vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE); @@ -2708,10 +2710,10 @@ DEFUN(config_password, password_cmd, if (host.encrypt) { if (host.password_encrypt) talloc_free(host.password_encrypt); - host.password_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(argv[0])); + host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0])); } else #endif - host.password = talloc_strdup(tall_vty_ctx, argv[0]); + host.password = talloc_strdup(tall_vty_cmd_ctx, argv[0]); return CMD_SUCCESS; } @@ -2744,7 +2746,7 @@ ALIAS(config_password, password_text_cmd, if (host.enable_encrypt) talloc_free(host.enable_encrypt); - host.enable_encrypt = talloc_strdup(tall_vty_ctx, argv[1]); + host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]); return CMD_SUCCESS; } else { @@ -2769,10 +2771,10 @@ ALIAS(config_password, password_text_cmd, if (host.encrypt) { if (host.enable_encrypt) talloc_free(host.enable_encrypt); - host.enable_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(argv[0])); + host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0])); } else #endif - host.enable = talloc_strdup(tall_vty_ctx, argv[0]); + host.enable = talloc_strdup(tall_vty_cmd_ctx, argv[0]); return CMD_SUCCESS; } @@ -2816,12 +2818,12 @@ DEFUN(service_password_encrypt, if (host.password) { if (host.password_encrypt) talloc_free(host.password_encrypt); - host.password_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(host.password)); + host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.password)); } if (host.enable) { if (host.enable_encrypt) talloc_free(host.enable_encrypt); - host.enable_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(host.enable)); + host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.enable)); } return CMD_SUCCESS; @@ -3095,7 +3097,7 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel) if (host.logfile) talloc_free(host.logfile); - host.logfile = talloc_strdup(tall_vty_ctx, fname); + host.logfile = talloc_strdup(tall_vty_cmd_ctx, fname); return CMD_SUCCESS; } @@ -3285,7 +3287,7 @@ DEFUN(banner_motd_file, { if (host.motdfile) talloc_free(host.motdfile); - host.motdfile = talloc_strdup(tall_vty_ctx, argv[0]); + host.motdfile = talloc_strdup(tall_vty_cmd_ctx, argv[0]); return CMD_SUCCESS; } @@ -3313,7 +3315,7 @@ DEFUN(no_banner_motd, /* Set config filename. Called from vty.c */ void host_config_set(const char *filename) { - host.config = talloc_strdup(tall_vty_ctx, filename); + host.config = talloc_strdup(tall_vty_cmd_ctx, filename); } void install_default(enum node_type node) diff --git a/openbsc/src/vty/vector.c b/openbsc/src/vty/vector.c index 371f71d95..06e1aaa8e 100644 --- a/openbsc/src/vty/vector.c +++ b/openbsc/src/vty/vector.c @@ -27,10 +27,12 @@ #include #include +void *tall_vty_vec_ctx; + /* Initialize vector : allocate memory and return vector. */ vector vector_init(unsigned int size) { - vector v = talloc_zero(tall_vty_ctx, struct _vector); + vector v = talloc_zero(tall_vty_vec_ctx, struct _vector); if (!v) return NULL; @@ -40,7 +42,7 @@ vector vector_init(unsigned int size) v->alloced = size; v->active = 0; - v->index = _talloc_zero(tall_vty_ctx, sizeof(void *) * size, + v->index = _talloc_zero(tall_vty_vec_ctx, sizeof(void *) * size, "vector_init:index"); if (!v->index) { talloc_free(v); @@ -68,7 +70,7 @@ void vector_free(vector v) vector vector_copy(vector v) { unsigned int size; - vector new = talloc_zero(tall_vty_ctx, struct _vector); + vector new = talloc_zero(tall_vty_vec_ctx, struct _vector); if (!new) return NULL; @@ -76,7 +78,7 @@ vector vector_copy(vector v) new->alloced = v->alloced; size = sizeof(void *) * (v->alloced); - new->index = _talloc_zero(tall_vty_ctx, size, "vector_copy:index"); + new->index = _talloc_zero(tall_vty_vec_ctx, size, "vector_copy:index"); if (!new->index) { talloc_free(new); return NULL; @@ -92,7 +94,7 @@ void vector_ensure(vector v, unsigned int num) if (v->alloced > num) return; - v->index = talloc_realloc_size(tall_vty_ctx, v->index, + v->index = talloc_realloc_size(tall_vty_vec_ctx, v->index, sizeof(void *) * (v->alloced * 2)); memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced); v->alloced *= 2; diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index 788c7fd6f..2339bbd4b 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -1633,6 +1633,8 @@ extern void *tall_bsc_ctx; void vty_init() { tall_vty_ctx = talloc_named_const(NULL, 0, "vty"); + tall_vty_vec_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_vector"); + tall_vty_cmd_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_command"); /* For further configuration read, preserve current directory. */ vty_save_cwd(); From aa6c9ca48b5dd15bab130b64136dfc8a1311fe8c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 11:11:54 +0100 Subject: [PATCH 183/365] debug: make sure we always zero-terminate after snprintf() --- openbsc/src/debug.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index c02c086bb..30e27a8d5 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -163,9 +163,12 @@ static void _output(struct debug_target *target, unsigned int subsys, char *file buf[0] = '\0'; /* are we using color */ - if (target->use_color) + if (target->use_color) { snprintf(col, sizeof(col), "%s", color(subsys)); + col[sizeof(col)-1] = '\0'; + } vsnprintf(buf, sizeof(buf), format, ap); + buf[sizeof(buf)-1] = '\0'; if (!cont) { if (target->print_timestamp) { @@ -175,11 +178,14 @@ static void _output(struct debug_target *target, unsigned int subsys, char *file timestr = ctime(&tm); timestr[strlen(timestr)-1] = '\0'; snprintf(tim, sizeof(tim), "%s ", timestr); + tim[sizeof(tim)-1] = '\0'; } snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line); + sub[sizeof(sub)-1] = '\0'; } snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf); + final[sizeof(final)-1] = '\0'; target->output(target, final); } From aa8989c4d538b19fd0890a1afbdda42a5f311752 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 11:12:11 +0100 Subject: [PATCH 184/365] debug: workaround for strange va_list corruption bug --- openbsc/src/debug.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 30e27a8d5..15271fe72 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -223,8 +223,15 @@ static void _debugp(unsigned int subsys, int level, char *file, int line, output = 1; } - if (output) - _output(tar, subsys, file, line, cont, format, ap); + if (output) { + /* FIXME: copying the va_list is an ugly workaround against a bug + * hidden somewhere in _output. If we do not copy here, the first + * call to _output() will corrupt the va_list contents, and any + * further _output() calls with the same va_list will segfault */ + va_list bp; + va_copy(bp, ap); + _output(tar, subsys, file, line, cont, format, bp); + } } } From 7ed2529c5b67548cefdb1f5a997b5aca54cebbed Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 11:14:03 +0100 Subject: [PATCH 185/365] debug: add missing va_end() --- openbsc/src/debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 15271fe72..8b0f25eb5 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -231,6 +231,7 @@ static void _debugp(unsigned int subsys, int level, char *file, int line, va_list bp; va_copy(bp, ap); _output(tar, subsys, file, line, cont, format, bp); + va_end(bp); } } } From 9094cbaf9c90dc86283eb66fdc75222ae10e7ec3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 24 Dec 2009 10:19:51 +0100 Subject: [PATCH 186/365] [ipaccess] Spend some more time on figuring out the format --- .../src/ipaccess-firmware/ipaccess-firmware.c | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c index e2e5008c0..4349f99da 100644 --- a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c +++ b/openbsc/src/ipaccess-firmware/ipaccess-firmware.c @@ -29,49 +29,57 @@ #include +struct sdp_firmware { + char magic[4]; + char more_magic[4]; + unsigned int header_length; + unsigned int file_length; + char sw_part[20]; + char text1[122]; + u_int8_t no_idea_1[4]; + char text2[64]; + char time[8]; + u_int8_t no_idea_2[4]; + char date[8]; + u_int8_t no_idea_3[6]; + /* stuff i don't know */ +} __attribute__((packed)); + /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; static void analyze_file(int fd) { + struct sdp_firmware *firmware_header; char buf[4096]; int rc; - unsigned int absolute_size; - rc = read(fd, buf, 4); - if (rc <= 0) { - fprintf(stderr, "Not enough space for the header.\n"); + rc = read(fd, buf, sizeof(*firmware_header)); + if (rc < 0) { + perror("can not read header"); return; } - if (strcmp(buf, " SDP") != 0) { - fprintf(stderr, "Wrong magic number at the beginning of the file.\n"); + firmware_header = (struct sdp_firmware *) &buf[0]; + if (strncmp(firmware_header->magic, " SDP", 4) != 0) { + fprintf(stderr, "Wrong magic.\n"); return; } - rc = read(fd, buf, 4); - if (rc <= 0) { - fprintf(stderr, "Not enough space for the more_magic.\n"); + if (memcmp(firmware_header->more_magic, more_magic, 4) != 0) { + fprintf(stderr, "Wrong more magic.\n"); return; } - if (strncmp(buf, more_magic, 4) != 0) { - fprintf(stderr, "The more magic is not right.\n"); - return; - } - - rc = read(fd, buf, 4); - if (rc <= 0) { - fprintf(stderr, "Trying to read the header length failed.\n"); - return; - } - - memcpy(&absolute_size, &buf[0], 4); - absolute_size = ntohl(absolute_size); - printf("Printing header information:\n"); - printf("The header is %u bytes long\n", absolute_size); + printf("header_length: %u\n", ntohl(firmware_header->header_length)); + printf("file_length: %u\n", ntohl(firmware_header->file_length)); + printf("sw_part: %.20s\n", firmware_header->sw_part); + printf("text1: %.122s\n", firmware_header->text1); + printf("text2: %.64s\n", firmware_header->text2); + printf("time: %.8s\n", firmware_header->time); + printf("date: %.8s\n", firmware_header->date); } int main(int argc, char** argv) From 426da090dbfc61776ea20d57468e9509fa136339 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 24 Dec 2009 11:26:30 +0100 Subject: [PATCH 187/365] [ipaccess] Move ipaccess utilities into a dedicated subdirectory --- openbsc/src/Makefile.am | 8 ++++---- openbsc/src/{ => ipaccess}/ipaccess-config.c | 0 openbsc/src/{ => ipaccess}/ipaccess-find.c | 0 .../{ipaccess-firmware => ipaccess}/ipaccess-firmware.c | 0 openbsc/src/{ => ipaccess}/ipaccess-proxy.c | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename openbsc/src/{ => ipaccess}/ipaccess-config.c (100%) rename openbsc/src/{ => ipaccess}/ipaccess-find.c (100%) rename openbsc/src/{ipaccess-firmware => ipaccess}/ipaccess-firmware.c (100%) rename openbsc/src/{ => ipaccess}/ipaccess-proxy.c (100%) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 54a8cde2d..080fed4d5 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -29,9 +29,9 @@ bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \ select.c timer.c rs232.c tlv_parser.c signal.c talloc.c -ipaccess_find_SOURCES = ipaccess-find.c select.c timer.c +ipaccess_find_SOURCES = ipaccess/ipaccess-find.c select.c timer.c -ipaccess_config_SOURCES = ipaccess-config.c +ipaccess_config_SOURCES = ipaccess/ipaccess-config.c ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) isdnsync_SOURCES = isdnsync.c @@ -39,6 +39,6 @@ isdnsync_SOURCES = isdnsync.c bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a -ipaccess_firmware_SOURCES = ipaccess-firmware/ipaccess-firmware.c +ipaccess_firmware_SOURCES = ipaccess/ipaccess-firmware.c -ipaccess_proxy_SOURCES = ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c +ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c similarity index 100% rename from openbsc/src/ipaccess-config.c rename to openbsc/src/ipaccess/ipaccess-config.c diff --git a/openbsc/src/ipaccess-find.c b/openbsc/src/ipaccess/ipaccess-find.c similarity index 100% rename from openbsc/src/ipaccess-find.c rename to openbsc/src/ipaccess/ipaccess-find.c diff --git a/openbsc/src/ipaccess-firmware/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c similarity index 100% rename from openbsc/src/ipaccess-firmware/ipaccess-firmware.c rename to openbsc/src/ipaccess/ipaccess-firmware.c diff --git a/openbsc/src/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c similarity index 100% rename from openbsc/src/ipaccess-proxy.c rename to openbsc/src/ipaccess/ipaccess-proxy.c From 0b906d0e1a00c0568b3574cd91d8682be4c4a12b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 11:21:42 +0100 Subject: [PATCH 188/365] db: coding style cleanup --- openbsc/src/db.c | 104 ++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 11fb4dd4e..3a261ac6d 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -139,8 +139,9 @@ static char *create_stmts[] = { ")", }; -void db_error_func(dbi_conn conn, void* data) { - const char* msg; +void db_error_func(dbi_conn conn, void *data) +{ + const char *msg; dbi_conn_error(conn, &msg); printf("DBI: %s\n", msg); } @@ -169,10 +170,12 @@ static int check_db_revision(void) return 0; } -int db_init(const char *name) { +int db_init(const char *name) +{ dbi_initialize(NULL); + conn = dbi_conn_new("sqlite3"); - if (conn==NULL) { + if (conn == NULL) { printf("DB: Failed to create connection.\n"); return 1; } @@ -206,13 +209,14 @@ out_err: } -int db_prepare() { +int db_prepare() +{ dbi_result result; int i; for (i = 0; i < ARRAY_SIZE(create_stmts); i++) { result = dbi_conn_query(conn, create_stmts[i]); - if (result==NULL) { + if (!result) { printf("DB: Failed to create some table.\n"); return 1; } @@ -228,7 +232,8 @@ int db_prepare() { return 0; } -int db_fini() { +int db_fini() +{ dbi_conn_close(conn); dbi_shutdown(); @@ -239,10 +244,10 @@ int db_fini() { return 0; } -struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi) +struct gsm_subscriber *db_create_subscriber(struct gsm_network *net, char *imsi) { dbi_result result; - struct gsm_subscriber* subscr; + struct gsm_subscriber *subscr; /* Is this subscriber known in the db? */ subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi); @@ -250,11 +255,10 @@ struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi) result = dbi_conn_queryf(conn, "UPDATE Subscriber set updated = datetime('now') " "WHERE imsi = %s " , imsi); - if (result==NULL) { + if (!result) printf("DB: failed to update timestamp\n"); - } else { + else dbi_result_free(result); - } return subscr; } @@ -269,9 +273,8 @@ struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi) "(%s, datetime('now'), datetime('now')) ", imsi ); - if (result==NULL) { + if (!result) printf("DB: Failed to create Subscriber by IMSI.\n"); - } subscr->net = net; subscr->id = dbi_conn_sequence_last(conn, NULL); strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1); @@ -456,7 +459,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, printf("DB: Unknown query selector for Subscriber.\n"); return NULL; } - if (result==NULL) { + if (!result) { printf("DB: Failed to query Subscriber.\n"); return NULL; } @@ -498,7 +501,8 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, return subscr; } -int db_sync_subscriber(struct gsm_subscriber* subscriber) { +int db_sync_subscriber(struct gsm_subscriber *subscriber) +{ dbi_result result; char tmsi[14]; char *q_tmsi; @@ -510,6 +514,7 @@ int db_sync_subscriber(struct gsm_subscriber* subscriber) { &q_tmsi); } else q_tmsi = strdup("NULL"); + result = dbi_conn_queryf(conn, "UPDATE Subscriber " "SET updated = datetime('now'), " @@ -524,14 +529,17 @@ int db_sync_subscriber(struct gsm_subscriber* subscriber) { subscriber->authorized, q_tmsi, subscriber->lac, - subscriber->imsi - ); + subscriber->imsi); + free(q_tmsi); - if (result==NULL) { + + if (!result) { printf("DB: Failed to update Subscriber (by IMSI).\n"); return 1; } + dbi_result_free(result); + return 0; } @@ -578,10 +586,12 @@ int db_sync_equipment(struct gsm_equipment *equip) return 0; } -int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) { - dbi_result result=NULL; +int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber) +{ + dbi_result result = NULL; char tmsi[14]; char* tmsi_quoted; + for (;;) { subscriber->tmsi = rand(); if (subscriber->tmsi == GSM_RESERVED_TMSI) @@ -592,14 +602,15 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) { result = dbi_conn_queryf(conn, "SELECT * FROM Subscriber " "WHERE tmsi = %s ", - tmsi_quoted - ); + tmsi_quoted); + free(tmsi_quoted); - if (result==NULL) { + + if (!result) { printf("DB: Failed to query Subscriber while allocating new TMSI.\n"); return 1; } - if (dbi_result_get_numrows(result)){ + if (dbi_result_get_numrows(result)) { dbi_result_free(result); continue; } @@ -613,9 +624,11 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) { return 0; } -int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) { - dbi_result result=NULL; +int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber) +{ + dbi_result result = NULL; u_int32_t try; + for (;;) { try = (rand()%(GSM_MAX_EXTEN-GSM_MIN_EXTEN+1)+GSM_MIN_EXTEN); result = dbi_conn_queryf(conn, @@ -623,7 +636,7 @@ int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) { "WHERE extension = %i", try ); - if (result==NULL) { + if (!result) { printf("DB: Failed to query Subscriber while allocating new extension.\n"); return 1; } @@ -647,7 +660,7 @@ int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) { * an error. */ -int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* token) +int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, u_int32_t *token) { dbi_result result; u_int32_t try; @@ -691,7 +704,8 @@ int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* toke return 0; } -int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IMEI_LENGTH]) { +int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IMEI_LENGTH]) +{ unsigned long long equipment_id, watch_id; dbi_result result; @@ -703,27 +717,27 @@ int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IM "(imei, created, updated) " "VALUES " "(%s, datetime('now'), datetime('now')) ", - imei - ); - if (result==NULL) { + imei); + if (!result) { printf("DB: Failed to create Equipment by IMEI.\n"); return 1; } + equipment_id = 0; if (dbi_result_get_numrows_affected(result)) { equipment_id = dbi_conn_sequence_last(conn, NULL); } dbi_result_free(result); - if (equipment_id) { + + if (equipment_id) printf("DB: New Equipment: ID %llu, IMEI %s\n", equipment_id, imei); - } else { result = dbi_conn_queryf(conn, "SELECT id FROM Equipment " "WHERE imei = %s ", imei ); - if (result==NULL) { + if (!result) { printf("DB: Failed to query Equipment by IMEI.\n"); return 1; } @@ -741,28 +755,26 @@ int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IM "(subscriber_id, equipment_id, created, updated) " "VALUES " "(%llu, %llu, datetime('now'), datetime('now')) ", - subscriber->id, equipment_id - ); - if (result==NULL) { + subscriber->id, equipment_id); + if (!result) { printf("DB: Failed to create EquipmentWatch.\n"); return 1; } + watch_id = 0; - if (dbi_result_get_numrows_affected(result)) { + if (dbi_result_get_numrows_affected(result)) watch_id = dbi_conn_sequence_last(conn, NULL); - } + dbi_result_free(result); - if (watch_id) { + if (watch_id) printf("DB: New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei); - } else { result = dbi_conn_queryf(conn, "UPDATE EquipmentWatch " "SET updated = datetime('now') " "WHERE subscriber_id = %llu AND equipment_id = %llu ", - subscriber->id, equipment_id - ); - if (result==NULL) { + subscriber->id, equipment_id); + if (!result) { printf("DB: Failed to update EquipmentWatch.\n"); return 1; } From ae1f159dc48a64e337eeb98269922169108d0ddf Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 11:39:14 +0100 Subject: [PATCH 189/365] Converrt the database later to use DEBUGP/LOGP instead of stderr --- openbsc/include/openbsc/debug.h | 1 + openbsc/src/db.c | 77 ++++++++++++++++++--------------- openbsc/src/debug.c | 2 + 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 129956d8e..a94be580e 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -26,6 +26,7 @@ enum { DMSC, DMGCP, DHO, + DDB, Debug_LastEntry, }; diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 3a261ac6d..57f86d6ea 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -143,7 +143,7 @@ void db_error_func(dbi_conn conn, void *data) { const char *msg; dbi_conn_error(conn, &msg); - printf("DBI: %s\n", msg); + LOGP(DDB, LOGL_ERROR, "DBI: %s\n", msg); } static int check_db_revision(void) @@ -176,7 +176,7 @@ int db_init(const char *name) conn = dbi_conn_new("sqlite3"); if (conn == NULL) { - printf("DB: Failed to create connection.\n"); + LOGP(DDB, LOGL_FATAL, "Failed to create connection.\n"); return 1; } @@ -217,14 +217,15 @@ int db_prepare() for (i = 0; i < ARRAY_SIZE(create_stmts); i++) { result = dbi_conn_query(conn, create_stmts[i]); if (!result) { - printf("DB: Failed to create some table.\n"); + LOGP(DDB, LOGL_ERROR, + "Failed to create some table.\n"); return 1; } dbi_result_free(result); } if (check_db_revision() < 0) { - fprintf(stderr, "Database schema revision invalid, " + LOGP(DDB, LOGL_FATAL, "Database schema revision invalid, " "please update your database schema\n"); return -1; } @@ -256,7 +257,7 @@ struct gsm_subscriber *db_create_subscriber(struct gsm_network *net, char *imsi) "UPDATE Subscriber set updated = datetime('now') " "WHERE imsi = %s " , imsi); if (!result) - printf("DB: failed to update timestamp\n"); + LOGP(DDB, LOGL_ERROR, "failed to update timestamp\n"); else dbi_result_free(result); return subscr; @@ -274,12 +275,12 @@ struct gsm_subscriber *db_create_subscriber(struct gsm_network *net, char *imsi) imsi ); if (!result) - printf("DB: Failed to create Subscriber by IMSI.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to create Subscriber by IMSI.\n"); subscr->net = net; subscr->id = dbi_conn_sequence_last(conn, NULL); strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1); dbi_result_free(result); - printf("DB: New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi); + LOGP(DDB, LOGL_NOTICE, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi); db_subscriber_alloc_exten(subscr); return subscr; } @@ -456,15 +457,15 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, free(quoted); break; default: - printf("DB: Unknown query selector for Subscriber.\n"); + LOGP(DDB, LOGL_NOTICE, "Unknown query selector for Subscriber.\n"); return NULL; } if (!result) { - printf("DB: Failed to query Subscriber.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber.\n"); return NULL; } if (!dbi_result_next_row(result)) { - printf("DB: Failed to find the Subscriber. '%u' '%s'\n", + DEBUGP(DDB, "Failed to find the Subscriber. '%u' '%s'\n", field, id); dbi_result_free(result); return NULL; @@ -491,7 +492,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, subscr->lac = dbi_result_get_uint(result, "lac"); subscr->authorized = dbi_result_get_uint(result, "authorized"); - printf("DB: Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n", + DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n", subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension, subscr->lac, subscr->authorized); dbi_result_free(result); @@ -534,7 +535,7 @@ int db_sync_subscriber(struct gsm_subscriber *subscriber) free(q_tmsi); if (!result) { - printf("DB: Failed to update Subscriber (by IMSI).\n"); + LOGP(DDB, LOGL_ERROR, "Failed to update Subscriber (by IMSI).\n"); return 1; } @@ -550,15 +551,15 @@ int db_sync_equipment(struct gsm_equipment *equip) u_int8_t classmark1; memcpy(&classmark1, &equip->classmark1, sizeof(classmark1)); - printf("DB: Sync Equipment IMEI=%s, classmark1=%02x", + DEBUGP(DDB, "Sync Equipment IMEI=%s, classmark1=%02x", equip->imei, classmark1); if (equip->classmark2_len) - printf(", classmark2=%s", + DEBUGPC(DDB, ", classmark2=%s", hexdump(equip->classmark2, equip->classmark2_len)); if (equip->classmark3_len) - printf(", classmark3=%s", + DEBUGPC(DDB, ", classmark3=%s", hexdump(equip->classmark3, equip->classmark3_len)); - printf("\n"); + DEBUGPC(DDB, "\n"); dbi_conn_quote_binary_copy(conn, equip->classmark2, equip->classmark2_len, &cm2); @@ -578,7 +579,7 @@ int db_sync_equipment(struct gsm_equipment *equip) free(cm3); if (!result) { - printf("DB: Failed to update Equipment\n"); + LOGP(DDB, LOGL_ERROR, "Failed to update Equipment\n"); return -EIO; } @@ -607,7 +608,8 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber) free(tmsi_quoted); if (!result) { - printf("DB: Failed to query Subscriber while allocating new TMSI.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber " + "while allocating new TMSI.\n"); return 1; } if (dbi_result_get_numrows(result)) { @@ -616,7 +618,8 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber) } if (!dbi_result_next_row(result)) { dbi_result_free(result); - printf("DB: Allocated TMSI %u for IMSI %s.\n", subscriber->tmsi, subscriber->imsi); + DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n", + subscriber->tmsi, subscriber->imsi); return db_sync_subscriber(subscriber); } dbi_result_free(result); @@ -637,7 +640,8 @@ int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber) try ); if (!result) { - printf("DB: Failed to query Subscriber while allocating new extension.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber " + "while allocating new extension.\n"); return 1; } if (dbi_result_get_numrows(result)){ @@ -651,7 +655,7 @@ int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber) dbi_result_free(result); } sprintf(subscriber->extension, "%i", try); - printf("DB: Allocated extension %i for IMSI %s.\n", try, subscriber->imsi); + DEBUGP(DDB, "Allocated extension %i for IMSI %s.\n", try, subscriber->imsi); return db_sync_subscriber(subscriber); } /* @@ -674,7 +678,8 @@ int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, u_int32_t *toke "WHERE subscriber_id = %llu OR token = \"%08X\" ", subscriber->id, try); if (!result) { - printf("DB: Failed to query AuthToken while allocating new token.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to query AuthToken " + "while allocating new token.\n"); return 1; } if (dbi_result_get_numrows(result)) { @@ -694,12 +699,13 @@ int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, u_int32_t *toke "(%llu, datetime('now'), \"%08X\") ", subscriber->id, try); if (!result) { - printf("DB: Failed to create token %08X for IMSI %s.\n", try, subscriber->imsi); + LOGP(DDB, LOGL_ERROR, "Failed to create token %08X for " + "IMSI %s.\n", try, subscriber->imsi); return 1; } dbi_result_free(result); *token = try; - printf("DB: Allocated token %08X for IMSI %s.\n", try, subscriber->imsi); + DEBUGP(DDB, "Allocated token %08X for IMSI %s.\n", try, subscriber->imsi); return 0; } @@ -719,7 +725,7 @@ int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IM "(%s, datetime('now'), datetime('now')) ", imei); if (!result) { - printf("DB: Failed to create Equipment by IMEI.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to create Equipment by IMEI.\n"); return 1; } @@ -730,7 +736,7 @@ int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IM dbi_result_free(result); if (equipment_id) - printf("DB: New Equipment: ID %llu, IMEI %s\n", equipment_id, imei); + DEBUGP(DDB, "New Equipment: ID %llu, IMEI %s\n", equipment_id, imei); else { result = dbi_conn_queryf(conn, "SELECT id FROM Equipment " @@ -738,11 +744,11 @@ int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IM imei ); if (!result) { - printf("DB: Failed to query Equipment by IMEI.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to query Equipment by IMEI.\n"); return 1; } if (!dbi_result_next_row(result)) { - printf("DB: Failed to find the Equipment.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to find the Equipment.\n"); dbi_result_free(result); return 1; } @@ -757,7 +763,7 @@ int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IM "(%llu, %llu, datetime('now'), datetime('now')) ", subscriber->id, equipment_id); if (!result) { - printf("DB: Failed to create EquipmentWatch.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to create EquipmentWatch.\n"); return 1; } @@ -767,7 +773,8 @@ int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IM dbi_result_free(result); if (watch_id) - printf("DB: New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei); + DEBUGP(DDB, "New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", + equipment_id, subscriber->imsi, imei); else { result = dbi_conn_queryf(conn, "UPDATE EquipmentWatch " @@ -775,11 +782,12 @@ int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IM "WHERE subscriber_id = %llu AND equipment_id = %llu ", subscriber->id, equipment_id); if (!result) { - printf("DB: Failed to update EquipmentWatch.\n"); + LOGP(DDB, LOGL_ERROR, "Failed to update EquipmentWatch.\n"); return 1; } dbi_result_free(result); - printf("DB: Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei); + DEBUGP(DDB, "Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", + equipment_id, subscriber->imsi, imei); } return 0; @@ -965,7 +973,7 @@ int db_sms_mark_sent(struct gsm_sms *sms) "SET sent = datetime('now') " "WHERE id = %llu", sms->id); if (!result) { - printf("DB: Failed to mark SMS %llu as sent.\n", sms->id); + LOGP(DDB, LOGL_ERROR, "Failed to mark SMS %llu as sent.\n", sms->id); return 1; } @@ -983,7 +991,8 @@ int db_sms_inc_deliver_attempts(struct gsm_sms *sms) "SET deliver_attempts = deliver_attempts + 1 " "WHERE id = %llu", sms->id); if (!result) { - printf("DB: Failed to inc deliver attempts for SMS %llu.\n", sms->id); + LOGP(DDB, LOGL_ERROR, "Failed to inc deliver attempts for " + "SMS %llu.\n", sms->id); return 1; } diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 8b0f25eb5..6d4d1b287 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -51,6 +51,7 @@ static struct debug_category default_categories[Debug_LastEntry] = { [DMSC] = { .enabled = 1, .loglevel = 0}, [DMGCP] = { .enabled = 1, .loglevel = 0}, [DHO] = { .enabled = 1, .loglevel = 0}, + [DDB] = { .enabled = 1, .loglevel = 0}, }; struct debug_info { @@ -93,6 +94,7 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DMSC, "DMSC", "", "") DEBUG_CATEGORY(DMGCP, "DMGCP", "", "") DEBUG_CATEGORY(DHO, "DHO", "", "") + DEBUG_CATEGORY(DDB, "DDB", "", "") }; /* From d0c19148ddbf4484aa55d7e738df1996555c5859 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 11:46:44 +0100 Subject: [PATCH 190/365] [debug] Introduce DREF debug category for reference counting --- openbsc/include/openbsc/debug.h | 1 + openbsc/include/openbsc/gsm_data.h | 4 ++-- openbsc/src/debug.c | 2 ++ openbsc/src/gsm_subscriber_base.c | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index a94be580e..f9c4afdbc 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -27,6 +27,7 @@ enum { DMGCP, DHO, DDB, + DREF, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index ff01d7287..af72e4765 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -101,14 +101,14 @@ typedef int gsm_cbfn(unsigned int hooknum, #define LCHAN_RELEASE_TIMEOUT 20, 0 #define use_lchan(lchan) \ do { lchan->use_count++; \ - DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \ + DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \ lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \ lchan->nr, lchan->use_count); \ bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0); #define put_lchan(lchan) \ do { lchan->use_count--; \ - DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \ + DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \ lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \ lchan->nr, lchan->use_count); \ } while(0); diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 6d4d1b287..1624e96a5 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -52,6 +52,7 @@ static struct debug_category default_categories[Debug_LastEntry] = { [DMGCP] = { .enabled = 1, .loglevel = 0}, [DHO] = { .enabled = 1, .loglevel = 0}, [DDB] = { .enabled = 1, .loglevel = 0}, + [DREF] = { .enabled = 0, .loglevel = 0}, }; struct debug_info { @@ -95,6 +96,7 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DMGCP, "DMGCP", "", "") DEBUG_CATEGORY(DHO, "DHO", "", "") DEBUG_CATEGORY(DDB, "DDB", "", "") + DEBUG_CATEGORY(DDB, "DREF", "", "") }; /* diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c index 48374eae5..0570061a2 100644 --- a/openbsc/src/gsm_subscriber_base.c +++ b/openbsc/src/gsm_subscriber_base.c @@ -137,7 +137,7 @@ static void subscr_free(struct gsm_subscriber *subscr) struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr) { subscr->use_count++; - DEBUGP(DCC, "subscr %s usage increases usage to: %d\n", + DEBUGP(DREF, "subscr %s usage increases usage to: %d\n", subscr->extension, subscr->use_count); return subscr; } @@ -145,7 +145,7 @@ struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr) struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr) { subscr->use_count--; - DEBUGP(DCC, "subscr %s usage decreased usage to: %d\n", + DEBUGP(DREF, "subscr %s usage decreased usage to: %d\n", subscr->extension, subscr->use_count); if (subscr->use_count <= 0) subscr_free(subscr); From 50720e76fea87423b2e31e4493e0af78f40e8342 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 11:50:20 +0100 Subject: [PATCH 191/365] 04_08: Differentiate between DEBUG and ERROR messages also, don't use stderr directly anymore --- openbsc/src/gsm_04_08_utils.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 2db46ca58..a85f20d6e 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -340,7 +340,7 @@ enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) if ((ra & chr->mask) == chr->val) return ctype_by_chreq[chr->type]; } - fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra); + LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra); return GSM_LCHAN_SDCCH; } @@ -363,7 +363,7 @@ enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, in if ((ra & chr->mask) == chr->val) return reason_by_chreq[chr->type]; } - fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra); + LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra); return GSM_CHREQ_REASON_OTHER; } @@ -475,7 +475,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr) if (!msg->lchan->subscr) { msg->lchan->subscr = subscr; } else if (msg->lchan->subscr != subscr) { - DEBUGP(DRR, "<- Channel already owned by someone else?\n"); + LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n"); subscr_put(subscr); return -EINVAL; } else { @@ -594,7 +594,8 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) /* in case of multi rate we need to attach a config */ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { if (lchan->mr_conf.ver == 0) { - DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n"); + LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec " + "without multirate config.\n"); } else { u_int8_t *data = msgb_put(msg, 4); data[0] = GSM48_IE_MUL_RATE_CFG; @@ -634,7 +635,8 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) /* in case of multi rate we need to attach a config */ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { if (lchan->mr_conf.ver == 0) { - DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n"); + LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec " + "without multirate config.\n"); } else { u_int8_t *data = msgb_put(msg, 4); data[0] = GSM48_IE_MUL_RATE_CFG; @@ -667,7 +669,7 @@ int gsm48_rx_rr_modif_ack(struct msgb *msg) DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n"); if (mod->mode != msg->lchan->tch_mode) { - DEBUGP(DRR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n", + LOGP(DRR, LOGL_ERROR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n", msg->lchan->tch_mode, mod->mode); return -1; } From 5d24ba1eb4808a534dab4153c121b902630eea11 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 12:13:17 +0100 Subject: [PATCH 192/365] don't print directly to stderr, use LOGP() --- openbsc/src/gsm_04_08.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 2b22122fb..6ab947043 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1405,7 +1405,7 @@ static int gsm0408_rcv_mm(struct msgb *msg) DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n"); break; default: - fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n", + LOGP(DMM, LOGL_NOTICE, "Unknown GSM 04.08 MM msg type 0x%02x\n", gh->msg_type); break; } @@ -1608,8 +1608,8 @@ static int gsm0408_rcv_rr(struct msgb *msg) rc = gsm48_rx_rr_ho_fail(msg); break; default: - fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n", - gh->msg_type); + LOGP(DRR, LOGL_NOTICE, "Unimplemented " + "GSM 04.08 RR msg type 0x%02x\n", gh->msg_type); break; } @@ -3510,15 +3510,15 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) break; case GSM48_PDISC_MM_GPRS: case GSM48_PDISC_SM_GPRS: - fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02x\n", - pdisc); + LOGP(DRLL, LOGL_NOTICE, "Unimplemented " + "GSM 04.08 discriminator 0x%02x\n", pdisc); break; case GSM48_PDISC_NC_SS: rc = handle_rcv_ussd(msg); break; default: - fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02x\n", - pdisc); + LOGP(DRLL, LOGL_NOTICE, "Unknown " + "GSM 04.08 discriminator 0x%02x\n", pdisc); break; } From 5b8ed4398ef5bf9c70384ce5e974844f07bfd921 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 12:20:20 +0100 Subject: [PATCH 193/365] [logging] differentiate DEBUG, NOTICE and ERROR log levels in NM and RSL --- openbsc/src/abis_nm.c | 28 ++++++------ openbsc/src/abis_rsl.c | 100 +++++++++++++++++++---------------------- 2 files changed, 59 insertions(+), 69 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index c99ffcfbb..f62356dcc 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1043,13 +1043,11 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) /* check if last message is to be acked */ if (is_ack_nack(nmh->last_msgtype)) { if (mt == MT_ACK(nmh->last_msgtype)) { - fprintf(stderr, "received ACK (0x%x)\n", - foh->msg_type); + DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type); /* we got our ACK, continue sending the next msg */ } else if (mt == MT_NACK(nmh->last_msgtype)) { /* we got a NACK, signal this to the caller */ - fprintf(stderr, "received NACK (0x%x)\n", - foh->msg_type); + DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type); /* FIXME: somehow signal this to the caller */ } else { /* really strange things happen */ @@ -2618,7 +2616,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) struct tlv_parsed tp; if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) { - DEBUGP(DNM, "id string is not com.ipaccess !?!\n"); + LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n"); return -EINVAL; } @@ -2646,7 +2644,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) DEBUGPC(DNM, "\n"); break; case NM_MT_IPACC_RSL_CONNECT_NACK: - DEBUGPC(DNM, "RSL CONNECT NACK "); + LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) DEBUGPC(DNM, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); @@ -2658,35 +2656,35 @@ static int abis_nm_rx_ipacc(struct msgb *msg) /* FIXME: decode and show the actual attributes */ break; case NM_MT_IPACC_SET_NVATTR_NACK: - DEBUGPC(DNM, "SET NVATTR NACK "); + LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else - DEBUGPC(DNM, "\n"); + LOGPC(DNM, LOGL_ERROR, "\n"); break; case NM_MT_IPACC_GET_NVATTR_ACK: DEBUGPC(DNM, "GET NVATTR ACK\n"); /* FIXME: decode and show the actual attributes */ break; case NM_MT_IPACC_GET_NVATTR_NACK: - DEBUGPC(DNM, "GET NVATTR NACK "); + LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else - DEBUGPC(DNM, "\n"); + LOGPC(DNM, LOGL_ERROR, "\n"); break; case NM_MT_IPACC_SET_ATTR_ACK: DEBUGPC(DNM, "SET ATTR ACK\n"); break; case NM_MT_IPACC_SET_ATTR_NACK: - DEBUGPC(DNM, "SET ATTR NACK "); + LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else - DEBUGPC(DNM, "\n"); + LOGPC(DNM, LOGL_ERROR, "\n"); break; default: DEBUGPC(DNM, "unknown\n"); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index d669ba06d..aa3127013 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -378,14 +378,14 @@ static const char *rsl_err_name(u_int8_t err) return "unknown"; } -static void print_rsl_cause(const u_int8_t *cause_v, u_int8_t cause_len) +static void print_rsl_cause(int lvl, const u_int8_t *cause_v, u_int8_t cause_len) { int i; - DEBUGPC(DRSL, "CAUSE=0x%02x(%s) ", + LOGPC(DRSL, lvl, "CAUSE=0x%02x(%s) ", cause_v[0], rsl_err_name(cause_v[0])); for (i = 1; i < cause_len-1; i++) - DEBUGPC(DRSL, "%02x ", cause_v[i]); + LOGPC(DRSL, lvl, "%02x ", cause_v[i]); } /* Send a BCCH_INFO message as per Chapter 8.5.1 */ @@ -721,8 +721,7 @@ int rsl_deact_sacch(struct gsm_lchan *lchan) msg->lchan = lchan; msg->trx = lchan->ts->trx; - DEBUGP(DRSL, "DEACTivate SACCH CMD channel=%s chan_nr=0x%02x\n", - gsm_ts_name(lchan->ts), dh->chan_nr); + DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_ts_name(lchan->ts)); return abis_rsl_sendmsg(msg); } @@ -740,8 +739,7 @@ int rsl_rf_chan_release(struct gsm_lchan *lchan) msg->lchan = lchan; msg->trx = lchan->ts->trx; - DEBUGP(DRSL, "RF Channel Release CMD channel=%s chan_nr=0x%02x\n", - gsm_ts_name(lchan->ts), dh->chan_nr); + DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_ts_name(lchan->ts)); /* BTS will respond by RF CHAN REL ACK */ return abis_rsl_sendmsg(msg); @@ -834,8 +832,8 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci) dh->chan_nr = lchan2chan_nr(lchan); msgb_tv_put(msg, RSL_IE_SIEMENS_MRPCI, *(u_int8_t *)mrpci); - DEBUGP(DRSL, "channel=%s chan_nr=0x%02x TX Siemens MRPCI 0x%02x\n", - gsm_ts_name(lchan->ts), dh->chan_nr, *(u_int8_t *)mrpci); + DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n", + gsm_ts_name(lchan->ts), *(u_int8_t *)mrpci); msg->trx = lchan->ts->trx; @@ -939,7 +937,7 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) - print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), + print_rsl_cause(LOGL_ERROR, TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); msg->lchan->state = LCHAN_S_NONE; @@ -962,7 +960,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) - print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), + print_rsl_cause(LOGL_NOTICE, TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); /* FIXME: only free it after channel release ACK */ @@ -1116,49 +1114,48 @@ static int abis_rsl_rx_dchan(struct msgb *msg) msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr); ts_name = gsm_ts_name(msg->lchan->ts); - if (rslh->c.msg_type != RSL_MT_MEAS_RES) - DEBUGP(DRSL, "channel=%s chan_nr=0x%02x ", ts_name, rslh->chan_nr); - switch (rslh->c.msg_type) { case RSL_MT_CHAN_ACTIV_ACK: - DEBUGPC(DRSL, "CHANNEL ACTIVATE ACK\n"); + DEBUGP(DRSL, "%s CHANNEL ACTIVATE ACK\n", ts_name); rc = rsl_rx_chan_act_ack(msg); break; case RSL_MT_CHAN_ACTIV_NACK: - DEBUGPC(DRSL, "CHANNEL ACTIVATE NACK\n"); + DEBUGP(DRSL, "%s CHANNEL ACTIVATE NACK\n", ts_name); rc = rsl_rx_chan_act_nack(msg); break; case RSL_MT_CONN_FAIL: + DEBUGP(DRSL, "%s ", ts_name); rc = rsl_rx_conn_fail(msg); break; case RSL_MT_MEAS_RES: rc = rsl_rx_meas_res(msg); break; case RSL_MT_HANDO_DET: + DEBUGP(DRSL, "%s ", ts_name); rc = rsl_rx_hando_det(msg); break; case RSL_MT_RF_CHAN_REL_ACK: - DEBUGPC(DRSL, "RF CHANNEL RELEASE ACK\n"); + DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name); msg->lchan->state = LCHAN_S_NONE; lchan_free(msg->lchan); break; case RSL_MT_MODE_MODIFY_ACK: - DEBUGPC(DRSL, "CHANNEL MODE MODIFY ACK\n"); + DEBUGP(DRSL, "%s CHANNEL MODE MODIFY ACK\n", ts_name); break; case RSL_MT_MODE_MODIFY_NACK: - DEBUGPC(DRSL, "CHANNEL MODE MODIFY NACK\n"); + LOGP(DRSL, LOGL_ERROR, "%s CHANNEL MODE MODIFY NACK\n", ts_name); break; case RSL_MT_IPAC_PDCH_ACT_ACK: - DEBUGPC(DRSL, "IPAC PDCH ACT ACK\n"); + DEBUGPC(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name); break; case RSL_MT_IPAC_PDCH_ACT_NACK: - DEBUGPC(DRSL, "IPAC PDCH ACT NACK\n"); + LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH ACT NACK\n", ts_name); break; case RSL_MT_IPAC_PDCH_DEACT_ACK: - DEBUGPC(DRSL, "IPAC PDCH DEACT ACK\n"); + DEBUGP(DRSL, "%s IPAC PDCH DEACT ACK\n", ts_name); break; case RSL_MT_IPAC_PDCH_DEACT_NACK: - DEBUGPC(DRSL, "IPAC PDCH DEACT NACK\n"); + LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH DEACT NACK\n", ts_name); break; case RSL_MT_PHY_CONTEXT_CONF: case RSL_MT_PREPROC_MEAS_RES: @@ -1168,12 +1165,12 @@ static int abis_rsl_rx_dchan(struct msgb *msg) case RSL_MT_MR_CODEC_MOD_ACK: case RSL_MT_MR_CODEC_MOD_NACK: case RSL_MT_MR_CODEC_MOD_PER: - DEBUGPC(DRSL, "Unimplemented Abis RSL DChan msg 0x%02x\n", - rslh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "%s Unimplemented Abis RSL DChan " + "msg 0x%02x\n", ts_name, rslh->c.msg_type); break; default: - DEBUGPC(DRSL, "unknown Abis RSL DChan msg 0x%02x\n", - rslh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "%s unknown Abis RSL DChan msg 0x%02x\n", + ts_name, rslh->c.msg_type); return -EINVAL; } @@ -1190,7 +1187,7 @@ static int rsl_rx_error_rep(struct msgb *msg) rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh)); if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) - print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), + print_rsl_cause(LOGL_ERROR, TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); LOGPC(DRSL, LOGL_ERROR, "\n"); @@ -1216,8 +1213,8 @@ static int abis_rsl_rx_trx(struct msgb *msg) LOGP(DRSL, LOGL_ERROR, "TRX: CCCH/ACCH/CPU Overload\n"); break; default: - DEBUGP(DRSL, "Unknown Abis RSL TRX message type 0x%02x\n", - rslh->msg_type); + LOGP(DRSL, LOGL_NOTICE, "Unknown Abis RSL TRX message " + "type 0x%02x\n", rslh->msg_type); return -EINVAL; } return rc; @@ -1268,7 +1265,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { - DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", + LOGP(DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x\n", gsm_lchan_name(lctype), rqd_ref->ra); counter_inc(bts->network->stats.chreq.no_channel); /* FIXME: send some kind of reject ?!? */ @@ -1302,10 +1299,9 @@ static int rsl_rx_chan_rqd(struct msgb *msg) ia.timing_advance = rqd_ta; ia.mob_alloc_len = 0; - DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %s " - "chan_nr=0x%02x r=%s ra=0x%02x\n", - arfcn, ts_number, subch, gsm_lchan_name(lchan->type), - ia.chan_desc.chan_nr, gsm_chreq_name(chreq_reason), + DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s " + "r=%s ra=0x%02x\n", gsm_ts_name(lchan->ts), arfcn, subch, + gsm_lchan_name(lchan->type), gsm_chreq_name(chreq_reason), rqd_ref->ra); /* Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */ @@ -1409,8 +1405,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr); ts_name = gsm_ts_name(msg->lchan->ts); - DEBUGP(DRLL, "channel=%s chan_nr=0x%02x sapi=%u ", ts_name, - rllh->chan_nr, sapi); + DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi); switch (rllh->c.msg_type) { case RSL_MT_DATA_IND: @@ -1580,9 +1575,8 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); - DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND " - "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), - dh->chan_nr, lchan->abis_ip.speech_mode); + DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x\n", + gsm_ts_name(lchan->ts), lchan->abis_ip.speech_mode); msg->trx = lchan->ts->trx; @@ -1611,9 +1605,8 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); ia.s_addr = htonl(ip); - DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_MDCX " - "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d speech_mode=0x%02x\n", - gsm_ts_name(lchan->ts), dh->chan_nr, inet_ntoa(ia), port, + DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d " + "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), inet_ntoa(ia), port, rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode); msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id); @@ -1654,8 +1647,7 @@ int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan) dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN; dh->chan_nr = lchan2chan_nr(lchan); - DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_PDCH_ACT\n", - gsm_ts_name(lchan->ts), dh->chan_nr); + DEBUGP(DRSL, "%s IPAC_PDCH_ACT\n", gsm_ts_name(lchan->ts)); msg->trx = lchan->ts->trx; @@ -1736,7 +1728,7 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (TLVP_PRESENT(&tv, RSL_IE_CAUSE)) - print_rsl_cause(TLVP_VAL(&tv, RSL_IE_CAUSE), + print_rsl_cause(LOGL_DEBUG, TLVP_VAL(&tv, RSL_IE_CAUSE), TLVP_LEN(&tv, RSL_IE_CAUSE)); /* the BTS tells us a RTP stream has been disconnected */ @@ -1753,38 +1745,38 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) static int abis_rsl_rx_ipacc(struct msgb *msg) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + char *ts_name; int rc = 0; msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr); - DEBUGP(DRSL, "channel=%s chan_nr=0x%02x ", - gsm_ts_name(msg->lchan->ts), rllh->chan_nr); + ts_name = gsm_ts_name(msg->lchan->ts); switch (rllh->c.msg_type) { case RSL_MT_IPAC_CRCX_ACK: - DEBUGPC(DRSL, "IPAC_CRCX_ACK "); + DEBUGP(DRSL, "%s IPAC_CRCX_ACK ", ts_name); rc = abis_rsl_rx_ipacc_crcx_ack(msg); break; case RSL_MT_IPAC_CRCX_NACK: /* somehow the BTS was unable to bind the lchan to its local * port?!? */ - DEBUGPC(DRSL, "IPAC_CRCX_NACK "); + LOGP(DRSL, LOGL_ERROR, "%s IPAC_CRCX_NACK\n", ts_name); break; case RSL_MT_IPAC_MDCX_ACK: /* the BTS tells us that a connect operation was successful */ - DEBUGPC(DRSL, "IPAC_MDCX_ACK "); + DEBUGP(DRSL, "%s IPAC_MDCX_ACK ", ts_name); rc = abis_rsl_rx_ipacc_mdcx_ack(msg); break; case RSL_MT_IPAC_MDCX_NACK: /* somehow the BTS was unable to connect the lchan to a remote * port */ - DEBUGPC(DRSL, "IPAC_MDCX_NACK "); + LOGP(DRSL, LOGL_ERROR, "%s IPAC_MDCX_NACK\n", ts_name); break; case RSL_MT_IPAC_DLCX_IND: - DEBUGPC(DRSL, "IPAC_DLCX_IND "); + DEBUGP(DRSL, "%s IPAC_DLCX_IND ", ts_name); rc = abis_rsl_rx_ipacc_dlcx_ind(msg); break; default: - LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x", + LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x\n", rllh->c.msg_type); break; } From da956931fab20413f658961d6aab798336acf2d7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 12:49:43 +0100 Subject: [PATCH 194/365] if we recv() from an abis-ip socket, don't consider -EAGAIN an error --- openbsc/src/input/ipaccess.c | 3 ++- openbsc/src/ipaccess/ipaccess-proxy.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 2f79a6b1b..4396269db 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -270,7 +270,8 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) hh = (struct ipaccess_head *) msg->data; ret = recv(bfd->fd, msg->data, 3, 0); if (ret < 0) { - LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno)); + if (ret != -EAGAIN) + LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno)); msgb_free(msg); *error = ret; return NULL; diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c index dd9d6b1b5..61c3c5b75 100644 --- a/openbsc/src/ipaccess/ipaccess-proxy.c +++ b/openbsc/src/ipaccess/ipaccess-proxy.c @@ -321,7 +321,8 @@ static int handle_udp_read(struct bsc_fd *bfd) hh = (struct ipaccess_head *) msg->data; ret = recv(bfd->fd, msg->data, msg->data_len, 0); if (ret < 0) { - DEBUGP(DINP, "recv error %s\n", strerror(errno)); + if (ret != -EAGAIN) + DEBUGP(DINP, "recv error %s\n", strerror(errno)); msgb_free(msg); return ret; } @@ -634,7 +635,8 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) hh = (struct ipaccess_head *) msg->data; ret = recv(bfd->fd, msg->data, 3, 0); if (ret < 0) { - LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno)); + if (ret != -EAGAIN) + LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno)); msgb_free(msg); *error = ret; return NULL; From e98d4278d0cf87c8e2345900d612bbbb607635a0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 13:27:02 +0100 Subject: [PATCH 195/365] [handover] CRCX ACK without HO reference is normal, not an error --- openbsc/src/handover_logic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 5297ab6ca..20eeb66ce 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -280,8 +280,8 @@ static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan) ho = bsc_ho_by_new_lchan(new_lchan); if (!ho) { - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); - return -ENODEV; + /* it is perfectly normal, we have CRCX even in non-HO cases */ + return 0; } if (ipacc_rtp_direct) { From fb33957405ea342ef81d307e1da983cedc5f1960 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 13:35:18 +0100 Subject: [PATCH 196/365] properly check for EAGAIN in recv() calls If recv() has no more messages on a non-blocking socket, errno will be EAGAIN, not the return value! --- openbsc/src/input/ipaccess.c | 4 ++-- openbsc/src/ipaccess/ipaccess-proxy.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 4396269db..c72176657 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -270,8 +270,8 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) hh = (struct ipaccess_head *) msg->data; ret = recv(bfd->fd, msg->data, 3, 0); if (ret < 0) { - if (ret != -EAGAIN) - LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno)); + if (errno != EAGAIN) + LOGP(DINP, LOGL_ERROR, "recv error %d %s\n", ret, strerror(errno)); msgb_free(msg); *error = ret; return NULL; diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c index 61c3c5b75..d018b6ebd 100644 --- a/openbsc/src/ipaccess/ipaccess-proxy.c +++ b/openbsc/src/ipaccess/ipaccess-proxy.c @@ -321,8 +321,8 @@ static int handle_udp_read(struct bsc_fd *bfd) hh = (struct ipaccess_head *) msg->data; ret = recv(bfd->fd, msg->data, msg->data_len, 0); if (ret < 0) { - if (ret != -EAGAIN) - DEBUGP(DINP, "recv error %s\n", strerror(errno)); + if (errno != EAGAIN) + LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno)); msgb_free(msg); return ret; } @@ -635,7 +635,7 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) hh = (struct ipaccess_head *) msg->data; ret = recv(bfd->fd, msg->data, 3, 0); if (ret < 0) { - if (ret != -EAGAIN) + if (errno != EAGAIN) LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno)); msgb_free(msg); *error = ret; From 19a3f0b12092598fd590c6c3fb8606dfffe332cd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 13:39:34 +0100 Subject: [PATCH 197/365] print ARFCN, LAC and CID when bootstrapping RSL --- openbsc/src/bsc_init.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 58cdafe7b..cc4a75b5b 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -754,9 +754,10 @@ static void patch_nm_tables(struct gsm_bts *bts) static void bootstrap_rsl(struct gsm_bts_trx *trx) { LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) " - "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", - trx->bts->nr, trx->nr, bsc_gsmnet->country_code, - bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc); + "on ARFCN %u using MCC=%u MNC=%u LAC=%u CID=%u BSIC=%u TSC=%u\n", + trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code, + bsc_gsmnet->network_code, trx->bts->location_area_code, + trx->bts->cell_identity, trx->bts->bsic, trx->bts->tsc); set_system_infos(trx); } From 77563daf79c5ec9640fc658f4c7365b5bd4ae134 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 13:48:14 +0100 Subject: [PATCH 198/365] Add LOGL_INFO messages about subscriber attach/detach --- openbsc/src/gsm_subscriber.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c index c81b522d4..74ec983a3 100644 --- a/openbsc/src/gsm_subscriber.c +++ b/openbsc/src/gsm_subscriber.c @@ -100,12 +100,15 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) s->net = bts->network; /* Indicate "attached to LAC" */ s->lac = bts->location_area_code; + LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n", + s->imsi, s->lac); dispatch_signal(SS_SUBSCR, S_SUBSCR_ATTACHED, s); break; case GSM_SUBSCRIBER_UPDATE_DETACHED: /* Only detach if we are currently in this area */ if (bts->location_area_code == s->lac) s->lac = GSM_LAC_RESERVED_DETACHED; + LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", s->imsi); dispatch_signal(SS_SUBSCR, S_SUBSCR_DETACHED, s); break; default: From 8410597dd739d4cd91b3152aa9c921ba9678307f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 13:48:33 +0100 Subject: [PATCH 199/365] [debug] Change the default log level to LOGL_NOTICE This marks the departure from printing all the debug messages to the console by default. We only print NOTICE and WARNING level messages by default If you're interested in more details, you need to enable it via command line options or the VTY --- openbsc/src/debug.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 1624e96a5..1aad1336d 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -33,26 +33,26 @@ /* default categories */ static struct debug_category default_categories[Debug_LastEntry] = { - [DRLL] = { .enabled = 1, .loglevel = 0}, - [DCC] = { .enabled = 1, .loglevel = 0}, - [DNM] = { .enabled = 1, .loglevel = 0}, - [DRR] = { .enabled = 1, .loglevel = 0}, - [DRSL] = { .enabled = 1, .loglevel = 0}, - [DMM] = { .enabled = 1, .loglevel = 0}, - [DMNCC] = { .enabled = 1, .loglevel = 0}, - [DSMS] = { .enabled = 1, .loglevel = 0}, - [DPAG] = { .enabled = 1, .loglevel = 0}, - [DMEAS] = { .enabled = 0, .loglevel = 0}, - [DMI] = { .enabled = 0, .loglevel = 0}, - [DMIB] = { .enabled = 0, .loglevel = 0}, - [DMUX] = { .enabled = 1, .loglevel = 0}, - [DINP] = { .enabled = 1, .loglevel = 0}, - [DSCCP] = { .enabled = 1, .loglevel = 0}, - [DMSC] = { .enabled = 1, .loglevel = 0}, - [DMGCP] = { .enabled = 1, .loglevel = 0}, - [DHO] = { .enabled = 1, .loglevel = 0}, - [DDB] = { .enabled = 1, .loglevel = 0}, - [DREF] = { .enabled = 0, .loglevel = 0}, + [DRLL] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DCC] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DNM] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DRR] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DRSL] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DMM] = { .enabled = 1, .loglevel = LOGL_INFO }, + [DMNCC] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DSMS] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DPAG] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DMEAS] = { .enabled = 0, .loglevel = LOGL_NOTICE }, + [DMI] = { .enabled = 0, .loglevel = LOGL_NOTICE }, + [DMIB] = { .enabled = 0, .loglevel = LOGL_NOTICE }, + [DMUX] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DINP] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DSCCP] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DMSC] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DMGCP] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DHO] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DDB] = { .enabled = 1, .loglevel = LOGL_NOTICE }, + [DREF] = { .enabled = 0, .loglevel = LOGL_NOTICE }, }; struct debug_info { From 844eab1df5fd6d09ec56f21ba59df910af8c8579 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 14:49:07 +0100 Subject: [PATCH 200/365] rsl: fix "CONNECTION FAIL: RELEASING" message --- openbsc/src/abis_rsl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index aa3127013..86f458f40 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -955,7 +955,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct tlv_parsed tp; /* FIXME: print which channel */ - LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING\n"); + LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING"); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -963,6 +963,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) print_rsl_cause(LOGL_NOTICE, TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); + LOGP(DRSL, LOGL_NOTICE, "\n"); /* FIXME: only free it after channel release ACK */ return rsl_rf_chan_release(msg->lchan); } From 2e6d4684ffd9bb908b6e9e2d16d669f8bb91d899 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 14:50:24 +0100 Subject: [PATCH 201/365] add (and use) new subscr_name() function to get name or IMSI --- openbsc/include/openbsc/gsm_subscriber.h | 2 ++ openbsc/src/gsm_04_08.c | 5 ++--- openbsc/src/gsm_subscriber.c | 12 ++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index d612ed566..c639f4046 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -86,6 +86,8 @@ void subscr_put_channel(struct gsm_lchan *lchan); void subscr_get_channel(struct gsm_subscriber *subscr, int type, gsm_cbfn *cbfn, void *param); +char *subscr_name(struct gsm_subscriber *subscr); + /* internal */ struct gsm_subscriber *subscr_alloc(void); extern struct llist_head active_subscribers; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 6ab947043..982870ba1 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1341,8 +1341,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) if (subscr) { subscr_update(subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_DETACHED); - DEBUGP(DMM, "Subscriber: %s\n", - subscr->name ? subscr->name : subscr->imsi); + DEBUGP(DMM, "Subscriber: %s\n", subscr_name(subscr)); subscr->equipment.classmark1 = idi->classmark1; db_sync_equipment(&subscr->equipment); @@ -1392,7 +1391,7 @@ static int gsm0408_rcv_mm(struct msgb *msg) case GSM48_MT_MM_TMSI_REALL_COMPL: DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n", msg->lchan->subscr ? - msg->lchan->subscr->imsi : + subscr_name(msg->lchan->subscr) : "unknown subscriber"); break; case GSM48_MT_MM_IMSI_DETACH_IND: diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c index 74ec983a3..692508753 100644 --- a/openbsc/src/gsm_subscriber.c +++ b/openbsc/src/gsm_subscriber.c @@ -34,6 +34,14 @@ extern struct llist_head *subscr_bsc_active_subscriber(void); +char *subscr_name(struct gsm_subscriber *subscr) +{ + if (strlen(subscr->name)) + return subscr->name; + + return subscr->imsi; +} + struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net, u_int32_t tmsi) { @@ -101,14 +109,14 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) /* Indicate "attached to LAC" */ s->lac = bts->location_area_code; LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n", - s->imsi, s->lac); + subscr_name(s), s->lac); dispatch_signal(SS_SUBSCR, S_SUBSCR_ATTACHED, s); break; case GSM_SUBSCRIBER_UPDATE_DETACHED: /* Only detach if we are currently in this area */ if (bts->location_area_code == s->lac) s->lac = GSM_LAC_RESERVED_DETACHED; - LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", s->imsi); + LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", subscr_name(s)); dispatch_signal(SS_SUBSCR, S_SUBSCR_DETACHED, s); break; default: From d0cf7ba687e99a46eabbfe0685cf7fd8f09c8a94 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 24 Dec 2009 15:08:18 +0100 Subject: [PATCH 202/365] introduce multiple log levels (DEBUG/INFO/NOTICE/ERROR) to SMS code --- openbsc/src/gsm_04_11.c | 71 +++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index d5b011609..4f19e2ce7 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -215,7 +215,8 @@ static u_int8_t unbcdify(u_int8_t value) u_int8_t ret; if ((value & 0x0F) > 9 || (value >> 4) > 9) - DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); + LOGP(DSMS, LOGL_ERROR, + "unbcdify got too big nibble: 0x%02X\n", value); ret = (value&0x0F)*10; ret += value>>4; @@ -311,7 +312,8 @@ static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp) unsigned long minutes; vp = *(sms_vp); if (vp == 0) { - DEBUGP(DSMS, "reserved relative_integer validity period\n"); + LOGP(DSMS, LOGL_ERROR, + "reserved relative_integer validity period\n"); return gsm340_vp_default(); } minutes = vp/60; @@ -356,7 +358,8 @@ static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) default: /* The GSM spec says that the SC should reject any unsupported and/or undefined values. FIXME */ - DEBUGP(DSMS, "Reserved enhanced validity period format\n"); + LOGP(DSMS, LOGL_ERROR, + "Reserved enhanced validity period format\n"); return gsm340_vp_default(); } case GSM340_TP_VPF_NONE: @@ -373,7 +376,8 @@ enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs) if ((cgbits & 0xc) == 0) { if (cgbits & 2) - DEBUGP(DSMS, "Compressed SMS not supported yet\n"); + LOGP(DSMS, LOGL_NOTICE, + "Compressed SMS not supported yet\n"); switch ((dcs >> 2)&0x03) { case 0: @@ -403,7 +407,7 @@ enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs) static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms) { if (db_sms_store(gsms) != 0) { - DEBUGP(DSMS, "Failed to store SMS in Database\n"); + LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n"); return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; } /* dispatch a signal to tell higher level about it */ @@ -497,7 +501,8 @@ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms) memcpy(smsp, sms->user_data, sms->user_data_len); break; default: - DEBUGP(DSMS, "Unhandled Data Coding Scheme: 0x%02X\n", sms->data_coding_scheme); + LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n", + sms->data_coding_scheme); break; } @@ -537,7 +542,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) /* length in bytes of the destination address */ da_len_bytes = 2 + *smsp/2 + *smsp%2; if (da_len_bytes > 12) { - DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n"); + LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n"); rc = GSM411_RP_CAUSE_SEMANT_INC_MSG; goto out; } @@ -570,8 +575,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) sms_vp = 0; break; default: - DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n", - sms_vpf); + LOGP(DSMS, LOGL_NOTICE, + "SMS Validity period not implemented: 0x%02x\n", sms_vpf); return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; } gsms->user_data_len = *smsp++; @@ -589,16 +594,17 @@ static int gsm340_rx_tpdu(struct msgb *msg) } } - DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x " - "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x " - "UserData: \"%s\"\n", sms_mti, sms_vpf, gsms->msg_ref, - gsms->protocol_id, gsms->data_coding_scheme, - gsms->dest_addr, gsms->user_data_len, + gsms->sender = subscr_get(msg->lchan->subscr); + + LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, " + "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, " + "UserDataLength: 0x%02x, UserData: \"%s\"\n", + subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref, + gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr, + gsms->user_data_len, sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text : hexdump(gsms->user_data, gsms->user_data_len)); - gsms->sender = subscr_get(msg->lchan->subscr); - gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp); dispatch_signal(SS_SMS, 0, gsms); @@ -618,11 +624,11 @@ static int gsm340_rx_tpdu(struct msgb *msg) break; case GSM340_SMS_COMMAND_MS2SC: case GSM340_SMS_DELIVER_REP_MS2SC: - DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms_mti); + LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti); rc = GSM411_RP_CAUSE_IE_NOTEXIST; break; default: - DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms_mti); + LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti); rc = GSM411_RP_CAUSE_IE_NOTEXIST; break; } @@ -652,7 +658,7 @@ static int gsm411_send_rp_error(struct gsm_trans *trans, msgb_tv_put(msg, 1, cause); - DEBUGP(DSMS, "TX: SMS RP ERROR, cause %d (%s)\n", cause, + LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause, get_value_string(rp_cause_strs, cause)); return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref); @@ -668,10 +674,11 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans, int rc = 0; if (src_len && src) - DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n"); + LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n"); if (!dst_len || !dst || !tpdu_len || !tpdu) { - DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n"); + LOGP(DSMS, LOGL_ERROR, + "RP-DATA (MO) without DST or TPDU ?!?\n"); gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_INV_MAND_INF); return -EIO; @@ -726,13 +733,13 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, * transmitted */ if (!trans->sms.is_mt) { - DEBUGP(DSMS, "RX RP-ACK on a MO transfer ?\n"); + LOGP(DSMS, LOGL_ERROR, "RX RP-ACK on a MO transfer ?\n"); return gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_MSG_INCOMP_STATE); } if (!sms) { - DEBUGP(DSMS, "RX RP-ACK but no sms in transaction?!?\n"); + LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n"); return gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_PROTOCOL_ERR); } @@ -770,11 +777,12 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, * successfully receive the SMS. We need to investigate * the cause and take action depending on it */ - DEBUGP(DSMS, "RX SMS RP-ERROR, cause %d:%d (%s)\n", cause_len, cause, - get_value_string(rp_cause_strs, cause)); + LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n", + subscr_name(msg->lchan->subscr), cause_len, cause, + get_value_string(rp_cause_strs, cause)); if (!trans->sms.is_mt) { - DEBUGP(DSMS, "RX RP-ERR on a MO transfer ?\n"); + LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n"); #if 0 return gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_MSG_INCOMP_STATE); @@ -782,7 +790,8 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, } if (!sms) { - DEBUGP(DSMS, "RX RP-ERR, but no sms in transaction?!?\n"); + LOGP(DSMS, LOGL_ERROR, + "RX RP-ERR, but no sms in transaction?!?\n"); return -EINVAL; #if 0 return gsm411_send_rp_error(trans, rph->msg_ref, @@ -859,7 +868,7 @@ static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh, rc = gsm411_rx_rp_error(msg, trans, rp_data); break; default: - DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type); + LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type); rc = gsm411_send_rp_error(trans, rp_data->msg_ref, GSM411_RP_CAUSE_MSGTYPE_NOTEXIST); break; @@ -890,7 +899,7 @@ static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause) struct msgb *msg = gsm411_msgb_alloc(); u_int8_t *causep; - DEBUGP(DSMS, "TX CP-ERROR, cause %d (%s)\n", cause, + LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause, get_value_string(cp_cause_strs, cause)); causep = msgb_put(msg, 1); @@ -1014,7 +1023,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0); if (transaction_id == -1) { - DEBUGP(DSMS, "No available transaction ids\n"); + LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n"); return -EBUSY; } @@ -1026,7 +1035,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { - DEBUGP(DSMS, "No memory for trans\n"); + LOGP(DSMS, LOGL_ERROR, "No memory for trans\n"); /* FIXME: send some error message */ return -ENOMEM; } From 926fcecc2ddc78aee4305d50972d01906b96756c Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 13:26:17 +0100 Subject: [PATCH 203/365] transaction: Change id allocator method to be 'circular' The idea is to find the highest used id and try to get the next. This way when there are transactions back to back with an overlap, we go 0 1 2 3 4 5 6 0 1 2 ... Signed-off-by: Sylvain Munaut --- openbsc/src/transaction.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index e49f75b28..c972037be 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -119,7 +119,7 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, struct gsm_network *net = subscr->net; struct gsm_trans *trans; unsigned int used_tid_bitmask = 0; - int i; + int i, j, h; if (ti_flag) ti_flag = 0x8; @@ -133,9 +133,14 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, used_tid_bitmask |= (1 << trans->transaction_id); } + /* find a new one, trying to go in a 'circular' pattern */ + for (h = 6; h > 0; h--) + if (used_tid_bitmask & (1 << (h | ti_flag))) + break; for (i = 0; i < 7; i++) { - if ((used_tid_bitmask & (1 << (i | ti_flag))) == 0) - return i | ti_flag; + j = ((h + i) % 7) | ti_flag; + if ((used_tid_bitmask & (1 << j)) == 0) + return j; } return -1; From c4052cf9a8c9c9cf3d376db9712b465019779083 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 13:27:36 +0100 Subject: [PATCH 204/365] gsm_04_11: In gsm411_send_sms_lchan fix transaction id error handling We need transaction_id to be a int (as returned by trans_assign_trans_id) to detect the error condition -1. Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 4f19e2ce7..d4572ca18 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -1018,7 +1018,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) struct gsm_trans *trans; u_int8_t *data, *rp_ud_len; u_int8_t msg_ref = 42; - u_int8_t transaction_id; + int transaction_id; int rc; transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0); From d6c35f6e8aee512830dac4792a3fbed4853349bb Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 13:33:51 +0100 Subject: [PATCH 205/365] gsm_04_11: Release SMS transaction only after starting next one. This ensures that we don't re-use the same transaction ID. Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index d4572ca18..c3a49f399 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -752,14 +752,16 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, sms_free(sms); trans->sms.sms = NULL; - /* free the transaction here */ - trans_free(trans); - /* check for more messages for this subscriber */ sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr); if (sms) gsm411_send_sms_lchan(msg->lchan, sms); - else + + /* free the transaction here */ + trans_free(trans); + + /* release channel if done */ + if (!sms) rsl_release_request(msg->lchan, trans->sms.link_id); return 0; From 42a5652eb2032e1d7df19278b9e353f9cb40c7b4 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 14:20:19 +0100 Subject: [PATCH 206/365] system_information: Fix BCCH Allocation when only 1 BTS present The current code used the variable bitmap format, but that's not possible since in this format the base ARFCN is part of the set. That lead to a neighbor list containing ARFCN 0. Signed-off-by: Sylvain Munaut --- openbsc/src/system_information.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index df4f1a0c8..6493794ef 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -98,7 +98,7 @@ static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, const struct gsm_bts *bts) { - int i, rc, min = 1024, max = 0; + int i, rc, min = 1024, max = -1; memset(chan_list, 0, 16); @@ -128,6 +128,12 @@ static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, } } + if (max == -1) { + /* Empty set, use 'bit map 0 format' */ + chan_list[0] = 0; + return 0; + } + if ((max - min) > 111) { LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, " "distance > 111\n", min, max); From 469b001b19d9fe63836f189e9e7a6461971b1bc6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Dec 2009 22:42:15 +0100 Subject: [PATCH 207/365] [meas rep] Correctly parse neighbor cell index of first reported neighbor cell --- openbsc/src/gsm_04_08_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index a85f20d6e..cda72797c 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -733,7 +733,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) /* an encoding nightmare in perfection */ rep->cell[0].rxlev = data[3] & 0x3f; - rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); + rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 3); rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; From a06c35e9e3f365e2b8e811a62870f0330dd7fc4e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Dec 2009 22:46:25 +0100 Subject: [PATCH 208/365] [meas rep] cosmetic cleanup --- openbsc/src/gsm_04_08_utils.c | 44 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index cda72797c..9813edba5 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -710,6 +710,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) u_int8_t *data = gh->data; struct gsm_bts *bts = msg->lchan->ts->trx->bts; struct bitvec *nbv = &bts->si_common.neigh_list; + struct gsm_meas_rep_cell *mrc; if (gh->msg_type != GSM48_MT_RR_MEAS_REP) return -EINVAL; @@ -731,42 +732,47 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) return 0; /* an encoding nightmare in perfection */ - - rep->cell[0].rxlev = data[3] & 0x3f; - rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 3); - rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); + mrc = &rep->cell[0]; + mrc->rxlev = data[3] & 0x3f; + mrc->arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 3); + mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; - rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); - rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); - rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); + mrc = &rep->cell[1]; + mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); + mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); if (rep->num_cell < 3) return 0; - rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); - rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); - rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); + mrc = &rep->cell[2]; + mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); + mrc->bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); if (rep->num_cell < 4) return 0; - rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); - rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); - rep->cell[3].bsic = data[11] >> 2; + mrc = &rep->cell[3]; + mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); + mrc->bsic = data[11] >> 2; if (rep->num_cell < 5) return 0; - rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); - rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, + mrc = &rep->cell[4]; + mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, ((data[12] & 0xf) << 1) | (data[13] >> 7)); - rep->cell[4].bsic = (data[13] >> 1) & 0x3f; + mrc->bsic = (data[13] >> 1) & 0x3f; if (rep->num_cell < 6) return 0; - rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); - rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, + mrc = &rep->cell[5]; + mrc-> rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, ((data[14] & 0x07) << 2) | (data[15] >> 6)); - rep->cell[5].bsic = data[15] & 0x3f; + mrc->bsic = data[15] & 0x3f; return 0; } From 950eca9b761ddb2ed8f7af142094d9fac64f30df Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Dec 2009 22:49:34 +0100 Subject: [PATCH 209/365] [meas_rep] Add raw neighbor index into per-cell parsed meas rep --- openbsc/include/openbsc/meas_rep.h | 1 + openbsc/src/gsm_04_08_utils.c | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/openbsc/include/openbsc/meas_rep.h b/openbsc/include/openbsc/meas_rep.h index fd5fced43..3c2c8d1c1 100644 --- a/openbsc/include/openbsc/meas_rep.h +++ b/openbsc/include/openbsc/meas_rep.h @@ -7,6 +7,7 @@ struct gsm_meas_rep_cell { u_int8_t rxlev; u_int8_t bsic; + u_int8_t neigh_idx; u_int16_t arfcn; unsigned int flags; }; diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 9813edba5..04440390a 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -734,44 +734,48 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) /* an encoding nightmare in perfection */ mrc = &rep->cell[0]; mrc->rxlev = data[3] & 0x3f; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 3); + mrc->neigh_idx = data[4] >> 3; + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; mrc = &rep->cell[1]; mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); + mrc->neigh_idx = (data[6] >> 2) & 0x1f; + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); if (rep->num_cell < 3) return 0; mrc = &rep->cell[2]; mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); + mrc->neigh_idx = (data[8] >> 1) & 0x1f; + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); mrc->bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); if (rep->num_cell < 4) return 0; mrc = &rep->cell[3]; mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); + mrc->neigh_idx = data[10] & 0x1f; + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); mrc->bsic = data[11] >> 2; if (rep->num_cell < 5) return 0; mrc = &rep->cell[4]; mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, - ((data[12] & 0xf) << 1) | (data[13] >> 7)); + mrc->neigh_idx = ((data[12] & 0xf) << 1) | (data[13] >> 7); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); mrc->bsic = (data[13] >> 1) & 0x3f; if (rep->num_cell < 6) return 0; mrc = &rep->cell[5]; - mrc-> rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, - ((data[14] & 0x07) << 2) | (data[15] >> 6)); + mrc->rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); + mrc->neigh_idx = ((data[14] & 0x07) << 2) | (data[15] >> 6); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); mrc->bsic = data[15] & 0x3f; return 0; From eaa95d545e7fa2f1bd485363d8fedce007864c5a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Dec 2009 23:01:54 +0100 Subject: [PATCH 210/365] fix off-by-one error when mapping from meas rep to neighbor cell --- openbsc/src/gsm_04_08_utils.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 04440390a..9bafe3d32 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -735,7 +735,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) mrc = &rep->cell[0]; mrc->rxlev = data[3] & 0x3f; mrc->neigh_idx = data[4] >> 3; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; @@ -743,7 +743,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) mrc = &rep->cell[1]; mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); mrc->neigh_idx = (data[6] >> 2) & 0x1f; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); if (rep->num_cell < 3) return 0; @@ -751,7 +751,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) mrc = &rep->cell[2]; mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); mrc->neigh_idx = (data[8] >> 1) & 0x1f; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); mrc->bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); if (rep->num_cell < 4) return 0; @@ -759,7 +759,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) mrc = &rep->cell[3]; mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); mrc->neigh_idx = data[10] & 0x1f; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); mrc->bsic = data[11] >> 2; if (rep->num_cell < 5) return 0; @@ -767,7 +767,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) mrc = &rep->cell[4]; mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); mrc->neigh_idx = ((data[12] & 0xf) << 1) | (data[13] >> 7); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); mrc->bsic = (data[13] >> 1) & 0x3f; if (rep->num_cell < 6) return 0; @@ -775,7 +775,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) mrc = &rep->cell[5]; mrc->rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); mrc->neigh_idx = ((data[14] & 0x07) << 2) | (data[15] >> 6); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx); + mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); mrc->bsic = data[15] & 0x3f; return 0; From 303e5e0314364bb8d5a9de4d8512ffd8cf67ae29 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Dec 2009 23:02:22 +0100 Subject: [PATCH 211/365] [meas rep] print the neighbor index when debugp'ing a neigh cell meas --- openbsc/src/abis_rsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 86f458f40..d4eb632ef 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1013,8 +1013,8 @@ static void print_meas_rep(struct gsm_meas_rep *mr) return; for (i = 0; i < mr->num_cell; i++) { struct gsm_meas_rep_cell *mrc = &mr->cell[i]; - DEBUGP(DMEAS, "ARFCN=%u BSIC=%u => %d dBm\n", mrc->arfcn, mrc->bsic, - rxlev2dbm(mrc->rxlev)); + DEBUGP(DMEAS, "IDX=%u ARFCN=%u BSIC=%u => %d dBm\n", + mrc->neigh_idx, mrc->arfcn, mrc->bsic, rxlev2dbm(mrc->rxlev)); } } From 7c639a05a3afa966464cc33309d258641c607f3e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 25 Dec 2009 23:02:50 +0100 Subject: [PATCH 212/365] [handover] print INFO message when doing handover --- openbsc/src/handover_logic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 20eeb66ce..1bf048fed 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -217,6 +217,11 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) return -ENODEV; } + LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN " + "%u->%u\n", subscr_name(ho->old_lchan->subscr), + ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, + ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); + counter_inc(net->stats.handover.completed); bsc_del_timer(&ho->T3103); From 6589858167ee953be1c639f170902be6bca53878 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 14:12:43 +0100 Subject: [PATCH 213/365] [meas rep] fix parsing of BSIC in third reported neighbor cell --- openbsc/src/gsm_04_08_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 9bafe3d32..a18427788 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -752,7 +752,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); mrc->neigh_idx = (data[8] >> 1) & 0x1f; mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); - mrc->bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); + mrc->bsic = ((data[8] & 0x01) << 5) | (data[9] >> 3); if (rep->num_cell < 4) return 0; From 1f3ecd4050b1aadd7e88ca02519438791a36bd64 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 18:56:00 +0100 Subject: [PATCH 214/365] 'classmark1' is not an integer field in the database --- openbsc/src/db.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 57f86d6ea..7dfc86801 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -312,7 +312,9 @@ static int get_equipment_by_subscr(struct gsm_subscriber *subscr) if (string) strncpy(equip->imei, string, sizeof(equip->imei)); - cm1 = dbi_result_get_uint(result, "classmark1") & 0xff; + string = dbi_result_get_string(result, "classmark1"); + if (string) + cm1 = atoi(string) & 0xff; equip->classmark1 = *((struct gsm48_classmark1 *) &cm1); equip->classmark2_len = dbi_result_get_field_length(result, "classmark2"); From 441e483bd4350e8e97c466d25865883eee2e5411 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 18:57:32 +0100 Subject: [PATCH 215/365] [db] A new subscriber is an INFO event, not NOTICE --- openbsc/src/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 7dfc86801..73e9c25ef 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -280,7 +280,7 @@ struct gsm_subscriber *db_create_subscriber(struct gsm_network *net, char *imsi) subscr->id = dbi_conn_sequence_last(conn, NULL); strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1); dbi_result_free(result); - LOGP(DDB, LOGL_NOTICE, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi); + LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi); db_subscriber_alloc_exten(subscr); return subscr; } From 240ce88185dc69265e4015cdfdc1a7af41006b8e Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 19:43:11 +0100 Subject: [PATCH 216/365] add 'get_string_value()' as inverse function of 'get_value_string()' --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/gsm_data.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index af72e4765..103466c98 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -9,6 +9,7 @@ struct value_string { }; const char *get_value_string(const struct value_string *vs, u_int32_t val); +int get_string_value(const struct value_string *vs, const char *str); enum gsm_band { GSM_BAND_400, diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index e2f56d539..774a1ce2d 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -45,6 +45,19 @@ const char *get_value_string(const struct value_string *vs, u_int32_t val) return "unknown"; } +int get_string_value(const struct value_string *vs, const char *str) +{ + int i; + + for (i = 0;; i++) { + if (vs[i].value == 0 && vs[i].str == NULL) + break; + if (!strcasecmp(vs[i].str, str)) + return vs[i].value; + } + return -EINVAL; +} + void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr, u_int8_t e1_ts, u_int8_t e1_ts_ss) { From 47df39931ca867fb2efadc9dd5057e0f06d41b3f Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 19:45:03 +0100 Subject: [PATCH 217/365] generate INFO events for CC SETUP and LOC UPD REJ --- openbsc/src/gsm_04_08.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 982870ba1..7bcfb6f22 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -829,7 +829,8 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT; gh->data[0] = cause; - DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr); + LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT\n", + lchan->subscr ? subscr_name(lchan->subscr) : "unknown"); counter_inc(bts->network->stats.loc_upd_resp.reject); @@ -2147,6 +2148,10 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_INITIATED); + LOGP(DCC, LOGL_INFO, "Subscriber %s (%s) sends SETUP to %s\n", + subscr_name(trans->subscr), trans->subscr->extension, + setup.called.number); + /* indicate setup to MNCC */ mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup); From b79bdd99e5c803e65ae77aef8d22c0b5c74fd175 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 19:45:22 +0100 Subject: [PATCH 218/365] [debug] add new 'logging level' command to set loglevel more user friendly --- openbsc/src/debug.c | 28 ++++++++++++++++++++++++++++ openbsc/src/vty_interface.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 1aad1336d..acfcba30d 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,33 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DDB, "DREF", "", "") }; +static const struct value_string loglevel_strs[] = { + { 0, "EVERYTHING" }, + { 1, "DEBUG" }, + { 3, "INFO" }, + { 5, "NOTICE" }, + { 7, "ERROR" }, + { 8, "FATAL" }, + { 0, NULL }, +}; + +int debug_parse_level(const char *lvl) +{ + return get_string_value(loglevel_strs, lvl); +} + +int debug_parse_category(const char *category) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(debug_info); ++i) { + if (!strcasecmp(debug_info[i].name+1, category)) + return debug_info[i].number; + } + + return -EINVAL; +} + /* * Parse the category mask. * The format can be this: category1:category2:category3 diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 9645af23a..483917297 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -925,7 +925,7 @@ DEFUN(logging_fltr_all, DEFUN(logging_use_clr, logging_use_clr_cmd, - "logging use color <0-1>", + "logging color <0-1>", "Use color for printing messages\n") { struct telnet_connection *conn; @@ -942,7 +942,7 @@ DEFUN(logging_use_clr, DEFUN(logging_prnt_timestamp, logging_prnt_timestamp_cmd, - "logging print timestamp <0-1>", + "logging timestamp <0-1>", "Print the timestamp of each message\n") { struct telnet_connection *conn; @@ -957,6 +957,32 @@ DEFUN(logging_prnt_timestamp, return CMD_SUCCESS; } +#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref)" +DEFUN(logging_level, + logging_level_cmd, + "logging level " VTY_DEBUG_CATEGORIES " <0-8>", + "Set the log level for a specified category\n") +{ + struct telnet_connection *conn; + int category = debug_parse_category(argv[0]); + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (category < 0) { + vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + conn->dbg->categories[category].enabled = 1; + conn->dbg->categories[category].loglevel = atoi(argv[1]); + + return CMD_SUCCESS; +} + DEFUN(logging_set_category_mask, logging_set_category_mask_cmd, "logging set debug mask MASK", @@ -1753,6 +1779,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &logging_use_clr_cmd); install_element(VIEW_NODE, &logging_prnt_timestamp_cmd); install_element(VIEW_NODE, &logging_set_category_mask_cmd); + install_element(VIEW_NODE, &logging_level_cmd); install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net); From 93c628477279da35bacc2536088cff00d1e122ec Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 20:11:24 +0100 Subject: [PATCH 219/365] fix missing space in log message --- openbsc/src/abis_rsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index d4eb632ef..0920abe4b 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -955,7 +955,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct tlv_parsed tp; /* FIXME: print which channel */ - LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING"); + LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING "); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); From 198d5ad6f4e3d0bfab07206a072f8ae081b70022 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 22:15:28 +0100 Subject: [PATCH 220/365] print LAC and BTS number when showing location update reject --- openbsc/src/gsm_04_08.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 7bcfb6f22..6eeddbf90 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -829,8 +829,10 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT; gh->data[0] = cause; - LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT\n", - lchan->subscr ? subscr_name(lchan->subscr) : "unknown"); + LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT " + "LAC=%u BTS=%u\n", lchan->subscr ? + subscr_name(lchan->subscr) : "unknown", + lchan->ts->trx->bts->location_area_code, lchan->ts->trx->bts->nr); counter_inc(bts->network->stats.loc_upd_resp.reject); From fc05750cd8674882e13a41be2058ab1741853052 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 22:33:09 +0100 Subject: [PATCH 221/365] [rsl] correctly print handover detect and connection fail --- openbsc/src/abis_rsl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 0920abe4b..8d76d3e8d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -955,7 +955,8 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct tlv_parsed tp; /* FIXME: print which channel */ - LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING "); + LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING ", + gsm_ts_name(msg->lchan->ts)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -963,7 +964,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) print_rsl_cause(LOGL_NOTICE, TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); - LOGP(DRSL, LOGL_NOTICE, "\n"); + LOGPC(DRSL, LOGL_NOTICE, "\n"); /* FIXME: only free it after channel release ACK */ return rsl_rf_chan_release(msg->lchan); } @@ -1091,7 +1092,7 @@ static int rsl_rx_hando_det(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - DEBUGP(DRSL, "HANDOVER DETECT "); + DEBUGP(DRSL, "%s HANDOVER DETECT ", gsm_ts_name(msg->lchan->ts)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1125,14 +1126,12 @@ static int abis_rsl_rx_dchan(struct msgb *msg) rc = rsl_rx_chan_act_nack(msg); break; case RSL_MT_CONN_FAIL: - DEBUGP(DRSL, "%s ", ts_name); rc = rsl_rx_conn_fail(msg); break; case RSL_MT_MEAS_RES: rc = rsl_rx_meas_res(msg); break; case RSL_MT_HANDO_DET: - DEBUGP(DRSL, "%s ", ts_name); rc = rsl_rx_hando_det(msg); break; case RSL_MT_RF_CHAN_REL_ACK: From 73b82bbf92ca64f5f96a1dbad2cb003fb740fcbe Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 22:40:22 +0100 Subject: [PATCH 222/365] print TS name in RLL ERR IND --- openbsc/src/abis_rsl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 8d76d3e8d..428cfdea7 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1380,7 +1380,8 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); u_int8_t *rlm_cause = rllh->data; - LOGP(DRLL, LOGL_ERROR, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]); + LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=0x%02x\n", + gsm_ts_name(msg->lchan->ts), rlm_cause[1]); rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); From 258e2f9a9cd71fddfcf212ec2cf4a8e23f5d2426 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 16:47:08 +0100 Subject: [PATCH 223/365] gsm_04_11: Support for implicit CP-ACK in case of multi-SMS See GSM 04.11 Chapter 5.4 for details. The idea is that when multi-SMS are mobile originated, it's possible the CP-ACK of the previous transaction to be lost and the reception of a new CP-DATA for a new transaction should close previous transaction "as-if" we had received the CP-ACK ... Note that testing is hard since it's an exceptional condition that's hard to create. I tested by temporarly disabling CP-ACK processing and checked it worked as expected. Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index c3a49f399..7f570b8e5 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -948,6 +948,33 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) switch(msg_type) { case GSM411_MT_CP_DATA: DEBUGPC(DSMS, "RX SMS CP-DATA\n"); + + /* 5.4: For MO, if a CP-DATA is received for a new + * transaction, equals reception of an implicit + * last CP-ACK for previous transaction */ + if (trans->sms.cp_state == GSM411_CPS_IDLE) { + int i; + struct gsm_trans *ptrans; + + /* Scan through all remote initiated transactions */ + for (i=8; i<15; i++) { + if (i == transaction_id) + continue; + + ptrans = trans_find_by_id(lchan->subscr, + GSM48_PDISC_SMS, i); + if (!ptrans) + continue; + + DEBUGP(DSMS, "Implicit CP-ACK for trans_id=%x\n", i); + + /* Finish it for good */ + bsc_del_timer(&ptrans->sms.cp_timer); + ptrans->sms.cp_state = GSM411_CPS_IDLE; + trans_free(ptrans); + } + } + /* 5.2.3.1.3: MO state exists when SMC has received * CP-DATA, including sending of the assoc. CP-ACK */ /* 5.2.3.2.4: MT state exists when SMC has received From f6f2ef9d24d93ec339e5bedd8089138842813966 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 27 Dec 2009 11:24:55 +0100 Subject: [PATCH 224/365] move get_string_value() und get_value_string() into debug.c this makes bsc_mgcp and ipaccess-proxy compile again --- openbsc/src/debug.c | 26 ++++++++++++++++++++++++++ openbsc/src/gsm_data.c | 26 -------------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index acfcba30d..90a9fc7e3 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -56,6 +56,32 @@ static struct debug_category default_categories[Debug_LastEntry] = { [DREF] = { .enabled = 0, .loglevel = LOGL_NOTICE }, }; +const char *get_value_string(const struct value_string *vs, u_int32_t val) +{ + int i; + + for (i = 0;; i++) { + if (vs[i].value == 0 && vs[i].str == NULL) + break; + if (vs[i].value == val) + return vs[i].str; + } + return "unknown"; +} + +int get_string_value(const struct value_string *vs, const char *str) +{ + int i; + + for (i = 0;; i++) { + if (vs[i].value == 0 && vs[i].str == NULL) + break; + if (!strcasecmp(vs[i].str, str)) + return vs[i].value; + } + return -EINVAL; +} + struct debug_info { const char *name; const char *color; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 774a1ce2d..e216420c2 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -32,32 +32,6 @@ void *tall_bsc_ctx; -const char *get_value_string(const struct value_string *vs, u_int32_t val) -{ - int i; - - for (i = 0;; i++) { - if (vs[i].value == 0 && vs[i].str == NULL) - break; - if (vs[i].value == val) - return vs[i].str; - } - return "unknown"; -} - -int get_string_value(const struct value_string *vs, const char *str) -{ - int i; - - for (i = 0;; i++) { - if (vs[i].value == 0 && vs[i].str == NULL) - break; - if (!strcasecmp(vs[i].str, str)) - return vs[i].value; - } - return -EINVAL; -} - void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr, u_int8_t e1_ts, u_int8_t e1_ts_ss) { From a25b20c174840602be2bf096f54bb9203c214c58 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 27 Dec 2009 07:23:02 +0100 Subject: [PATCH 225/365] [ipaccess] Call it ipaccess-firmware --- openbsc/src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 080fed4d5..e665c99eb 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess_firmware ipaccess-proxy + isdnsync bsc_mgcp ipaccess-firmware ipaccess-proxy noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h From 30b9ecda334693a3ae1157254bf90d7347f7900c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 27 Dec 2009 14:03:11 +0100 Subject: [PATCH 226/365] [ipaccess] Verify the size part of the header --- openbsc/src/ipaccess/ipaccess-firmware.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 4349f99da..8fdc2e9a4 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -52,6 +52,7 @@ static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; static void analyze_file(int fd) { struct sdp_firmware *firmware_header; + struct stat stat; char buf[4096]; int rc; @@ -80,6 +81,17 @@ static void analyze_file(int fd) printf("text2: %.64s\n", firmware_header->text2); printf("time: %.8s\n", firmware_header->time); printf("date: %.8s\n", firmware_header->date); + + /* verify the file */ + if (fstat(fd, &stat) == -1) { + perror("Can not stat the file"); + return; + } + + if (ntohl(firmware_header->file_length) != stat.st_size) { + fprintf(stderr, "The filesize and the header do not match.\n"); + return; + } } int main(int argc, char** argv) From f413a0811a608d4f7eaabdf343683422940ccc44 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 03:11:33 +0100 Subject: [PATCH 227/365] [ipaccess] Add firmware download option to ipaccess-config This will mostly work like the downloading in bs11_config and is based on the bs11_config state machine as well. Once it is working we can see how to unite both implementations. --- openbsc/src/ipaccess/ipaccess-config.c | 71 +++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 7df4cefeb..c0fc2c469 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -1,6 +1,8 @@ /* ip.access nanoBTS configuration tool */ /* (C) 2009 by Harald Welte + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by On Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -48,6 +50,7 @@ static char *prim_oml_ip; static char *unit_id; static u_int16_t nv_flags; static u_int16_t nv_mask; +static char *software = NULL; /* static u_int8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 }; @@ -164,6 +167,58 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal, return 0; } +/* callback function passed to the ABIS OML code */ +static int percent; +static int percent_old; +static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg, + void *data, void *param) +{ + struct gsm_bts *bts; + + if (hook != GSM_HOOK_NM_SWLOAD) + return 0; + + bts = (struct gsm_bts *) data; + + switch (event) { + case NM_MT_LOAD_INIT_ACK: + fprintf(stdout, "Software Load Initiate ACK\n"); + break; + case NM_MT_LOAD_INIT_NACK: + fprintf(stderr, "ERROR: Software Load Initiate NACK\n"); + exit(5); + break; + case NM_MT_LOAD_END_ACK: + fprintf(stderr, "LOAD END ACK..."); +#if 0 + if (data) { + /* we did a safety load and must activate it */ + abis_nm_software_activate(g_bts, fname_safety, + swload_cbfn, bts); + sleep(5); + } +#endif + break; + case NM_MT_LOAD_END_NACK: + fprintf(stderr, "ERROR: Software Load End NACK\n"); + exit(3); + break; + case NM_MT_ACTIVATE_SW_NACK: + fprintf(stderr, "ERROR: Activate Software NACK\n"); + exit(4); + break; + case NM_MT_ACTIVATE_SW_ACK: + break; + case NM_MT_LOAD_SEG_ACK: + percent = abis_nm_software_load_status(bts); + if (percent > percent_old) + printf("Software Download Progress: %d%%\n", percent); + percent_old = percent; + break; + } + return 0; +} + static void bootstrap_om(struct gsm_bts *bts) { int len; @@ -226,6 +281,16 @@ static void bootstrap_om(struct gsm_bts *bts) printf("restarting BTS\n"); abis_nm_ipaccess_restart(bts); } + + if (software) { + int rc; + printf("Attempting software upload with '%s'\n", software); + rc = abis_nm_software_load(bts, software, 19, 0, swload_cbfn, bts); + if (rc < 0) { + fprintf(stderr, "Failed to start software load\n"); + exit(-3); + } + } } void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) @@ -310,9 +375,10 @@ int main(int argc, char **argv) { "help", 0, 0, 'h' }, { "listen", 1, 0, 'l' }, { "stream-id", 1, 0, 's' }, + { "software", 1, 0, 'd' }, }; - c = getopt_long(argc, argv, "u:o:rn:l:hs:", long_options, + c = getopt_long(argc, argv, "u:o:rn:l:hs:d:", long_options, &option_index); if (c == -1) @@ -343,6 +409,9 @@ int main(int argc, char **argv) case 's': stream_id = atoi(optarg); break; + case 'd': + software = strdup(optarg); + break; case 'h': print_usage(); print_help(); From ab2c8b109d06df8ad1e7c237c00f8267f5ae3e08 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 07:27:43 +0100 Subject: [PATCH 228/365] [ipaccess] Start flashing once the BTS has started enough... Strictly speaking we would only need to start the Site Manager and could probably start flashing afterwards but it is more easy to have one config path... --- openbsc/src/ipaccess/ipaccess-config.c | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index c0fc2c469..c7d223438 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -282,15 +282,6 @@ static void bootstrap_om(struct gsm_bts *bts) abis_nm_ipaccess_restart(bts); } - if (software) { - int rc; - printf("Attempting software upload with '%s'\n", software); - rc = abis_nm_software_load(bts, software, 19, 0, swload_cbfn, bts); - if (rc < 0) { - fprintf(stderr, "Failed to start software load\n"); - exit(-3); - } - } } void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) @@ -322,13 +313,23 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, { if (evt == EVT_STATECHG_OPER && obj_class == NM_OC_RADIO_CARRIER && - new_state->availability == 3 && - net_listen_testnr) { + new_state->availability == 3) { struct gsm_bts_trx *trx = obj; - u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 }; - abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff, - net_listen_testnr, 1, - phys_config, sizeof(phys_config)); + + if (net_listen_testnr) { + u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 }; + abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff, + net_listen_testnr, 1, + phys_config, sizeof(phys_config)); + } else if (software) { + int rc; + printf("Attempting software upload with '%s'\n", software); + rc = abis_nm_software_load(trx->bts, software, 19, 0, swload_cbfn, trx->bts); + if (rc < 0) { + fprintf(stderr, "Failed to start software load\n"); + exit(-3); + } + } } return 0; } From a6faea83e0629d77a941fa840f8460d0eaab9a72 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 07:28:43 +0100 Subject: [PATCH 229/365] [ipaccess] Verify the SDP header before flashing Print a big fat warning that we do not carefully check the firmware as the format is not known and that flashing could be dangerous.. --- openbsc/src/abis_nm.c | 50 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index f62356dcc..b3e12e97a 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1339,9 +1339,57 @@ static int sw_activate(struct abis_nm_sw *sw) return abis_nm_sendmsg(sw->bts, msg); } +struct sdp_firmware { + char magic[4]; + char more_magic[4]; + unsigned int header_length; + unsigned int file_length; +} __attribute__ ((packed)); + static int parse_sdp_header(struct abis_nm_sw *sw) { - return -1; + struct sdp_firmware firmware_header; + int rc; + struct stat stat; + + rc = read(sw->fd, &firmware_header, sizeof(firmware_header)); + if (rc != sizeof(firmware_header)) { + LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n"); + return -1; + } + + if (strncmp(firmware_header.magic, " SDP", 4) != 0) { + LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n"); + return -1; + } + + if (firmware_header.more_magic[0] != 0x10 || + firmware_header.more_magic[1] != 0x02 || + firmware_header.more_magic[2] != 0x00 || + firmware_header.more_magic[3] != 0x00) { + LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n"); + return -1; + } + + + if (fstat(sw->fd, &stat) == -1) { + LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n"); + return -1; + } + + if (ntohl(firmware_header.file_length) != stat.st_size) { + LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n"); + return -1; + } + + /* go back to the start as we checked the whole filesize.. */ + lseek(sw->fd, 0l, SEEK_SET); + LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n" + "There might be checksums in the file that are not\n" + "verified and incomplete firmware might be flashed.\n" + "There is absolutely no WARRANTY that flashing will\n" + "work.\n"); + return 0; } static int sw_open_file(struct abis_nm_sw *sw, const char *fname) From cf269a7f859dd14fef800289cd096ff5a0e41431 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 09:02:41 +0100 Subject: [PATCH 230/365] [ipaccess] Send the correct Software Load Init for the ipaccess BTS * The FOM header needs to be different. We need to address the base station transceiver, bts, trx set to 0 and ts to 255 * We need to transfer the the \0 of 'id' and 'version' * We need to issue a NM_ATT_SW_DESCR (just the value) * We need to use 16bit length for the other two ids.. * After this our Software Load Init is getting an Ack. --- openbsc/src/abis_nm.c | 47 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index b3e12e97a..c3b2c0769 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1225,11 +1225,19 @@ static int sw_load_init(struct abis_nm_sw *sw) fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class, sw->obj_instance[0], sw->obj_instance[1], sw->obj_instance[2]); - - /* FIXME: this is BS11 specific format */ - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); + + if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) { + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else if (sw->bts->type == GSM_BTS_TYPE_BS11) { + msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else { + return -1; + } msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size); return abis_nm_sendmsg(sw->bts, msg); @@ -1436,6 +1444,11 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname) fprintf(stderr, "Could not parse the ipaccess SDP header\n"); return -1; } + + strcpy((char *)sw->file_id, "id"); + sw->file_id_len = 3; + strcpy((char *)sw->file_version, "version"); + sw->file_version_len = 8; break; default: /* We don't know how to treat them yet */ @@ -1624,10 +1637,26 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname, return -EBUSY; sw->bts = bts; - sw->obj_class = NM_OC_SITE_MANAGER; - sw->obj_instance[0] = 0xff; - sw->obj_instance[1] = 0xff; - sw->obj_instance[2] = 0xff; + + switch (bts->type) { + case GSM_BTS_TYPE_BS11: + sw->obj_class = NM_OC_SITE_MANAGER; + sw->obj_instance[0] = 0xff; + sw->obj_instance[1] = 0xff; + sw->obj_instance[2] = 0xff; + break; + case GSM_BTS_TYPE_NANOBTS: + sw->obj_class = NM_OC_BASEB_TRANSC; + sw->obj_instance[0] = 0x00; + sw->obj_instance[1] = 0x00; + sw->obj_instance[2] = 0xff; + break; + case GSM_BTS_TYPE_UNKNOWN: + default: + LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n"); + return -1; + break; + } sw->window_size = win_size; sw->state = SW_STATE_WAIT_INITACK; sw->cbfn = cbfn; From 64d9ddde5d53ce69c8b469c3dc11e0c70c097d23 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 09:21:18 +0100 Subject: [PATCH 231/365] [abis] Warn if sw_load_segment is not implemented for the given bts type --- openbsc/src/abis_nm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index c3b2c0769..2be71f5ed 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1296,6 +1296,7 @@ static int sw_load_segment(struct abis_nm_sw *sw) len = strlen(line_buf)+2; break; default: + LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n"); /* FIXME: Other BTS types */ return -1; } From 71bc11e757c49e67ca7c5fbc25ca89ba8a1a757e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 10:04:26 +0100 Subject: [PATCH 232/365] [ipaccess] Implement the Load Segment messages... --- openbsc/src/abis_nm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 2be71f5ed..64c409388 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -47,6 +47,7 @@ #define OM_ALLOC_SIZE 1024 #define OM_HEADROOM_SIZE 128 +#define IPACC_SEGMENT_SIZE 245 /* unidirectional messages from BTS to BSC */ static const enum abis_nm_msgtype reports[] = { @@ -1295,6 +1296,21 @@ static int sw_load_segment(struct abis_nm_sw *sw) /* we only now know the exact length for the OM hdr */ len = strlen(line_buf)+2; break; + case GSM_BTS_TYPE_NANOBTS: { + static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough); + len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE); + if (len < 0) { + perror("read failed"); + return -EINVAL; + } + + if (len != IPACC_SEGMENT_SIZE) + sw->last_seg = 1; + + msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf); + len += 3; + break; + } default: LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n"); /* FIXME: Other BTS types */ From 5a2291e96a21474363ce9105800b3e3612ce0698 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 10:16:54 +0100 Subject: [PATCH 233/365] [ipaccess] No need to use fdopen for the file (that was leaked too) --- openbsc/src/abis_nm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 64c409388..9ed72530d 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1449,12 +1449,6 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname) rewind(sw->stream); break; case GSM_BTS_TYPE_NANOBTS: - sw->stream = fdopen(sw->fd, "r"); - if (!sw->stream) { - perror("fdopen"); - return -1; - } - /* TODO: extract that from the filename or content */ rc = parse_sdp_header(sw); if (rc < 0) { @@ -1701,7 +1695,10 @@ int abis_nm_software_load_status(struct gsm_bts *bts) return rc; } - percent = (ftell(sw->stream) * 100) / st.st_size; + if (sw->stream) + percent = (ftell(sw->stream) * 100) / st.st_size; + else + percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size; return percent; } From c5dc0f7ac70041c58d219a983c20e5c755cd60f3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 11:28:51 +0100 Subject: [PATCH 234/365] [ipaccess] Properly increment the segs_in_window Somehow this should be done in the fill method.. --- openbsc/src/abis_nm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 9ed72530d..17e8d0f4c 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1307,6 +1307,7 @@ static int sw_load_segment(struct abis_nm_sw *sw) if (len != IPACC_SEGMENT_SIZE) sw->last_seg = 1; + ++sw->seg_in_window; msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf); len += 3; break; From 326a632c462f0ac2f441075e3e1b92f81b9d4e0a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 11:45:43 +0100 Subject: [PATCH 235/365] [ipacess] Implement sw_load_end for the nanoBTS * This should be shared with the sw_load_init routines as it is the about the same. --- openbsc/src/abis_nm.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 17e8d0f4c..db95f213c 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1337,10 +1337,18 @@ static int sw_load_end(struct abis_nm_sw *sw) sw->obj_instance[0], sw->obj_instance[1], sw->obj_instance[2]); - /* FIXME: this is BS11 specific format */ - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); + if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) { + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else if (sw->bts->type == GSM_BTS_TYPE_BS11) { + msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else { + return -1; + } return abis_nm_sendmsg(sw->bts, msg); } From 8f31a8fdaeb57204b2bf43c48d24a06212f787e8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 11:48:12 +0100 Subject: [PATCH 236/365] [abis] Set rc to 0 to avoid running into a warning about unknown states When we have received the End Ack we are just doing nothing as we are done. This means rc remains -1 and we will print a warning but there is no need to have a warning... --- openbsc/src/abis_nm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index db95f213c..8b3ac9c62 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1581,6 +1581,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb) sw->cbfn(GSM_HOOK_NM_SWLOAD, NM_MT_LOAD_END_ACK, mb, sw->cb_data, NULL); + rc = 0; break; case NM_MT_LOAD_END_NACK: if (sw->forced) { From b29b57a19860d87b9c149c99d41025cb922e0aa5 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 16:54:47 +0100 Subject: [PATCH 237/365] include BTS and TRX number in TRX overload message report --- openbsc/src/abis_rsl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 428cfdea7..df0f1bc22 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1210,7 +1210,8 @@ static int abis_rsl_rx_trx(struct msgb *msg) break; case RSL_MT_OVERLOAD: /* indicate CCCH / ACCH / processor overload */ - LOGP(DRSL, LOGL_ERROR, "TRX: CCCH/ACCH/CPU Overload\n"); + LOGP(DRSL, LOGL_ERROR, "(bts=%u, trx=%u) CCCH/ACCH/CPU Overload\n", + msg->trx->bts->nr, msg->trx->nr); break; default: LOGP(DRSL, LOGL_NOTICE, "Unknown Abis RSL TRX message " From 9fcf6d78b73590cb51731bfaeeb6d55dd62de25c Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 17:01:40 +0100 Subject: [PATCH 238/365] correction of RTP timestamps is a NOTICE event, not debug --- openbsc/src/rtp_proxy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 0f4e32799..83b774f97 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -240,7 +240,8 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) if (abs(frame_diff) > 1) { long int frame_diff_excess = frame_diff - 1; - DEBUGP(DMUX, "Correcting frame difference of %ld frames\n", frame_diff_excess); + LOGP(DMUX, LOGL_NOTICE, + "Correcting frame difference of %ld frames\n", frame_diff_excess); rs->transmit.sequence += frame_diff_excess; rs->transmit.timestamp += frame_diff_excess * duration; } From 28f1d37380514df4810f723c80d86b9585fd1db1 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 11:43:56 +0100 Subject: [PATCH 239/365] print TS name when out of resources during CHAN RQD --- openbsc/src/abis_rsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index df0f1bc22..bd04fe245 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1266,8 +1266,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { - LOGP(DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x\n", - gsm_lchan_name(lctype), rqd_ref->ra); + LOGP(DRSL, LOGL_NOTICE, "%s CHAN RQD: no resources for %s 0x%x\n", + gsm_ts_name(lchan->ts), gsm_lchan_name(lctype), rqd_ref->ra); counter_inc(bts->network->stats.chreq.no_channel); /* FIXME: send some kind of reject ?!? */ return -ENOMEM; From 91b603db57db631c350dcb72117d20286d36aa21 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 11:48:11 +0100 Subject: [PATCH 240/365] correctly print chan act nack error --- openbsc/src/abis_rsl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index bd04fe245..ec716144f 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -931,6 +931,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; + LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK", + gsm_ts_name(msg->lchan->ts)); + /* BTS has rejected channel activation ?!? */ if (dh->ie_chan != RSL_IE_CHAN_NR) return -EINVAL; @@ -942,6 +945,8 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) msg->lchan->state = LCHAN_S_NONE; + LOGPC(DRSL, LOGL_ERROR, "\n"); + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan); lchan_free(msg->lchan); @@ -1122,7 +1127,6 @@ static int abis_rsl_rx_dchan(struct msgb *msg) rc = rsl_rx_chan_act_ack(msg); break; case RSL_MT_CHAN_ACTIV_NACK: - DEBUGP(DRSL, "%s CHANNEL ACTIVATE NACK\n", ts_name); rc = rsl_rx_chan_act_nack(msg); break; case RSL_MT_CONN_FAIL: From 2f5df85c26424f1889ecd4fdabfc361a549c0683 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 13:48:09 +0100 Subject: [PATCH 241/365] fix segfault in CHAN RQD log message --- openbsc/src/abis_rsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index ec716144f..f6892ca36 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1270,8 +1270,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { - LOGP(DRSL, LOGL_NOTICE, "%s CHAN RQD: no resources for %s 0x%x\n", - gsm_ts_name(lchan->ts), gsm_lchan_name(lctype), rqd_ref->ra); + LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", + msg->lchan->ts->trx->bts->nr, gsm_lchan_name(lctype), rqd_ref->ra); counter_inc(bts->network->stats.chreq.no_channel); /* FIXME: send some kind of reject ?!? */ return -ENOMEM; From ccd8845449bbeacf9d4e787be7995cef84f5db4b Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 18:05:25 +0100 Subject: [PATCH 242/365] rename gsm_lchan_name() to gsm_lchant_name() --- openbsc/include/openbsc/gsm_data.h | 2 +- openbsc/src/abis_rsl.c | 4 ++-- openbsc/src/gsm_data.c | 2 +- openbsc/src/vty_interface.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 103466c98..0b6054216 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -625,7 +625,7 @@ struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num); const char *gsm_pchan_name(enum gsm_phys_chan_config c); enum gsm_phys_chan_config gsm_pchan_parse(const char *name); -const char *gsm_lchan_name(enum gsm_chan_t c); +const char *gsm_lchant_name(enum gsm_chan_t c); const char *gsm_chreq_name(enum gsm_chreq_reason_t c); char *gsm_ts_name(struct gsm_bts_trx_ts *ts); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index f6892ca36..a1b20a47a 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1271,7 +1271,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) lchan = lchan_alloc(bts, lctype); if (!lchan) { LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", - msg->lchan->ts->trx->bts->nr, gsm_lchan_name(lctype), rqd_ref->ra); + msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); counter_inc(bts->network->stats.chreq.no_channel); /* FIXME: send some kind of reject ?!? */ return -ENOMEM; @@ -1306,7 +1306,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s " "r=%s ra=0x%02x\n", gsm_ts_name(lchan->ts), arfcn, subch, - gsm_lchan_name(lchan->type), gsm_chreq_name(chreq_reason), + gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason), rqd_ref->ra); /* Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */ diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index e216420c2..7fc969445 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -80,7 +80,7 @@ static const char *lchan_names[] = { [GSM_LCHAN_UNKNOWN] = "UNKNOWN", }; -const char *gsm_lchan_name(enum gsm_chan_t c) +const char *gsm_lchant_name(enum gsm_chan_t c) { if (c >= ARRAY_SIZE(lchan_names)) return "INVALID"; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 483917297..0d66cb3a6 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -568,7 +568,7 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s", lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, - lchan->ts->trx->bts->nr, gsm_lchan_name(lchan->type), + lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE); vty_out(vty, " Use Count: %u%s", lchan->use_count, VTY_NEWLINE); vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s", From 3e46031f52535651e07ba5333914d83e1cffcf73 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 18:12:29 +0100 Subject: [PATCH 243/365] Introduce new ACT_REQ state to prevent race condition during channel allocation When we allocate a channel, we send the RSL CHAN ACT REQ and wait until we get a CHAN ACT ACK. Only the ACK will change the state, so there is a race where we allocate that same channel to a different channel request before we get the ACT ACK. Introducing a new ACT_REQ state resolves this issue. --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/abis_rsl.c | 15 ++++++++++----- openbsc/src/chan_alloc.c | 3 ++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 0b6054216..37c9ff2e5 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -170,6 +170,7 @@ struct neigh_meas_proc { /* state of a logical channel */ enum gsm_lchan_state { LCHAN_S_NONE, /* channel is not active */ + LCHAN_S_ACT_REQ, /* channel activatin requested */ LCHAN_S_ACTIVE, /* channel is active and operational */ LCHAN_S_INACTIVE, /* channel is set inactive */ }; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index a1b20a47a..26da704b6 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -939,12 +939,15 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) return -EINVAL; rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) - print_rsl_cause(LOGL_ERROR, TLVP_VAL(&tp, RSL_IE_CAUSE), + if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) { + const u_int8_t *cause = TLVP_VAL(&tp, RSL_IE_CAUSE); + print_rsl_cause(LOGL_ERROR, cause, TLVP_LEN(&tp, RSL_IE_CAUSE)); - - msg->lchan->state = LCHAN_S_NONE; - + if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC) + msg->lchan->state = LCHAN_S_NONE; + } else + msg->lchan->state = LCHAN_S_NONE; + LOGPC(DRSL, LOGL_ERROR, "\n"); dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan); @@ -1277,6 +1280,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) return -ENOMEM; } + lchan->state = LCHAN_S_ACT_REQ; + ts_number = lchan->ts->nr; arfcn = lchan->ts->trx->arfcn; subch = lchan->nr; diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 4bdf722b0..abf4de891 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -175,7 +175,8 @@ _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan) /* check if all sub-slots are allocated yet */ for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) { struct gsm_lchan *lc = &ts->lchan[ss]; - if (lc->type == GSM_LCHAN_NONE) + if (lc->type == GSM_LCHAN_NONE && + lc->state == LCHAN_S_NONE) return lc; } } From 9538efc8a72b4a88998a71267b7b01bddfcfb86e Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sat, 26 Dec 2009 23:55:00 +0100 Subject: [PATCH 244/365] RLL: print human-readable value of RLM CAUSE in ERROR IND --- openbsc/src/abis_rsl.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 26da704b6..0cfb65f57 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -370,6 +370,24 @@ static const char *rsl_err_vals[0xff] = { [RSL_ERR_INTERWORKING] = "Interworking error, unspecified", }; +static const struct value_string rlm_cause_strs[] = { + { RLL_CAUSE_T200_EXPIRED, "Timer T200 expired (N200+1) times" }, + { RLL_CAUSE_REEST_REQ, "Re-establishment request" }, + { RLL_CAUSE_UNSOL_UA_RESP, "Unsolicited UA response" }, + { RLL_CAUSE_UNSOL_DM_RESP, "Unsolicited DM response" }, + { RLL_CAUSE_UNSOL_DM_RESP_MF, "Unsolicited DM response, multiple frame" }, + { RLL_CAUSE_UNSOL_SPRV_RESP, "Unsolicited supervisory response" }, + { RLL_CAUSE_SEQ_ERR, "Sequence Error" }, + { RLL_CAUSE_UFRM_INC_PARAM, "U-Frame with incorrect parameters" }, + { RLL_CAUSE_SFRM_INC_PARAM, "S-Frame with incorrect parameters" }, + { RLL_CAUSE_IFRM_INC_MBITS, "I-Frame with incorrect use of M bit" }, + { RLL_CAUSE_IFRM_INC_LEN, "I-Frame with incorrect length" }, + { RLL_CAUSE_FRM_UNIMPL, "Fraeme not implemented" }, + { RLL_CAUSE_SABM_MF, "SABM command, multiple frame established state" }, + { RLL_CAUSE_SABM_INFO_NOTALL, "SABM frame with information not allowed in this state" }, + { 0, NULL }, +}; + static const char *rsl_err_name(u_int8_t err) { if (rsl_err_vals[err]) @@ -1390,11 +1408,12 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); u_int8_t *rlm_cause = rllh->data; - LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=0x%02x\n", - gsm_ts_name(msg->lchan->ts), rlm_cause[1]); + LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s\n", + gsm_ts_name(msg->lchan->ts), + get_value_string(rlm_cause_strs, rlm_cause[1])); rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); - + if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) return rsl_rf_chan_release(msg->lchan); From 19ef62a0a56a9c61d65283d005019ef9563cd8ae Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 18:16:36 +0100 Subject: [PATCH 245/365] Introduce and use gsm_lchan_name() in addition to gsm_ts_name() In many cases we actually want a name / unique ID for the lchan, not just for the on-air timeslot... especially in SDCCH/8 case, where 8 SDCCHs share one timeslot... --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/abis_rsl.c | 28 ++++++++++++++-------------- openbsc/src/gsm_data.c | 10 ++++++++++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 37c9ff2e5..31d34608a 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -629,6 +629,7 @@ enum gsm_phys_chan_config gsm_pchan_parse(const char *name); const char *gsm_lchant_name(enum gsm_chan_t c); const char *gsm_chreq_name(enum gsm_chreq_reason_t c); char *gsm_ts_name(struct gsm_bts_trx_ts *ts); +char *gsm_lchan_name(struct gsm_lchan *lchan); enum gsm_e1_event { EVT_E1_NONE, diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 0cfb65f57..667313b0a 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -739,7 +739,7 @@ int rsl_deact_sacch(struct gsm_lchan *lchan) msg->lchan = lchan; msg->trx = lchan->ts->trx; - DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_ts_name(lchan->ts)); + DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_lchan_name(lchan)); return abis_rsl_sendmsg(msg); } @@ -757,7 +757,7 @@ int rsl_rf_chan_release(struct gsm_lchan *lchan) msg->lchan = lchan; msg->trx = lchan->ts->trx; - DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_ts_name(lchan->ts)); + DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_lchan_name(lchan)); /* BTS will respond by RF CHAN REL ACK */ return abis_rsl_sendmsg(msg); @@ -851,7 +851,7 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci) msgb_tv_put(msg, RSL_IE_SIEMENS_MRPCI, *(u_int8_t *)mrpci); DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n", - gsm_ts_name(lchan->ts), *(u_int8_t *)mrpci); + gsm_lchan_name(lchan), *(u_int8_t *)mrpci); msg->trx = lchan->ts->trx; @@ -950,7 +950,7 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) struct tlv_parsed tp; LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK", - gsm_ts_name(msg->lchan->ts)); + gsm_lchan_name(msg->lchan)); /* BTS has rejected channel activation ?!? */ if (dh->ie_chan != RSL_IE_CHAN_NR) @@ -982,7 +982,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) /* FIXME: print which channel */ LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING ", - gsm_ts_name(msg->lchan->ts)); + gsm_lchan_name(msg->lchan)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1118,7 +1118,7 @@ static int rsl_rx_hando_det(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - DEBUGP(DRSL, "%s HANDOVER DETECT ", gsm_ts_name(msg->lchan->ts)); + DEBUGP(DRSL, "%s HANDOVER DETECT ", gsm_lchan_name(msg->lchan)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1140,7 +1140,7 @@ static int abis_rsl_rx_dchan(struct msgb *msg) char *ts_name; msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr); - ts_name = gsm_ts_name(msg->lchan->ts); + ts_name = gsm_lchan_name(msg->lchan); switch (rslh->c.msg_type) { case RSL_MT_CHAN_ACTIV_ACK: @@ -1328,7 +1328,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) ia.mob_alloc_len = 0; DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s " - "r=%s ra=0x%02x\n", gsm_ts_name(lchan->ts), arfcn, subch, + "r=%s ra=0x%02x\n", gsm_lchan_name(lchan), arfcn, subch, gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason), rqd_ref->ra); @@ -1409,7 +1409,7 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) u_int8_t *rlm_cause = rllh->data; LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s\n", - gsm_ts_name(msg->lchan->ts), + gsm_lchan_name(msg->lchan), get_value_string(rlm_cause_strs, rlm_cause[1])); rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); @@ -1434,7 +1434,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) u_int8_t sapi = rllh->link_id & 7; msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr); - ts_name = gsm_ts_name(msg->lchan->ts); + ts_name = gsm_lchan_name(msg->lchan); DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi); switch (rllh->c.msg_type) { @@ -1606,7 +1606,7 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x\n", - gsm_ts_name(lchan->ts), lchan->abis_ip.speech_mode); + gsm_lchan_name(lchan), lchan->abis_ip.speech_mode); msg->trx = lchan->ts->trx; @@ -1636,7 +1636,7 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, ia.s_addr = htonl(ip); DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d " - "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), inet_ntoa(ia), port, + "speech_mode=0x%02x\n", gsm_lchan_name(lchan), inet_ntoa(ia), port, rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode); msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id); @@ -1677,7 +1677,7 @@ int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan) dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN; dh->chan_nr = lchan2chan_nr(lchan); - DEBUGP(DRSL, "%s IPAC_PDCH_ACT\n", gsm_ts_name(lchan->ts)); + DEBUGP(DRSL, "%s IPAC_PDCH_ACT\n", gsm_lchan_name(lchan)); msg->trx = lchan->ts->trx; @@ -1779,7 +1779,7 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) int rc = 0; msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr); - ts_name = gsm_ts_name(msg->lchan->ts); + ts_name = gsm_lchan_name(msg->lchan); switch (rllh->c.msg_type) { case RSL_MT_IPAC_CRCX_ACK: diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 7fc969445..ae6d49e73 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -304,6 +304,16 @@ char *gsm_ts_name(struct gsm_bts_trx_ts *ts) return ts2str; } +char *gsm_lchan_name(struct gsm_lchan *lchan) +{ + struct gsm_bts_trx_ts *ts = lchan->ts; + + snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,ss=%d)", + ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr); + + return ts2str; +} + static const char *bts_types[] = { [GSM_BTS_TYPE_UNKNOWN] = "unknown", [GSM_BTS_TYPE_BS11] = "bs11", From 7b37d9710d119675f374f10a780a8d93440c29d8 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 20:56:38 +0100 Subject: [PATCH 246/365] set the TRX nominal power by default and/or VTY --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/gsm_data.c | 18 ++++++++++++++++++ openbsc/src/vty_interface.c | 21 +++++++++++++++------ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 31d34608a..aee359219 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -615,6 +615,7 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, u_int8_t tsc, u_int8_t bsic); struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts); +void gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type); struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num); diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index ae6d49e73..7e62aa846 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -133,6 +133,9 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) } } + if (trx->nr != 0) + trx->nominal_power = bts->c0->nominal_power; + llist_add_tail(&trx->list, &bts->trx_list); return trx; @@ -464,3 +467,18 @@ struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) return meas_rep; } + +void gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type) +{ + bts->type = type; + + switch (bts->type) { + case GSM_BTS_TYPE_NANOBTS: + /* Set the default OML Stream ID to 0xff */ + bts->oml_tei = 0xff; + bts->c0->nominal_power = 23; + break; + case GSM_BTS_TYPE_BS11: + break; + } +} diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 0d66cb3a6..51c802842 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -266,6 +266,7 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx) vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE); vty_out(vty, " arfcn %u%s", trx->arfcn, VTY_NEWLINE); + vty_out(vty, " nominal power %u%s", trx->nominal_power, VTY_NEWLINE); vty_out(vty, " max_power_red %u%s", trx->max_power_red, VTY_NEWLINE); config_write_e1_link(vty, &trx->rsl_e1_link, " rsl "); vty_out(vty, " rsl e1 tei %u%s", trx->rsl_tei, VTY_NEWLINE); @@ -1323,12 +1324,7 @@ DEFUN(cfg_bts_type, { struct gsm_bts *bts = vty->index; - bts->type = parse_btstype(argv[0]); - - if (is_ipaccess_bts(bts)) { - /* Set the default OML Stream ID to 0xff */ - bts->oml_tei = 0xff; - } + gsm_set_bts_type(bts, parse_btstype(argv[0])); return CMD_SUCCESS; } @@ -1635,6 +1631,18 @@ DEFUN(cfg_trx_arfcn, return CMD_SUCCESS; } +DEFUN(cfg_trx_nominal_power, + cfg_trx_nominal_power_cmd, + "nominal power <0-100>", + "Nominal TRX RF Power in dB\n") +{ + struct gsm_bts_trx *trx = vty->index; + + trx->nominal_power = atoi(argv[0]); + + return CMD_SUCCESS; +} + DEFUN(cfg_trx_max_power_red, cfg_trx_max_power_red_cmd, "max_power_red <0-100>", @@ -1840,6 +1848,7 @@ int bsc_vty_init(struct gsm_network *net) install_node(&trx_node, dummy_config_write); install_default(TRX_NODE); install_element(TRX_NODE, &cfg_trx_arfcn_cmd); + install_element(TRX_NODE, &cfg_trx_nominal_power_cmd); install_element(TRX_NODE, &cfg_trx_max_power_red_cmd); install_element(TRX_NODE, &cfg_trx_rsl_e1_cmd); install_element(TRX_NODE, &cfg_trx_rsl_e1_tei_cmd); From 66169152f6c4458cf7380d6e447fa74e5ae66654 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Sun, 27 Dec 2009 21:02:20 +0100 Subject: [PATCH 247/365] vty: replace'logging level' numeric value with human readable string --- openbsc/include/openbsc/debug.h | 2 ++ openbsc/src/vty_interface.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index f9c4afdbc..c40eec3fb 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -118,6 +118,8 @@ void debug_set_use_color(struct debug_target *target, int); void debug_set_print_timestamp(struct debug_target *target, int); void debug_set_log_level(struct debug_target *target, int log_level); void debug_parse_category_mask(struct debug_target *target, const char* mask); +int debug_parse_level(const char *lvl); +int debug_parse_category(const char *category); void debug_set_category_filter(struct debug_target *target, int category, int enable, int level); diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 51c802842..59865d52a 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -958,14 +958,17 @@ DEFUN(logging_prnt_timestamp, return CMD_SUCCESS; } +/* FIXME: those have to be kept in sync with the log levels and categories */ #define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref)" +#define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)" DEFUN(logging_level, logging_level_cmd, - "logging level " VTY_DEBUG_CATEGORIES " <0-8>", + "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS, "Set the log level for a specified category\n") { struct telnet_connection *conn; int category = debug_parse_category(argv[0]); + int level = debug_parse_level(argv[1]); conn = (struct telnet_connection *) vty->priv; if (!conn->dbg) { @@ -978,8 +981,13 @@ DEFUN(logging_level, return CMD_WARNING; } + if (level < 0) { + vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + conn->dbg->categories[category].enabled = 1; - conn->dbg->categories[category].loglevel = atoi(argv[1]); + conn->dbg->categories[category].loglevel = level; return CMD_SUCCESS; } From c7aabcad1b6435d0f439c487e8825e1dbc4c0775 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 12:23:02 +0100 Subject: [PATCH 248/365] [ipaccess] Handle LoadAbort coming from the BTS. * Be bale to abort the load when the BTS is rejecting the file.. --- openbsc/src/abis_nm.c | 6 ++++++ openbsc/src/ipaccess/ipaccess-config.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 8b3ac9c62..211f70ee4 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1568,6 +1568,12 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb) rc = sw_load_end(sw); } break; + case NM_MT_LOAD_ABORT: + if (sw->cbfn) + sw->cbfn(GSM_HOOK_NM_SWLOAD, + NM_MT_LOAD_ABORT, mb, + sw->cb_data, NULL); + break; } break; case SW_STATE_WAIT_ENDACK: diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index c7d223438..e96b1abac 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -215,6 +215,10 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg, printf("Software Download Progress: %d%%\n", percent); percent_old = percent; break; + case NM_MT_LOAD_ABORT: + fprintf(stderr, "ERROR: Load aborted by the BTS.\n"); + exit(6); + break; } return 0; } From 0b864db429cd3282003bbe355e9d669ed12bfcc3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 28 Dec 2009 12:18:37 +0100 Subject: [PATCH 249/365] [ipaccess] Send a NVATTR to activate the new software after load end * The struct is similiar to the one in abis_nm.. * The generation of the data is similiar to sw_end_load and sw_init_load and we should unite this.. --- openbsc/src/ipaccess/ipaccess-config.c | 50 +++++++++++++++++++++----- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index e96b1abac..ce2a17533 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -51,6 +51,18 @@ static char *unit_id; static u_int16_t nv_flags; static u_int16_t nv_mask; static char *software = NULL; +static int sw_load_state = 0; + +struct sw_load { + u_int8_t file_id[255]; + u_int8_t file_id_len; + + u_int8_t file_version[255]; + u_int8_t file_version_len; +}; + +static struct sw_load *sw_load1 = NULL; +static struct sw_load *sw_load2 = NULL; /* static u_int8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 }; @@ -170,9 +182,10 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal, /* callback function passed to the ABIS OML code */ static int percent; static int percent_old; -static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg, +static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, void *data, void *param) { + struct msgb *msg; struct gsm_bts *bts; if (hook != GSM_HOOK_NM_SWLOAD) @@ -190,14 +203,35 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg, break; case NM_MT_LOAD_END_ACK: fprintf(stderr, "LOAD END ACK..."); -#if 0 - if (data) { - /* we did a safety load and must activate it */ - abis_nm_software_activate(g_bts, fname_safety, - swload_cbfn, bts); - sleep(5); + /* now make it the default */ + sw_load_state = 1; + + msg = msgb_alloc(1024, "sw: nvattr"); + msg->l2h = msgb_put(msg, 3); + msg->l3h = &msg->l2h[3]; + + /* activate software */ + if (sw_load1) { + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw_load1->file_id_len, sw_load1->file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw_load1->file_version_len, + sw_load1->file_version); } -#endif + + if (sw_load2) { + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw_load2->file_id_len, sw_load1->file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw_load2->file_version_len, + sw_load2->file_version); + } + + /* fill in the data */ + msg->l2h[0] = NM_ATT_IPACC_CUR_SW_CFG; + msg->l2h[1] = msgb_l3len(msg) >> 8; + msg->l2h[2] = msgb_l3len(msg) & 0xff; + printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg)); + abis_nm_ipaccess_set_nvattr(bts, msg->l2h, msgb_l2len(msg)); + msgb_free(msg); break; case NM_MT_LOAD_END_NACK: fprintf(stderr, "ERROR: Software Load End NACK\n"); From 304db15bd44a79a3fbc9991dc97cd3c2a046aba0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 04:16:37 +0100 Subject: [PATCH 250/365] [wireshark] Decode NM_ATT_IPACC_FILE_DATA as TL16V This can be decoded like the plain FILE_DATA and I don't understand the need for a custom version. --- wireshark/abis_oml.patch | 1 + 1 file changed, 1 insertion(+) diff --git a/wireshark/abis_oml.patch b/wireshark/abis_oml.patch index 1b2439c86..7dbfd6964 100644 --- a/wireshark/abis_oml.patch +++ b/wireshark/abis_oml.patch @@ -2167,6 +2167,7 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.h + [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V, 0 }, + [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V, 0 }, + [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V, 0 }, ++ [NM_ATT_IPACC_FILE_DATA] = { TLV_TYPE_TL16V, 0 }, + }, +}; + From 615e650fd457430e9b4685231725d7f1a47b625f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 04:22:12 +0100 Subject: [PATCH 251/365] [wireshark] Add config option to decide which flavor of OML to use This option can currently toggle between BS11 and nanoBTS (in the form of having BS11 default). The next step will be to make use of this in the code. --- wireshark/abis_oml.patch | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/wireshark/abis_oml.patch b/wireshark/abis_oml.patch index 7dbfd6964..9f06b4d82 100644 --- a/wireshark/abis_oml.patch +++ b/wireshark/abis_oml.patch @@ -10,14 +10,16 @@ Index: wireshark/epan/dissectors/Makefile.common packet-gsm_ipa.c \ packet-gsm_bsslap.c \ packet-gsm_bssmap_le.c \ -Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c -=================================================================== +diff --git a/epan/dissectors/packet-gsm_abis_oml.c b/epan/dissectors/packet-gsm_abis_oml.c +new file mode 100644 +index 0000000..2de9dca --- /dev/null -+++ wireshark/epan/dissectors/packet-gsm_abis_oml.c -@@ -0,0 +1,1365 @@ ++++ b/epan/dissectors/packet-gsm_abis_oml.c +@@ -0,0 +1,1382 @@ +/* packet-abis_oml.c + * Routines for packet dissection of GSM A-bis over IP (3GPP TS 12.21) + * Copyright 2009 by Harald Welte ++ * Copyright 2009 by Holger Hans Peter Freyther + * based on A-bis OML code in OpenBSC + * + * $Id$ @@ -50,6 +52,7 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c +#include +#include +#include ++#include + +#include "packet-gsm_abis_oml.h" +#include "packet-gsm_a_common.h" @@ -128,6 +131,9 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c +static int ett_oml_fom = -1; +static int ett_oml_fom_att = -1; + ++/* Decode things as nanoBTS traces */ ++static gboolean global_oml_use_nano_bts = FALSE; ++ +static proto_tree *top_tree; + +/* TS 12.21 Chapter 8.1 / TS 08.59 */ @@ -1053,6 +1059,9 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c +} + +void ++proto_reg_handoff_abis_oml(void); ++ ++void +proto_register_abis_oml(void) +{ + static hf_register_info hf[] = { @@ -1362,6 +1371,8 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c + &ett_oml_fom_att, + }; + ++ module_t *oml_module; ++ + proto_abis_oml = proto_register_protocol("GSM A-bis OML", "OML", + "gsm_abis_oml"); + @@ -1370,6 +1381,13 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.c + proto_register_subtree_array(ett, array_length(ett)); + + register_dissector("gsm_abis_oml", dissect_abis_oml, proto_abis_oml); ++ ++ ++ oml_module = prefs_register_protocol(proto_abis_oml, proto_reg_handoff_abis_oml); ++ prefs_register_bool_preference(oml_module, "use_ipaccess_oml", ++ "Use nanoBTS definitions", ++ "Use ipaccess nanoBTS specific definitions for OML", ++ &global_oml_use_nano_bts); +} + +void From 46a920c36ce90f3ab5443ffb02aa1b4503a75d5f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 05:43:57 +0100 Subject: [PATCH 252/365] [ipaccess] Do not pick in the wrong headers... I must have picked in the wrong section of these files... There are some kind of header entries that are all 138 byte long and this is the total length... --- openbsc/src/ipaccess/ipaccess-firmware.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 8fdc2e9a4..5cf99d428 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -28,6 +28,7 @@ #include #include +#define PART_LENGTH 138 struct sdp_firmware { char magic[4]; @@ -36,12 +37,7 @@ struct sdp_firmware { unsigned int file_length; char sw_part[20]; char text1[122]; - u_int8_t no_idea_1[4]; - char text2[64]; - char time[8]; - u_int8_t no_idea_2[4]; - char date[8]; - u_int8_t no_idea_3[6]; + unsigned int short part_length; /* stuff i don't know */ } __attribute__((packed)); @@ -77,10 +73,9 @@ static void analyze_file(int fd) printf("header_length: %u\n", ntohl(firmware_header->header_length)); printf("file_length: %u\n", ntohl(firmware_header->file_length)); printf("sw_part: %.20s\n", firmware_header->sw_part); - printf("text1: %.122s\n", firmware_header->text1); - printf("text2: %.64s\n", firmware_header->text2); - printf("time: %.8s\n", firmware_header->time); - printf("date: %.8s\n", firmware_header->date); + printf("text1: %.120s\n", firmware_header->text1); + printf("items: %u (rest %u)\n", ntohs(firmware_header->part_length) / PART_LENGTH, + ntohs(firmware_header->part_length) % PART_LENGTH); /* verify the file */ if (fstat(fd, &stat) == -1) { From 567b3261d9fb10aba13850a9ee7f18dd9b15bc93 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 06:01:36 +0100 Subject: [PATCH 253/365] [ipaccess] Attempt to read the header entries.. --- openbsc/src/ipaccess/ipaccess-firmware.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 5cf99d428..5df3a3864 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -19,6 +19,8 @@ * */ +#include + #include #include #include @@ -41,6 +43,12 @@ struct sdp_firmware { /* stuff i don't know */ } __attribute__((packed)); +struct sdp_header_entry { + u_int8_t entry[138]; +} __attribute__((packed)); + +static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); + /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; @@ -87,6 +95,11 @@ static void analyze_file(int fd) fprintf(stderr, "The filesize and the header do not match.\n"); return; } + + if (ntohs(firmware_header->part_length) % PART_LENGTH != 0) { + fprintf(stderr, "The part length seems to be wrong.\n"); + return; + } } int main(int argc, char** argv) From c823c89c766829c738db19ccebb690b7fb5cfd71 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 08:08:47 +0100 Subject: [PATCH 254/365] [ipaccess] Use the u_intX_t types in the firmware tool --- openbsc/src/ipaccess/ipaccess-firmware.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 5df3a3864..806e6be5c 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -35,11 +35,11 @@ struct sdp_firmware { char magic[4]; char more_magic[4]; - unsigned int header_length; - unsigned int file_length; + u_int32_t header_length; + u_int32_t file_length; char sw_part[20]; char text1[122]; - unsigned int short part_length; + u_int16_t part_length; /* stuff i don't know */ } __attribute__((packed)); From 07a4026b38a6661edfafb4742cf243121ab1ee6b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 08:09:54 +0100 Subject: [PATCH 255/365] [ipaccess] Start figuring out what the header entry is meaning.. --- openbsc/src/ipaccess/ipaccess-firmware.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 806e6be5c..345de0618 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -44,7 +44,16 @@ struct sdp_firmware { } __attribute__((packed)); struct sdp_header_entry { - u_int8_t entry[138]; + u_int16_t something1; + char text1[64]; + char time[12]; + char date[14]; + char text2[10]; + char text3[20]; + u_int32_t something2; + u_int32_t addr1; + u_int32_t addr2; + u_int32_t something3; } __attribute__((packed)); static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); @@ -58,7 +67,7 @@ static void analyze_file(int fd) struct sdp_firmware *firmware_header; struct stat stat; char buf[4096]; - int rc; + int rc, i; rc = read(fd, buf, sizeof(*firmware_header)); if (rc < 0) { @@ -100,6 +109,12 @@ static void analyze_file(int fd) fprintf(stderr, "The part length seems to be wrong.\n"); return; } + + /* look into each firmware now */ + for (i = 0; i < ntohs(firmware_header->part_length) % PART_LENGTH; ++i) { + unsigned int offset = sizeof(struct sdp_firmware); + offset += i * 138; + } } int main(int argc, char** argv) From ebdcee27b8b6b85982cf830be0a508d55cdffce5 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 08:27:21 +0100 Subject: [PATCH 256/365] [ipaccess] Start reading the header entry * Read the entry and print it out --- openbsc/src/ipaccess/ipaccess-firmware.c | 26 +++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 345de0618..7f9d27a28 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -111,9 +111,33 @@ static void analyze_file(int fd) } /* look into each firmware now */ - for (i = 0; i < ntohs(firmware_header->part_length) % PART_LENGTH; ++i) { + for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) { + struct sdp_header_entry entry; unsigned int offset = sizeof(struct sdp_firmware); offset += i * 138; + + if (lseek(fd, offset, SEEK_SET) != offset) { + fprintf(stderr, "Can not seek to the offset: %u.\n", offset); + return; + } + + rc = read(fd, &entry, sizeof(entry)); + if (rc != sizeof(entry)) { + fprintf(stderr, "Can not read the header entry.\n"); + return; + } + + printf("Header Entry: %d\n", i); + printf("\tsomething1: %u\n", ntohs(entry.something1)); + printf("\ttext1: %.64s\n", entry.text1); + printf("\ttime: %.12s\n", entry.time); + printf("\tdate: %.14s\n", entry.date); + printf("\ttext2: %.10s\n", entry.text2); + printf("\ttext3: %.20s\n", entry.text3); + printf("\tsomething2: 0x%x\n", ntohl(entry.something2)); + printf("\taddr1: 0x%x\n", entry.addr1); + printf("\taddr2: 0x%x\n", entry.addr2); + printf("\tsomething3: 0x%x\n", ntohl(entry.something3)); } } From 8e93b7908f09e5c356989677e21dd8b8e9cb4371 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 29 Dec 2009 10:44:17 +0100 Subject: [PATCH 257/365] RSL: Introduce LCHAN_S_REL_REQ state This state will help us to differentiate between channels where we have requested the release, and channels that are actually released. --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/abis_rsl.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index aee359219..cd1209303 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -172,6 +172,7 @@ enum gsm_lchan_state { LCHAN_S_NONE, /* channel is not active */ LCHAN_S_ACT_REQ, /* channel activatin requested */ LCHAN_S_ACTIVE, /* channel is active and operational */ + LCHAN_S_REL_REQ, /* channel release has been requested */ LCHAN_S_INACTIVE, /* channel is set inactive */ }; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 667313b0a..6f13b4b30 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -921,6 +921,9 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id) rh->link_id = link_id; msgb_tv_put(msg, RSL_IE_RELEASE_MODE, 0); /* normal release */ + lchan->state = LCHAN_S_REL_REQ; + /* FIXME: start some timer in case we don't receive a REL ACK ? */ + msg->trx = lchan->ts->trx; return abis_rsl_sendmsg(msg); @@ -936,6 +939,9 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) if (rslh->ie_chan != RSL_IE_CHAN_NR) return -EINVAL; + if (msg->lchan->state != LCHAN_S_ACT_REQ) + LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %u\n", + gsm_lchan_name(msg->lchan), msg->lchan->state); msg->lchan->state = LCHAN_S_ACTIVE; dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan); @@ -1056,8 +1062,11 @@ static int rsl_rx_meas_res(struct msgb *msg) /* check if this channel is actually active */ /* FIXME: maybe this check should be way more generic/centralized */ - if (msg->lchan->state != LCHAN_S_ACTIVE) + if (msg->lchan->state != LCHAN_S_ACTIVE) { + LOGP(DRSL, LOGL_NOTICE, "%s: MEAS RES for inactive channel\n", + gsm_lchan_name(msg->lchan)); return 0; + } memset(mr, 0, sizeof(*mr)); mr->lchan = msg->lchan; @@ -1161,6 +1170,9 @@ static int abis_rsl_rx_dchan(struct msgb *msg) break; case RSL_MT_RF_CHAN_REL_ACK: DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name); + if (msg->lchan->state != LCHAN_S_REL_REQ) + LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state=%u\n", + gsm_lchan_name(msg->lchan), msg->lchan->state); msg->lchan->state = LCHAN_S_NONE; lchan_free(msg->lchan); break; @@ -1298,6 +1310,9 @@ static int rsl_rx_chan_rqd(struct msgb *msg) return -ENOMEM; } + if (lchan->state != LCHAN_S_NONE) + LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel " + "in state %u\n", gsm_lchan_name(lchan), lchan->state); lchan->state = LCHAN_S_ACT_REQ; ts_number = lchan->ts->nr; From 1887f9d153497adc37cec5b8db6b7423ff64d6c0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 29 Dec 2009 10:52:38 +0100 Subject: [PATCH 258/365] Introduce gsm_lchans_name() for human readable lchan state name Also, use this new function to dump lchan state on VTY and to improve readability of RSL log messages. --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/abis_rsl.c | 13 ++++++++----- openbsc/src/gsm_data.c | 14 ++++++++++++++ openbsc/src/vty_interface.c | 3 ++- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index cd1209303..2e5779383 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -632,6 +632,7 @@ const char *gsm_lchant_name(enum gsm_chan_t c); const char *gsm_chreq_name(enum gsm_chreq_reason_t c); char *gsm_ts_name(struct gsm_bts_trx_ts *ts); char *gsm_lchan_name(struct gsm_lchan *lchan); +const char *gsm_lchans_name(enum gsm_lchan_state s); enum gsm_e1_event { EVT_E1_NONE, diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 6f13b4b30..164d27d1f 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -940,8 +940,9 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) return -EINVAL; if (msg->lchan->state != LCHAN_S_ACT_REQ) - LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %u\n", - gsm_lchan_name(msg->lchan), msg->lchan->state); + LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n", + gsm_lchan_name(msg->lchan), + gsm_lchans_name(msg->lchan->state)); msg->lchan->state = LCHAN_S_ACTIVE; dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan); @@ -1171,8 +1172,9 @@ static int abis_rsl_rx_dchan(struct msgb *msg) case RSL_MT_RF_CHAN_REL_ACK: DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name); if (msg->lchan->state != LCHAN_S_REL_REQ) - LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state=%u\n", - gsm_lchan_name(msg->lchan), msg->lchan->state); + LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n", + gsm_lchan_name(msg->lchan), + gsm_lchans_name(msg->lchan->state)); msg->lchan->state = LCHAN_S_NONE; lchan_free(msg->lchan); break; @@ -1312,7 +1314,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) if (lchan->state != LCHAN_S_NONE) LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel " - "in state %u\n", gsm_lchan_name(lchan), lchan->state); + "in state %s\n", gsm_lchan_name(lchan), + gsm_lchans_name(lchan->state)); lchan->state = LCHAN_S_ACT_REQ; ts_number = lchan->ts->nr; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 7e62aa846..0dfd31f17 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -88,6 +88,20 @@ const char *gsm_lchant_name(enum gsm_chan_t c) return lchan_names[c]; } +static const struct value_string lchan_s_names[] = { + { LCHAN_S_NONE, "NONE" }, + { LCHAN_S_ACT_REQ, "ACTIVATION REQUESTED" }, + { LCHAN_S_ACTIVE, "ACTIVE" }, + { LCHAN_S_INACTIVE, "INACTIVE" }, + { LCHAN_S_REL_REQ, "RELEASE REQUESTED" }, + { 0, NULL }, +}; + +const char *gsm_lchans_name(enum gsm_lchan_state s) +{ + return get_value_string(lchan_s_names, s); +} + static const char *chreq_names[] = { [GSM_CHREQ_REASON_EMERG] = "EMERGENCY", [GSM_CHREQ_REASON_PAG] = "PAGING", diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 59865d52a..22284d803 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -571,7 +571,8 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE); - vty_out(vty, " Use Count: %u%s", lchan->use_count, VTY_NEWLINE); + vty_out(vty, " Use Count: %u, State: %s%s", lchan->use_count, + gsm_lchans_name(lchan->state), VTY_NEWLINE); vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s", lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red - lchan->bs_power*2, From 82ff397e3118936e4a714334d82b75f765e6d842 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Mon, 28 Dec 2009 16:36:28 +0100 Subject: [PATCH 259/365] export the 'trx_is_usable() function and use it from paging this ensures we don't send paging requests to currently inactive transceivers. --- openbsc/include/openbsc/chan_alloc.h | 2 ++ openbsc/src/chan_alloc.c | 2 +- openbsc/src/paging.c | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h index fa8663056..f564e9e4d 100644 --- a/openbsc/include/openbsc/chan_alloc.h +++ b/openbsc/include/openbsc/chan_alloc.h @@ -61,4 +61,6 @@ struct pchan_load { void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts); void network_chan_load(struct pchan_load *pl, struct gsm_network *net); +int trx_is_usable(struct gsm_bts_trx *trx); + #endif /* _CHAN_ALLOC_H */ diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index abf4de891..8141e4774 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -47,7 +47,7 @@ static int ts_is_usable(struct gsm_bts_trx_ts *ts) return 1; } -static int trx_is_usable(struct gsm_bts_trx *trx) +int trx_is_usable(struct gsm_bts_trx *trx) { /* FIXME: How does this behave for BS-11 ? */ if (is_ipaccess_bts(trx->bts)) { diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 820773a9e..b5dc2d052 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -265,6 +265,11 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, bts = gsm_bts_by_lac(network, subscr->lac, bts); if (!bts) break; + + /* skip all currently inactive TRX */ + if (!trx_is_usable(bts->c0)) + continue; + num_pages++; /* Trigger paging, pass any error to caller */ From 5fe33189a9833597df23dec7039b304cb78ad7f5 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Mon, 28 Dec 2009 17:05:43 +0100 Subject: [PATCH 260/365] rsl_sendmsg: Print message in case trx == NULL --- openbsc/src/e1_input.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index 0a0cc8d7e..c894fe40f 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -234,10 +234,16 @@ int abis_rsl_sendmsg(struct msgb *msg) msg->l2h = msg->data; - if (!msg->trx || !msg->trx->rsl_link) { - LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL\n"); + if (!msg->trx) { + LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL: %s\n", + hexdump(msg->data, msg->len)); talloc_free(msg); return -EINVAL; + } else if (!msg->trx->rsl_link) { + LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx->rsl_link == NULL: %s\n", + hexdump(msg->data, msg->len)); + talloc_free(msg); + return -EIO; } sign_link = msg->trx->rsl_link; From 7971d3d28199c9927ae34364ff5e35506d4dde90 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Mon, 28 Dec 2009 17:52:11 +0100 Subject: [PATCH 261/365] ipaccess input: Print BTS number that has disappeared --- openbsc/src/input/ipaccess.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index c72176657..90d7cea85 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -311,12 +311,15 @@ static int handle_ts1_read(struct bsc_fd *bfd) msg = ipaccess_read_msg(bfd, &error); if (!msg) { if (error == 0) { - LOGP(DINP, LOGL_NOTICE, "BTS disappeared, dead socket\n"); + link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0); + if (link) { + link->trx->bts->ip_access.flags = 0; + LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n", + link->trx->bts->nr); + } else + LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n"); e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL); e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML); - link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0); - if (link) - link->trx->bts->ip_access.flags = 0; bsc_unregister_fd(bfd); close(bfd->fd); bfd->fd = -1; From d48f4ebb24c13d7cbbcd9131648a16a57fbd9787 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Mon, 28 Dec 2009 23:14:22 +0100 Subject: [PATCH 262/365] rsl: add new 'gsm_trx_name()' function and use it --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/abis_rsl.c | 12 ++++++------ openbsc/src/gsm_data.c | 9 +++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 2e5779383..c0c485e84 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -630,6 +630,7 @@ const char *gsm_pchan_name(enum gsm_phys_chan_config c); enum gsm_phys_chan_config gsm_pchan_parse(const char *name); const char *gsm_lchant_name(enum gsm_chan_t c); const char *gsm_chreq_name(enum gsm_chreq_reason_t c); +char *gsm_trx_name(struct gsm_bts_trx *trx); char *gsm_ts_name(struct gsm_bts_trx_ts *ts); char *gsm_lchan_name(struct gsm_lchan *lchan); const char *gsm_lchans_name(enum gsm_lchan_state s); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 164d27d1f..11a4355a7 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1221,7 +1221,7 @@ static int rsl_rx_error_rep(struct msgb *msg) struct abis_rsl_common_hdr *rslh = msgb_l2(msg); struct tlv_parsed tp; - LOGP(DRSL, LOGL_ERROR, "ERROR REPORT "); + LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(msg->trx)); rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh)); @@ -1245,16 +1245,16 @@ static int abis_rsl_rx_trx(struct msgb *msg) break; case RSL_MT_RF_RES_IND: /* interference on idle channels of TRX */ - //DEBUGP(DRSL, "TRX: RF Interference Indication\n"); + //DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(msg->trx)); break; case RSL_MT_OVERLOAD: /* indicate CCCH / ACCH / processor overload */ - LOGP(DRSL, LOGL_ERROR, "(bts=%u, trx=%u) CCCH/ACCH/CPU Overload\n", - msg->trx->bts->nr, msg->trx->nr); + LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n", + gsm_trx_name(msg->trx)); break; default: - LOGP(DRSL, LOGL_NOTICE, "Unknown Abis RSL TRX message " - "type 0x%02x\n", rslh->msg_type); + LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message " + "type 0x%02x\n", gsm_trx_name(msg->trx), rslh->msg_type); return -EINVAL; } return rc; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 0dfd31f17..21d9e4b27 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -313,6 +313,15 @@ struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num) static char ts2str[255]; +char *gsm_trx_name(struct gsm_bts_trx *trx) +{ + snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d)", + trx->bts->nr, trx->nr); + + return ts2str; +} + + char *gsm_ts_name(struct gsm_bts_trx_ts *ts) { snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)", From 93f4207ce62cba043a217c3eefb0023a8c429357 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Mon, 28 Dec 2009 23:15:36 +0100 Subject: [PATCH 263/365] ipaccess-config: re-enable DNM logging, add support for multi-TRX --- openbsc/src/ipaccess/ipaccess-config.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index ce2a17533..8cd0526b0 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -399,6 +399,8 @@ int main(int argc, char **argv) stderr_target = debug_target_create_stderr(); debug_add_target(stderr_target); debug_set_all_filter(stderr_target, 1); + debug_set_log_level(stderr_target, 0); + debug_parse_category_mask(stderr_target, "DNM,0"); printf("ipaccess-config (C) 2009 by Harald Welte\n"); printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); @@ -469,6 +471,10 @@ int main(int argc, char **argv) bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_NANOBTS, HARDCODED_TSC, HARDCODED_BSIC); + /* ip.access supports up to 4 chained TRX */ + gsm_bts_trx_alloc(bts); + gsm_bts_trx_alloc(bts); + gsm_bts_trx_alloc(bts); bts->oml_tei = stream_id; register_signal_handler(SS_NM, nm_sig_cb, NULL); From e5198967a6745e36b164fb1d18314c9d1a251719 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 11:12:00 +0100 Subject: [PATCH 264/365] [ipaccess] Use the right variable... *sigh* * I will refactor all this in the future.. --- openbsc/src/ipaccess/ipaccess-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 8cd0526b0..016459bdd 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -220,7 +220,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, if (sw_load2) { msgb_v_put(msg, NM_ATT_SW_DESCR); - msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw_load2->file_id_len, sw_load1->file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw_load2->file_id_len, sw_load2->file_id); msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw_load2->file_version_len, sw_load2->file_version); } From 086ffa51b4f56eb875e4918a2ee1802581c6cd67 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 11:26:38 +0100 Subject: [PATCH 265/365] [abis] Add ACK signal and send it on SET NVATTR ACK * Add the signal definition to signal.h * Dispatch the signal from abis_nm.c * Handle it in ipaccess-config.c and say we are done with work --- openbsc/include/openbsc/signal.h | 1 + openbsc/src/abis_nm.c | 3 +++ openbsc/src/ipaccess/ipaccess-config.c | 13 +++++++++++++ 3 files changed, 17 insertions(+) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 8c815f89e..f13b12be8 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -69,6 +69,7 @@ enum signal_nm { S_NM_FAIL_REP, /* GSM 12.21 failure event report */ S_NM_NACK, /* GSM 12.21 various NM_MT_*_NACK happened */ S_NM_IPACC_NACK, /* GSM 12.21 nanoBTS extensions NM_MT_IPACC_*_*_NACK happened */ + S_NM_IPACC_ACK, /* GSM 12.21 nanoBTS extensions NM_MT_IPACC_*_*_ACK happened */ S_NM_TEST_REP, /* GSM 12.21 Test Report */ }; diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 211f70ee4..9dedcaf5d 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2805,6 +2805,9 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_GET_NVATTR_NACK: dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type); break; + case NM_MT_IPACC_SET_NVATTR_ACK: + dispatch_signal(SS_NM, S_NM_IPACC_ACK, &foh->msg_type); + break; default: break; } diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 016459bdd..3b81c2a38 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -83,6 +83,16 @@ static int ipacc_msg_nack(u_int8_t mt) return 0; } +static int ipacc_msg_ack(u_int8_t mt) +{ + if (sw_load_state == 1) { + fprintf(stderr, "The new software is activaed.\n"); + exit(0); + } + + return 0; +} + struct ipacc_ferr_elem { int16_t freq_err; u_int8_t freq_qual; @@ -170,6 +180,9 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal, case S_NM_IPACC_NACK: msg_type = signal_data; return ipacc_msg_nack(*msg_type); + case S_NM_IPACC_ACK: + msg_type = signal_data; + return ipacc_msg_ack(*msg_type); case S_NM_TEST_REP: return test_rep(signal_data); default: From e29be15ac57ecf88c45d14652d45c24e29272314 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 13:02:19 +0100 Subject: [PATCH 266/365] [ipaccess] The firmware format is recursive... The something3 points to the next start of the SDP entry. The four bytes in front of the " SDP" are not known and just discarded. Prepare to be able to recursively parse the SDP header... --- openbsc/src/ipaccess/ipaccess-firmware.c | 45 ++++++++++++++++-------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 7f9d27a28..8b5a9d511 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -50,10 +50,10 @@ struct sdp_header_entry { char date[14]; char text2[10]; char text3[20]; - u_int32_t something2; + u_int32_t length; u_int32_t addr1; u_int32_t addr2; - u_int32_t something3; + u_int32_t start; } __attribute__((packed)); static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); @@ -62,10 +62,9 @@ static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; -static void analyze_file(int fd) +static void analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset) { struct sdp_firmware *firmware_header; - struct stat stat; char buf[4096]; int rc, i; @@ -94,13 +93,7 @@ static void analyze_file(int fd) printf("items: %u (rest %u)\n", ntohs(firmware_header->part_length) / PART_LENGTH, ntohs(firmware_header->part_length) % PART_LENGTH); - /* verify the file */ - if (fstat(fd, &stat) == -1) { - perror("Can not stat the file"); - return; - } - - if (ntohl(firmware_header->file_length) != stat.st_size) { + if (ntohl(firmware_header->file_length) != st_size) { fprintf(stderr, "The filesize and the header do not match.\n"); return; } @@ -113,7 +106,7 @@ static void analyze_file(int fd) /* look into each firmware now */ for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) { struct sdp_header_entry entry; - unsigned int offset = sizeof(struct sdp_firmware); + unsigned int offset = sizeof(struct sdp_firmware) + base_offset; offset += i * 138; if (lseek(fd, offset, SEEK_SET) != offset) { @@ -134,16 +127,32 @@ static void analyze_file(int fd) printf("\tdate: %.14s\n", entry.date); printf("\ttext2: %.10s\n", entry.text2); printf("\ttext3: %.20s\n", entry.text3); - printf("\tsomething2: 0x%x\n", ntohl(entry.something2)); printf("\taddr1: 0x%x\n", entry.addr1); printf("\taddr2: 0x%x\n", entry.addr2); - printf("\tsomething3: 0x%x\n", ntohl(entry.something3)); + printf("\tstart: 0x%x\n", ntohl(entry.start)); + printf("\tlength: 0x%x\n", ntohl(entry.length)); + + /* now we need to find the SDP file... */ + offset = ntohl(entry.start) + 4 + base_offset; + if (lseek(fd, offset, SEEK_SET) != offset) { + perror("can't seek to sdp"); + return; + } + + rc = read(fd, &buf, 4); + if (rc != 4) { + perror("peek failed"); + return; + } + + printf("FOO %.4s\n", buf); } } int main(int argc, char** argv) { int i, fd; + struct stat stat; for (i = 1; i < argc; ++i) { printf("Opening possible firmware '%s'\n", argv[i]); @@ -153,7 +162,13 @@ int main(int argc, char** argv) continue; } - analyze_file(fd); + /* verify the file */ + if (fstat(fd, &stat) == -1) { + perror("Can not stat the file"); + return EXIT_FAILURE; + } + + analyze_file(fd, stat.st_size, 0); } return EXIT_SUCCESS; From 1029f84435be2b47ef66ed8e78bd48e11ae3b01a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 14:27:10 +0100 Subject: [PATCH 267/365] [ipaccess] Read the " SDP" and version first and then the rest of the header Read everything we need to determine the version first and then the rest. This will allow to be able to poke into the other SDP bits. --- openbsc/src/ipaccess/ipaccess-firmware.c | 30 ++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 8b5a9d511..1325e5576 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -32,9 +32,12 @@ #define PART_LENGTH 138 -struct sdp_firmware { +struct sdp_firmware_start { char magic[4]; char more_magic[4]; +} __attribute__((packed)); + +struct sdp_firmware { u_int32_t header_length; u_int32_t file_length; char sw_part[20]; @@ -57,6 +60,7 @@ struct sdp_header_entry { } __attribute__((packed)); static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); +static_assert(sizeof(struct sdp_firmware_start) + sizeof(struct sdp_firmware) == 160, _right_header_length); /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; @@ -64,27 +68,39 @@ static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; static void analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset) { + struct sdp_firmware_start *firmware_start; struct sdp_firmware *firmware_header; char buf[4096]; int rc, i; + unsigned int start_offset = 0; - rc = read(fd, buf, sizeof(*firmware_header)); + rc = read(fd, buf, sizeof(*firmware_start)); if (rc < 0) { - perror("can not read header"); + perror("Can not read header start."); return; } - firmware_header = (struct sdp_firmware *) &buf[0]; - if (strncmp(firmware_header->magic, " SDP", 4) != 0) { + firmware_start = (struct sdp_firmware_start *) &buf[0]; + if (strncmp(firmware_start->magic, " SDP", 4) != 0) { fprintf(stderr, "Wrong magic.\n"); return; } - if (memcmp(firmware_header->more_magic, more_magic, 4) != 0) { + if (memcmp(firmware_start->more_magic, more_magic, 4) != 0) { fprintf(stderr, "Wrong more magic.\n"); return; } + + start_offset = sizeof(*firmware_start); + rc = read(fd, &buf[start_offset], sizeof(*firmware_header)); + if (rc < 0) { + perror("Can not read header."); + return; + } + firmware_header = (struct sdp_firmware *) &buf[start_offset]; + start_offset += sizeof(*firmware_header); + printf("Printing header information:\n"); printf("header_length: %u\n", ntohl(firmware_header->header_length)); printf("file_length: %u\n", ntohl(firmware_header->file_length)); @@ -106,7 +122,7 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int /* look into each firmware now */ for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) { struct sdp_header_entry entry; - unsigned int offset = sizeof(struct sdp_firmware) + base_offset; + unsigned int offset = start_offset + base_offset; offset += i * 138; if (lseek(fd, offset, SEEK_SET) != offset) { From b1414d99c49304e75024b0a5988b282d01d69121 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 18:22:29 +0100 Subject: [PATCH 268/365] [ipaccess] Start the parser recursively... * Start parsing the sub SDPs with the same analyze method --- openbsc/src/ipaccess/ipaccess-firmware.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 1325e5576..f0c23e395 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -155,13 +155,9 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int return; } - rc = read(fd, &buf, 4); - if (rc != 4) { - perror("peek failed"); - return; - } - - printf("FOO %.4s\n", buf); + printf("------> parsing\n"); + analyze_file(fd, ntohl(entry.length), offset); + printf("<------ parsing\n"); } } From 1684e79365b89059b20a7965bc913d2f1aad3f7b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 18:23:06 +0100 Subject: [PATCH 269/365] [ipaccess] Allow to parse the second magic2 as well * The internal SDP appears to have a different magic number than the first entry and a slightly different packet format * There are 8 byte of binary for at the beginning and the header ends with a table pointing to some strings and then the actual firmware follows. * We currently only parse the strings of that header. --- openbsc/src/ipaccess/ipaccess-firmware.c | 56 +++++++++++++++++++----- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index f0c23e395..d2afb5057 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -46,6 +46,17 @@ struct sdp_firmware { /* stuff i don't know */ } __attribute__((packed)); +struct sdp_firmware_2 { + u_int8_t no_idea[8]; + char text1[20]; + char text2[64]; + char time[12]; + char date[14]; + char text3[10]; + char text4[20]; + u_int16_t some_length; +} __attribute__((packed)); + struct sdp_header_entry { u_int16_t something1; char text1[64]; @@ -64,12 +75,14 @@ static_assert(sizeof(struct sdp_firmware_start) + sizeof(struct sdp_firmware) == /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; +static char more_magic_internal[] = { 0x10, 0x02, 0x20, 0x0 }; static void analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset) { struct sdp_firmware_start *firmware_start; - struct sdp_firmware *firmware_header; + struct sdp_firmware *firmware_header = 0; + struct sdp_firmware_2 *firmware_2 = 0; char buf[4096]; int rc, i; unsigned int start_offset = 0; @@ -86,20 +99,39 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int return; } - if (memcmp(firmware_start->more_magic, more_magic, 4) != 0) { - fprintf(stderr, "Wrong more magic.\n"); - return; - } - - start_offset = sizeof(*firmware_start); - rc = read(fd, &buf[start_offset], sizeof(*firmware_header)); - if (rc < 0) { - perror("Can not read header."); + if (memcmp(firmware_start->more_magic, more_magic, 4) == 0) { + rc = read(fd, &buf[start_offset], sizeof(*firmware_header)); + if (rc != sizeof(*firmware_header)) { + perror("Can not read header."); + return; + } + firmware_header = (struct sdp_firmware *) &buf[start_offset]; + start_offset += sizeof(*firmware_header); + } else if (memcmp(firmware_start->more_magic, more_magic_internal, 4) == 0) { + rc = read(fd, &buf[start_offset], sizeof(*firmware_2)); + if (rc != sizeof(*firmware_2)) { + perror("Can not read header version type 2."); + return; + } + firmware_2 = (struct sdp_firmware_2 *) &buf[start_offset]; + start_offset += sizeof(*firmware_2); + printf("Firmware header 2\n"); + printf("text1: %.64s\n", firmware_2->text1); + printf("time: %.12s\n", firmware_2->time); + printf("date: %.14s\n", firmware_2->date); + printf("text2: %.10s\n", firmware_2->text2); + printf("text3: %.20s\n", firmware_2->text3); + } else { + fprintf(stderr, "Wrong more magic. Got: 0x%x %x %x %x\n", + firmware_start->more_magic[0] & 0xff, firmware_start->more_magic[1] & 0xff, + firmware_start->more_magic[2] & 0xff, firmware_start->more_magic[3] & 0xff); return; } - firmware_header = (struct sdp_firmware *) &buf[start_offset]; - start_offset += sizeof(*firmware_header); + + + if (!firmware_header) + return; printf("Printing header information:\n"); printf("header_length: %u\n", ntohl(firmware_header->header_length)); From 67b05d590beb4aeb9d9f37329b3dff3996f98993 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 29 Dec 2009 18:41:43 +0100 Subject: [PATCH 270/365] [ipaccess] There is only one second magic number * The second magic number is only a short and it is the same for all of my cases * This also means that the first and second header are the same which means the unknown 8 byte are header and file size... and the 122 bytes are actually multiple strings (just all empty on the outermost SDP). Adding the strings left us with 120 bytes so we have two bytes of unknown usage.. * This is now capable of parsing outer and inner SDP files and print their header. --- openbsc/src/ipaccess/ipaccess-firmware.c | 59 +++++++++--------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index d2afb5057..fcdc2e6f9 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -34,27 +34,22 @@ struct sdp_firmware_start { char magic[4]; - char more_magic[4]; + char more_magic[2]; + u_int16_t more_more_magic; } __attribute__((packed)); struct sdp_firmware { u_int32_t header_length; u_int32_t file_length; char sw_part[20]; - char text1[122]; - u_int16_t part_length; - /* stuff i don't know */ -} __attribute__((packed)); - -struct sdp_firmware_2 { - u_int8_t no_idea[8]; - char text1[20]; - char text2[64]; + char text1[64]; char time[12]; char date[14]; - char text3[10]; - char text4[20]; - u_int16_t some_length; + char text2[10]; + char text3[20]; + u_int8_t dummy[2]; + u_int16_t part_length; + /* stuff i don't know */ } __attribute__((packed)); struct sdp_header_entry { @@ -74,15 +69,12 @@ static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); static_assert(sizeof(struct sdp_firmware_start) + sizeof(struct sdp_firmware) == 160, _right_header_length); /* more magic, the second "int" in the header */ -static char more_magic[] = { 0x10, 0x02, 0x00, 0x0 }; -static char more_magic_internal[] = { 0x10, 0x02, 0x20, 0x0 }; - +static char more_magic[] = { 0x10, 0x02 }; static void analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset) { struct sdp_firmware_start *firmware_start; struct sdp_firmware *firmware_header = 0; - struct sdp_firmware_2 *firmware_2 = 0; char buf[4096]; int rc, i; unsigned int start_offset = 0; @@ -100,7 +92,7 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int } start_offset = sizeof(*firmware_start); - if (memcmp(firmware_start->more_magic, more_magic, 4) == 0) { + if (memcmp(firmware_start->more_magic, more_magic, 2) == 0) { rc = read(fd, &buf[start_offset], sizeof(*firmware_header)); if (rc != sizeof(*firmware_header)) { perror("Can not read header."); @@ -108,20 +100,6 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int } firmware_header = (struct sdp_firmware *) &buf[start_offset]; start_offset += sizeof(*firmware_header); - } else if (memcmp(firmware_start->more_magic, more_magic_internal, 4) == 0) { - rc = read(fd, &buf[start_offset], sizeof(*firmware_2)); - if (rc != sizeof(*firmware_2)) { - perror("Can not read header version type 2."); - return; - } - firmware_2 = (struct sdp_firmware_2 *) &buf[start_offset]; - start_offset += sizeof(*firmware_2); - printf("Firmware header 2\n"); - printf("text1: %.64s\n", firmware_2->text1); - printf("time: %.12s\n", firmware_2->time); - printf("date: %.14s\n", firmware_2->date); - printf("text2: %.10s\n", firmware_2->text2); - printf("text3: %.20s\n", firmware_2->text3); } else { fprintf(stderr, "Wrong more magic. Got: 0x%x %x %x %x\n", firmware_start->more_magic[0] & 0xff, firmware_start->more_magic[1] & 0xff, @@ -134,18 +112,27 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int return; printf("Printing header information:\n"); + printf("more_more_magic: 0x%x\n", ntohs(firmware_start->more_more_magic)); printf("header_length: %u\n", ntohl(firmware_header->header_length)); printf("file_length: %u\n", ntohl(firmware_header->file_length)); printf("sw_part: %.20s\n", firmware_header->sw_part); - printf("text1: %.120s\n", firmware_header->text1); - printf("items: %u (rest %u)\n", ntohs(firmware_header->part_length) / PART_LENGTH, - ntohs(firmware_header->part_length) % PART_LENGTH); - + printf("text1: %.64s\n", firmware_header->text1); + printf("time: %.12s\n", firmware_header->time); + printf("date: %.14s\n", firmware_header->date); + printf("text2: %.10s\n", firmware_header->text2); + printf("text3: %.20s\n", firmware_header->text3); if (ntohl(firmware_header->file_length) != st_size) { fprintf(stderr, "The filesize and the header do not match.\n"); return; } + /* this semantic appears to be only the case for 0x0000 */ + if (firmware_start->more_more_magic != 0) + return; + + printf("items: %u (rest %u)\n", ntohs(firmware_header->part_length) / PART_LENGTH, + ntohs(firmware_header->part_length) % PART_LENGTH); + if (ntohs(firmware_header->part_length) % PART_LENGTH != 0) { fprintf(stderr, "The part length seems to be wrong.\n"); return; From 8f99562474acbc05e97fca26e9ce0d5fc17c1dd3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 04:47:27 +0100 Subject: [PATCH 271/365] [ipaccess] Add return values to the analyze_file --- openbsc/src/ipaccess/ipaccess-firmware.c | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index fcdc2e6f9..e9b1c61c7 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -71,7 +71,7 @@ static_assert(sizeof(struct sdp_firmware_start) + sizeof(struct sdp_firmware) == /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02 }; -static void analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset) +static int analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset) { struct sdp_firmware_start *firmware_start; struct sdp_firmware *firmware_header = 0; @@ -82,13 +82,13 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int rc = read(fd, buf, sizeof(*firmware_start)); if (rc < 0) { perror("Can not read header start."); - return; + return -1; } firmware_start = (struct sdp_firmware_start *) &buf[0]; if (strncmp(firmware_start->magic, " SDP", 4) != 0) { fprintf(stderr, "Wrong magic.\n"); - return; + return -1; } start_offset = sizeof(*firmware_start); @@ -96,7 +96,7 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int rc = read(fd, &buf[start_offset], sizeof(*firmware_header)); if (rc != sizeof(*firmware_header)) { perror("Can not read header."); - return; + return -1; } firmware_header = (struct sdp_firmware *) &buf[start_offset]; start_offset += sizeof(*firmware_header); @@ -104,12 +104,12 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int fprintf(stderr, "Wrong more magic. Got: 0x%x %x %x %x\n", firmware_start->more_magic[0] & 0xff, firmware_start->more_magic[1] & 0xff, firmware_start->more_magic[2] & 0xff, firmware_start->more_magic[3] & 0xff); - return; + return -1; } if (!firmware_header) - return; + return -1; printf("Printing header information:\n"); printf("more_more_magic: 0x%x\n", ntohs(firmware_start->more_more_magic)); @@ -123,19 +123,19 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int printf("text3: %.20s\n", firmware_header->text3); if (ntohl(firmware_header->file_length) != st_size) { fprintf(stderr, "The filesize and the header do not match.\n"); - return; + return -1; } /* this semantic appears to be only the case for 0x0000 */ if (firmware_start->more_more_magic != 0) - return; + return -1; printf("items: %u (rest %u)\n", ntohs(firmware_header->part_length) / PART_LENGTH, ntohs(firmware_header->part_length) % PART_LENGTH); if (ntohs(firmware_header->part_length) % PART_LENGTH != 0) { fprintf(stderr, "The part length seems to be wrong.\n"); - return; + return -1; } /* look into each firmware now */ @@ -146,13 +146,13 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int if (lseek(fd, offset, SEEK_SET) != offset) { fprintf(stderr, "Can not seek to the offset: %u.\n", offset); - return; + return -1; } rc = read(fd, &entry, sizeof(entry)); if (rc != sizeof(entry)) { fprintf(stderr, "Can not read the header entry.\n"); - return; + return -1; } printf("Header Entry: %d\n", i); @@ -171,13 +171,15 @@ static void analyze_file(int fd, const unsigned int st_size, const unsigned int offset = ntohl(entry.start) + 4 + base_offset; if (lseek(fd, offset, SEEK_SET) != offset) { perror("can't seek to sdp"); - return; + return -1; } printf("------> parsing\n"); analyze_file(fd, ntohl(entry.length), offset); printf("<------ parsing\n"); } + + return 0; } int main(int argc, char** argv) From 4a98cad85e196ee3e23c527862d8c524e150366a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 05:56:49 +0100 Subject: [PATCH 272/365] [ipaccess] Turn firmware parsing into a routine so it can be used * text3 seems to be a version as the text content starts with a 'v' * move the sdp_firmware into the ipaccess.h and declare the function. The headers are returned through a list. --- openbsc/include/openbsc/ipaccess.h | 28 ++++++ openbsc/src/ipaccess/ipaccess-firmware.c | 112 ++++++++--------------- 2 files changed, 68 insertions(+), 72 deletions(-) diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index 21a5c1759..5040de02f 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -2,6 +2,7 @@ #define _IPACCESS_H #include "e1_input.h" +#include "linuxlist.h" #define IPA_TCP_PORT_OML 3002 #define IPA_TCP_PORT_RSL 3003 @@ -48,4 +49,31 @@ int ipaccess_rcvmsg_base(struct msgb *msg, struct bsc_fd *bfd); struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error); void ipaccess_prepend_header(struct msgb *msg, int proto); +/* + * Firmware specific header + */ +struct sdp_firmware { + char magic[4]; + char more_magic[2]; + u_int16_t more_more_magic; + u_int32_t header_length; + u_int32_t file_length; + char sw_part[20]; + char text1[64]; + char time[12]; + char date[14]; + char text2[10]; + char version[20]; + u_int8_t dummy[2]; + u_int16_t part_length; + /* stuff i don't know */ +} __attribute__((packed)); + +struct sdp_header { + struct sdp_firmware firmware_info; + struct llist_head list; +}; + +int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned base_offset, struct llist_head *list); + #endif /* _IPACCESS_H */ diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index e9b1c61c7..6edef91d5 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -32,33 +33,13 @@ #define PART_LENGTH 138 -struct sdp_firmware_start { - char magic[4]; - char more_magic[2]; - u_int16_t more_more_magic; -} __attribute__((packed)); - -struct sdp_firmware { - u_int32_t header_length; - u_int32_t file_length; - char sw_part[20]; - char text1[64]; - char time[12]; - char date[14]; - char text2[10]; - char text3[20]; - u_int8_t dummy[2]; - u_int16_t part_length; - /* stuff i don't know */ -} __attribute__((packed)); - struct sdp_header_entry { u_int16_t something1; char text1[64]; char time[12]; char date[14]; char text2[10]; - char text3[20]; + char version[20]; u_int32_t length; u_int32_t addr1; u_int32_t addr2; @@ -66,44 +47,34 @@ struct sdp_header_entry { } __attribute__((packed)); static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); -static_assert(sizeof(struct sdp_firmware_start) + sizeof(struct sdp_firmware) == 160, _right_header_length); +static_assert(sizeof(struct sdp_firmware) == 160, _right_header_length); /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02 }; -static int analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset) +int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset, struct llist_head *list) { - struct sdp_firmware_start *firmware_start; struct sdp_firmware *firmware_header = 0; + struct sdp_header *header; char buf[4096]; int rc, i; - unsigned int start_offset = 0; - rc = read(fd, buf, sizeof(*firmware_start)); + rc = read(fd, buf, sizeof(*firmware_header)); if (rc < 0) { perror("Can not read header start."); return -1; } - firmware_start = (struct sdp_firmware_start *) &buf[0]; - if (strncmp(firmware_start->magic, " SDP", 4) != 0) { + firmware_header = (struct sdp_firmware *) &buf[0]; + if (strncmp(firmware_header->magic, " SDP", 4) != 0) { fprintf(stderr, "Wrong magic.\n"); return -1; } - start_offset = sizeof(*firmware_start); - if (memcmp(firmware_start->more_magic, more_magic, 2) == 0) { - rc = read(fd, &buf[start_offset], sizeof(*firmware_header)); - if (rc != sizeof(*firmware_header)) { - perror("Can not read header."); - return -1; - } - firmware_header = (struct sdp_firmware *) &buf[start_offset]; - start_offset += sizeof(*firmware_header); - } else { + if (memcmp(firmware_header->more_magic, more_magic, 2) != 0) { fprintf(stderr, "Wrong more magic. Got: 0x%x %x %x %x\n", - firmware_start->more_magic[0] & 0xff, firmware_start->more_magic[1] & 0xff, - firmware_start->more_magic[2] & 0xff, firmware_start->more_magic[3] & 0xff); + firmware_header->more_magic[0] & 0xff, firmware_header->more_magic[1] & 0xff, + firmware_header->more_magic[2] & 0xff, firmware_header->more_magic[3] & 0xff); return -1; } @@ -111,27 +82,19 @@ static int analyze_file(int fd, const unsigned int st_size, const unsigned int b if (!firmware_header) return -1; - printf("Printing header information:\n"); - printf("more_more_magic: 0x%x\n", ntohs(firmware_start->more_more_magic)); - printf("header_length: %u\n", ntohl(firmware_header->header_length)); - printf("file_length: %u\n", ntohl(firmware_header->file_length)); - printf("sw_part: %.20s\n", firmware_header->sw_part); - printf("text1: %.64s\n", firmware_header->text1); - printf("time: %.12s\n", firmware_header->time); - printf("date: %.14s\n", firmware_header->date); - printf("text2: %.10s\n", firmware_header->text2); - printf("text3: %.20s\n", firmware_header->text3); if (ntohl(firmware_header->file_length) != st_size) { fprintf(stderr, "The filesize and the header do not match.\n"); return -1; } - /* this semantic appears to be only the case for 0x0000 */ - if (firmware_start->more_more_magic != 0) - return -1; + /* add the firmware */ + header = malloc(sizeof(*header)); + header->firmware_info = *firmware_header; + llist_add(&header->list, list); - printf("items: %u (rest %u)\n", ntohs(firmware_header->part_length) / PART_LENGTH, - ntohs(firmware_header->part_length) % PART_LENGTH); + /* this semantic appears to be only the case for 0x0000 */ + if (firmware_header->more_more_magic != 0) + return -1; if (ntohs(firmware_header->part_length) % PART_LENGTH != 0) { fprintf(stderr, "The part length seems to be wrong.\n"); @@ -141,7 +104,7 @@ static int analyze_file(int fd, const unsigned int st_size, const unsigned int b /* look into each firmware now */ for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) { struct sdp_header_entry entry; - unsigned int offset = start_offset + base_offset; + unsigned int offset = base_offset + sizeof(struct sdp_firmware); offset += i * 138; if (lseek(fd, offset, SEEK_SET) != offset) { @@ -155,18 +118,6 @@ static int analyze_file(int fd, const unsigned int st_size, const unsigned int b return -1; } - printf("Header Entry: %d\n", i); - printf("\tsomething1: %u\n", ntohs(entry.something1)); - printf("\ttext1: %.64s\n", entry.text1); - printf("\ttime: %.12s\n", entry.time); - printf("\tdate: %.14s\n", entry.date); - printf("\ttext2: %.10s\n", entry.text2); - printf("\ttext3: %.20s\n", entry.text3); - printf("\taddr1: 0x%x\n", entry.addr1); - printf("\taddr2: 0x%x\n", entry.addr2); - printf("\tstart: 0x%x\n", ntohl(entry.start)); - printf("\tlength: 0x%x\n", ntohl(entry.length)); - /* now we need to find the SDP file... */ offset = ntohl(entry.start) + 4 + base_offset; if (lseek(fd, offset, SEEK_SET) != offset) { @@ -174,9 +125,7 @@ static int analyze_file(int fd, const unsigned int st_size, const unsigned int b return -1; } - printf("------> parsing\n"); - analyze_file(fd, ntohl(entry.length), offset); - printf("<------ parsing\n"); + ipacces_analyze_file(fd, ntohl(entry.length), offset, list); } return 0; @@ -188,6 +137,10 @@ int main(int argc, char** argv) struct stat stat; for (i = 1; i < argc; ++i) { + struct sdp_header *header; + struct llist_head entry; + INIT_LLIST_HEAD(&entry); + printf("Opening possible firmware '%s'\n", argv[i]); fd = open(argv[i], O_RDONLY); if (!fd) { @@ -201,8 +154,23 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - analyze_file(fd, stat.st_size, 0); + ipacces_analyze_file(fd, stat.st_size, 0, &entry); + + llist_for_each_entry(header, &entry, list) { + printf("Printing header information:\n"); + printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic)); + printf("header_length: %u\n", ntohl(header->firmware_info.header_length)); + printf("file_length: %u\n", ntohl(header->firmware_info.file_length)); + printf("sw_part: %.20s\n", header->firmware_info.sw_part); + printf("text1: %.64s\n", header->firmware_info.text1); + printf("time: %.12s\n", header->firmware_info.time); + printf("date: %.14s\n", header->firmware_info.date); + printf("text2: %.10s\n", header->firmware_info.text2); + printf("version: %.20s\n", header->firmware_info.version); + printf("\n\n"); + } } + return EXIT_SUCCESS; } From c9f8a6dca32be1b2037707f59e681767fd32951f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 06:10:56 +0100 Subject: [PATCH 273/365] [ipaccess] Expose the sub header list as well.. --- openbsc/include/openbsc/ipaccess.h | 25 ++++++++++++++- openbsc/src/ipaccess/ipaccess-firmware.c | 40 +++++++++++++++--------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index 5040de02f..31393811c 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -69,9 +69,32 @@ struct sdp_firmware { /* stuff i don't know */ } __attribute__((packed)); +struct sdp_header_entry { + u_int16_t something1; + char text1[64]; + char time[12]; + char date[14]; + char text2[10]; + char version[20]; + u_int32_t length; + u_int32_t addr1; + u_int32_t addr2; + u_int32_t start; +} __attribute__((packed)); + +struct sdp_header_entry_list { + struct sdp_header_entry header_entry; + struct llist_head entry; +}; + struct sdp_header { struct sdp_firmware firmware_info; - struct llist_head list; + + /* for more_magic a list of sdp_header_entry_list */ + struct llist_head header_list; + + /* the entry of the sdp_header */ + struct llist_head entry; }; int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned base_offset, struct llist_head *list); diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 6edef91d5..2fb7befe0 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -33,19 +33,6 @@ #define PART_LENGTH 138 -struct sdp_header_entry { - u_int16_t something1; - char text1[64]; - char time[12]; - char date[14]; - char text2[10]; - char version[20]; - u_int32_t length; - u_int32_t addr1; - u_int32_t addr2; - u_int32_t start; -} __attribute__((packed)); - static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); static_assert(sizeof(struct sdp_firmware) == 160, _right_header_length); @@ -90,7 +77,8 @@ int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int /* add the firmware */ header = malloc(sizeof(*header)); header->firmware_info = *firmware_header; - llist_add(&header->list, list); + INIT_LLIST_HEAD(&header->header_list); + llist_add(&header->entry, list); /* this semantic appears to be only the case for 0x0000 */ if (firmware_header->more_more_magic != 0) @@ -104,6 +92,7 @@ int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int /* look into each firmware now */ for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) { struct sdp_header_entry entry; + struct sdp_header_entry_list *header_entry; unsigned int offset = base_offset + sizeof(struct sdp_firmware); offset += i * 138; @@ -125,6 +114,10 @@ int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int return -1; } + header_entry = malloc(sizeof(*header_entry)); + header_entry->header_entry = entry; + llist_add(&header_entry->entry, &header->header_list); + ipacces_analyze_file(fd, ntohl(entry.length), offset, list); } @@ -138,6 +131,7 @@ int main(int argc, char** argv) for (i = 1; i < argc; ++i) { struct sdp_header *header; + struct sdp_header_entry_list *sub_entry; struct llist_head entry; INIT_LLIST_HEAD(&entry); @@ -156,7 +150,7 @@ int main(int argc, char** argv) ipacces_analyze_file(fd, stat.st_size, 0, &entry); - llist_for_each_entry(header, &entry, list) { + llist_for_each_entry(header, &entry, entry) { printf("Printing header information:\n"); printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic)); printf("header_length: %u\n", ntohl(header->firmware_info.header_length)); @@ -167,7 +161,23 @@ int main(int argc, char** argv) printf("date: %.14s\n", header->firmware_info.date); printf("text2: %.10s\n", header->firmware_info.text2); printf("version: %.20s\n", header->firmware_info.version); + printf("subitems...\n"); + + llist_for_each_entry(sub_entry, &header->header_list, entry) { + printf("\tsomething1: %u\n", sub_entry->header_entry.something1); + printf("\ttext1: %.64s\n", sub_entry->header_entry.text1); + printf("\ttime: %.12s\n", sub_entry->header_entry.time); + printf("\tdate: %.14s\n", sub_entry->header_entry.date); + printf("\ttext2: %.10s\n", sub_entry->header_entry.text2); + printf("\tversion: %.20s\n", sub_entry->header_entry.version); + printf("\tlength: %u\n", ntohl(sub_entry->header_entry.length)); + printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1)); + printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2)); + printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start)); + printf("\n\n"); + } printf("\n\n"); + } } From 0183edd18c0b45b200b711e4b8ec9f185fa4e1a1 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 06:13:36 +0100 Subject: [PATCH 274/365] [ipaccess] Change the name to be slightly better.. --- openbsc/include/openbsc/ipaccess.h | 2 +- openbsc/src/ipaccess/ipaccess-firmware.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index 31393811c..8c12e59cc 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -82,7 +82,7 @@ struct sdp_header_entry { u_int32_t start; } __attribute__((packed)); -struct sdp_header_entry_list { +struct sdp_header_item { struct sdp_header_entry header_entry; struct llist_head entry; }; diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 2fb7befe0..431fe315c 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -92,7 +92,7 @@ int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int /* look into each firmware now */ for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) { struct sdp_header_entry entry; - struct sdp_header_entry_list *header_entry; + struct sdp_header_item *header_entry; unsigned int offset = base_offset + sizeof(struct sdp_firmware); offset += i * 138; @@ -131,7 +131,7 @@ int main(int argc, char** argv) for (i = 1; i < argc; ++i) { struct sdp_header *header; - struct sdp_header_entry_list *sub_entry; + struct sdp_header_item *sub_entry; struct llist_head entry; INIT_LLIST_HEAD(&entry); From af351a21f24be576687e060d17a2951466b7be21 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 06:40:36 +0100 Subject: [PATCH 275/365] [ipaccess] Start using talloc in the firmware code * We are not leaking anything... *yeah*, talloc rocks --- openbsc/src/Makefile.am | 2 +- openbsc/src/ipaccess/ipaccess-firmware.c | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index e665c99eb..2d9df992c 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -39,6 +39,6 @@ isdnsync_SOURCES = isdnsync.c bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a -ipaccess_firmware_SOURCES = ipaccess/ipaccess-firmware.c +ipaccess_firmware_SOURCES = ipaccess/ipaccess-firmware.c talloc.c ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 431fe315c..36a42df58 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -39,6 +40,9 @@ static_assert(sizeof(struct sdp_firmware) == 160, _right_header_length); /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02 }; +/* talloc context */ +void *tall_firm_ctx; + int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset, struct llist_head *list) { struct sdp_firmware *firmware_header = 0; @@ -75,7 +79,7 @@ int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int } /* add the firmware */ - header = malloc(sizeof(*header)); + header = talloc_zero(list, struct sdp_header); header->firmware_info = *firmware_header; INIT_LLIST_HEAD(&header->header_list); llist_add(&header->entry, list); @@ -114,7 +118,7 @@ int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int return -1; } - header_entry = malloc(sizeof(*header_entry)); + header_entry = talloc_zero(header, struct sdp_header_item); header_entry->header_entry = entry; llist_add(&header_entry->entry, &header->header_list); @@ -132,8 +136,10 @@ int main(int argc, char** argv) for (i = 1; i < argc; ++i) { struct sdp_header *header; struct sdp_header_item *sub_entry; - struct llist_head entry; - INIT_LLIST_HEAD(&entry); + struct llist_head *entry; + + entry = talloc_zero(tall_firm_ctx, struct llist_head); + INIT_LLIST_HEAD(entry); printf("Opening possible firmware '%s'\n", argv[i]); fd = open(argv[i], O_RDONLY); @@ -148,9 +154,9 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - ipacces_analyze_file(fd, stat.st_size, 0, &entry); + ipacces_analyze_file(fd, stat.st_size, 0, entry); - llist_for_each_entry(header, &entry, entry) { + llist_for_each_entry(header, entry, entry) { printf("Printing header information:\n"); printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic)); printf("header_length: %u\n", ntohl(header->firmware_info.header_length)); @@ -177,8 +183,9 @@ int main(int argc, char** argv) printf("\n\n"); } printf("\n\n"); - } + + talloc_free(entry); } From 1f71d9c4c0f2df38191453d488c1841279bd5313 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 06:55:38 +0100 Subject: [PATCH 276/365] [ipaccess] Document the software argument for firmware loading --- openbsc/src/ipaccess/ipaccess-config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 3b81c2a38..f9746c2a4 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -399,6 +399,7 @@ static void print_help(void) printf(" -l --listen testnr \tPerform specified test number\n"); printf(" -h --help this text\n"); printf(" -s --stream-id ID\n"); + printf(" -d --software firmware\n"); } int main(int argc, char **argv) From dade8980e36a063f78e8cdcafe38d40552d0384a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 07:08:39 +0100 Subject: [PATCH 277/365] [ipaccess] Move firmware analysis into the ipaccess-config utility * This turns ipaccess-firmware.c into a plain helper, fix the ipaccess name... --- openbsc/src/Makefile.am | 6 +- openbsc/src/ipaccess/ipaccess-config.c | 69 ++++++++++++++++++++- openbsc/src/ipaccess/ipaccess-firmware.c | 76 +----------------------- 3 files changed, 73 insertions(+), 78 deletions(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 2d9df992c..544aea060 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess-firmware ipaccess-proxy + isdnsync bsc_mgcp ipaccess-proxy noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h @@ -31,7 +31,7 @@ bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \ ipaccess_find_SOURCES = ipaccess/ipaccess-find.c select.c timer.c -ipaccess_config_SOURCES = ipaccess/ipaccess-config.c +ipaccess_config_SOURCES = ipaccess/ipaccess-config.c ipaccess/ipaccess-firmware.c ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) isdnsync_SOURCES = isdnsync.c @@ -39,6 +39,4 @@ isdnsync_SOURCES = isdnsync.c bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a -ipaccess_firmware_SOURCES = ipaccess/ipaccess-firmware.c talloc.c - ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index f9746c2a4..cec7664f3 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -41,6 +43,7 @@ #include #include #include +#include static struct gsm_network *gsmnet; @@ -385,6 +388,65 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, return 0; } +static void analyze_firmware(const char *filename) +{ + struct stat stat; + struct sdp_header *header; + struct sdp_header_item *sub_entry; + struct llist_head *entry; + int fd; + void *tall_firm_ctx = 0; + + entry = talloc_zero(tall_firm_ctx, struct llist_head); + INIT_LLIST_HEAD(entry); + + printf("Opening possible firmware '%s'\n", filename); + fd = open(filename, O_RDONLY); + if (!fd) { + perror("nada"); + return; + } + + /* verify the file */ + if (fstat(fd, &stat) == -1) { + perror("Can not stat the file"); + return; + } + + ipaccess_analyze_file(fd, stat.st_size, 0, entry); + + llist_for_each_entry(header, entry, entry) { + printf("Printing header information:\n"); + printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic)); + printf("header_length: %u\n", ntohl(header->firmware_info.header_length)); + printf("file_length: %u\n", ntohl(header->firmware_info.file_length)); + printf("sw_part: %.20s\n", header->firmware_info.sw_part); + printf("text1: %.64s\n", header->firmware_info.text1); + printf("time: %.12s\n", header->firmware_info.time); + printf("date: %.14s\n", header->firmware_info.date); + printf("text2: %.10s\n", header->firmware_info.text2); + printf("version: %.20s\n", header->firmware_info.version); + printf("subitems...\n"); + + llist_for_each_entry(sub_entry, &header->header_list, entry) { + printf("\tsomething1: %u\n", sub_entry->header_entry.something1); + printf("\ttext1: %.64s\n", sub_entry->header_entry.text1); + printf("\ttime: %.12s\n", sub_entry->header_entry.time); + printf("\tdate: %.14s\n", sub_entry->header_entry.date); + printf("\ttext2: %.10s\n", sub_entry->header_entry.text2); + printf("\tversion: %.20s\n", sub_entry->header_entry.version); + printf("\tlength: %u\n", ntohl(sub_entry->header_entry.length)); + printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1)); + printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2)); + printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start)); + printf("\n\n"); + } + printf("\n\n"); + } + + talloc_free(tall_firm_ctx); +} + static void print_usage(void) { printf("Usage: ipaccess-config\n"); @@ -400,6 +462,7 @@ static void print_help(void) printf(" -h --help this text\n"); printf(" -s --stream-id ID\n"); printf(" -d --software firmware\n"); + printf(" -f --firmware firmware Provide firmware information\n"); } int main(int argc, char **argv) @@ -431,9 +494,10 @@ int main(int argc, char **argv) { "listen", 1, 0, 'l' }, { "stream-id", 1, 0, 's' }, { "software", 1, 0, 'd' }, + { "firmware", 1, 0, 'f' }, }; - c = getopt_long(argc, argv, "u:o:rn:l:hs:d:", long_options, + c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:", long_options, &option_index); if (c == -1) @@ -467,6 +531,9 @@ int main(int argc, char **argv) case 'd': software = strdup(optarg); break; + case 'f': + analyze_firmware(optarg); + exit(0); case 'h': print_usage(); print_help(); diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 36a42df58..ed4bc9a0c 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -23,14 +23,10 @@ #include #include -#include -#include -#include -#include -#include #include #include #include +#include #define PART_LENGTH 138 @@ -40,10 +36,7 @@ static_assert(sizeof(struct sdp_firmware) == 160, _right_header_length); /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02 }; -/* talloc context */ -void *tall_firm_ctx; - -int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset, struct llist_head *list) +int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset, struct llist_head *list) { struct sdp_firmware *firmware_header = 0; struct sdp_header *header; @@ -122,72 +115,9 @@ int ipacces_analyze_file(int fd, const unsigned int st_size, const unsigned int header_entry->header_entry = entry; llist_add(&header_entry->entry, &header->header_list); - ipacces_analyze_file(fd, ntohl(entry.length), offset, list); + ipaccess_analyze_file(fd, ntohl(entry.length), offset, list); } return 0; } -int main(int argc, char** argv) -{ - int i, fd; - struct stat stat; - - for (i = 1; i < argc; ++i) { - struct sdp_header *header; - struct sdp_header_item *sub_entry; - struct llist_head *entry; - - entry = talloc_zero(tall_firm_ctx, struct llist_head); - INIT_LLIST_HEAD(entry); - - printf("Opening possible firmware '%s'\n", argv[i]); - fd = open(argv[i], O_RDONLY); - if (!fd) { - perror("nada"); - continue; - } - - /* verify the file */ - if (fstat(fd, &stat) == -1) { - perror("Can not stat the file"); - return EXIT_FAILURE; - } - - ipacces_analyze_file(fd, stat.st_size, 0, entry); - - llist_for_each_entry(header, entry, entry) { - printf("Printing header information:\n"); - printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic)); - printf("header_length: %u\n", ntohl(header->firmware_info.header_length)); - printf("file_length: %u\n", ntohl(header->firmware_info.file_length)); - printf("sw_part: %.20s\n", header->firmware_info.sw_part); - printf("text1: %.64s\n", header->firmware_info.text1); - printf("time: %.12s\n", header->firmware_info.time); - printf("date: %.14s\n", header->firmware_info.date); - printf("text2: %.10s\n", header->firmware_info.text2); - printf("version: %.20s\n", header->firmware_info.version); - printf("subitems...\n"); - - llist_for_each_entry(sub_entry, &header->header_list, entry) { - printf("\tsomething1: %u\n", sub_entry->header_entry.something1); - printf("\ttext1: %.64s\n", sub_entry->header_entry.text1); - printf("\ttime: %.12s\n", sub_entry->header_entry.time); - printf("\tdate: %.14s\n", sub_entry->header_entry.date); - printf("\ttext2: %.10s\n", sub_entry->header_entry.text2); - printf("\tversion: %.20s\n", sub_entry->header_entry.version); - printf("\tlength: %u\n", ntohl(sub_entry->header_entry.length)); - printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1)); - printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2)); - printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start)); - printf("\n\n"); - } - printf("\n\n"); - } - - talloc_free(entry); - } - - - return EXIT_SUCCESS; -} From 322127413e6eef6dead82f2d0ef5dcab50472f4f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 07:33:23 +0100 Subject: [PATCH 278/365] [ipaccess] Close the firmware file as well --- openbsc/src/ipaccess/ipaccess-config.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index cec7664f3..2577c49ff 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -414,6 +414,10 @@ static void analyze_firmware(const char *filename) } ipaccess_analyze_file(fd, stat.st_size, 0, entry); + if (close(fd) != 0) { + perror("Close failed.\n"); + return; + } llist_for_each_entry(header, entry, entry) { printf("Printing header information:\n"); From f9811defe28eb8fde03c4dfa91f27ecbd876eb97 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 08:11:18 +0100 Subject: [PATCH 279/365] [ipaccess] Make SW activation work by filling out sw_load1 and sw_load2 We are filling sw_load1 with the information found with type 0x1000 and sw_load2 with type 0x2001. It appears from the protocol traces that these information is not extracted from them. We also need to include the \0 from the string. With this firmware flashing seems to work. --- openbsc/src/ipaccess/ipaccess-config.c | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 2577c49ff..759161490 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -64,6 +64,7 @@ struct sw_load { u_int8_t file_version_len; }; +static void *tall_ctx_config = NULL; static struct sw_load *sw_load1 = NULL; static struct sw_load *sw_load2 = NULL; @@ -388,6 +389,59 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, return 0; } +static void find_sw_load_params(const char *filename) +{ + struct stat stat; + struct sdp_header *header; + struct llist_head *entry; + int fd; + void *tall_firm_ctx = 0; + + entry = talloc_zero(tall_firm_ctx, struct llist_head); + INIT_LLIST_HEAD(entry); + + fd = open(filename, O_RDONLY); + if (!fd) { + perror("nada"); + return; + } + + /* verify the file */ + if (fstat(fd, &stat) == -1) { + perror("Can not stat the file"); + return; + } + + ipaccess_analyze_file(fd, stat.st_size, 0, entry); + if (close(fd) != 0) { + perror("Close failed.\n"); + return; + } + + /* try to find what we are looking for */ + llist_for_each_entry(header, entry, entry) { + if (ntohs(header->firmware_info.more_more_magic) == 0x1000) { + sw_load1 = talloc_zero(tall_ctx_config, struct sw_load); + + strncpy((char *)sw_load1->file_id, header->firmware_info.sw_part, 20); + sw_load1->file_id_len = strlen(header->firmware_info.sw_part) + 1; + + strncpy((char *)sw_load1->file_version, header->firmware_info.version, 20); + sw_load1->file_version_len = strlen(header->firmware_info.version) + 1; + } else if (ntohs(header->firmware_info.more_more_magic) == 0x2001) { + sw_load2 = talloc_zero(tall_ctx_config, struct sw_load); + + strncpy((char *)sw_load2->file_id, header->firmware_info.sw_part, 20); + sw_load2->file_id_len = strlen(header->firmware_info.sw_part) + 1; + + strncpy((char *)sw_load2->file_version, header->firmware_info.version, 20); + sw_load2->file_version_len = strlen(header->firmware_info.version) + 1; + } + } + + talloc_free(tall_firm_ctx); +} + static void analyze_firmware(const char *filename) { struct stat stat; @@ -534,6 +588,7 @@ int main(int argc, char **argv) break; case 'd': software = strdup(optarg); + find_sw_load_params(optarg); break; case 'f': analyze_firmware(optarg); From 2e83782b1c185bd63544bdd74de2e5e4d965f981 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 08:38:43 +0100 Subject: [PATCH 280/365] [ipaccess] Restart only after setting the OML IP, software load * Do not issue the restart right aways if we have OML IP or software load in the queue (hint, we need a real queue of operations to carry out... with one big state machine) * Change the signal_data of ipacc ACK/NACK to contain the msg type and the bts pointer. * Issue a restart for software load and OML and use the BTS pointer we got out of the new signal data. --- openbsc/include/openbsc/signal.h | 5 +++++ openbsc/src/abis_nm.c | 9 ++++++-- openbsc/src/ipaccess/ipaccess-config.c | 30 +++++++++++++++++++------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index f13b12be8..8b6b4a628 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -124,6 +124,11 @@ struct scall_signal_data { void *data; }; +struct ipacc_ack_signal_data { + struct gsm_bts *bts; + u_int8_t msg_type; +}; + /* Management */ int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data); void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data); diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 9dedcaf5d..8a9670477 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2721,6 +2721,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) struct abis_om_fom_hdr *foh; u_int8_t idstrlen = oh->data[0]; struct tlv_parsed tp; + struct ipacc_ack_signal_data signal; if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) { LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n"); @@ -2803,10 +2804,14 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_RSL_CONNECT_NACK: case NM_MT_IPACC_SET_NVATTR_NACK: case NM_MT_IPACC_GET_NVATTR_NACK: - dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type); + signal.bts = msg->trx->bts; + signal.msg_type = foh->msg_type; + dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal); break; case NM_MT_IPACC_SET_NVATTR_ACK: - dispatch_signal(SS_NM, S_NM_IPACC_ACK, &foh->msg_type); + signal.bts = msg->trx->bts; + signal.msg_type = foh->msg_type; + dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal); break; default: break; diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 759161490..29b9a9bf7 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -55,6 +55,7 @@ static u_int16_t nv_flags; static u_int16_t nv_mask; static char *software = NULL; static int sw_load_state = 0; +static int oml_state = 0; struct sw_load { u_int8_t file_id[255]; @@ -87,11 +88,23 @@ static int ipacc_msg_nack(u_int8_t mt) return 0; } -static int ipacc_msg_ack(u_int8_t mt) +static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts *bts) { if (sw_load_state == 1) { fprintf(stderr, "The new software is activaed.\n"); - exit(0); + + if (restart) { + abis_nm_ipaccess_restart(bts); + } else { + exit(0); + } + } else if (oml_state == 1) { + fprintf(stderr, "Set the primary OML IP.\n"); + if (restart) { + abis_nm_ipaccess_restart(bts); + } else { + exit(0); + } } return 0; @@ -178,15 +191,15 @@ static int test_rep(void *_msg) static int nm_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { - u_int8_t *msg_type; + struct ipacc_ack_signal_data *ipacc_data; switch (signal) { case S_NM_IPACC_NACK: - msg_type = signal_data; - return ipacc_msg_nack(*msg_type); + ipacc_data = signal_data; + return ipacc_msg_nack(ipacc_data->msg_type); case S_NM_IPACC_ACK: - msg_type = signal_data; - return ipacc_msg_ack(*msg_type); + ipacc_data = signal_data; + return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->bts); case S_NM_TEST_REP: return test_rep(signal_data); default: @@ -315,6 +328,7 @@ static void bootstrap_om(struct gsm_bts *bts) *cur++ = 0; *cur++ = 0; printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia)); + oml_state = 1; abis_nm_ipaccess_set_nvattr(bts, buf, 3+len); } if (nv_mask) { @@ -332,7 +346,7 @@ static void bootstrap_om(struct gsm_bts *bts) abis_nm_ipaccess_set_nvattr(bts, buf, 3+len); } - if (restart) { + if (restart && !prim_oml_ip && !software) { printf("restarting BTS\n"); abis_nm_ipaccess_restart(bts); } From 1356c08cc8f22b4b75a845ebd96651577c984744 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 09:00:01 +0100 Subject: [PATCH 281/365] [abis] Dispatch a IPAC restart ACK/NACK signal * Add the NACK version to the list * Dispatch the signal when we receive the message * Handle it in ipaccess-config by exiting the application --- openbsc/include/openbsc/abis_nm.h | 1 + openbsc/include/openbsc/signal.h | 2 ++ openbsc/src/abis_nm.c | 6 ++++++ openbsc/src/ipaccess/ipaccess-config.c | 8 ++++++++ 4 files changed, 17 insertions(+) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index c237613c8..a122342f2 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -211,6 +211,7 @@ enum abis_nm_msgtype_bs11 { enum abis_nm_msgtype_ipacc { NM_MT_IPACC_RESTART = 0x87, NM_MT_IPACC_RESTART_ACK, + NM_MT_IPACC_RESTART_NACK, NM_MT_IPACC_RSL_CONNECT = 0xe0, NM_MT_IPACC_RSL_CONNECT_ACK, NM_MT_IPACC_RSL_CONNECT_NACK, diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 8b6b4a628..23551f743 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -70,6 +70,8 @@ enum signal_nm { S_NM_NACK, /* GSM 12.21 various NM_MT_*_NACK happened */ S_NM_IPACC_NACK, /* GSM 12.21 nanoBTS extensions NM_MT_IPACC_*_*_NACK happened */ S_NM_IPACC_ACK, /* GSM 12.21 nanoBTS extensions NM_MT_IPACC_*_*_ACK happened */ + S_NM_IPACC_RESTART_ACK, /* nanoBTS has send a restart ack */ + S_NM_IPACC_RESTART_NACK,/* nanoBTS has send a restart ack */ S_NM_TEST_REP, /* GSM 12.21 Test Report */ }; diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 8a9670477..bb2455d37 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1070,6 +1070,12 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) case NM_MT_CONN_MDROP_LINK_ACK: DEBUGP(DNM, "CONN MDROP LINK ACK\n"); break; + case NM_MT_IPACC_RESTART_ACK: + dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL); + break; + case NM_MT_IPACC_RESTART_NACK: + dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL); + break; } return 0; diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 29b9a9bf7..432179eb5 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -202,6 +202,14 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal, return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->bts); case S_NM_TEST_REP: return test_rep(signal_data); + case S_NM_IPACC_RESTART_ACK: + printf("The BTS has acked the restart. Exiting.\n"); + exit(0); + break; + case S_NM_IPACC_RESTART_NACK: + printf("The BTS has nacked the restart. Exiting.\n"); + exit(0); + break; default: break; } From 7992867f4b54dc99d5dbf0e03226ca844a6dc550 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 09:23:48 +0100 Subject: [PATCH 282/365] [abis] Refactor sw descr generation to a new methods * This is used in sw_load_init and sw_load_end and both needs to be touche for every BTS. Move it into a common method. * This was only verified on the nanoBTS. --- openbsc/src/abis_nm.c | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index bb2455d37..f82dc6f39 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1221,6 +1221,22 @@ struct abis_nm_sw { static struct abis_nm_sw g_sw; +static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg) +{ + if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) { + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else if (sw->bts->type == GSM_BTS_TYPE_BS11) { + msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else { + LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n"); + } +} + /* 6.2.1 / 8.3.1: Load Data Initiate */ static int sw_load_init(struct abis_nm_sw *sw) { @@ -1233,18 +1249,7 @@ static int sw_load_init(struct abis_nm_sw *sw) sw->obj_instance[0], sw->obj_instance[1], sw->obj_instance[2]); - if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) { - msgb_v_put(msg, NM_ATT_SW_DESCR); - msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - } else if (sw->bts->type == GSM_BTS_TYPE_BS11) { - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - } else { - return -1; - } + sw_add_file_id_and_ver(sw, msg); msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size); return abis_nm_sendmsg(sw->bts, msg); @@ -1343,19 +1348,7 @@ static int sw_load_end(struct abis_nm_sw *sw) sw->obj_instance[0], sw->obj_instance[1], sw->obj_instance[2]); - if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) { - msgb_v_put(msg, NM_ATT_SW_DESCR); - msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - } else if (sw->bts->type == GSM_BTS_TYPE_BS11) { - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - } else { - return -1; - } - + sw_add_file_id_and_ver(sw, msg); return abis_nm_sendmsg(sw->bts, msg); } From f7dbd589abdf321c9535d2bafa5b084474e83d4f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 30 Dec 2009 09:31:31 +0100 Subject: [PATCH 283/365] [ipaccess] Remove some code duplication in the recently added firmware flashing. Share the creation of the sw_load. --- openbsc/src/ipaccess/ipaccess-config.c | 31 ++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 432179eb5..ceac7bdf4 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -411,6 +411,21 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, return 0; } +static struct sw_load *create_swload(struct sdp_header *header) +{ + struct sw_load *load; + + load = talloc_zero(tall_ctx_config, struct sw_load); + + strncpy((char *)load->file_id, header->firmware_info.sw_part, 20); + load->file_id_len = strlen(header->firmware_info.sw_part) + 1; + + strncpy((char *)load->file_version, header->firmware_info.version, 20); + load->file_version_len = strlen(header->firmware_info.version) + 1; + + return load; +} + static void find_sw_load_params(const char *filename) { struct stat stat; @@ -443,21 +458,9 @@ static void find_sw_load_params(const char *filename) /* try to find what we are looking for */ llist_for_each_entry(header, entry, entry) { if (ntohs(header->firmware_info.more_more_magic) == 0x1000) { - sw_load1 = talloc_zero(tall_ctx_config, struct sw_load); - - strncpy((char *)sw_load1->file_id, header->firmware_info.sw_part, 20); - sw_load1->file_id_len = strlen(header->firmware_info.sw_part) + 1; - - strncpy((char *)sw_load1->file_version, header->firmware_info.version, 20); - sw_load1->file_version_len = strlen(header->firmware_info.version) + 1; + sw_load1 = create_swload(header); } else if (ntohs(header->firmware_info.more_more_magic) == 0x2001) { - sw_load2 = talloc_zero(tall_ctx_config, struct sw_load); - - strncpy((char *)sw_load2->file_id, header->firmware_info.sw_part, 20); - sw_load2->file_id_len = strlen(header->firmware_info.sw_part) + 1; - - strncpy((char *)sw_load2->file_version, header->firmware_info.version, 20); - sw_load2->file_version_len = strlen(header->firmware_info.version) + 1; + sw_load2 = create_swload(header); } } From f31e4745bb32d120f55d8442669d666d88619fa0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 31 Dec 2009 03:05:52 +0100 Subject: [PATCH 284/365] [misc] Utilize rf_locking by setting the nm_state.administrative * On start the vty code will call the abis_nm method and this will set the administrative state to unlock/lock * During startup the BTS will report its state as well and would possible overwrite the set administrative. We are only going to update the administrative if it was 0 before. This appears to work on all of my tests. In case this will not be the case for others we will have to split the administrative into two sets one for the BTS and one for the BSC. --- openbsc/include/openbsc/gsm_data.h | 3 --- openbsc/src/abis_nm.c | 11 ++++++++--- openbsc/src/bsc_init.c | 3 +-- openbsc/src/gsm_data.c | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index c0c485e84..8272289e0 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -303,9 +303,6 @@ struct gsm_bts_trx { } bs11; }; struct gsm_bts_trx_ts ts[TRX_NR_TS]; - - /* NM state */ - int rf_locked; }; enum gsm_bts_type { diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index f82dc6f39..38c8c2bf5 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -813,12 +813,17 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb) } DEBUGPC(DNM, "\n"); - if (memcmp(&new_state, nm_state, sizeof(new_state))) { + if ((new_state.administrative != 0 && nm_state->administrative == 0) || + new_state.operational != nm_state->operational || + new_state.availability != nm_state->availability) { /* Update the operational state of a given object in our in-memory data * structures and send an event to the higher layer */ void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst); rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state); - *nm_state = new_state; + nm_state->operational = new_state.operational; + nm_state->availability = new_state.availability; + if (nm_state->administrative == 0) + nm_state->administrative = new_state.administrative; } #if 0 if (op_state == 1) { @@ -2912,7 +2917,7 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked) { int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; - trx->rf_locked = locked; + trx->nm_state.administrative = new_state; if (!trx->bts || !trx->bts->oml_link) return; diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index cc4a75b5b..ee81b6a80 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -431,8 +431,7 @@ static int sw_activ_rep(struct msgb *mb) * This code is here to make sure that on start * a TRX remains locked. */ - int rc_state = trx->rf_locked ? - NM_STATE_LOCKED : NM_STATE_UNLOCKED; + int rc_state = trx->nm_state.administrative; /* Patch ARFCN into radio attribute */ nanobts_attr_radio[5] &= 0xf0; nanobts_attr_radio[5] |= trx->arfcn >> 8; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 21d9e4b27..291d407b6 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -128,6 +128,7 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) trx->bts = bts; trx->nr = bts->num_trx++; + trx->nm_state.administrative = NM_STATE_UNLOCKED; for (k = 0; k < TRX_NR_TS; k++) { struct gsm_bts_trx_ts *ts = &trx->ts[k]; From 83579ca8ff706cd2d5ed27a10fa90129bdd943f4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 29 Dec 2009 11:17:18 +0100 Subject: [PATCH 285/365] keep 'silent call' state in struct lchan This enables us to reliably detect if a lchan is part of a silent call or not. --- openbsc/include/openbsc/gsm_data.h | 2 ++ openbsc/src/chan_alloc.c | 2 ++ openbsc/src/silent_call.c | 6 +++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 8272289e0..cc023b3ab 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -198,6 +198,8 @@ struct gsm_lchan { u_int8_t key_len; u_int8_t key[MAX_A5_KEY_LEN]; } encr; + /* Are we part of a special "silent" call */ + int silent_call; /* AMR bits */ struct gsm48_multi_rate_conf mr_conf; diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 8141e4774..48f87f211 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -302,6 +302,8 @@ void lchan_free(struct gsm_lchan *lchan) for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) lchan->neigh_meas[i].arfcn = 0; + lchan->silent_call = 0; + /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ } diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c index 82b656327..500d1873d 100644 --- a/openbsc/src/silent_call.c +++ b/openbsc/src/silent_call.c @@ -53,6 +53,7 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event, case GSM_PAGING_SUCCEEDED: DEBUGPC(DSMS, "success, using Timeslot %u on ARFCN %u\n", lchan->ts->nr, lchan->ts->trx->arfcn); + lchan->silent_call = 1; /* increment lchan reference count */ dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata); use_lchan(lchan); @@ -86,7 +87,10 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr) if (!lchan) return -EINVAL; - /* FIXME: did we actually establish a silent call for this guy? */ + /* did we actually establish a silent call for this guy? */ + if (!lchan->silent_call) + return -EINVAL; + put_lchan(lchan); return 0; From 510087752e46489b7ea61d72b3ab39540ce0d908 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 29 Dec 2009 11:49:12 +0100 Subject: [PATCH 286/365] introduce and implement silent_call_reroute() and silent_call_rx() Thise two functions are interfacing with the 04.08 layer 3 to determine if a particular message should be handled inside the OpenBSC layer 3, or if it should be handled in the silent call handler. --- openbsc/include/openbsc/silent_call.h | 2 ++ openbsc/src/gsm_04_08.c | 4 +++ openbsc/src/silent_call.c | 44 +++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/openbsc/include/openbsc/silent_call.h b/openbsc/include/openbsc/silent_call.h index 53ed4e248..b5bc5c035 100644 --- a/openbsc/include/openbsc/silent_call.h +++ b/openbsc/include/openbsc/silent_call.h @@ -3,5 +3,7 @@ extern int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data); extern int gsm_silent_call_stop(struct gsm_subscriber *subscr); +extern int silent_call_rx(struct msgb *msg); +extern int silent_call_reroute(struct msgb *msg); #endif /* _SILENT_CALL_H */ diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 6eeddbf90..cd66d255f 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -50,6 +50,7 @@ #include #include #include +#include #define GSM_MAX_FACILITY 128 #define GSM_MAX_SSVERSION 128 @@ -3500,6 +3501,9 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) struct gsm48_hdr *gh = msgb_l3(msg); u_int8_t pdisc = gh->proto_discr & 0x0f; int rc = 0; + + if (silent_call_reroute(msg)) + return silent_call_rx(msg); switch (pdisc) { case GSM48_PDISC_CC: diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c index 500d1873d..2679db7a9 100644 --- a/openbsc/src/silent_call.c +++ b/openbsc/src/silent_call.c @@ -34,6 +34,7 @@ #include #include +/* paging of the requested subscriber has completed */ static int paging_cb_silent(unsigned int hooknum, unsigned int event, struct msgb *msg, void *_lchan, void *_data) { @@ -70,6 +71,48 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event, return rc; } +/* receive a layer 3 message from a silent call */ +int silent_call_rx(struct msgb *msg) +{ + /* FIXME: do something like sending it through a UDP port */ + return 0; +} + +struct msg_match { + u_int8_t pdisc; + u_int8_t msg_type; +}; + +/* list of messages that are handled inside OpenBSC, even in a silent call */ +static const struct msg_match silent_call_accept[] = { + { GSM48_PDISC_MM, GSM48_MT_MM_LOC_UPD_REQUEST }, + { GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_REQ }, +}; + +/* decide if we need to reroute a message as part of a silent call */ +int silent_call_reroute(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + u_int8_t pdisc = gh->proto_discr & 0x0f; + int i; + + /* if we're not part of a silent call, never reroute */ + if (!msg->lchan->silent_call) + return 0; + + /* check if we are a special message that is handled in openbsc */ + for (i = 0; i < ARRAY_SIZE(silent_call_accept); i++) { + if (silent_call_accept[i].pdisc == pdisc && + silent_call_accept[i].msg_type == gh->msg_type) + return 0; + } + + /* otherwise, reroute */ + return 1; +} + + +/* initiate a silent call with a given subscriber */ int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data) { int rc; @@ -79,6 +122,7 @@ int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data) return rc; } +/* end a silent call with a given subscriber */ int gsm_silent_call_stop(struct gsm_subscriber *subscr) { struct gsm_lchan *lchan; From 730bc653d1197c57cdc89e9e22c06ed687749e21 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 1 Jan 2010 15:08:38 +0100 Subject: [PATCH 287/365] hlrstat: Print numeric MCC/MNC in case no name is available --- openbsc/tools/hlrstat.pl | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/openbsc/tools/hlrstat.pl b/openbsc/tools/hlrstat.pl index a3fd2b81e..668fc9a4a 100755 --- a/openbsc/tools/hlrstat.pl +++ b/openbsc/tools/hlrstat.pl @@ -8,6 +8,18 @@ my $dbh = DBI->connect("dbi:SQLite:dbname=hlr.sqlite3","",""); my %mcc_names; my %mcc_mnc_names; +sub get_mcc_mnc_name($) +{ + my $mcc_mnc = shift; + my $ret = $mcc_mnc; + + if ($mcc_mnc_names{$mcc_mnc} ne '') { + $ret = $mcc_mnc_names{$mcc_mnc}; + } + + return $ret; +} + sub read_networks($) { my $filename = shift; @@ -37,6 +49,7 @@ read_networks("networks.tab"); my %oper_count; my %country_count; +#my $sth = $dbh->prepare("SELECT imsi FROM subscriber where authorized=1"); my $sth = $dbh->prepare("SELECT imsi FROM subscriber"); $sth->execute(); @@ -49,10 +62,12 @@ while (my $href = $sth->fetchrow_hashref) { } -foreach my $c (keys %country_count) { +foreach my $c (sort{$country_count{$b} <=> $country_count{$a}} keys %country_count) { printf("%s: %d\n", $mcc_names{$c}, $country_count{$c}); -} - foreach my $k (keys %oper_count) { - printf("\t%s: %d\n", $mcc_mnc_names{$k}, $oper_count{$k}); + + foreach my $k (sort{$oper_count{$b} <=> $oper_count{$a}} keys %oper_count) { + if ($k =~ /^$c-/) { + printf("\t%s: %d\n", get_mcc_mnc_name($k), $oper_count{$k}); + } } -#//} +} From 7de67960e786fbaecd2348fdbcfb660150959f8f Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 17:45:45 +0100 Subject: [PATCH 288/365] [bsc_init] Send OPSTART if SITE_MANAGER reports off-line The exact sequence the states the BTS goes through is slightly different for one of the nanoBTS 139 I have and it needs this to start. Signed-off-by: Sylvain Munaut --- openbsc/src/bsc_init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index ee81b6a80..622fb98cd 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -355,8 +355,10 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, switch (obj_class) { case NM_OC_SITE_MANAGER: bts = container_of(obj, struct gsm_bts, site_mgr); - if (new_state->operational == 2 && - new_state->availability == NM_AVSTATE_OK) + if ((new_state->operational == 2 && + new_state->availability == NM_AVSTATE_OK) || + (new_state->operational == 1 && + new_state->availability == NM_AVSTATE_OFF_LINE)) abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff); break; case NM_OC_BTS: From b6c273e9e399f31bbf653ae6946ffff5cae2025a Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 16:48:33 +0100 Subject: [PATCH 289/365] vty: Register logging_set_log_level_cmd Signed-off-by: Sylvain Munaut --- openbsc/src/vty_interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 22284d803..f510f0edb 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1797,6 +1797,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &logging_prnt_timestamp_cmd); install_element(VIEW_NODE, &logging_set_category_mask_cmd); install_element(VIEW_NODE, &logging_level_cmd); + install_element(VIEW_NODE, &logging_set_log_level_cmd); install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net); From 504807001d4d8340434e023d58016050f7faa889 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sat, 2 Jan 2010 14:29:43 +0100 Subject: [PATCH 290/365] silent_call: Add option to choose channel type Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/silent_call.h | 3 +- openbsc/src/silent_call.c | 4 +- openbsc/src/vty_interface_layer3.c | 62 ++++++++++++++++++++------- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/openbsc/include/openbsc/silent_call.h b/openbsc/include/openbsc/silent_call.h index b5bc5c035..fefc5182d 100644 --- a/openbsc/include/openbsc/silent_call.h +++ b/openbsc/include/openbsc/silent_call.h @@ -1,7 +1,8 @@ #ifndef _SILENT_CALL_H #define _SILENT_CALL_H -extern int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data); +extern int gsm_silent_call_start(struct gsm_subscriber *subscr, + void *data, int type); extern int gsm_silent_call_stop(struct gsm_subscriber *subscr); extern int silent_call_rx(struct msgb *msg); extern int silent_call_reroute(struct msgb *msg); diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c index 2679db7a9..a0c166e0a 100644 --- a/openbsc/src/silent_call.c +++ b/openbsc/src/silent_call.c @@ -113,11 +113,11 @@ int silent_call_reroute(struct msgb *msg) /* initiate a silent call with a given subscriber */ -int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data) +int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type) { int rc; - rc = paging_request(subscr->net, subscr, RSL_CHANNEED_TCH_F, + rc = paging_request(subscr->net, subscr, type, paging_cb_silent, data); return rc; } diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 70e8445f0..e3d9260db 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -266,10 +266,46 @@ DEFUN(subscriber_silent_sms, return rc; } -DEFUN(subscriber_silent_call, - subscriber_silent_call_cmd, - "subscriber " SUBSCR_TYPES " EXTEN silent call (start|stop)", - "Send a silent call to a subscriber") +DEFUN(subscriber_silent_call_start, + subscriber_silent_call_start_cmd, + "subscriber " SUBSCR_TYPES " EXTEN silent call start (any|tch/f|tch/any|sdcch)", + "Start a silent call to a subscriber") +{ + struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]); + int rc, type; + + if (!subscr) { + vty_out(vty, "%% No subscriber found for %s %s%s", + argv[0], argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[2], "tch/f")) + type = RSL_CHANNEED_TCH_F; + else if (!strcmp(argv[2], "tch/any")) + type = RSL_CHANNEED_TCH_ForH; + else if (!strcmp(argv[2], "sdcch")) + type = RSL_CHANNEED_SDCCH; + else + type = RSL_CHANNEED_ANY; /* Defaults to ANY */ + + rc = gsm_silent_call_start(subscr, vty, type); + if (rc <= 0) { + vty_out(vty, "%% Subscriber not attached%s", + VTY_NEWLINE); + subscr_put(subscr); + return CMD_WARNING; + } + + subscr_put(subscr); + + return CMD_SUCCESS; +} + +DEFUN(subscriber_silent_call_stop, + subscriber_silent_call_stop_cmd, + "subscriber " SUBSCR_TYPES " EXTEN silent call stop", + "Stop a silent call to a subscriber") { struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]); int rc; @@ -280,17 +316,10 @@ DEFUN(subscriber_silent_call, return CMD_WARNING; } - if (!strcmp(argv[2], "start")) { - rc = gsm_silent_call_start(subscr, vty); - if (rc <= 0) { - vty_out(vty, "%% Subscriber not attached%s", - VTY_NEWLINE); - return CMD_WARNING; - } - } else { - rc = gsm_silent_call_stop(subscr); - if (rc < 0) - return CMD_WARNING; + rc = gsm_silent_call_stop(subscr); + if (rc < 0) { + subscr_put(subscr); + return CMD_WARNING; } subscr_put(subscr); @@ -378,7 +407,8 @@ int bsc_vty_init_extra(struct gsm_network *net) install_element(VIEW_NODE, &subscriber_send_sms_cmd); install_element(VIEW_NODE, &subscriber_silent_sms_cmd); - install_element(VIEW_NODE, &subscriber_silent_call_cmd); + install_element(VIEW_NODE, &subscriber_silent_call_start_cmd); + install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd); install_element(CONFIG_NODE, &cfg_subscr_cmd); install_node(&subscr_node, dummy_config_write); From 15e1024e49d8d8295de69d4e8af0cad8d393bb78 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sat, 2 Jan 2010 14:51:52 +0100 Subject: [PATCH 291/365] update .gitignore Signed-off-by: Sylvain Munaut --- openbsc/.gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openbsc/.gitignore b/openbsc/.gitignore index 7b7b11a1e..267c906ec 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -3,8 +3,12 @@ .deps Makefile Makefile.in +bscconfig.h +bscconfig.h.in +openbsc.pc bsc_hack bsc_msc_ip +bsc_mgcp *.*~ *.sw? @@ -26,6 +30,8 @@ hlr.sqlite3 bs11_config ipaccess-config ipaccess-find +ipaccess-firmware +ipaccess-proxy isdnsync #tests From 1f6c11fda80fca9915531c22e41c62279ba2c2a0 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sat, 2 Jan 2010 16:32:17 +0100 Subject: [PATCH 292/365] abis_nm: Introduce & use a nm_is_running function to test gsm_nm_state This returns true if the gsm_nm_state can be considered 'running'. Note that we also accept availability==0xff (which is a code for no value) because according to 12.21 it is perfectly valid. Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/abis_nm.h | 1 + openbsc/src/abis_nm.c | 7 +++++++ openbsc/src/chan_alloc.c | 15 ++++++--------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index a122342f2..6876435dc 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -826,4 +826,5 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, const char *nm_opstate_name(u_int8_t os); const char *nm_avail_name(u_int8_t avail); +int nm_is_running(struct gsm_nm_state *s); #endif /* _NM_H */ diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 38c8c2bf5..7a67fdf3b 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -599,6 +599,13 @@ const char *nm_adm_name(u_int8_t adm) } } +int nm_is_running(struct gsm_nm_state *s) { + return (s->operational == NM_OPSTATE_ENABLED) && ( + (s->availability == NM_AVSTATE_OK) || + (s->availability == 0xff) + ); +} + static void debugp_foh(struct abis_om_fom_hdr *foh) { DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 48f87f211..ab26fcaf2 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -39,8 +39,7 @@ static int ts_is_usable(struct gsm_bts_trx_ts *ts) { /* FIXME: How does this behave for BS-11 ? */ if (is_ipaccess_bts(ts->trx->bts)) { - if (ts->nm_state.operational != NM_OPSTATE_ENABLED || - ts->nm_state.availability != NM_AVSTATE_OK) + if (!nm_is_running(&ts->nm_state)) return 0; } @@ -51,10 +50,8 @@ int trx_is_usable(struct gsm_bts_trx *trx) { /* FIXME: How does this behave for BS-11 ? */ if (is_ipaccess_bts(trx->bts)) { - if (trx->nm_state.operational != NM_OPSTATE_ENABLED || - trx->nm_state.availability != NM_AVSTATE_OK || - trx->bb_transc.nm_state.operational != NM_OPSTATE_ENABLED || - trx->bb_transc.nm_state.availability != NM_AVSTATE_OK) + if (!nm_is_running(&trx->nm_state) || + !nm_is_running(&trx->bb_transc.nm_state)) return 0; } @@ -380,8 +377,8 @@ void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts) int i; /* skip administratively deactivated tranxsceivers */ - if (trx->nm_state.availability != NM_AVSTATE_OK || - trx->bb_transc.nm_state.availability != NM_AVSTATE_OK) + if (!nm_is_running(&trx->nm_state) || + !nm_is_running(&trx->bb_transc.nm_state)) continue; for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { @@ -390,7 +387,7 @@ void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts) int j; /* skip administratively deactivated timeslots */ - if (ts->nm_state.availability != NM_AVSTATE_OK) + if (!nm_is_running(&ts->nm_state)) continue; for (j = 0; j < subslots_per_pchan[ts->pchan]; j++) { From deebb113ac23ffc8b929828f940054c85a695e7b Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 15:24:55 +0100 Subject: [PATCH 293/365] db: Fix missing commas in AuthTuples table creation Signed-off-by: Sylvain Munaut --- openbsc/src/db.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 73e9c25ef..57ea9baf6 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -133,9 +133,9 @@ static char *create_stmts[] = { "CREATE TABLE IF NOT EXISTS AuthTuples (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "subscriber_id NUMERIC UNIQUE NOT NULL, " - "rand BLOB" - "sres BLOB" - "kc BLOB" + "rand BLOB, " + "sres BLOB, " + "kc BLOB " ")", }; From 77d334ac4d64fec8a0708160fc2753c6354eb869 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 19:26:12 +0100 Subject: [PATCH 294/365] db: Fix type of algorithm_id (NUMERIC -> INTEGER) This fixes a DB warning and no need for NUMERIC here. Signed-off-by: Sylvain Munaut --- openbsc/src/db.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 57ea9baf6..bfc7d9310 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -126,8 +126,8 @@ static char *create_stmts[] = { ")", "CREATE TABLE IF NOT EXISTS AuthKeys (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "subscriber_id NUMERIC UNIQUE NOT NULL, " - "algorithm_id NUMERIC NOT NULL, " + "subscriber_id INTEGER UNIQUE NOT NULL, " + "algorithm_id INTEGER NOT NULL, " "a3a8_ki BLOB " ")", "CREATE TABLE IF NOT EXISTS AuthTuples (" From 70881b7e8acf5ef6cdd57a084a99055d7decc1c2 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 15:41:59 +0100 Subject: [PATCH 295/365] db: Add issued/use_count/key_seq fields to AuthTuples Theses will be useful to know if we can reuse the tuples or if we should renew. The 'issued' is currently purely informative. Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/gsm_data.h | 2 ++ openbsc/src/db.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index cc023b3ab..a50d9f21d 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -605,6 +605,8 @@ struct gsm_auth_info { }; struct gsm_auth_tuple { + int use_count; + int key_seq; u_int8_t rand[16]; u_int8_t sres[8]; u_int8_t kc[8]; diff --git a/openbsc/src/db.c b/openbsc/src/db.c index bfc7d9310..5ad951ac1 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -133,9 +133,12 @@ static char *create_stmts[] = { "CREATE TABLE IF NOT EXISTS AuthTuples (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "subscriber_id NUMERIC UNIQUE NOT NULL, " - "rand BLOB, " - "sres BLOB, " - "kc BLOB " + "issued TIMESTAMP NOT NULL, " + "use_count INTEGER NOT NULL DEFAULT 0, " + "key_seq INTEGER NOT NULL, " + "rand BLOB NOT NULL, " + "sres BLOB NOT NULL, " + "kc BLOB NOT NULL " ")", }; @@ -383,6 +386,9 @@ int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple, memset(atuple, 0, sizeof(atuple)); + atuple->use_count = dbi_result_get_ulonglong(result, "use_count"); + atuple->key_seq = dbi_result_get_ulonglong(result, "key_seq"); + len = dbi_result_get_field_length(result, "rand"); if (len != sizeof(atuple->rand)) goto err_size; From c863cbb171ad016288a2b1e637142e4202f28258 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 15:43:28 +0100 Subject: [PATCH 296/365] gsm_data: Fix sres to be 4 bytes Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/gsm_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index a50d9f21d..a6bc16a14 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -608,7 +608,7 @@ struct gsm_auth_tuple { int use_count; int key_seq; u_int8_t rand[16]; - u_int8_t sres[8]; + u_int8_t sres[4]; u_int8_t kc[8]; }; From e1cb4debb087222a6a50de0d4bc0856c10b2c707 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 19:24:05 +0100 Subject: [PATCH 297/365] db: Fix bad size comparison when retrieving Ki Signed-off-by: Sylvain Munaut --- openbsc/src/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 5ad951ac1..529e15d73 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -357,7 +357,7 @@ int get_authinfo_by_subscr(struct gsm_auth_info *ainfo, ainfo->auth_algo = dbi_result_get_ulonglong(result, "algorithm_id"); ainfo->a3a8_ki_len = dbi_result_get_field_length(result, "a3a8_ki"); a3a8_ki = dbi_result_get_binary(result, "a3a8_ki"); - if (ainfo->a3a8_ki_len > sizeof(ainfo->a3a8_ki_len)) + if (ainfo->a3a8_ki_len > sizeof(ainfo->a3a8_ki)) ainfo->a3a8_ki_len = sizeof(ainfo->a3a8_ki_len); memcpy(ainfo->a3a8_ki, a3a8_ki, ainfo->a3a8_ki_len); From c5f488b6bc8b7cc81c4f2341adc53e517b3191c6 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 19:25:22 +0100 Subject: [PATCH 298/365] db: Add declaration for get_auth{info,tuple_for_subscriber Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/db.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index 8059668ed..14c50a621 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -43,6 +43,12 @@ int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* toke int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char *imei); int db_sync_equipment(struct gsm_equipment *equip); +/* auth info */ +int get_authinfo_by_subscr(struct gsm_auth_info *ainfo, + struct gsm_subscriber *subscr); +int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr); + /* SMS store-and-forward */ int db_sms_store(struct gsm_sms *sms); struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id); From 062d5efc5ce140d7df7fdaf609b1fcfc07f11f00 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 19:27:53 +0100 Subject: [PATCH 299/365] db: Add methods to set auth{info,tuple} for a subscriber Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/db.h | 4 ++ openbsc/src/db.c | 125 +++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index 14c50a621..df664dbc1 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -46,8 +46,12 @@ int db_sync_equipment(struct gsm_equipment *equip); /* auth info */ int get_authinfo_by_subscr(struct gsm_auth_info *ainfo, struct gsm_subscriber *subscr); +int set_authinfo_for_subscr(struct gsm_auth_info *ainfo, + struct gsm_subscriber *subscr); int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple, struct gsm_subscriber *subscr); +int set_authtuple_for_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr); /* SMS store-and-forward */ int db_sms_store(struct gsm_sms *sms); diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 529e15d73..5be47ff64 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -366,6 +366,62 @@ int get_authinfo_by_subscr(struct gsm_auth_info *ainfo, return 0; } +int set_authinfo_for_subscr(struct gsm_auth_info *ainfo, + struct gsm_subscriber *subscr) +{ + dbi_result result; + struct gsm_auth_info ainfo_old; + int rc, upd; + unsigned char *ki_str; + + /* Deletion ? */ + if (ainfo == NULL) { + result = dbi_conn_queryf(conn, + "DELETE FROM AuthKeys WHERE subscriber_id=%u", + subscr->id); + + if (!result) + return -EIO; + + dbi_result_free(result); + + return 0; + } + + /* Check if already existing */ + rc = get_authinfo_by_subscr(&ainfo_old, subscr); + if (rc && rc != -ENOENT) + return rc; + upd = rc ? 0 : 1; + + /* Update / Insert */ + dbi_conn_quote_binary_copy(conn, + ainfo->a3a8_ki, ainfo->a3a8_ki_len, &ki_str); + + if (!upd) { + result = dbi_conn_queryf(conn, + "INSERT INTO AuthKeys " + "(subscriber_id, algorithm_id, a3a8_ki) " + "VALUES (%u, %u, %s)", + subscr->id, ainfo->auth_algo, ki_str); + } else { + result = dbi_conn_queryf(conn, + "UPDATE AuthKeys " + "SET algorithm_id=%u, a3a8_ki=%s " + "WHERE subscriber_id=%u", + ainfo->auth_algo, ki_str, subscr->id); + } + + free(ki_str); + + if (!result) + return -EIO; + + dbi_result_free(result); + + return 0; +} + int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple, struct gsm_subscriber *subscr) { @@ -419,6 +475,75 @@ err_size: return -EIO; } +int set_authtuple_for_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr) +{ + dbi_result result; + int rc, upd; + struct gsm_auth_tuple atuple_old; + unsigned char *rand_str, *sres_str, *kc_str; + + /* Deletion ? */ + if (atuple == NULL) { + result = dbi_conn_queryf(conn, + "DELETE FROM AuthTuples WHERE subscriber_id=%u", + subscr->id); + + if (!result) + return -EIO; + + dbi_result_free(result); + + return 0; + } + + /* Check if already existing */ + rc = get_authtuple_by_subscr(&atuple_old, subscr); + if (rc && rc != -ENOENT) + return rc; + upd = rc ? 0 : 1; + + /* Update / Insert */ + dbi_conn_quote_binary_copy(conn, + atuple->rand, sizeof(atuple->rand), &rand_str); + dbi_conn_quote_binary_copy(conn, + atuple->sres, sizeof(atuple->sres), &sres_str); + dbi_conn_quote_binary_copy(conn, + atuple->kc, sizeof(atuple->kc), &kc_str); + + if (!upd) { + result = dbi_conn_queryf(conn, + "INSERT INTO AuthTuples " + "(subscriber_id, issued, use_count, " + "key_seq, rand, sres, kc) " + "VALUES (%u, datetime('now'), %u, " + "%u, %s, %s, %s ) ", + subscr->id, atuple->use_count, atuple->key_seq, + rand_str, sres_str, kc_str); + } else { + char *issued = atuple->key_seq == atuple_old.key_seq ? + "issued" : "datetime('now')"; + result = dbi_conn_queryf(conn, + "UPDATE AuthKeys " + "SET issued=%s, use_count=%u, " + "key_seq=%u, rand=%s, sres=%s, kc=%s " + "WHERE subscriber_id = %u", + issued, atuple->use_count, atuple->key_seq, + rand_str, sres_str, kc_str, subscr->id); + } + + free(rand_str); + free(sres_str); + free(kc_str); + + if (!result) + return -EIO; + + dbi_result_free(result); + + return 0; +} + #define BASE_QUERY "SELECT * FROM Subscriber " struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, enum gsm_subscriber_field field, From af29264039bc14641ec11e39cebd779ff4cb6864 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 19:29:28 +0100 Subject: [PATCH 300/365] vty: dump subscriber authentication (a3/a8) infos if available Signed-off-by: Sylvain Munaut --- openbsc/src/vty_interface.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index f510f0edb..c9a5c1767 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -514,6 +514,10 @@ DEFUN(show_ts, void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) { + int rc; + struct gsm_auth_info ainfo; + struct gsm_auth_tuple atuple; + vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id, subscr->authorized, VTY_NEWLINE); if (subscr->name) @@ -526,6 +530,33 @@ void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) if (subscr->tmsi != GSM_RESERVED_TMSI) vty_out(vty, " TMSI: %08X%s", subscr->tmsi, VTY_NEWLINE); + + rc = get_authinfo_by_subscr(&ainfo, subscr); + if (!rc) { + vty_out(vty, " A3A8 algorithm id: %d%s", + ainfo.auth_algo, VTY_NEWLINE); + vty_out(vty, " A3A8 Ki: %s%s", + hexdump(ainfo.a3a8_ki, ainfo.a3a8_ki_len), + VTY_NEWLINE); + } + + rc = get_authtuple_by_subscr(&atuple, subscr); + if (!rc) { + vty_out(vty, " A3A8 last tuple (used %d times):%s", + atuple.use_count, VTY_NEWLINE); + vty_out(vty, " seq # : %d%s", + atuple.key_seq, VTY_NEWLINE); + vty_out(vty, " RAND : %s%s", + hexdump(atuple.rand, sizeof(atuple.rand)), + VTY_NEWLINE); + vty_out(vty, " SRES : %s%s", + hexdump(atuple.sres, sizeof(atuple.sres)), + VTY_NEWLINE); + vty_out(vty, " Kc : %s%s", + hexdump(atuple.kc, sizeof(atuple.kc)), + VTY_NEWLINE); + } + vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE); } From 99792900e8a8aefacf7f5c931014a45d0c57d411 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 19:30:46 +0100 Subject: [PATCH 301/365] vty: Add command to set auth algo & Ki for a subscriber Signed-off-by: Sylvain Munaut --- openbsc/src/vty_interface_layer3.c | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index e3d9260db..bc2bfaa6c 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -74,6 +74,33 @@ static struct buffer *argv_to_buffer(int argc, const char *argv[], int base) return b; } +static int hexparse(const char *str, u_int8_t *b, int max_len) + +{ + int i, l, v; + + l = strlen(str); + if ((l&1) || ((l>>1) > max_len)) + return -1; + + memset(b, 0x00, max_len); + + for (i=0; i= '0' && c <= '9') + v = c - '0'; + else if (c >= 'a' && c <= 'f') + v = 10 + (c - 'a'); + else if (c >= 'A' && c <= 'F') + v = 10 + (c - 'a'); + else + return -1; + b[i>>1] |= v << (i&1 ? 0 : 4); + } + + return i>>1; +} + /* per-subscriber configuration */ DEFUN(cfg_subscr, cfg_subscr_cmd, @@ -375,6 +402,40 @@ DEFUN(cfg_subscr_authorized, return CMD_SUCCESS; } +#define A3A8_ALG_TYPES "(none|comp128v1)" + +DEFUN(cfg_subscr_a3a8, + cfg_subscr_a3a8_cmd, + "a3a8 " A3A8_ALG_TYPES " [KI]", + "Set a3a8 parameters for the subscriber") +{ + struct gsm_subscriber *subscr = vty->index; + const char *alg_str = argv[0]; + const char *ki_str = argv[1]; + struct gsm_auth_info ainfo; + int rc; + + if (!strcasecmp(alg_str, "none")) { + /* Just erase */ + rc = set_authinfo_for_subscr(NULL, subscr); + } else if (!strcasecmp(alg_str, "comp128v1")) { + /* Parse hex string Ki */ + rc = hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki)); + if (rc != 16) + return CMD_WARNING; + + /* Set the infos */ + ainfo.auth_algo = AUTH_ALGO_COMP128v1; + ainfo.a3a8_ki_len = rc; + rc = set_authinfo_for_subscr(&ainfo, subscr); + } else { + /* Unknown method */ + return CMD_WARNING; + } + + return rc ? CMD_WARNING : CMD_SUCCESS; +} + static int scall_cbfn(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { @@ -417,6 +478,7 @@ int bsc_vty_init_extra(struct gsm_network *net) install_element(SUBSCR_NODE, &cfg_subscr_name_cmd); install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd); install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd); + install_element(SUBSCR_NODE, &cfg_subscr_a3a8_cmd); return 0; } From bd55a6dd316f49e11b20f7935c8a8b7153cdf698 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 00:23:46 +0100 Subject: [PATCH 302/365] gsm_04_08: Specify key_seq when calling gsm48_tx_mm_auth_req Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/gsm_04_08.h | 2 +- openbsc/src/gsm_04_08.c | 5 ++--- openbsc/src/token_auth.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index b8671554e..9cf8afcf3 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -756,7 +756,7 @@ enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci); enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci); int gsm48_tx_mm_info(struct gsm_lchan *lchan); -int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand); +int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq); int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan); struct msgb *gsm48_msgb_alloc(void); int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index cd66d255f..e09928f0e 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1175,7 +1175,7 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) } /* Section 9.2.2 */ -int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand) +int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -1187,8 +1187,7 @@ int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand) gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_AUTH_REQ; - /* Key Sequence: FIXME fixed to 0 */ - ar->key_seq = 0; + ar->key_seq = key_seq; /* 16 bytes RAND parameters */ if (rand) diff --git a/openbsc/src/token_auth.c b/openbsc/src/token_auth.c index f6be0bc98..fd81f035a 100644 --- a/openbsc/src/token_auth.c +++ b/openbsc/src/token_auth.c @@ -103,7 +103,7 @@ unauth: if (lchan) { u_int8_t auth_rand[16]; /* kick the subscriber off the network */ - gsm48_tx_mm_auth_req(lchan, auth_rand); + gsm48_tx_mm_auth_req(lchan, auth_rand, 0); gsm48_tx_mm_auth_rej(lchan); /* FIXME: close the channel early ?*/ //gsm48_send_rr_Release(lchan); @@ -139,7 +139,7 @@ static int token_sms_cb(unsigned int subsys, unsigned int signal, lchan = lchan_for_subscr(sms->receiver); if (lchan) { /* kick the subscriber off the network */ - gsm48_tx_mm_auth_req(lchan, auth_rand); + gsm48_tx_mm_auth_req(lchan, auth_rand, 0); gsm48_tx_mm_auth_rej(lchan); /* FIXME: close the channel early ?*/ //gsm48_send_rr_Release(lchan); From 8608e7c1334afa0fce145517c9b48c4e9a146941 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 24 Dec 2009 00:24:29 +0100 Subject: [PATCH 303/365] gsm_04_08: Add RAND debug output in gsm48_tx_mm_auth_req Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_08.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index e09928f0e..61eba2c5a 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1181,7 +1181,7 @@ int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq) struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); struct gsm48_auth_req *ar = (struct gsm48_auth_req *) msgb_put(msg, sizeof(*ar)); - DEBUGP(DMM, "-> AUTH REQ\n"); + DEBUGP(DMM, "-> AUTH REQ (rand = %s)\n", hexdump(rand, 16)); msg->lchan = lchan; gh->proto_discr = GSM48_PDISC_MM; From d7c9e5cad887cd5bcfff9dfcc726e070750404bf Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 23 Dec 2009 15:49:16 +0100 Subject: [PATCH 304/365] encryption: Import a GPL comp128 implementation Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/comp128.h | 22 +++ openbsc/src/Makefile.am | 2 +- openbsc/src/comp128.c | 230 ++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 openbsc/include/openbsc/comp128.h create mode 100644 openbsc/src/comp128.c diff --git a/openbsc/include/openbsc/comp128.h b/openbsc/include/openbsc/comp128.h new file mode 100644 index 000000000..691ade54b --- /dev/null +++ b/openbsc/include/openbsc/comp128.h @@ -0,0 +1,22 @@ +/* + * COMP128 header + * + * See comp128.c for details + */ + +#ifndef __COMP128_H__ +#define __COMP128_H__ + +#include + +/* + * Performs the COMP128 algorithm (used as A3/A8) + * ki : u_int8_t [16] + * srand : u_int8_t [16] + * sres : u_int8_t [4] + * kc : u_int8_t [8] + */ +void comp128(u_int8_t *ki, u_int8_t *srand, u_int8_t *sres, u_int8_t *kc); + +#endif /* __COMP128_H__ */ + diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 544aea060..7d7fee79e 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -17,7 +17,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \ - handover_logic.c handover_decision.c meas_rep.c + handover_logic.c handover_decision.c meas_rep.c comp128.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c diff --git a/openbsc/src/comp128.c b/openbsc/src/comp128.c new file mode 100644 index 000000000..9df545256 --- /dev/null +++ b/openbsc/src/comp128.c @@ -0,0 +1,230 @@ +/* + * COMP128 implementation + * + * + * This code is inspired by original code from : + * Marc Briceno , Ian Goldberg , + * and David Wagner + * + * But it has been fully rewritten from various PDFs found online describing + * the algorithm because the licence of the code referenced above was unclear. + * A comment snippet from the original code is included below, it describes + * where the doc came from and how the algorithm was reverse engineered. + * + * + * (C) 2009 by Sylvain Munaut + * + * 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. + * + */ + +/* + * --- SNIP --- + * + * This code derived from a leaked document from the GSM standards. + * Some missing pieces were filled in by reverse-engineering a working SIM. + * We have verified that this is the correct COMP128 algorithm. + * + * The first page of the document identifies it as + * _Technical Information: GSM System Security Study_. + * 10-1617-01, 10th June 1988. + * The bottom of the title page is marked + * Racal Research Ltd. + * Worton Drive, Worton Grange Industrial Estate, + * Reading, Berks. RG2 0SB, England. + * Telephone: Reading (0734) 868601 Telex: 847152 + * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy! + * + * Note: There are three typos in the spec (discovered by + * reverse-engineering). + * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read + * "z = (2 * x[m] + x[n]) mod 2^(9-j)". + * Second, the "k" loop in the "Form bits from bytes" section is severely + * botched: the k index should run only from 0 to 3, and clearly the range + * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8, + * to be consistent with the subsequent section). + * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as + * claimed in the document. (And the document doesn't specify how Kc is + * derived, but that was also easily discovered with reverse engineering.) + * All of these typos have been corrected in the following code. + * + * --- /SNIP --- + */ + +#include +#include + +/* The compression tables (just copied ...) */ +static const u_int8_t table_0[512] = { + 102, 177, 186, 162, 2, 156, 112, 75, 55, 25, 8, 12, 251, 193, 246, 188, + 109, 213, 151, 53, 42, 79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161, + 252, 37, 244, 47, 64, 211, 6, 237, 185, 160, 139, 113, 76, 138, 59, 70, + 67, 26, 13, 157, 63, 179, 221, 30, 214, 36, 166, 69, 152, 124, 207, 116, + 247, 194, 41, 84, 71, 1, 49, 14, 95, 35, 169, 21, 96, 78, 215, 225, + 182, 243, 28, 92, 201, 118, 4, 74, 248, 128, 17, 11, 146, 132, 245, 48, + 149, 90, 120, 39, 87, 230, 106, 232, 175, 19, 126, 190, 202, 141, 137, 176, + 250, 27, 101, 40, 219, 227, 58, 20, 51, 178, 98, 216, 140, 22, 32, 121, + 61, 103, 203, 72, 29, 110, 85, 212, 180, 204, 150, 183, 15, 66, 172, 196, + 56, 197, 158, 0, 100, 45, 153, 7, 144, 222, 163, 167, 60, 135, 210, 231, + 174, 165, 38, 249, 224, 34, 220, 229, 217, 208, 241, 68, 206, 189, 125, 255, + 239, 54, 168, 89, 123, 122, 73, 145, 117, 234, 143, 99, 129, 200, 192, 82, + 104, 170, 136, 235, 93, 81, 205, 173, 236, 94, 105, 52, 46, 228, 198, 5, + 57, 254, 97, 155, 142, 133, 199, 171, 187, 50, 65, 181, 127, 107, 147, 226, + 184, 218, 131, 33, 77, 86, 31, 44, 88, 62, 238, 18, 24, 43, 154, 23, + 80, 159, 134, 111, 9, 114, 3, 91, 16, 130, 83, 10, 195, 240, 253, 119, + 177, 102, 162, 186, 156, 2, 75, 112, 25, 55, 12, 8, 193, 251, 188, 246, + 213, 109, 53, 151, 79, 42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108, + 37, 252, 47, 244, 211, 64, 237, 6, 160, 185, 113, 139, 138, 76, 70, 59, + 26, 67, 157, 13, 179, 63, 30, 221, 36, 214, 69, 166, 124, 152, 116, 207, + 194, 247, 84, 41, 1, 71, 14, 49, 35, 95, 21, 169, 78, 96, 225, 215, + 243, 182, 92, 28, 118, 201, 74, 4, 128, 248, 11, 17, 132, 146, 48, 245, + 90, 149, 39, 120, 230, 87, 232, 106, 19, 175, 190, 126, 141, 202, 176, 137, + 27, 250, 40, 101, 227, 219, 20, 58, 178, 51, 216, 98, 22, 140, 121, 32, + 103, 61, 72, 203, 110, 29, 212, 85, 204, 180, 183, 150, 66, 15, 196, 172, + 197, 56, 0, 158, 45, 100, 7, 153, 222, 144, 167, 163, 135, 60, 231, 210, + 165, 174, 249, 38, 34, 224, 229, 220, 208, 217, 68, 241, 189, 206, 255, 125, + 54, 239, 89, 168, 122, 123, 145, 73, 234, 117, 99, 143, 200, 129, 82, 192, + 170, 104, 235, 136, 81, 93, 173, 205, 94, 236, 52, 105, 228, 46, 5, 198, + 254, 57, 155, 97, 133, 142, 171, 199, 50, 187, 181, 65, 107, 127, 226, 147, + 218, 184, 33, 131, 86, 77, 44, 31, 62, 88, 18, 238, 43, 24, 23, 154, + 159, 80, 111, 134, 114, 9, 91, 3, 130, 16, 10, 83, 240, 195, 119, 253, +}, table_1[256] = { + 19, 11, 80, 114, 43, 1, 69, 94, 39, 18, 127, 117, 97, 3, 85, 43, + 27, 124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, + 35, 107, 103, 68, 21, 86, 36, 91, 85, 126, 32, 50, 109, 94, 120, 6, + 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55, 110, 125, 105, 20, + 90, 80, 76, 96, 23, 60, 89, 64, 121, 56, 14, 74, 101, 8, 19, 78, + 76, 66, 104, 46, 111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, + 57, 65, 119, 116, 22, 109, 7, 86, 59, 93, 62, 110, 78, 99, 77, 67, + 12, 113, 87, 98, 102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, + 95, 63, 28, 49, 123, 120, 20, 112, 44, 30, 15, 98, 106, 2, 103, 29, + 82, 107, 42, 124, 24, 30, 41, 16, 108, 100, 117, 40, 73, 40, 7, 114, + 82, 115, 36, 112, 12, 102, 100, 84, 92, 48, 72, 97, 9, 54, 55, 74, + 113, 123, 17, 26, 53, 58, 4, 9, 69, 122, 21, 118, 42, 60, 27, 73, + 118, 125, 34, 15, 65, 115, 84, 64, 62, 81, 70, 1, 24, 111, 121, 83, + 104, 81, 49, 127, 48, 105, 31, 10, 6, 91, 87, 37, 16, 54, 116, 126, + 31, 38, 13, 0, 72, 106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, + 101, 17, 44, 108, 71, 52, 66, 57, 33, 51, 25, 90, 2, 119, 122, 35, +}, table_2[128] = { + 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, + 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, + 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, + 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, + 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, + 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, + 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, + 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7, +}, table_3[64] = { + 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, + 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, + 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, + 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19, +}, table_4[32] = { + 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, + 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12, +}; + +static const u_int8_t *_comp128_table[5] = { table_0, table_1, table_2, table_3, table_4 }; + + +static inline void +_comp128_compression_round(u_int8_t *x, int n, const u_int8_t *tbl) +{ + int i, j, m, a, b, y, z; + m = 4 - n; + for (i=0; i<(1<>2] & (1<<(3-(i&3)))) + bits[i] = 1; +} + +static inline void +_comp128_permutation(u_int8_t *x, u_int8_t *bits) +{ + int i; + memset(&x[16], 0x00, 16); + for (i=0; i<128; i++) + x[(i>>3)+16] |= bits[(i*17) & 127] << (7-(i&7)); +} + +void +comp128(u_int8_t *ki, u_int8_t *rand, u_int8_t *sres, u_int8_t *kc) +{ + int i; + u_int8_t x[32], bits[128]; + + /* x[16-31] = RAND */ + memcpy(&x[16], rand, 16); + + /* Round 1-7 */ + for (i=0; i<7; i++) { + /* x[0-15] = Ki */ + memcpy(x, ki, 16); + + /* Compression */ + _comp128_compression(x); + + /* FormBitFromBytes */ + _comp128_bitsfrombytes(x, bits); + + /* Permutation */ + _comp128_permutation(x, bits); + } + + /* Round 8 (final) */ + /* x[0-15] = Ki */ + memcpy(x, ki, 16); + + /* Compression */ + _comp128_compression(x); + + /* Output stage */ + for (i=0; i<8; i+=2) + sres[i>>1] = x[i]<<4 | x[i+1]; + + for (i=0; i<12; i+=2) + kc[i>>1] = (x[i + 18] << 6) | + (x[i + 19] << 2) | + (x[i + 20] >> 2); + + kc[6] = (x[30]<<6) | (x[31]<<2); + kc[7] = 0; +} + From 4719307f502a8746a04a78987f65d787b281bffc Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 27 Dec 2009 21:56:14 +0100 Subject: [PATCH 305/365] gsm_data: Move auth related structure earlier This is gonna be needed by the next commit ... Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/gsm_data.h | 42 ++++++++++++++++-------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index a6bc16a14..4a6acb52a 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -120,6 +120,28 @@ struct gsm_bts_link { struct gsm_bts *bts; }; +/* Real authentication information containing Ki */ +enum gsm_auth_algo { + AUTH_ALGO_NONE, + AUTH_ALGO_XOR, + AUTH_ALGO_COMP128v1, +}; + +struct gsm_auth_info { + enum gsm_auth_algo auth_algo; + unsigned int a3a8_ki_len; + u_int8_t a3a8_ki[16]; +}; + +struct gsm_auth_tuple { + int use_count; + int key_seq; + u_int8_t rand[16]; + u_int8_t sres[4]; + u_int8_t kc[8]; +}; + + struct gsm_lchan; struct gsm_subscriber; struct gsm_mncc; @@ -591,26 +613,6 @@ struct gsm_sms { char text[SMS_TEXT_SIZE]; }; -enum gsm_auth_algo { - AUTH_ALGO_NONE, - AUTH_ALGO_XOR, - AUTH_ALGO_COMP128v1, -}; - -/* Real authentication information containing Ki */ -struct gsm_auth_info { - enum gsm_auth_algo auth_algo; - unsigned int a3a8_ki_len; - u_int8_t a3a8_ki[16]; -}; - -struct gsm_auth_tuple { - int use_count; - int key_seq; - u_int8_t rand[16]; - u_int8_t sres[4]; - u_int8_t kc[8]; -}; struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_code, int (*mncc_recv)(struct gsm_network *, int, void *)); From 0b11414f38e53317d0d3fc4eb5cf7d85c356b6b7 Mon Sep 17 00:00:00 2001 From: "Harald Welte (local)" Date: Mon, 28 Dec 2009 23:22:43 +0100 Subject: [PATCH 306/365] print full lchan name when recycling it --- openbsc/src/chan_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index ab26fcaf2..2e885241c 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -322,7 +322,7 @@ int lchan_auto_release(struct gsm_lchan *lchan) LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n", lchan->use_count); - DEBUGP(DRLL, "Recycling the channel with: %d (%x)\n", lchan->nr, lchan->nr); + DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan)); rsl_release_request(lchan, 0); return 1; } From 424c4f0e2927d5a7538b31c69113c6e4f861d2c9 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 6 Jan 2010 06:00:40 +0100 Subject: [PATCH 307/365] [vty] Move db usage out of the libbsc (fork dumping of subscr) vty_interface.c is part of libbsc.a but it started to use code which is found in db.c recently. Fork the subscriber dumping and provide more information on the layer3+ (MSC) commands. This is restoring the separation again. --- openbsc/src/vty_interface.c | 2 +- openbsc/src/vty_interface_layer3.c | 57 +++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index c9a5c1767..8301f7893 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -512,7 +512,7 @@ DEFUN(show_ts, return CMD_SUCCESS; } -void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) +static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) { int rc; struct gsm_auth_info ainfo; diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index bc2bfaa6c..f2b572895 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -40,9 +40,7 @@ #include #include #include - -/* forward declarations */ -void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr); +#include static struct gsm_network *gsmnet; @@ -124,6 +122,55 @@ DEFUN(cfg_subscr, return CMD_SUCCESS; } +static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr) +{ + int rc; + struct gsm_auth_info ainfo; + struct gsm_auth_tuple atuple; + + vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id, + subscr->authorized, VTY_NEWLINE); + if (subscr->name) + vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE); + if (subscr->extension) + vty_out(vty, " Extension: %s%s", subscr->extension, + VTY_NEWLINE); + if (subscr->imsi) + vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE); + if (subscr->tmsi != GSM_RESERVED_TMSI) + vty_out(vty, " TMSI: %08X%s", subscr->tmsi, + VTY_NEWLINE); + + rc = get_authinfo_by_subscr(&ainfo, subscr); + if (!rc) { + vty_out(vty, " A3A8 algorithm id: %d%s", + ainfo.auth_algo, VTY_NEWLINE); + vty_out(vty, " A3A8 Ki: %s%s", + hexdump(ainfo.a3a8_ki, ainfo.a3a8_ki_len), + VTY_NEWLINE); + } + + rc = get_authtuple_by_subscr(&atuple, subscr); + if (!rc) { + vty_out(vty, " A3A8 last tuple (used %d times):%s", + atuple.use_count, VTY_NEWLINE); + vty_out(vty, " seq # : %d%s", + atuple.key_seq, VTY_NEWLINE); + vty_out(vty, " RAND : %s%s", + hexdump(atuple.rand, sizeof(atuple.rand)), + VTY_NEWLINE); + vty_out(vty, " SRES : %s%s", + hexdump(atuple.sres, sizeof(atuple.sres)), + VTY_NEWLINE); + vty_out(vty, " Kc : %s%s", + hexdump(atuple.kc, sizeof(atuple.kc)), + VTY_NEWLINE); + } + + vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE); +} + + /* Subscriber */ DEFUN(show_subscr, show_subscr_cmd, @@ -141,7 +188,7 @@ DEFUN(show_subscr, VTY_NEWLINE); return CMD_WARNING; } - subscr_dump_vty(vty, subscr); + subscr_dump_full_vty(vty, subscr); subscr_put(subscr); return CMD_SUCCESS; @@ -162,7 +209,7 @@ DEFUN(show_subscr_cache, llist_for_each_entry(subscr, &active_subscribers, entry) { vty_out(vty, " Subscriber:%s", VTY_NEWLINE); - subscr_dump_vty(vty, subscr); + subscr_dump_full_vty(vty, subscr); } return CMD_SUCCESS; From b91a106932187125e00646ff9fd919050f533464 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 6 Jan 2010 06:38:14 +0100 Subject: [PATCH 308/365] [si] Go through the system_information structs and add static_asserts The structs are correct, the problem is coming from the rest octets --- openbsc/src/system_information.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 6493794ef..42cd8ec6a 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -38,6 +38,22 @@ #define GSM_MACBLOCK_LEN 23 #define GSM_MACBLOCK_PADDING 0x2b +/* verify the sizes of the system information type structs */ + +/* rest octets are not part of the struct */ +static_assert(sizeof(struct gsm48_system_information_type_header) == 3, _si_header_size); +static_assert(sizeof(struct gsm48_rach_control) == 3, _si_rach_control); +static_assert(sizeof(struct gsm48_system_information_type_1) == 22, _si1_size); +static_assert(sizeof(struct gsm48_system_information_type_2) == 23, _si2_size); +static_assert(sizeof(struct gsm48_system_information_type_3) == 19, _si3_size); +static_assert(sizeof(struct gsm48_system_information_type_4) == 13, _si4_size); + +/* bs11 forgot the l2 len, 0-6 rest octets */ +static_assert(sizeof(struct gsm48_system_information_type_5) == 18, _si5_size); +static_assert(sizeof(struct gsm48_system_information_type_6) == 11, _si6_size); + +static_assert(sizeof(struct gsm48_system_information_type_13) == 3, _si13_size); + /* Frequency Lists as per TS 04.08 10.5.2.13 */ /* 10.5.2.13.2: Bit map 0 format */ From b3fc1eb53c077b50e84439926683e334fd7f1d57 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 6 Jan 2010 09:43:08 +0100 Subject: [PATCH 309/365] [vty] Move db usage out of the libbsc (fork dumping of subscr) (2nd part) Follow up on 424c4f0e2927d5a7538b31c69113c6e4f861d2c9. As pointed out by Sylvain on the mailinglist I need to remove this here as well. Do not call db.c code from code that is located in libbsc.a --- openbsc/src/vty_interface.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 8301f7893..f978c27fc 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -531,32 +531,6 @@ static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) vty_out(vty, " TMSI: %08X%s", subscr->tmsi, VTY_NEWLINE); - rc = get_authinfo_by_subscr(&ainfo, subscr); - if (!rc) { - vty_out(vty, " A3A8 algorithm id: %d%s", - ainfo.auth_algo, VTY_NEWLINE); - vty_out(vty, " A3A8 Ki: %s%s", - hexdump(ainfo.a3a8_ki, ainfo.a3a8_ki_len), - VTY_NEWLINE); - } - - rc = get_authtuple_by_subscr(&atuple, subscr); - if (!rc) { - vty_out(vty, " A3A8 last tuple (used %d times):%s", - atuple.use_count, VTY_NEWLINE); - vty_out(vty, " seq # : %d%s", - atuple.key_seq, VTY_NEWLINE); - vty_out(vty, " RAND : %s%s", - hexdump(atuple.rand, sizeof(atuple.rand)), - VTY_NEWLINE); - vty_out(vty, " SRES : %s%s", - hexdump(atuple.sres, sizeof(atuple.sres)), - VTY_NEWLINE); - vty_out(vty, " Kc : %s%s", - hexdump(atuple.kc, sizeof(atuple.kc)), - VTY_NEWLINE); - } - vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE); } From 9a2370b5915cbf40b2c2f63804633b9761031469 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 00:00:45 +0100 Subject: [PATCH 310/365] rrlp-ephemeris: Fix memory leak We need to go through all the object release code ... Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/rrlp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rrlp-ephemeris/rrlp.c b/rrlp-ephemeris/rrlp.c index 8b0d14acf..ad8eb5bda 100644 --- a/rrlp-ephemeris/rrlp.c +++ b/rrlp-ephemeris/rrlp.c @@ -582,7 +582,7 @@ rrlp_gps_assist_pdus( o_len[i] = rv; } - return lst_cnt; + rv = lst_cnt; /* Release ASN.1 objects */ error: From 41c32b49b7eea9e0d5cc6ee6ecb58d8e28ee99ed Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 00:04:56 +0100 Subject: [PATCH 311/365] rrlp-ephemeris: Properly implement pseudo segmentation flag See 3GPP TS 44.031 section 2.2/2.3 for a example/description. Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/rrlp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rrlp-ephemeris/rrlp.c b/rrlp-ephemeris/rrlp.c index ad8eb5bda..0ff9321ae 100644 --- a/rrlp-ephemeris/rrlp.c +++ b/rrlp-ephemeris/rrlp.c @@ -575,6 +575,14 @@ rrlp_gps_assist_pdus( /* Serialize & Release all PDUs */ for (i=0; icomponent.choice.assistanceData.moreAssDataToBeSent = mad; + + /* Serialization */ // asn_fprint(stdout, &asn_DEF_PDU, lst_pdu[i]); rv = uper_encode_to_new_buffer(&asn_DEF_PDU, NULL, lst_pdu[i], &o_pdu[i]); if (rv < 0) From 3930b3f9a9014e8e428ff8b9fd001cf6425063c5 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 00:29:21 +0100 Subject: [PATCH 312/365] rrlp-ephemeris: Add .gitignore Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 rrlp-ephemeris/.gitignore diff --git a/rrlp-ephemeris/.gitignore b/rrlp-ephemeris/.gitignore new file mode 100644 index 000000000..88b45e491 --- /dev/null +++ b/rrlp-ephemeris/.gitignore @@ -0,0 +1,4 @@ +asn1_gen/* +*.o +*.a +rrlp-test From 2d6057e8cf7870b8517df64fbf2181d6beed6bdd Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 00:30:02 +0100 Subject: [PATCH 313/365] rrlp-ephemeris: Comment alignment fix Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/gps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rrlp-ephemeris/gps.h b/rrlp-ephemeris/gps.h index f6f7cc07b..50a7e5ec3 100644 --- a/rrlp-ephemeris/gps.h +++ b/rrlp-ephemeris/gps.h @@ -113,7 +113,7 @@ struct gps_ephemeris_sv { int c_rs; /* s 16 2^-5 meters */ int delta_n; /* s 16 2^-43 semi-circles / s */ - int m_0; /* s 32 2^-31 semi-circles */ + int m_0; /* s 32 2^-31 semi-circles */ int c_uc; /* s 16 2^-29 radians */ unsigned int e; /* u 32 2^-33 0.03 / */ int c_us; /* s 16 2^-29 radians */ From c74f953fb90b7cb66714e143381113fb8e9c07f3 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 14:31:41 +0100 Subject: [PATCH 314/365] rrlp-ephemeris: Support filling of ReferencePositon IE Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/Makefile | 2 +- rrlp-ephemeris/gps.h | 10 ++++++ rrlp-ephemeris/rrlp.c | 68 ++++++++++++++++++++++++++++++++--------- 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/rrlp-ephemeris/Makefile b/rrlp-ephemeris/Makefile index a1f22650c..742cac7a6 100644 --- a/rrlp-ephemeris/Makefile +++ b/rrlp-ephemeris/Makefile @@ -11,7 +11,7 @@ all: rrlp-test rrlp-test: libgsm-asn1.a gps.o ubx.o ubx-parse.o rrlp.o main.o - $(CC) -o $@ gps.o ubx.o ubx-parse.o rrlp.o main.o -L. -lgsm-asn1 + $(CC) -o $@ gps.o ubx.o ubx-parse.o rrlp.o main.o -L. -lgsm-asn1 -lm # diff --git a/rrlp-ephemeris/gps.h b/rrlp-ephemeris/gps.h index 50a7e5ec3..03d643fb4 100644 --- a/rrlp-ephemeris/gps.h +++ b/rrlp-ephemeris/gps.h @@ -143,11 +143,20 @@ struct gps_ephemeris { }; +/* Reference position */ +struct gps_ref_pos { /* WSG84 ellipsoid */ + double latitude; /* deg */ + double longitude; /* deg */ + double altitude; /* m above ellipsoid */ +}; + + /* All assist data */ #define GPS_FIELD_IONOSPHERE (1<<0) #define GPS_FIELD_UTC (1<<1) #define GPS_FIELD_ALMANAC (1<<2) #define GPS_FIELD_EPHEMERIS (1<<3) +#define GPS_FIELD_REFPOS (1<<4) struct gps_assist_data { int fields; @@ -155,6 +164,7 @@ struct gps_assist_data { struct gps_utc_model utc; struct gps_almanac almanac; struct gps_ephemeris ephemeris; + struct gps_ref_pos ref_pos; }; diff --git a/rrlp-ephemeris/rrlp.c b/rrlp-ephemeris/rrlp.c index 0ff9321ae..5e55d1d3a 100644 --- a/rrlp-ephemeris/rrlp.c +++ b/rrlp-ephemeris/rrlp.c @@ -22,6 +22,7 @@ #include +#include #include "gps.h" #include "rrlp.h" @@ -181,6 +182,47 @@ rrlp_decode_assistance_request( /* RRLP elements fill */ /* ---------------------------------------------------------------------{{{ */ + /* Helpers */ + +static void +_ts_23_032_store_latitude(double lat, uint8_t *b) +{ + uint32_t x; + x = (uint32_t) floor(fabs(lat/90.0) * ((double)(1<<23))); + if (x >= (1<<23)) + x = (1<<23) - 1; + if (lat < 0.0) + x |= (1<<23); + b[0] = (x >> 16) & 0xff; + b[1] = (x >> 8) & 0xff; + b[2] = x & 0xff; +} + +static void +_ts_23_032_store_longitude(double lon, uint8_t *b) +{ + int32_t x; + x = floor((lon/360.0) * ((double)(1<<24))); + if (x >= (1<<23)) + x = 0x007fffff; + else if (x < -(1<<23)) + x = 0x00800000; + b[0] = (x >> 16) & 0xff; + b[1] = (x >> 8) & 0xff; + b[2] = x & 0xff; +} + +static void +_ts_23_032_store_altitude(double alt, uint8_t *b) +{ + int alt_i = (int)fabs(alt); + b[0] = ((alt_i >> 8) & 0x7f) | (alt<0.0 ? 0x80 : 0x00); + b[1] = alt_i & 0xff; +} + + + /* Fill methods */ + static void _rrlp_fill_navigation_model_element( struct NavModelElement *rrlp_nme, @@ -358,27 +400,25 @@ _rrlp_add_reference_location( struct gps_assist_data *gps_ad) { struct RefLocation *rrlp_refloc; + uint8_t *b; - /* FIXME: Check if info is in gps_ad */ + if (!(gps_ad->fields & GPS_FIELD_REFPOS)) + return -EINVAL; rrlp_refloc = calloc(1, sizeof(*rrlp_refloc)); if (!rrlp_refloc) return -ENOMEM; rrlp_gps_ad->controlHeader.refLocation = rrlp_refloc; - /* FIXME */ - { - uint8_t gps_loc[] = { - 0x80, /* Ellipsoid Point with altitude */ - 0x48, 0x0f, 0x93, /* 50.667778 N */ - 0x03, 0x47, 0x87, /* 4.611667 E */ - 0x00, 0x72, /* 114m */ - }; - uint8_t *b = malloc(sizeof(gps_loc)); - memcpy(b, gps_loc, sizeof(gps_loc)); - rrlp_refloc->threeDLocation.buf = b; - rrlp_refloc->threeDLocation.size = sizeof(gps_loc); - } + b = malloc(9); + + b[0] = 0x80; /* Ellipsoid Point with altitude */ + _ts_23_032_store_latitude(gps_ad->ref_pos.latitude, &b[1]); + _ts_23_032_store_longitude(gps_ad->ref_pos.longitude, &b[4]); + _ts_23_032_store_altitude(gps_ad->ref_pos.altitude, &b[7]); + + rrlp_refloc->threeDLocation.buf = b; + rrlp_refloc->threeDLocation.size = 9; return 0; } From ccea43902808717c81facef188872abebae0a290 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 14:51:08 +0100 Subject: [PATCH 315/365] rrlp-ephemeris: Fill ref pos with UBX NAV_POSLLH messages Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/ubx-parse.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rrlp-ephemeris/ubx-parse.c b/rrlp-ephemeris/ubx-parse.c index cb8c22e83..60bc05763 100644 --- a/rrlp-ephemeris/ubx-parse.c +++ b/rrlp-ephemeris/ubx-parse.c @@ -69,7 +69,11 @@ _ubx_msg_parse_nav_posllh(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) //printf("[.] NAV_POSLLH\n"); - // FIXME: Extract info for "Reference Position" + gps->fields |= GPS_FIELD_REFPOS; + + gps->ref_pos.latitude = (double)(nav_posllh->lat) * 1e-7; + gps->ref_pos.longitude = (double)(nav_posllh->lon) * 1e-7; + gps->ref_pos.altitude = (double)(nav_posllh->height) * 1e-3; } static void From a17324c7fe86497879f3e4891b2ecbcc63d972d6 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 15:34:30 +0100 Subject: [PATCH 316/365] rrlp-ephemeris: Add a note about extracting RefPos from AID_INI Yeah we could do it if anyone is willing to implement conversion from ecef to WGS84. See http://en.wikipedia.org/wiki/Geodetic_system Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/ubx-parse.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rrlp-ephemeris/ubx-parse.c b/rrlp-ephemeris/ubx-parse.c index 60bc05763..1dbb279f7 100644 --- a/rrlp-ephemeris/ubx-parse.c +++ b/rrlp-ephemeris/ubx-parse.c @@ -85,6 +85,10 @@ _ubx_msg_parse_aid_ini(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) //printf("[.] AID_INI\n"); // FIXME: Extract info for "Reference Time" + + // FIXME: We could extract ref position as well but we need it in + // WGS84 geodetic coordinates and it's provided as ecef, so + // we need a lot of math ... } static void From b74cbcf7ec94f0d927f94e8152f6a8c395fd6e3a Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 15:47:21 +0100 Subject: [PATCH 317/365] rrlp-ephemeris: Add support for filling ReferenceTime IE Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/gps.h | 9 +++++++++ rrlp-ephemeris/rrlp.c | 9 +++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/rrlp-ephemeris/gps.h b/rrlp-ephemeris/gps.h index 03d643fb4..241b9d743 100644 --- a/rrlp-ephemeris/gps.h +++ b/rrlp-ephemeris/gps.h @@ -151,12 +151,20 @@ struct gps_ref_pos { /* WSG84 ellipsoid */ }; +/* Reference time */ +struct gps_ref_time { + int wn; /* GPS week number */ + double tow; /* in seconds */ +}; + + /* All assist data */ #define GPS_FIELD_IONOSPHERE (1<<0) #define GPS_FIELD_UTC (1<<1) #define GPS_FIELD_ALMANAC (1<<2) #define GPS_FIELD_EPHEMERIS (1<<3) #define GPS_FIELD_REFPOS (1<<4) +#define GPS_FIELD_REFTIME (1<<5) struct gps_assist_data { int fields; @@ -165,6 +173,7 @@ struct gps_assist_data { struct gps_almanac almanac; struct gps_ephemeris ephemeris; struct gps_ref_pos ref_pos; + struct gps_ref_time ref_time; }; diff --git a/rrlp-ephemeris/rrlp.c b/rrlp-ephemeris/rrlp.c index 5e55d1d3a..e60c3ab01 100644 --- a/rrlp-ephemeris/rrlp.c +++ b/rrlp-ephemeris/rrlp.c @@ -430,16 +430,17 @@ _rrlp_add_reference_time( { struct ReferenceTime *rrlp_reftime; - /* FIXME: Check if info is in gps_ad */ + if (!(gps_ad->fields & GPS_FIELD_REFTIME)) + return -EINVAL; rrlp_reftime = calloc(1, sizeof(*rrlp_reftime)); if (!rrlp_reftime) return -ENOMEM; rrlp_gps_ad->controlHeader.referenceTime = rrlp_reftime; - /* FIXME */ -// rrlp_reftime.gpsTime.gpsTOW23b = g_gps_tow / 80; /* 23 bits */ -// rrlp_reftime.gpsTime.gpsWeek = g_gps_week & 0x3ff; /* 10 bits */ + rrlp_reftime->gpsTime.gpsWeek = gps_ad->ref_time.wn & 0x3ff; /* 10b */ + rrlp_reftime->gpsTime.gpsTOW23b = + ((int)floor(gps_ad->ref_time.tow / 0.08)) & 0x7fffff; /* 23b */ return 0; } From ad0140572c1f5769cd589c807bedbde228e51615 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 28 Dec 2009 15:49:29 +0100 Subject: [PATCH 318/365] rrlp-ephemeris: Fill ref time with UBX AID_INI messages Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/ubx-parse.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rrlp-ephemeris/ubx-parse.c b/rrlp-ephemeris/ubx-parse.c index 1dbb279f7..c3d0f70d7 100644 --- a/rrlp-ephemeris/ubx-parse.c +++ b/rrlp-ephemeris/ubx-parse.c @@ -84,8 +84,12 @@ _ubx_msg_parse_aid_ini(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud) //printf("[.] AID_INI\n"); - // FIXME: Extract info for "Reference Time" - + /* Extract info for "Reference Time" */ + gps->fields |= GPS_FIELD_REFTIME; + + gps->ref_time.wn = aid_ini->wn; + gps->ref_time.tow = (double)aid_ini->tow * 1e-3; + // FIXME: We could extract ref position as well but we need it in // WGS84 geodetic coordinates and it's provided as ecef, so // we need a lot of math ... From a9923753ea65b94cc46a9c774c8d385a44fb38db Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sat, 2 Jan 2010 23:57:15 +0100 Subject: [PATCH 319/365] rrlp-ephemeris: Add script to get test data from UBX receiver Simple script illustrating how data.ubx (the test sample) is generated. Signed-off-by: Sylvain Munaut --- rrlp-ephemeris/get-test-data.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 rrlp-ephemeris/get-test-data.sh diff --git a/rrlp-ephemeris/get-test-data.sh b/rrlp-ephemeris/get-test-data.sh new file mode 100755 index 000000000..169f43c8f --- /dev/null +++ b/rrlp-ephemeris/get-test-data.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +DEV=$1 +OUTF=$2 + +# Change mode +echo -en "\$PUBX,41,1,0001,0001,9600,0*14\r\n" > ${DEV} + +# Wait a little +sleep 2 + +# Start dump +echo -en "\xb5\x62\x01\x02\x00\x00\x03\x0a" | \ + socat -t5 ${DEV},b9600,raw,clocal=1,echo=0 - > ${OUTF} +echo -en "\xb5\x62\x0b\x10\x00\x00\x1b\x5c" | \ + socat -t10 ${DEV},b9600,raw,clocal=1,echo=0 - >> ${OUTF} + From b1a83585a27c00a33ff1cb30ddeb082515595ba3 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 3 Jan 2010 00:00:47 +0100 Subject: [PATCH 320/365] rrlp-ephemeris: Add directory with asn1c patches - One is just to improve the debug prints - The other fixes a problem in PER encoding found by Dieter Spaar. Signed-off-by: Sylvain Munaut --- .../00_add_enumerated_verbose.diff | 56 +++++++++++++++++++ .../01_fix_per_encoding_dieter.diff | 17 ++++++ 2 files changed, 73 insertions(+) create mode 100644 rrlp-ephemeris/asn1c_patches/00_add_enumerated_verbose.diff create mode 100644 rrlp-ephemeris/asn1c_patches/01_fix_per_encoding_dieter.diff diff --git a/rrlp-ephemeris/asn1c_patches/00_add_enumerated_verbose.diff b/rrlp-ephemeris/asn1c_patches/00_add_enumerated_verbose.diff new file mode 100644 index 000000000..64c22a3cf --- /dev/null +++ b/rrlp-ephemeris/asn1c_patches/00_add_enumerated_verbose.diff @@ -0,0 +1,56 @@ +Index: skeletons/NativeEnumerated.c +=================================================================== +--- skeletons/NativeEnumerated.c (revision 1407) ++++ skeletons/NativeEnumerated.c (working copy) +@@ -22,7 +22,7 @@ + "ENUMERATED", /* The ASN.1 type is still ENUMERATED */ + "ENUMERATED", + NativeInteger_free, +- NativeInteger_print, ++ NativeEnumerated_print, + asn_generic_no_constraint, + NativeInteger_decode_ber, + NativeInteger_encode_der, +@@ -205,3 +205,30 @@ + _ASN_ENCODED_OK(er); + } + ++int ++NativeEnumerated_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; ++ const long *native = (const long *)sptr; ++ char scratch[256]; ++ int ret; ++ ++ (void)td; /* Unused argument */ ++ (void)ilevel; /* Unused argument */ ++ ++ if(native) { ++ const asn_INTEGER_enum_map_t *map = INTEGER_map_value2enum(specs, *native); ++ if (map && map->enum_len && map->enum_name) { ++ ret = snprintf(scratch, sizeof(scratch), ++ "%s", map->enum_name); ++ } else { ++ ret = snprintf(scratch, sizeof(scratch), ++ (specs && specs->field_unsigned) ++ ? "%lu" : "%ld", *native); ++ } ++ assert(ret > 0 && (size_t)ret < sizeof(scratch)); ++ return (cb(scratch, ret, app_key) < 0) ? -1 : 0; ++ } else { ++ return (cb("", 8, app_key) < 0) ? -1 : 0; ++ } ++} +Index: skeletons/NativeEnumerated.h +=================================================================== +--- skeletons/NativeEnumerated.h (revision 1407) ++++ skeletons/NativeEnumerated.h (working copy) +@@ -24,6 +24,7 @@ + xer_type_encoder_f NativeEnumerated_encode_xer; + per_type_decoder_f NativeEnumerated_decode_uper; + per_type_encoder_f NativeEnumerated_encode_uper; ++asn_struct_print_f NativeEnumerated_print; + + #ifdef __cplusplus + } diff --git a/rrlp-ephemeris/asn1c_patches/01_fix_per_encoding_dieter.diff b/rrlp-ephemeris/asn1c_patches/01_fix_per_encoding_dieter.diff new file mode 100644 index 000000000..a09c20159 --- /dev/null +++ b/rrlp-ephemeris/asn1c_patches/01_fix_per_encoding_dieter.diff @@ -0,0 +1,17 @@ +Index: skeletons/per_support.c +=================================================================== +--- skeletons/per_support.c (revision 1407) ++++ skeletons/per_support.c (working copy) +@@ -336,7 +336,12 @@ + buf[3] = bits; + else { + ASN_DEBUG("->[PER out split %d]", obits); ++#if 1 // Dieter ++ po->nboff -= obits; // undo incrementation from a few lines above ++ per_put_few_bits(po, bits >> (obits - 24), 24); // shift according to the rest of the bits ++#else + per_put_few_bits(po, bits >> 8, 24); ++#endif + per_put_few_bits(po, bits, obits - 24); + ASN_DEBUG("<-[PER out split %d]", obits); + } From 65542c7f597c5c94b16904108056d3c99de1a8cc Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sat, 2 Jan 2010 16:35:26 +0100 Subject: [PATCH 321/365] abis_nm: Consider a STATE CHG without avail_status as an empty avail_status At least some nanoBTS 139 send the last even (going online) as 'enabled' 'unlocked' but no avail status IE (which I guess mean an empty set, the doc 12.21 isn't that clear about that). Signed-off-by: Sylvain Munaut --- openbsc/src/abis_nm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 7a67fdf3b..8789674e0 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -813,7 +813,8 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb) new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS); DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability), new_state.availability); - } + } else + new_state.availability = 0xff; if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) { new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE); DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative)); From ef24dff2a22c907f08a24b19773dde5ce20ba5d6 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sat, 19 Dec 2009 12:38:10 +0100 Subject: [PATCH 322/365] [signal] Differentiate paging success from expiration in SS_PAGING This is useful information to know and actually fixes a segfault in rllp.c where lchan is accessed even tough it could be NULL in case of failure. Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/signal.h | 3 ++- openbsc/src/gsm_04_08_utils.c | 2 +- openbsc/src/paging.c | 2 +- openbsc/src/rrlp.c | 8 +++----- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 23551f743..07b4e393d 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -45,7 +45,8 @@ enum signal_subsystems { /* SS_PAGING signals */ enum signal_paging { - S_PAGING_COMPLETED, + S_PAGING_SUCCEEDED, + S_PAGING_EXPIRED, }; /* SS_SMS signals */ diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index a18427788..d5785f971 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -490,7 +490,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr) bts->network->stats.paging.completed++; - dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); + dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data); /* Stop paging on the bts we received the paging response */ paging_request_stop(msg->trx->bts, subscr, msg->lchan); diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index b5dc2d052..91de70241 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -214,7 +214,7 @@ static void paging_T3113_expired(void *data) counter_inc(req->bts->network->stats.paging.expired); - dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); + dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data); if (cbfn) cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL, cbfn_param); diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c index d4665d570..35044518c 100644 --- a/openbsc/src/rrlp.c +++ b/openbsc/src/rrlp.c @@ -89,14 +89,12 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal, struct paging_signal_data *psig_data = signal_data; switch (signal) { - case S_PAGING_COMPLETED: - /* paging might have "completed' unsucessfully, - * in this case we don't have a lchan */ - if (!psig_data->lchan) - break; + case S_PAGING_SUCCEEDED: /* A subscriber has attached. */ send_rrlp_req(psig_data->lchan); break; + case S_PAGING_EXPIRED: + break; } return 0; } From 493db4ee3db9d10b4af931972bd505f8d5cbb9b7 Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Thu, 7 Jan 2010 00:43:11 +0100 Subject: [PATCH 323/365] [abis_nm] Add generic abis_nm_bs11_logon function Factoring out common logon functionality will allow us to logon as different user. abis_nm_bs11_factory_logon now uses this function. --- openbsc/include/openbsc/abis_nm.h | 1 + openbsc/src/abis_nm.c | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 6876435dc..8fe4b0ce4 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -787,6 +787,7 @@ int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts); int abis_nm_bs11_get_serno(struct gsm_bts *bts); int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level); int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx); +int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on); int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on); int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password); int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked); diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 8789674e0..bfc3de2c9 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2417,10 +2417,13 @@ int abis_nm_bs11_get_cclk(struct gsm_bts *bts) } //static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 }; -static const u_int8_t bs11_logon_c8[] = { 0x02 }; -static const u_int8_t bs11_logon_c9[] = "FACTORY"; int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on) +{ + return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on); +} + +int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on) { struct abis_om_hdr *oh; struct msgb *msg = nm_msgb_alloc(); @@ -2431,15 +2434,15 @@ int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on) oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); if (on) { u_int8_t len = 3*2 + sizeof(bdt) - + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9); + + 1 + strlen(name); fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON, NM_OC_BS11_BTSE, 0xff, 0xff, 0xff); msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME, sizeof(bdt), (u_int8_t *) &bdt); msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV, - sizeof(bs11_logon_c8), bs11_logon_c8); + 1, &level); msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME, - sizeof(bs11_logon_c9), bs11_logon_c9); + strlen(name), (u_int8_t *)name); } else { fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF, NM_OC_BS11_BTSE, 0xff, 0xff, 0xff); From 4b054c8788f008e948c0d75057a74655a6c427fe Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Thu, 7 Jan 2010 00:46:26 +0100 Subject: [PATCH 324/365] [abis_nm] Add abis_nm_bs11_infield_logon to logon as user field As this user you are able to set the PLL work value which is especially useful if your BS11 got detuned by an inaccurate oscillator in your E1 card. --- openbsc/include/openbsc/abis_nm.h | 1 + openbsc/src/abis_nm.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 8fe4b0ce4..9d9b8c11a 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -789,6 +789,7 @@ int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level); int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx); int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on); int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on); +int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on); int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password); int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked); int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts); diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index bfc3de2c9..bcfce681b 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2423,6 +2423,11 @@ int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on) return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on); } +int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on) +{ + return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on); +} + int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on) { struct abis_om_hdr *oh; From 7b1dd748ea7333e8f5f19ad5256ae7deb1f25c43 Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Thu, 7 Jan 2010 00:54:01 +0100 Subject: [PATCH 325/365] [abis_nm] Add abis_nm_bs11_set_pll function to change the set/work value Whether this function changes the set or the work value depends on your type of login. In FACTORY login it changes the set value, in FIELD login it changes the work value (which is what is used by the BS11 to tune the frequency). --- openbsc/include/openbsc/abis_nm.h | 1 + openbsc/src/abis_nm.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 9d9b8c11a..d5c7a13d4 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -793,6 +793,7 @@ int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on); int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password); int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked); int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts); +int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value); int abis_nm_bs11_get_cclk(struct gsm_bts *bts); int abis_nm_bs11_get_state(struct gsm_bts *bts); int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname, diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index bcfce681b..d679d7851 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2495,6 +2495,27 @@ int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked) return abis_nm_sendmsg(bts, msg); } +/* Set the calibration value of the PLL (work value/set value) + * It depends on the login which one is changed */ +int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value) +{ + struct abis_om_hdr *oh; + struct msgb *msg; + u_int8_t tlv_value[2]; + + msg = nm_msgb_alloc(); + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11, + BS11_OBJ_TRX1, 0x00, 0x00); + + tlv_value[0] = value>>8; + tlv_value[1] = value&0xff; + + msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value); + + return abis_nm_sendmsg(bts, msg); +} + int abis_nm_bs11_get_state(struct gsm_bts *bts) { return __simple_cmd(bts, NM_MT_BS11_GET_STATE); From f904fa80ee8aea959ebb339de042e34c2140b9ed Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Thu, 7 Jan 2010 01:26:32 +0100 Subject: [PATCH 326/365] [bs11_config] Whitespace changes so the help text looks nice --- openbsc/src/bs11_config.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index b2470a9fc..3d719bb5d 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -706,25 +706,25 @@ static void print_help(void) printf("\t-p --port \t\tSpecify serial port\n"); printf("\t-s --software \t\tSpecify Software file\n"); printf("\t-S --safety \t\tSpecify Safety Load file\n"); - printf("\t-d --delay \t\tSpecify delay in milliseconds\n"); + printf("\t-d --delay \t\t\tSpecify delay in milliseconds\n"); printf("\t-D --disconnect\t\t\tDisconnect BTS from BSC\n"); printf("\t-w --win-size \t\tSpecify Window Size\n"); printf("\t-f --forced\t\t\tForce Software Load\n"); printf("\nSupported commands:\n"); - printf("\tquery\t\tQuery the BS-11 about serial number and configuration\n"); - printf("\tdisconnect\tDisconnect A-bis link (go into administrative state)\n"); - printf("\tresconnect\tReconnect A-bis link (go into normal state)\n"); - printf("\trestart\t\tRestart the BTS\n"); - printf("\tsoftware\tDownload Software (only in administrative state)\n"); - printf("\tcreate-trx1\tCreate objects for TRX1 (Danger: Your BS-11 might overheat)\n"); - printf("\tdelete-trx1\tDelete objects for TRX1\n"); - printf("\tpll-e1-locked\tSet the PLL to be locked to E1 clock\n"); - printf("\tpll-standalone\tSet the PLL to be in standalone mode\n"); - printf("\toml-tei\tSet OML E1 TS and TEI\n"); - printf("\tbport0-star\tSet BPORT0 line config to star\n"); + printf("\tquery\t\t\tQuery the BS-11 about serial number and configuration\n"); + printf("\tdisconnect\t\tDisconnect A-bis link (go into administrative state)\n"); + printf("\tresconnect\t\tReconnect A-bis link (go into normal state)\n"); + printf("\trestart\t\t\tRestart the BTS\n"); + printf("\tsoftware\t\tDownload Software (only in administrative state)\n"); + printf("\tcreate-trx1\t\tCreate objects for TRX1 (Danger: Your BS-11 might overheat)\n"); + printf("\tdelete-trx1\t\tDelete objects for TRX1\n"); + printf("\tpll-e1-locked\t\tSet the PLL to be locked to E1 clock\n"); + printf("\tpll-standalone\t\tSet the PLL to be in standalone mode\n"); + printf("\toml-tei\t\t\tSet OML E1 TS and TEI\n"); + printf("\tbport0-star\t\tSet BPORT0 line config to star\n"); printf("\tbport0-multiport\tSet BPORT0 line config to multiport\n"); - printf("\tcreate-bport1\tCreate BPORT1 object\n"); - printf("\tdelete-bport1\tDelete BPORT1 object\n"); + printf("\tcreate-bport1\t\tCreate BPORT1 object\n"); + printf("\tdelete-bport1\t\tDelete BPORT1 object\n"); } static void handle_options(int argc, char **argv) From 6a9fa7308db906c8a92ac610ad3f05e14f2c2af5 Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Thu, 7 Jan 2010 01:27:50 +0100 Subject: [PATCH 327/365] [bs11_config] Add pll-setvalue and pll-workvalue commands These commands let you change the PLL set and work values. Many thanks to Dieter Spaar for figuring out how to do this! Now you can just reset your PLL work value if it drifts away due to your E1 card. Use it like this: bs11_config pll-workvalue 1000 --- openbsc/src/bs11_config.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index 3d719bb5d..6a76b962d 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -51,7 +51,7 @@ enum bs11cfg_state { STATE_QUERY, }; static enum bs11cfg_state bs11cfg_state = STATE_NONE; -static char *command; +static char *command, *value; struct timer_list status_timer; static const u_int8_t obj_li_attr[] = { @@ -540,6 +540,21 @@ static int handle_state_resp(enum abis_bs11_phase state) sleep(1); abis_nm_bs11_factory_logon(g_bts, 0); command = NULL; + } else if (!strcmp(command, "pll-setvalue")) { + abis_nm_bs11_set_pll(g_bts, atoi(value)); + sleep(1); + abis_nm_bs11_factory_logon(g_bts, 0); + command = NULL; + } else if (!strcmp(command, "pll-workvalue")) { + /* To set the work value we need to login as FIELD */ + abis_nm_bs11_factory_logon(g_bts, 0); + sleep(1); + abis_nm_bs11_infield_logon(g_bts, 1); + sleep(1); + abis_nm_bs11_set_pll(g_bts, atoi(value)); + sleep(1); + abis_nm_bs11_infield_logon(g_bts, 0); + command = NULL; } else if (!strcmp(command, "oml-tei")) { abis_nm_bs11_conn_oml_tei(g_bts, 0, 1, 0xff, TEI_OML); command = NULL; @@ -720,6 +735,8 @@ static void print_help(void) printf("\tdelete-trx1\t\tDelete objects for TRX1\n"); printf("\tpll-e1-locked\t\tSet the PLL to be locked to E1 clock\n"); printf("\tpll-standalone\t\tSet the PLL to be in standalone mode\n"); + printf("\tpll-setvalue \tSet the PLL set value\n"); + printf("\tpll-workvalue \tSet the PLL work value\n"); printf("\toml-tei\t\t\tSet OML E1 TS and TEI\n"); printf("\tbport0-star\t\tSet BPORT0 line config to star\n"); printf("\tbport0-multiport\tSet BPORT0 line config to multiport\n"); @@ -791,6 +808,9 @@ static void handle_options(int argc, char **argv) } if (optind < argc) command = argv[optind]; + if (optind+1 < argc) + value = argv[optind+1]; + } static int num_sigint; From 4cffc45cbc6e0945845ee57ebe14e31eecc423a0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 6 Jan 2010 06:44:37 +0100 Subject: [PATCH 328/365] [rest_octets] Change data_len to the sizes of the spec Is that right? --- openbsc/src/rest_octets.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index 6226203ec..6c8c40314 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -37,7 +37,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos) memset(&bv, 0, sizeof(bv)); bv.data = data; - bv.data_len = 2; + bv.data_len = 1; if (nch_pos) { bitvec_set_bit(&bv, H); @@ -45,7 +45,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos) } else bitvec_set_bit(&bv, L); - bitvec_spare_padding(&bv, 15); + bitvec_spare_padding(&bv, 7); return 0; } @@ -95,7 +95,7 @@ int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3) memset(&bv, 0, sizeof(bv)); bv.data = data; - bv.data_len = 5; + bv.data_len = 4; /* Optional Selection Parameters */ append_selection_params(&bv, &si3->selection_params); @@ -141,7 +141,7 @@ int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4) memset(&bv, 0, sizeof(bv)); bv.data = data; - bv.data_len = 11; /* FIXME: up to ? */ + bv.data_len = 10; /* FIXME: up to ? */ /* SI4 Rest Octets O */ append_selection_params(&bv, &si4->selection_params); @@ -340,7 +340,7 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) memset(&bv, 0, sizeof(bv)); bv.data = data; - bv.data_len = 21; + bv.data_len = 20; if (0) { /* No rest octets */ From caa14869c08b55d55168d29f5f6e3c23a22c833c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 6 Jan 2010 07:49:58 +0100 Subject: [PATCH 329/365] [rest_octets] Return bv.data_len to indicate how was written Return the used data_len for the bitvector. This indicates how much data might have been written. --- openbsc/src/rest_octets.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index 6c8c40314..74874bd9a 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -46,7 +46,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos) bitvec_set_bit(&bv, L); bitvec_spare_padding(&bv, 7); - return 0; + return bv.data_len; } /* Append selection parameters to bitvec */ @@ -125,7 +125,8 @@ int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3) /* GPRS Indicator */ append_gprs_ind(&bv, &si3->gprs_ind); - return bitvec_spare_padding(&bv, (bv.data_len*8)-1); + bitvec_spare_padding(&bv, (bv.data_len*8)-1); + return bv.data_len; } static int append_lsa_params(struct bitvec *bv, @@ -178,7 +179,7 @@ int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4) bitvec_set_bit(&bv, si4->break_ind ? H : L); } - return 0; + return bv.data_len; } /* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a: @@ -390,5 +391,6 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) } } } - return bitvec_spare_padding(&bv, (bv.data_len*8)-1); + bitvec_spare_padding(&bv, (bv.data_len*8)-1); + return bv.data_len; } From 7ec448d0312f658a78f7d7cf1e3cbd03cce2a1ca Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 6 Jan 2010 07:52:31 +0100 Subject: [PATCH 330/365] [system_information] Return how much byte were written into output --- openbsc/src/system_information.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 42cd8ec6a..7fd12346e 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -222,9 +222,8 @@ static int generate_si1(u_int8_t *output, struct gsm_bts *bts) si1->rach_control = bts->si_common.rach_control; /* SI1 Rest Octets (10.5.2.32), contains NCH position */ - rest_octets_si1(si1->rest_octets, NULL); - - return GSM_MACBLOCK_LEN; + rc = rest_octets_si1(si1->rest_octets, NULL); + return sizeof(*si1) + rc; } static int generate_si2(u_int8_t *output, struct gsm_bts *bts) @@ -247,7 +246,7 @@ static int generate_si2(u_int8_t *output, struct gsm_bts *bts) si2->ncc_permitted = bts->si_common.ncc_permitted; si2->rach_control = bts->si_common.rach_control; - return GSM_MACBLOCK_LEN; + return sizeof(*si2); } struct gsm48_si_ro_info si_info = { @@ -276,6 +275,7 @@ struct gsm48_si_ro_info si_info = { static int generate_si3(u_int8_t *output, struct gsm_bts *bts) { + int rc; struct gsm48_system_information_type_3 *si3 = (struct gsm48_system_information_type_3 *) output; @@ -299,13 +299,14 @@ static int generate_si3(u_int8_t *output, struct gsm_bts *bts) CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME Power Offset, 2ter Indicator, Early Classmark Sending, Scheduling if and WHERE, GPRS Indicator, SI13 position */ - rest_octets_si3(si3->rest_octets, &si_info); + rc = rest_octets_si3(si3->rest_octets, &si_info); - return GSM_MACBLOCK_LEN; + return sizeof(*si3) + rc; } static int generate_si4(u_int8_t *output, struct gsm_bts *bts) { + int rc; struct gsm48_system_information_type_4 *si4 = (struct gsm48_system_information_type_4 *) output; @@ -331,9 +332,9 @@ static int generate_si4(u_int8_t *output, struct gsm_bts *bts) /* SI4 Rest Octets (10.5.2.35), containing Optional Power offset, GPRS Indicator, Cell Identity, LSA ID, Selection Parameter */ - rest_octets_si4(si4->data, &si_info); + rc = rest_octets_si4(si4->data, &si_info); - return GSM_MACBLOCK_LEN; + return sizeof(*si4) + rc; } static int generate_si5(u_int8_t *output, struct gsm_bts *bts) @@ -438,7 +439,7 @@ static int generate_si13(u_int8_t *output, struct gsm_bts *bts) si13->header.l2_plen = ret & 0xff; - return GSM_MACBLOCK_LEN; + return sizeof (*si13) + ret; } int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type) From 17d81e2f9552546f93227036a94301ef266e12b9 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 6 Jan 2010 07:52:55 +0100 Subject: [PATCH 331/365] [system_information] Initialize the buffer before moving it In the case of ipaccess we are doing a ++output but then still try to write 23 bytes into it and on my system this is leading to a stack corruption. --- openbsc/src/system_information.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 7fd12346e..9bdf2c139 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -342,6 +342,8 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts) struct gsm48_system_information_type_5 *si5; int rc, l2_plen = 18; + memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + /* ip.access nanoBTS needs l2_plen!! */ if (is_ipaccess_bts(bts)) { *output++ = (l2_plen << 2) | 1; @@ -349,7 +351,6 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts) } si5 = (struct gsm48_system_information_type_5 *) output; - memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); /* l2 pseudo length, not part of msg: 18 */ si5->rr_protocol_discriminator = GSM48_PDISC_RR; @@ -368,6 +369,8 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) struct gsm48_system_information_type_6 *si6; int l2_plen = 11; + memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + /* ip.access nanoBTS needs l2_plen!! */ if (is_ipaccess_bts(bts)) { *output++ = (l2_plen << 2) | 1; @@ -375,7 +378,6 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) } si6 = (struct gsm48_system_information_type_6 *) output; - memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); /* l2 pseudo length, not part of msg: 11 */ si6->rr_protocol_discriminator = GSM48_PDISC_RR; From d0c540210a72ad1f1062b44a73ce7fe2d2bc2cf3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 7 Jan 2010 16:08:42 +0100 Subject: [PATCH 332/365] Initialize reject_cause to a valid number Currently starting with the opencfg.cfg.nanobts and writing it out and then trying to start again will not work. The network reject_cause is initialized to 0 which is not a valid reject reason and when writing this to the config file and trying to parse it will fail. Pick roaming not allowed as a harmless option to those phones accidently trying to connect to the BTS. --- openbsc/src/gsm_data.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 291d407b6..446a82011 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -216,6 +216,7 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c net->country_code = country_code; net->network_code = network_code; net->num_bts = 0; + net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED; net->T3101 = GSM_T3101_DEFAULT; net->T3113 = GSM_T3113_DEFAULT; /* FIXME: initialize all other timers! */ From cbcfe24fee18981de0765cddb9fa02e79b3c156d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 7 Jan 2010 16:14:38 +0100 Subject: [PATCH 333/365] [vty] In case of handover only warn about the proxy mode when it is enabled Do not warn if the user has put "handover 0" in his configuration as this will not enable handover, only warn if it is going to be enabled. --- openbsc/src/vty_interface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index f978c27fc..8d6e202c1 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1212,13 +1212,15 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd, "handover (0|1)", "Whether or not to use in-call handover") { - if (ipacc_rtp_direct) { + int enable = atoi(argv[0]); + + if (enable && ipacc_rtp_direct) { vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode " "is enabled by using the -P command line option%s", VTY_NEWLINE); return CMD_WARNING; } - gsmnet->handover.active = atoi(argv[0]); + gsmnet->handover.active = enable; return CMD_SUCCESS; } From 2ef156db4356bc2ffb31c59a12b71f8a4f7a75fb Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 7 Jan 2010 20:39:42 +0100 Subject: [PATCH 334/365] bis_nm_ipaccess_set_nvattr() executes on a TRX, not a BTS --- openbsc/include/openbsc/abis_nm.h | 2 +- openbsc/src/abis_nm.c | 6 +++--- openbsc/src/ipaccess/ipaccess-config.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index d5c7a13d4..d6469c466 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -808,7 +808,7 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type, u_int8_t obj_class, u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr, u_int8_t *attr, int attr_len); -int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr, +int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len); int abis_nm_ipaccess_restart(struct gsm_bts *bts); int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index d679d7851..aaa7dd5fb 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2899,11 +2899,11 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type, } /* set some attributes in NVRAM */ -int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr, +int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len) { - return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR, - NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr, + return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR, + NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr, attr_len); } diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index ceac7bdf4..3b2a8bfd0 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -268,7 +268,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, msg->l2h[1] = msgb_l3len(msg) >> 8; msg->l2h[2] = msgb_l3len(msg) & 0xff; printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg)); - abis_nm_ipaccess_set_nvattr(bts, msg->l2h, msgb_l2len(msg)); + abis_nm_ipaccess_set_nvattr(bts->c0, msg->l2h, msgb_l2len(msg)); msgb_free(msg); break; case NM_MT_LOAD_END_NACK: @@ -313,7 +313,7 @@ static void bootstrap_om(struct gsm_bts *bts) memcpy(buf+3, unit_id, len); buf[3+len] = 0; printf("setting Unit ID to '%s'\n", unit_id); - abis_nm_ipaccess_set_nvattr(bts, buf, 3+len+1); + abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len+1); } if (prim_oml_ip) { struct in_addr ia; @@ -337,7 +337,7 @@ static void bootstrap_om(struct gsm_bts *bts) *cur++ = 0; printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia)); oml_state = 1; - abis_nm_ipaccess_set_nvattr(bts, buf, 3+len); + abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len); } if (nv_mask) { len = 4; @@ -351,7 +351,7 @@ static void bootstrap_om(struct gsm_bts *bts) *cur++ = nv_mask >> 8; printf("setting NV Flags/Mask to 0x%04x/0x%04x\n", nv_flags, nv_mask); - abis_nm_ipaccess_set_nvattr(bts, buf, 3+len); + abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len); } if (restart && !prim_oml_ip && !software) { From 6e670aab5af6a355ea69edafb5d4f8adf387557a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 7 Jan 2010 20:44:32 +0100 Subject: [PATCH 335/365] introduce new gsm_bts_trx_by_nr() function --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/gsm_data.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 4a6acb52a..573ce5fb7 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -648,6 +648,7 @@ void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr, u_int8_t e1_ts, u_int8_t e1_ts_ss); enum gsm_bts_type parse_btstype(const char *arg); const char *btstype2str(enum gsm_bts_type type); +struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr); struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac, struct gsm_bts *start_bts); diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 446a82011..d2676db1b 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -365,6 +365,17 @@ const char *btstype2str(enum gsm_bts_type type) return bts_types[type]; } +struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr) +{ + struct gsm_bts_trx *trx; + + llist_for_each_entry(trx, &bts->trx_list, list) { + if (trx->nr == nr) + return trx; + } + return NULL; +} + /* Search for a BTS in the given Location Area; optionally start searching * with start_bts (for continuing to search after the first result) */ struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac, From 5078148829920b7e7b8269b5a6420c0a999cc877 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 10 Jan 2010 17:45:23 +0100 Subject: [PATCH 336/365] TLV: add function to patch a tlv definition table --- openbsc/include/openbsc/tlv.h | 3 +++ openbsc/src/tlv_parser.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/openbsc/include/openbsc/tlv.h b/openbsc/include/openbsc/tlv.h index e970ce468..c90643eed 100644 --- a/openbsc/include/openbsc/tlv.h +++ b/openbsc/include/openbsc/tlv.h @@ -185,6 +185,7 @@ struct tlv_p_entry { }; enum tlv_type { + TLV_TYPE_NONE, TLV_TYPE_FIXED, TLV_TYPE_T, TLV_TYPE_TV, @@ -213,6 +214,8 @@ int tlv_parse_one(u_int8_t *o_tag, u_int16_t *o_len, const u_int8_t **o_val, const u_int8_t *buf, int buf_len); int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, const u_int8_t *buf, int buf_len, u_int8_t lv_tag, u_int8_t lv_tag2); +/* take a master (src) tlvdev and fill up all empty slots in 'dst' */ +void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src); #define TLVP_PRESENT(x, y) ((x)->lv[y].val) #define TLVP_LEN(x, y) (x)->lv[y].len diff --git a/openbsc/src/tlv_parser.c b/openbsc/src/tlv_parser.c index fd0045f97..13ca7b14b 100644 --- a/openbsc/src/tlv_parser.c +++ b/openbsc/src/tlv_parser.c @@ -149,6 +149,19 @@ int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, return num_parsed; } +/* take a master (src) tlvdev and fill up all empty slots in 'dst' */ +void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dst->def); i++) { + if (src->def[i].type == TLV_TYPE_NONE) + continue; + if (dst->def[i].type == TLV_TYPE_NONE) + dst->def[i] = src->def[i]; + } +} + static __attribute__((constructor)) void on_dso_load_tlv(void) { int i; From 39315c47989326275823d1589425ee62d15bc823 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 10 Jan 2010 18:01:52 +0100 Subject: [PATCH 337/365] [OML] parse attributes depending on BTS type Some NM attributes are defined differently depending on the BTS type. Having one big nm_att_tlvdef[] table for all BTS types is no longer sufficient. This patch * introduces 'struct gsm_bts_model' to describe a BTS model * adds definitions of gsm_bts_model for BS-11 and nanoBTS * changes the abis_nm_tlv_parse() function: include a bts pointer --- openbsc/include/openbsc/abis_nm.h | 4 +- openbsc/include/openbsc/gsm_data.h | 12 +++- openbsc/src/Makefile.am | 5 +- openbsc/src/abis_nm.c | 93 ++++-------------------------- openbsc/src/bs11_config.c | 5 +- openbsc/src/bsc_hack.c | 6 ++ openbsc/src/bts_ipaccess_nanobts.c | 84 +++++++++++++++++++++++++++ openbsc/src/bts_siemens_bs11.c | 66 +++++++++++++++++++++ openbsc/src/gsm_data.c | 43 +++++++++++++- openbsc/src/vty_interface.c | 5 +- 10 files changed, 234 insertions(+), 89 deletions(-) create mode 100644 openbsc/src/bts_ipaccess_nanobts.c create mode 100644 openbsc/src/bts_siemens_bs11.c diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index d6469c466..81b4eda61 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -719,6 +719,8 @@ struct ipac_bcch_info { u_int8_t ca_list_si1[16]; }; +extern const struct tlv_definition nm_att_tlvdef; + /* PUBLIC */ struct msgb; @@ -733,7 +735,7 @@ struct abis_nm_cfg { extern int abis_nm_rcvmsg(struct msgb *msg); -int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len); +int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len); int abis_nm_rx(struct msgb *msg); int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2); int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 573ce5fb7..5567d89bd 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -335,6 +335,15 @@ enum gsm_bts_type { GSM_BTS_TYPE_NANOBTS, }; +struct gsm_bts_model { + struct llist_head list; + + enum gsm_bts_type type; + const char *name; + + struct tlv_definition nm_att_tlvdef; +}; + /** * A pending paging request */ @@ -402,6 +411,7 @@ struct gsm_bts { u_int8_t bsic; /* type of BTS */ enum gsm_bts_type type; + struct gsm_bts_model *model; enum gsm_band band; /* should the channel allocator allocate channels from high TRX to TRX0, * rather than starting from TRX0 and go upwards? */ @@ -619,7 +629,7 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, u_int8_t tsc, u_int8_t bsic); struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts); -void gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type); +int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type); struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 7d7fee79e..aa50b8cbc 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,7 +12,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - rtp_proxy.c statistics.c + rtp_proxy.c statistics.c bts_siemens_bs11.c bts_ipaccess_nanobts.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ @@ -27,7 +27,8 @@ bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \ - select.c timer.c rs232.c tlv_parser.c signal.c talloc.c + select.c timer.c rs232.c tlv_parser.c signal.c talloc.c \ + bts_siemens_bs11.c ipaccess_find_SOURCES = ipaccess/ipaccess-find.c select.c timer.c diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index aaa7dd5fb..82d7b0254 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -264,7 +264,7 @@ static const enum abis_nm_attr nm_att_settable[] = { NM_ATT_MEAS_TYPE, }; -static const struct tlv_definition nm_att_tlvdef = { +const struct tlv_definition nm_att_tlvdef = { .def = { [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 }, [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V }, @@ -330,77 +330,6 @@ static const struct tlv_definition nm_att_tlvdef = { [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V }, [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV }, [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V }, - /* BS11 specifics */ - [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV }, - [0xd5] = { TLV_TYPE_TLV }, - [0xa8] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV }, - [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV }, - [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV }, - [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV }, - /* ip.access specifics */ - [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 }, - [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, }, - [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, }, - [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 }, - [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 }, - [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 }, - [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 }, - [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V }, - //[0x95] = { TLV_TYPE_FIXED, 2 }, - [0x85] = { TLV_TYPE_TV }, - }, }; @@ -423,9 +352,11 @@ int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan) return -EINVAL; } -int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len) +int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len) { - return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0); + if (!bts->model) + return -EIO; + return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0); } static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size) @@ -801,7 +732,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb) new_state = *nm_state; - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh)); if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) { new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE); DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational)); @@ -853,7 +784,7 @@ static int rx_fail_evt_rep(struct msgb *mb) DEBUGPC(DNM, "Failure Event Report "); - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh)); if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE)) DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE))); @@ -947,7 +878,7 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb) if (nack) return ret; - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh)); sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG); sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG); if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) { @@ -981,7 +912,7 @@ static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb) struct tlv_parsed tp; u_int8_t adm_state; - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh)); if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) return -EINVAL; @@ -997,7 +928,7 @@ static int abis_nm_rx_lmt_event(struct msgb *mb) struct tlv_parsed tp; DEBUGP(DNM, "LMT Event "); - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh)); if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) && TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) { u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION); @@ -1043,7 +974,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) else DEBUGPC(DNM, "NACK 0x%02x ", mt); - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh)); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) DEBUGPC(DNM, "CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); @@ -2770,7 +2701,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) } foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen); - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh)); debugp_foh(foh); diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index 6a76b962d..703591eed 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -649,7 +649,7 @@ int handle_serial_msg(struct msgb *rx_msg) exit(0); break; case NM_MT_BS11_GET_STATE_ACK: - rc = abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + rc = abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh)); print_state(&tp); if (TLVP_PRESENT(&tp, NM_ATT_BS11_BTS_STATE) && TLVP_LEN(&tp, NM_ATT_BS11_BTS_STATE) >= 1) @@ -657,7 +657,7 @@ int handle_serial_msg(struct msgb *rx_msg) break; case NM_MT_GET_ATTR_RESP: printf("\n%sATTRIBUTES:\n", obj_name(foh)); - abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh)); rc = print_attr(&tp); //hexdump(foh->data, oh->length-sizeof(*foh)); break; @@ -839,6 +839,7 @@ int main(int argc, char **argv) debug_add_target(stderr_target); debug_set_all_filter(stderr_target, 1); handle_options(argc, argv); + bts_model_bs11_init(); gsmnet = gsm_network_init(1, 1, NULL); if (!gsmnet) { diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 3122fae9c..581e9be4d 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -178,6 +178,9 @@ static void db_sync_timer_cb(void *data) bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); } +extern int bts_model_bs11_init(void); +extern int bts_model_nanobts_init(void); + int main(int argc, char **argv) { int rc; @@ -191,6 +194,9 @@ int main(int argc, char **argv) stderr_target = debug_target_create_stderr(); debug_add_target(stderr_target); + bts_model_bs11_init(); + bts_model_nanobts_init(); + /* enable filters */ debug_set_all_filter(stderr_target, 1); diff --git a/openbsc/src/bts_ipaccess_nanobts.c b/openbsc/src/bts_ipaccess_nanobts.c new file mode 100644 index 000000000..6765517b3 --- /dev/null +++ b/openbsc/src/bts_ipaccess_nanobts.c @@ -0,0 +1,84 @@ +/* ip.access nanoBTS specific code */ + +/* (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 + +static struct gsm_bts_model model_nanobts = { + .type = GSM_BTS_TYPE_NANOBTS, + .nm_att_tlvdef = { + .def = { + /* ip.access specifics */ + [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 }, + [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, }, + [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, }, + [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 }, + [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 }, + [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 }, + [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 }, + [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V }, + }, + }, +}; + +int bts_model_nanobts_init(void) +{ + return gsm_bts_model_register(&model_nanobts); +} diff --git a/openbsc/src/bts_siemens_bs11.c b/openbsc/src/bts_siemens_bs11.c new file mode 100644 index 000000000..1c8f889e1 --- /dev/null +++ b/openbsc/src/bts_siemens_bs11.c @@ -0,0 +1,66 @@ +/* Siemens BS-11 specific code */ + +/* (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 + +static struct gsm_bts_model model_bs11 = { + .type = GSM_BTS_TYPE_BS11, + .nm_att_tlvdef = { + .def = { + [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TLV }, + /* BS11 specifics */ + [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV }, + [0xd5] = { TLV_TYPE_TLV }, + [0xa8] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV }, + [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV }, + [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV }, + [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV }, + [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV }, + [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV }, + [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV }, + [0x95] = { TLV_TYPE_FIXED, 2 }, + }, + }, +}; + +int bts_model_bs11_init(void) +{ + return gsm_bts_model_register(&model_bs11); +} diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index d2676db1b..694ae06c6 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -32,6 +32,8 @@ void *tall_bsc_ctx; +static LLIST_HEAD(bts_models); + void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr, u_int8_t e1_ts, u_int8_t e1_ts_ss) { @@ -118,6 +120,29 @@ const char *gsm_chreq_name(enum gsm_chreq_reason_t c) return chreq_names[c]; } +static struct gsm_bts_model *bts_model_find(enum gsm_bts_type type) +{ + struct gsm_bts_model *model; + + llist_for_each_entry(model, &bts_models, list) { + if (model->type == type) + return model; + } + + return NULL; +} + +int gsm_bts_model_register(struct gsm_bts_model *model) +{ + if (bts_model_find(model->type)) + return -EEXIST; + + tlv_def_patch(&model->nm_att_tlvdef, &nm_att_tlvdef); + llist_add_tail(&model->list, &bts_models); + return 0; +} + + struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) { struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx); @@ -160,14 +185,21 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, u_int8_t tsc, u_int8_t bsic) { struct gsm_bts *bts = talloc_zero(net, struct gsm_bts); + struct gsm_bts_model *model = bts_model_find(type); int i; if (!bts) return NULL; + if (!model) { + talloc_free(bts); + return NULL; + } + bts->network = net; bts->nr = net->num_bts++; bts->type = type; + bts->model = model; bts->tsc = tsc; bts->bsic = bsic; bts->num_trx = 0; @@ -504,9 +536,16 @@ struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) return meas_rep; } -void gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type) +int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type) { + struct gsm_bts_model *model; + + model = bts_model_find(type); + if (!model) + return -EINVAL; + bts->type = type; + bts->model = model; switch (bts->type) { case GSM_BTS_TYPE_NANOBTS: @@ -517,4 +556,6 @@ void gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type) case GSM_BTS_TYPE_BS11: break; } + + return 0; } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 8d6e202c1..265444779 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1339,8 +1339,11 @@ DEFUN(cfg_bts_type, "Set the BTS type\n") { struct gsm_bts *bts = vty->index; + int rc; - gsm_set_bts_type(bts, parse_btstype(argv[0])); + rc = gsm_set_bts_type(bts, parse_btstype(argv[0])); + if (rc < 0) + return CMD_WARNING; return CMD_SUCCESS; } From 202259c31e8d1fbfc3af1a872b8e285e878287de Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 10 Jan 2010 18:21:33 +0100 Subject: [PATCH 338/365] add sylvain and andreas as authors --- openbsc/AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/AUTHORS b/openbsc/AUTHORS index 1a74f5102..daf60e447 100644 --- a/openbsc/AUTHORS +++ b/openbsc/AUTHORS @@ -3,3 +3,5 @@ Holger Freyther Jan Luebbe Stefan Schmidt Daniel Willmann +Andreas Eversberg +Sylvain Munaut <246tnt@gmail.com> From a855d1f846795d3dfa322e02f6de1b7a1a8c961e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 10 Jan 2010 18:37:38 +0100 Subject: [PATCH 339/365] fix ipaccess-config, call missing nanobts initialization FIXME: We really need to have some libbsc and libmsc initialization functions that clean up this mess. --- openbsc/src/ipaccess/ipaccess-config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 3b2a8bfd0..7d559b03a 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -561,6 +561,7 @@ int main(int argc, char **argv) debug_set_all_filter(stderr_target, 1); debug_set_log_level(stderr_target, 0); debug_parse_category_mask(stderr_target, "DNM,0"); + bts_model_nanobts_init(); printf("ipaccess-config (C) 2009 by Harald Welte\n"); printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); From 98657d5dee59fbe84e6a53aa481edb6a82185ab3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 11 Jan 2010 16:42:07 +0100 Subject: [PATCH 340/365] misc: Fix compilation of the test cases. --- openbsc/tests/channel/Makefile.am | 5 ++++- openbsc/tests/channel/channel_test.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am index 564cbafe2..6b9f6e3cb 100644 --- a/openbsc/tests/channel/Makefile.am +++ b/openbsc/tests/channel/Makefile.am @@ -13,6 +13,9 @@ channel_test_SOURCES = channel_test.c \ $(top_srcdir)/src/talloc.c \ $(top_srcdir)/src/gsm_data.c \ $(top_srcdir)/src/signal.c \ - $(top_srcdir)/src/statistics.c + $(top_srcdir)/src/statistics.c \ + $(top_srcdir)/src/bts_ipaccess_nanobts.c \ + $(top_srcdir)/src/bts_siemens_bs11.c \ + $(top_srcdir)/src/tlv_parser.c channel_test_LDADD = -ldl -ldbi diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c index 1b01878b5..36d057273 100644 --- a/openbsc/tests/channel/channel_test.c +++ b/openbsc/tests/channel/channel_test.c @@ -77,3 +77,5 @@ void nm_state_event() {} void input_event() {} void sms_alloc() {} +struct tlv_definition nm_att_tlvdef; + From 14083bef0f77dc2af080e0239e97e905f3a37b69 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 5 Jan 2010 12:21:36 +0100 Subject: [PATCH 341/365] [bsc_mgcp] Add a new forward only mode to the bsc_mgcp With forward IP in the config and early bind on we will simply forward RTP data on the endpoints from BTS to the forward IP address. This is implemented by disabling MGCP functionality when a forward IP address was specified, setting the forward IP in the endp->remote and assigning a ci != CI_UNUSED. Early bind will make sure the sockets are created, the BSC FD's are registered and then the normal dispatch code will do the forwarding. --- openbsc/src/bsc_mgcp.c | 86 ++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index fff6d6039..17c54d1bb 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -64,6 +64,7 @@ static int audio_payload = 97; static int audio_loop = 0; static int early_bind = 0; +static char *forward_ip = NULL; static char *config_file = "mgcp.cfg"; /* used by msgb and mgcp */ @@ -1055,6 +1056,17 @@ DEFUN(cfg_mgcp_number_endp, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_forward, + cfg_mgcp_forward_cmd, + "forward audio IP", + "Forward packets from and to the IP. This disables most of the MGCP feature.") +{ + if (forward_ip) + talloc_free(forward_ip); + forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + int bsc_vty_init(struct gsm_network *dummy) { cmd_init(1); @@ -1076,6 +1088,7 @@ int bsc_vty_init(struct gsm_network *dummy) install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); + install_element(MGCP_NODE, &cfg_mgcp_forward_cmd); return 0; } @@ -1123,37 +1136,60 @@ int main(int argc, char** argv) endpoints[i].ci = CI_UNUSED; } - /* initialize the socket */ - bfd.when = BSC_FD_READ; - bfd.cb = read_call_agent; - bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); - if (bfd.fd < 0) { - perror("Gateway failed to listen"); - return -1; - } + /* + * This application supports two modes. + * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX + * 2.) plain forwarding of RTP packets on the endpoints. + * both modes are mutual exclusive + */ + if (forward_ip) { - setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (!early_bind) { + DEBUGP(DMGCP, "Forwarding requires early bind.\n"); + return -1; + } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(source_port); - inet_aton(source_addr, &addr.sin_addr); + /* + * Store the forward IP and assign a ci. For early bind + * the sockets will be created after this. + */ + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + inet_aton(forward_ip, &endp->remote); + endp->ci = CI_UNUSED + 23; + } + } else { + bfd.when = BSC_FD_READ; + bfd.cb = read_call_agent; + bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); + if (bfd.fd < 0) { + perror("Gateway failed to listen"); + return -1; + } - if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("Gateway failed to bind"); - return -1; - } + setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - bfd.data = msgb_alloc(4096, "mgcp-msg"); - if (!bfd.data) { - fprintf(stderr, "Gateway memory error.\n"); - return -1; - } + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(source_port); + inet_aton(source_addr, &addr.sin_addr); + + if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("Gateway failed to bind"); + return -1; + } + + bfd.data = msgb_alloc(4096, "mgcp-msg"); + if (!bfd.data) { + fprintf(stderr, "Gateway memory error.\n"); + return -1; + } - if (bsc_register_fd(&bfd) != 0) { - DEBUGP(DMGCP, "Failed to register the fd\n"); - return -1; + if (bsc_register_fd(&bfd) != 0) { + DEBUGP(DMGCP, "Failed to register the fd\n"); + return -1; + } } /* initialisation */ From f986cfc5085e9149d4cabeaf2b89c22996279edf Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 5 Jan 2010 12:25:25 +0100 Subject: [PATCH 342/365] [bsc_mgcp] Print a message which mode is configured --- openbsc/src/bsc_mgcp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 17c54d1bb..3d130db3a 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -1158,6 +1158,8 @@ int main(int argc, char** argv) inet_aton(forward_ip, &endp->remote); endp->ci = CI_UNUSED + 23; } + + DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); } else { bfd.when = BSC_FD_READ; bfd.cb = read_call_agent; @@ -1190,6 +1192,8 @@ int main(int argc, char** argv) DEBUGP(DMGCP, "Failed to register the fd\n"); return -1; } + + DEBUGP(DMGCP, "Configured for MGCP.\n"); } /* initialisation */ From 2c492ed276012054a4a4dacebf675c651a0146fa Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 5 Jan 2010 12:29:36 +0100 Subject: [PATCH 343/365] [bsc_mgcp] Fix writing of the config file... * Add the new forward audio option --- openbsc/src/bsc_mgcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 3d130db3a..72ff421b9 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -910,6 +910,8 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); + if (forward_ip) + vty_out(vty, " forward audio %s%s", forward_ip, VTY_NEWLINE); return CMD_SUCCESS; } From 620961983c595e387ce9494f30aff25effa8424f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 5 Jan 2010 12:35:16 +0100 Subject: [PATCH 344/365] [bsc_mgcp] Set the right remote rtp and rtcp port * It is the same as local endpoint port --- openbsc/src/bsc_mgcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 72ff421b9..ecc13ca68 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -1159,6 +1159,8 @@ int main(int argc, char** argv) struct mgcp_endpoint *endp = &endpoints[i]; inet_aton(forward_ip, &endp->remote); endp->ci = CI_UNUSED + 23; + endp->rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port)); + endp->rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1); } DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); From 6af56d1501244f4ce3cfd2e3bf07da19a59108da Mon Sep 17 00:00:00 2001 From: laforge Date: Tue, 12 Jan 2010 10:44:26 +0100 Subject: [PATCH 345/365] Fix allocation of BTS from VTY In 39315c47989326275823d1589425ee62d15bc823 we introduced per-bts OML attribute parser definitions and disallowed a BTS of type unknown. However, the VTY code first allocates a BTS with unknown type. --- openbsc/src/gsm_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 694ae06c6..1f2e1a1fc 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -191,7 +191,7 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, if (!bts) return NULL; - if (!model) { + if (!model && type != GSM_BTS_TYPE_UNKNOWN) { talloc_free(bts); return NULL; } From 06770617570340bd171be7e067d77c3e07b2c787 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 12 Jan 2010 10:46:27 +0100 Subject: [PATCH 346/365] update copyright statements * include 2010 * add Andreas Eversberg and Sylvain --- openbsc/src/bsc_hack.c | 2 +- openbsc/src/telnet_interface.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 581e9be4d..e7db3c733 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -1,6 +1,6 @@ /* A hackish minimal BSC (+MSC +HLR) implementation */ -/* (C) 2008-2009 by Harald Welte +/* (C) 2008-2010 by Harald Welte * (C) 2009 by Holger Hans Peter Freyther * All Rights Reserved * diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index ebddaf57a..6f452a55b 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -102,9 +102,9 @@ static void print_welcome(int fd) { int ret; static char *msg = "Welcome to the OpenBSC Control interface\n" - "Copyright (C) 2008, 2009 Harald Welte\n" + "Copyright (C) 2008-2010 Harald Welte\n" "Contributions by Daniel Willmann, Jan Lübbe, " - "Stefan Schmidt, Holger Freyther\n\n" + "Stefan Schmidt, Holger Freyther, Andreas Eversberg\n\n" "License GPLv2+: GNU GPL version 2 or later " "\n" "This is free software: you are free to change " From f15c276382a10ae6634694ed0cde06fdea0606cb Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Mon, 11 Jan 2010 13:43:07 +0100 Subject: [PATCH 347/365] [vty_interface.c]: Warn if no BTS could be allocated --- openbsc/src/vty_interface.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 265444779..76598d377 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1324,8 +1324,11 @@ DEFUN(cfg_bts, } else bts = gsm_bts_num(gsmnet, bts_nr); - if (!bts) + if (!bts) { + vty_out(vty, "%% Unable to allocate BTS %u%s", + gsmnet->num_bts, VTY_NEWLINE); return CMD_WARNING; + } vty->index = bts; vty->node = BTS_NODE; From 604d851b89d2d62f024223d333c833ebebd42060 Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Mon, 11 Jan 2010 13:50:44 +0100 Subject: [PATCH 348/365] Register GSM_BTS_TYPE_UNKNOWN in bsc_hack.c The way the VTY configuration sytem works is that it first registers a BTS of type GSM_BTS_TYPE_UNKNOWN and then sets the type correctly (after encountering the type statement). This makes sure that registering a BTS of type UNKNOWN succeeds. --- openbsc/src/Makefile.am | 3 ++- openbsc/src/bsc_hack.c | 2 ++ openbsc/src/bts_unknown.c | 40 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/bts_unknown.c diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index aa50b8cbc..e18c35e18 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,7 +12,8 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - rtp_proxy.c statistics.c bts_siemens_bs11.c bts_ipaccess_nanobts.c + rtp_proxy.c statistics.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \ + bts_unknown.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index e7db3c733..7755726c9 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -178,6 +178,7 @@ static void db_sync_timer_cb(void *data) bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL); } +extern int bts_model_unknown_init(void); extern int bts_model_bs11_init(void); extern int bts_model_nanobts_init(void); @@ -194,6 +195,7 @@ int main(int argc, char **argv) stderr_target = debug_target_create_stderr(); debug_add_target(stderr_target); + bts_model_unknown_init(); bts_model_bs11_init(); bts_model_nanobts_init(); diff --git a/openbsc/src/bts_unknown.c b/openbsc/src/bts_unknown.c new file mode 100644 index 000000000..1e604a9e4 --- /dev/null +++ b/openbsc/src/bts_unknown.c @@ -0,0 +1,40 @@ +/* Generic BTS - VTY code tries to allocate this BTS before type is known */ + +/* (C) 2010 by Daniel Willmann + * + * 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 + +static struct gsm_bts_model model_unknown = { + .type = GSM_BTS_TYPE_UNKNOWN, + .nm_att_tlvdef = { + .def = { + }, + }, +}; + +int bts_model_unknown_init(void) +{ + return gsm_bts_model_register(&model_unknown); +} From 1e1c6aa5a3db4680d1f8088ef6f7c0cb1117d032 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 23 Jan 2010 10:52:38 +0100 Subject: [PATCH 349/365] Make sure select() callbacks are not called multiple times the unix select function returns a set of file descriptors to be handled. the result-loop (the loop after the select()) is called again, if more than one descriptor is removed by the callback funtion. this may lead to a another call to the callback function, because the bits of the FD_SETs do not change and still set. i think we must clear these bits, if they are handled, so the handler will not be called twice in case of a "restart" of that loop. --- openbsc/src/select.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/openbsc/src/select.c b/openbsc/src/select.c index c11f3a511..bed96498c 100644 --- a/openbsc/src/select.c +++ b/openbsc/src/select.c @@ -95,14 +95,20 @@ restart: llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) { int flags = 0; - if (FD_ISSET(ufd->fd, &readset)) + if (FD_ISSET(ufd->fd, &readset)) { flags |= BSC_FD_READ; + FD_CLR(ufd->fd, &readset); + } - if (FD_ISSET(ufd->fd, &writeset)) + if (FD_ISSET(ufd->fd, &writeset)) { flags |= BSC_FD_WRITE; + FD_CLR(ufd->fd, &writeset); + } - if (FD_ISSET(ufd->fd, &exceptset)) + if (FD_ISSET(ufd->fd, &exceptset)) { flags |= BSC_FD_EXCEPT; + FD_CLR(ufd->fd, &exceptset); + } if (flags) { work = 1; From 93b6c6555ce0724cb668ea4bda5e31c50aaa7e4c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 28 Jan 2010 04:45:05 +0100 Subject: [PATCH 350/365] [rsl] Send the MultiRateConfig in the RSL Channel Activate msg If the lchan has AMR as speech codec we also need to send the multirate config IE in the channel activation. This is already done for the RSL Channel Modify message. --- openbsc/src/abis_rsl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 11a4355a7..10ebd6d44 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -650,6 +650,10 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power); msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); + if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) + msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf), + (u_int8_t *) &lchan->mr_conf); + msg->trx = lchan->ts->trx; return abis_rsl_sendmsg(msg); From 550197fd8cace3ac974609886fbba8c39680515d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 28 Jan 2010 09:43:49 +0100 Subject: [PATCH 351/365] [gsm48] Allow to send the assignment command on a different lchan Change the signature to take the lchan were the message is supposed to be sent and the lchan which is supposed to be assigned. --- openbsc/include/openbsc/gsm_04_08.h | 2 +- openbsc/src/gsm_04_08_utils.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 9cf8afcf3..826ea5e7a 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -768,7 +768,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan); int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, u_int8_t apdu_len, const u_int8_t *apdu); -int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); +int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_class); int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, u_int8_t power_command, u_int8_t ho_ref); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index d5785f971..e95d426d0 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -567,7 +567,7 @@ int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, } /* Chapter 9.1.2: Assignment Command */ -int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) +int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_command) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -576,7 +576,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode); - msg->lchan = lchan; + msg->lchan = dest_lchan; gh->proto_discr = GSM48_PDISC_RR; gh->msg_type = GSM48_MT_RR_ASS_CMD; From 1b891fd7bab5f2c3ea3f0c2a296a605305ac984d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 28 Jan 2010 11:51:24 +0100 Subject: [PATCH 352/365] [gsm48] Use optional Chan Mode 1 for the assignment command Specify how we intend to use the assigned channel. This is needed to make CC with early assignment work properly. --- openbsc/src/gsm_04_08_utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index e95d426d0..821bde266 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -591,6 +591,8 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, gsm48_chan_desc(&ass->chan_desc, lchan); ass->power_command = power_command; + msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode); + /* in case of multi rate we need to attach a config */ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { if (lchan->mr_conf.ver == 0) { From 601a67e274d88a943fd791d091e80f63582873c3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 13 Jan 2010 16:37:32 +0100 Subject: [PATCH 353/365] [mgcp] Make it possible to not specify a bts ip This way the mgcp will allow anyone to be the BTS.. in the future we might need to communicate things properly between BSC and MGCP. --- openbsc/src/bsc_mgcp.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index ecc13ca68..16e74c82e 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -108,6 +108,7 @@ struct mgcp_endpoint { struct bsc_fd local_rtcp; struct in_addr remote; + struct in_addr bts; /* in network byte order */ int rtp, rtcp; @@ -254,13 +255,14 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) /* We have no idea who called us, maybe it is the BTS. */ if (dest == DEST_NETWORK && endp->bts_rtp == 0) { /* it was the BTS... */ - if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { + if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { if (fd == &endp->local_rtp) { endp->bts_rtp = addr.sin_port; } else { endp->bts_rtcp = addr.sin_port; } + endp->bts = addr.sin_addr; DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); } @@ -275,7 +277,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) proto == PROTO_RTP ? endp->rtp : endp->rtcp, buf, rc); } else { - return _send(fd->fd, &bts_in, + return _send(fd->fd, &endp->bts, proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, buf, rc); } @@ -901,7 +903,8 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, "mgcp%s", VTY_NEWLINE); if (local_ip) vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); - vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); + if (bts_ip) + vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE); @@ -1118,10 +1121,8 @@ int main(int argc, char** argv) } - if (!bts_ip) { - fprintf(stderr, "Need to specify the BTS ip address for RTP handling.\n"); - return -1; - } + if (!bts_ip) + fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n"); endpoints = _talloc_zero_array(tall_bsc_ctx, sizeof(struct mgcp_endpoint), From 6c796460895281368c7211ed3cd51f0b173381a2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 13 Jan 2010 22:49:55 +0100 Subject: [PATCH 354/365] [mgcp] Rename rtp and rtcp variables to net_rtp and net_rtcp Rename the variables to refer to the fact that they are the ports of the remote. So we have: rtp_port as the local address we are binding to net_rtp for the network rtp bsc_rtp for the bsc rtp --- openbsc/src/bsc_mgcp.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 16e74c82e..60135d681 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -96,7 +96,7 @@ struct mgcp_endpoint { char *local_options; int conn_mode; - /* the local rtp port */ + /* the local rtp port we are binding to */ int rtp_port; /* @@ -111,7 +111,7 @@ struct mgcp_endpoint { struct in_addr bts; /* in network byte order */ - int rtp, rtcp; + int net_rtp, net_rtcp; int bts_rtp, bts_rtcp; }; @@ -274,7 +274,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) if (dest == DEST_NETWORK) { return _send(fd->fd, &endp->remote, - proto == PROTO_RTP ? endp->rtp : endp->rtcp, + proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, buf, rc); } else { return _send(fd->fd, &endp->bts, @@ -639,7 +639,7 @@ static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) MSG_TOKENIZE_END /* initialize */ - endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; /* bind to the port now */ endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); @@ -719,8 +719,8 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source) const char *param = (const char *)&msg->l3h[line_start]; if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { - endp->rtp = htons(port); - endp->rtcp = htons(port + 1); + endp->net_rtp = htons(port); + endp->net_rtcp = htons(port + 1); } break; } @@ -743,7 +743,7 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source) /* modify */ DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", - ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->rtp); + ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); return send_with_sdp(endp, "MDCX", trans_id, source); error: @@ -805,7 +805,7 @@ static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source) bsc_unregister_fd(&endp->local_rtcp); } - endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; return send_response(250, "DLCX", trans_id, source); @@ -929,7 +929,7 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", struct mgcp_endpoint *endp = &endpoints[i]; vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", i, endp->ci, - ntohs(endp->rtp), ntohs(endp->rtcp), + ntohs(endp->net_rtp), ntohs(endp->net_rtcp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); } @@ -1160,8 +1160,8 @@ int main(int argc, char** argv) struct mgcp_endpoint *endp = &endpoints[i]; inet_aton(forward_ip, &endp->remote); endp->ci = CI_UNUSED + 23; - endp->rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port)); - endp->rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1); + endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port)); + endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1); } DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); From bd5130d3c1e274fe044b2f60713d1b664ee8ecff Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 13 Jan 2010 23:36:53 +0100 Subject: [PATCH 355/365] [mgcp] Allow to forward to a different port --- openbsc/src/bsc_mgcp.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 60135d681..66c8d74ed 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -65,6 +65,7 @@ static int audio_loop = 0; static int early_bind = 0; static char *forward_ip = NULL; +static int forward_port = 0; static char *config_file = "mgcp.cfg"; /* used by msgb and mgcp */ @@ -914,7 +915,9 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); if (forward_ip) - vty_out(vty, " forward audio %s%s", forward_ip, VTY_NEWLINE); + vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE); + if (forward_port != 0) + vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE); return CMD_SUCCESS; } @@ -1061,9 +1064,9 @@ DEFUN(cfg_mgcp_number_endp, return CMD_SUCCESS; } -DEFUN(cfg_mgcp_forward, - cfg_mgcp_forward_cmd, - "forward audio IP", +DEFUN(cfg_mgcp_forward_ip, + cfg_mgcp_forward_ip_cmd, + "forward audio ip IP", "Forward packets from and to the IP. This disables most of the MGCP feature.") { if (forward_ip) @@ -1072,6 +1075,15 @@ DEFUN(cfg_mgcp_forward, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_forward_port, + cfg_mgcp_forward_port_cmd, + "forward audio port <1-15000>", + "Forward packets from and to the port. This disables most of the MGCP feature.") +{ + forward_port = atoi(argv[0]); + return CMD_SUCCESS; +} + int bsc_vty_init(struct gsm_network *dummy) { cmd_init(1); @@ -1093,7 +1105,8 @@ int bsc_vty_init(struct gsm_network *dummy) install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); - install_element(MGCP_NODE, &cfg_mgcp_forward_cmd); + install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd); return 0; } @@ -1146,6 +1159,9 @@ int main(int argc, char** argv) * both modes are mutual exclusive */ if (forward_ip) { + int port = rtp_base_port; + if (forward_port != 0) + port = forward_port; if (!early_bind) { DEBUGP(DMGCP, "Forwarding requires early bind.\n"); @@ -1160,8 +1176,8 @@ int main(int argc, char** argv) struct mgcp_endpoint *endp = &endpoints[i]; inet_aton(forward_ip, &endp->remote); endp->ci = CI_UNUSED + 23; - endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port)); - endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1); + endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port)); + endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1); } DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); From 9b28fc8be293e1ca1c11edb541881657b0d3d9e9 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 13 Jan 2010 23:53:59 +0100 Subject: [PATCH 356/365] [mgcp] Warn about unknown messages... --- openbsc/src/bsc_mgcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 66c8d74ed..a16c03cc2 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -238,8 +238,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) } /* do not forward aynthing... maybe there is a packet from the bts */ - if (endp->ci == CI_UNUSED) + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); return -1; + } /* * Figure out where to forward it to. This code assumes that we From 9100e1dea4286bc3edf9af5644c20ccb3ed76fc6 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 14 Jan 2010 00:15:44 +0100 Subject: [PATCH 357/365] [mgcp] Handle BTS and NET being on the same host * Do not only check the IP but also the port to figure out where to send the data * Do not memset the endp->remote inside the bind_rtp but from inside the crcx as this will be modified by the MDCX --- openbsc/src/bsc_mgcp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index a16c03cc2..320d0b16e 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -251,7 +251,8 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) * able to tell if this is legitimate. */ #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." - dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 + dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 && + (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) ? DEST_BTS : DEST_NETWORK; proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; @@ -309,9 +310,6 @@ static int create_bind(struct bsc_fd *fd, int port) static int bind_rtp(struct mgcp_endpoint *endp) { - /* set to zero until we get the info */ - memset(&endp->remote, 0, sizeof(endp->remote)); - if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", endp->rtp_port, ENDPOINT_NUMBER(endp)); @@ -644,6 +642,9 @@ static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) /* initialize */ endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + /* set to zero until we get the info */ + memset(&endp->remote, 0, sizeof(endp->remote)); + /* bind to the port now */ endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); if (!early_bind && bind_rtp(endp) != 0) From e01ee97cd33f9ecd51cfdc7fff8c4e01293a46ad Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 14 Jan 2010 08:35:57 +0100 Subject: [PATCH 358/365] [mgcp] In forward mode we need to rediscover the BTS more often In plain forward mode we don't have DLCX which will clean and reset the configuration. We will need to remember the last GSM BTS port and send data to it. --- openbsc/src/bsc_mgcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 320d0b16e..d89eb8399 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -257,7 +257,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; /* We have no idea who called us, maybe it is the BTS. */ - if (dest == DEST_NETWORK && endp->bts_rtp == 0) { + if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) { /* it was the BTS... */ if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { if (fd == &endp->local_rtp) { From a18445d262218682d6210516067e91159b78d5d7 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 1 Feb 2010 14:00:07 +0100 Subject: [PATCH 359/365] [mgcp] Move the MGCP procoess into a sub directory --- openbsc/src/Makefile.am | 2 +- openbsc/src/{ => mgcp}/bsc_mgcp.c | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename openbsc/src/{ => mgcp}/bsc_mgcp.c (100%) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index e18c35e18..cc5f0ec7a 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -38,7 +38,7 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c -bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c +bsc_mgcp_SOURCES = mgcp/bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/mgcp/bsc_mgcp.c similarity index 100% rename from openbsc/src/bsc_mgcp.c rename to openbsc/src/mgcp/bsc_mgcp.c From 89f3cb8606019892ae626a40f2423278ac4b88f1 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 2 Feb 2010 12:07:21 +0100 Subject: [PATCH 360/365] [mgcp] Rename the source to mgcp_main.c --- openbsc/src/Makefile.am | 2 +- openbsc/src/mgcp/{bsc_mgcp.c => mgcp_main.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename openbsc/src/mgcp/{bsc_mgcp.c => mgcp_main.c} (100%) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index cc5f0ec7a..5fb7620bd 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -38,7 +38,7 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c -bsc_mgcp_SOURCES = mgcp/bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c +bsc_mgcp_SOURCES = mgcp/mgcp_main.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/mgcp/bsc_mgcp.c b/openbsc/src/mgcp/mgcp_main.c similarity index 100% rename from openbsc/src/mgcp/bsc_mgcp.c rename to openbsc/src/mgcp/mgcp_main.c From e0955029a141c52921b408d12b23469bcd919b81 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 3 Feb 2010 08:50:33 +0100 Subject: [PATCH 361/365] [mgcp] Prepare to do MGCP over TCP and inside the bsc_msc_ip process * Separate main process and protocol handling into two parts. * Change the protocol handling to work with UDP and TCP connection * This will allow to speak MGCP over TCP between the BSC MUX and the real BSC. --- openbsc/include/openbsc/mgcp.h | 10 +- openbsc/src/Makefile.am | 2 +- openbsc/src/mgcp/mgcp_main.c | 1047 +--------------------------- openbsc/src/mgcp/mgcp_protocol.c | 1114 ++++++++++++++++++++++++++++++ 4 files changed, 1133 insertions(+), 1040 deletions(-) create mode 100644 openbsc/src/mgcp/mgcp_protocol.c diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index fa6224c12..17dd2ec4f 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -21,7 +21,8 @@ * */ -unsigned int rtp_base_port = 4000; +#define RTP_PORT_DEFAULT 4000 +extern unsigned int rtp_base_port; /** * Calculate the RTP audio port for the given multiplex @@ -42,7 +43,12 @@ unsigned int rtp_base_port = 4000; * network and BTS. * */ -int rtp_calculate_port(int multiplex, int base) +static inline int rtp_calculate_port(int multiplex, int base) { return base + (multiplex * 2); } + +int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network); +int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source); +int mgcp_send_rsip(int fd, struct sockaddr_in *source); +int mgcp_vty_init(void); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 5fb7620bd..161c283f6 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -38,7 +38,7 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c -bsc_mgcp_SOURCES = mgcp/mgcp_main.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c +bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c index d89eb8399..134148c62 100644 --- a/openbsc/src/mgcp/mgcp_main.c +++ b/openbsc/src/mgcp/mgcp_main.c @@ -1,4 +1,5 @@ /* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ +/* The main method to drive it as a standalone process */ /* * (C) 2009 by Holger Hans Peter Freyther @@ -52,776 +53,16 @@ void subscr_put() { abort(); } #warning "Make use of the rtp proxy code" static int source_port = 2427; -static const char *local_ip = NULL; static const char *source_addr = "0.0.0.0"; static struct bsc_fd bfd; -static unsigned int number_endpoints = 0; -static const char *bts_ip = NULL; -static struct in_addr bts_in; static int first_request = 1; -static const char *audio_name = "GSM-EFR/8000"; -static int audio_payload = 97; -static int audio_loop = 0; -static int early_bind = 0; -static char *forward_ip = NULL; -static int forward_port = 0; static char *config_file = "mgcp.cfg"; /* used by msgb and mgcp */ void *tall_bsc_ctx = NULL; -enum mgcp_connection_mode { - MGCP_CONN_NONE = 0, - MGCP_CONN_RECV_ONLY = 1, - MGCP_CONN_SEND_ONLY = 2, - MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, -}; - -enum { - DEST_NETWORK = 0, - DEST_BTS = 1, -}; - -enum { - PROTO_RTP, - PROTO_RTCP, -}; - -#define CI_UNUSED 0 -static unsigned int last_call_id = 0; - -struct mgcp_endpoint { - int ci; - char *callid; - char *local_options; - int conn_mode; - - /* the local rtp port we are binding to */ - int rtp_port; - - /* - * RTP mangling: - * - we get RTP and RTCP to us and need to forward to the BTS - * - we get RTP and RTCP from the BTS and forward to the network - */ - struct bsc_fd local_rtp; - struct bsc_fd local_rtcp; - - struct in_addr remote; - struct in_addr bts; - - /* in network byte order */ - int net_rtp, net_rtcp; - int bts_rtp, bts_rtcp; -}; - -static struct mgcp_endpoint *endpoints = NULL; -#define ENDPOINT_NUMBER(endp) abs(endp - endpoints) - -/** - * Macro for tokenizing MGCP messages and SDP in one go. - * - */ -#define MSG_TOKENIZE_START \ - line_start = 0; \ - for (i = 0; i < msgb_l3len(msg); ++i) { \ - /* we have a line end */ \ - if (msg->l3h[i] == '\n') { \ - /* skip the first line */ \ - if (line_start == 0) { \ - line_start = i + 1; \ - continue; \ - } \ - \ - /* check if we have a proper param */ \ - if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \ - } else if (i - line_start > 2 \ - && islower(msg->l3h[line_start]) \ - && msg->l3h[line_start + 1] == '=') { \ - } else if (i - line_start < 3 \ - || msg->l3h[line_start + 1] != ':' \ - || msg->l3h[line_start + 2] != ' ') \ - goto error; \ - \ - msg->l3h[i] = '\0'; \ - if (msg->l3h[i-1] == '\r') \ - msg->l3h[i-1] = '\0'; - -#define MSG_TOKENIZE_END \ - line_start = i + 1; \ - } \ - } - - -struct mgcp_msg_ptr { - unsigned int start; - unsigned int length; -}; - -struct mgcp_request { - char *name; - void (*handle_request) (struct msgb *msg, struct sockaddr_in *source); - char *debug_name; -}; - -#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \ - { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME }, - -static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source); -static void handle_create_con(struct msgb *msg, struct sockaddr_in *source); -static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source); -static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source); - -static int generate_call_id() -{ - int i; - - /* use the call id */ - ++last_call_id; - - /* handle wrap around */ - if (last_call_id == CI_UNUSED) - ++last_call_id; - - /* callstack can only be of size number_of_endpoints */ - /* verify that the call id is free, e.g. in case of overrun */ - for (i = 1; i < number_endpoints; ++i) - if (endpoints[i].ci == last_call_id) - return generate_call_id(); - - return last_call_id; -} - -/* FIXIME/TODO: need to have a list of pending transactions and check that */ -static unsigned int generate_transaction_id() -{ - return abs(rand()); -} - -static int _send(int fd, struct in_addr *addr, int port, char *buf, int len) -{ - struct sockaddr_in out; - out.sin_family = AF_INET; - out.sin_port = port; - memcpy(&out.sin_addr, addr, sizeof(*addr)); - - return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out)); -} - -/* - * There is data coming. We will have to figure out if it - * came from the BTS or the MediaGateway of the MSC. On top - * of that we need to figure out if it was RTP or RTCP. - * - * Currently we do not communicate with the BSC so we have - * no idea where the BTS is listening for RTP and need to - * do the classic routing trick. Wait for the first packet - * from the BTS and then go ahead. - */ -static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) -{ - char buf[4096]; - struct sockaddr_in addr; - socklen_t slen = sizeof(addr); - struct mgcp_endpoint *endp; - int rc, dest, proto; - - endp = (struct mgcp_endpoint *) fd->data; - - rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, - (struct sockaddr *) &addr, &slen); - if (rc < 0) { - DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n", - ENDPOINT_NUMBER(endp)); - return -1; - } - - /* do not forward aynthing... maybe there is a packet from the bts */ - if (endp->ci == CI_UNUSED) { - DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); - return -1; - } - - /* - * Figure out where to forward it to. This code assumes that we - * have received the Connection Modify and know who is a legitimate - * partner. According to the spec we could attempt to forward even - * after the Create Connection but we will not as we are not really - * able to tell if this is legitimate. - */ - #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." - dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 && - (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) - ? DEST_BTS : DEST_NETWORK; - proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; - - /* We have no idea who called us, maybe it is the BTS. */ - if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) { - /* it was the BTS... */ - if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { - if (fd == &endp->local_rtp) { - endp->bts_rtp = addr.sin_port; - } else { - endp->bts_rtcp = addr.sin_port; - } - - endp->bts = addr.sin_addr; - DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", - ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); - } - } - - /* dispatch */ - if (audio_loop) - dest = !dest; - - if (dest == DEST_NETWORK) { - return _send(fd->fd, &endp->remote, - proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, - buf, rc); - } else { - return _send(fd->fd, &endp->bts, - proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, - buf, rc); - } -} - -static int create_bind(struct bsc_fd *fd, int port) -{ - struct sockaddr_in addr; - int on = 1; - - fd->fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd->fd < 0) - return -1; - - setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - inet_aton(source_addr, &addr.sin_addr); - - if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) - return -1; - - return 0; -} - -static int bind_rtp(struct mgcp_endpoint *endp) -{ - if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { - DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", - endp->rtp_port, ENDPOINT_NUMBER(endp)); - goto cleanup0; - } - - if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) { - DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n", - endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); - goto cleanup1; - } - - endp->local_rtp.cb = rtp_data_cb; - endp->local_rtp.data = endp; - endp->local_rtp.when = BSC_FD_READ; - if (bsc_register_fd(&endp->local_rtp) != 0) { - DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n", - endp->rtp_port, ENDPOINT_NUMBER(endp)); - goto cleanup2; - } - - endp->local_rtcp.cb = rtp_data_cb; - endp->local_rtcp.data = endp; - endp->local_rtcp.when = BSC_FD_READ; - if (bsc_register_fd(&endp->local_rtcp) != 0) { - DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n", - endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); - goto cleanup3; - } - - return 0; - -cleanup3: - bsc_unregister_fd(&endp->local_rtp); -cleanup2: - close(endp->local_rtcp.fd); - endp->local_rtcp.fd = -1; -cleanup1: - close(endp->local_rtp.fd); - endp->local_rtp.fd = -1; -cleanup0: - return -1; -} - -/* - * array of function pointers for handling various - * messages. In the future this might be binary sorted - * for performance reasons. - */ -static const struct mgcp_request mgcp_requests [] = { - MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint") - MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection") - MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection") - MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection") -}; - -static void send_response_with_data(int code, const char *msg, const char *trans, - const char *data, struct sockaddr_in *source) -{ - char buf[4096]; - int len; - - if (data) { - len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data); - } else { - len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans); - } - DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg); - - sendto(bfd.fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source)); -} - -static void send_response(int code, const char *msg, const char *trans, struct sockaddr_in *source) -{ - send_response_with_data(code, msg, trans, NULL, source); -} - -static void send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source) -{ - const char *addr = local_ip; - char sdp_record[4096]; - - if (!addr) - addr = source_addr; - - snprintf(sdp_record, sizeof(sdp_record) - 1, - "I: %d\n\n" - "v=0\r\n" - "c=IN IP4 %s\r\n" - "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d %s\r\n", - endp->ci, addr, endp->rtp_port, - audio_payload, audio_payload, audio_name); - return send_response_with_data(200, msg, trans_id, sdp_record, source); -} - -/* send a static record */ -static void send_rsip(struct sockaddr_in *source) -{ - char reset[4096]; - int len, rc; - - len = snprintf(reset, sizeof(reset) - 1, - "RSIP %u *@mgw MGCP 1.0\n" - "RM: restart\n", generate_transaction_id()); - rc = sendto(bfd.fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source)); - if (rc < 0) { - DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc); - } -} - -/* - * handle incoming messages: - * - this can be a command (four letters, space, transaction id) - * - or a response (three numbers, space, transaction id) - */ -static void handle_message(struct msgb *msg, struct sockaddr_in *source) -{ - int code; - - if (msg->len < 4) { - DEBUGP(DMGCP, "mgs too short: %d\n", msg->len); - return; - } - - /* attempt to treat it as a response */ - if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) { - DEBUGP(DMGCP, "Response: Code: %d\n", code); - } else { - int i, handled = 0; - msg->l3h = &msg->l2h[4]; - for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) - if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) { - handled = 1; - mgcp_requests[i].handle_request(msg, source); - } - if (!handled) { - DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]); - } - } -} - -/* string tokenizer for the poor */ -static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length) -{ - int i, found = 0; - - int whitespace = 1; - for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) { - /* if we have a space we found an end */ - if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { - if (!whitespace) { - ++found; - whitespace = 1; - ptrs->length = i - ptrs->start - 1; - ++ptrs; - --ptrs_length; - } else { - /* skip any number of whitespace */ - } - - /* line end... stop */ - if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') - break; - } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { - /* line end, be done */ - break; - } else if (whitespace) { - whitespace = 0; - ptrs->start = i; - } - } - - if (ptrs_length == 0) - return -1; - return found; -} - -static struct mgcp_endpoint *find_endpoint(const char *mgcp) -{ - char *endptr = NULL; - unsigned int gw = INT_MAX; - - gw = strtoul(mgcp, &endptr, 16); - if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) { - DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp); - return NULL; - } - - return &endpoints[gw]; -} - -static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, - const char **transaction_id, struct mgcp_endpoint **endp) -{ - int found; - - if (size < 3) { - DEBUGP(DMGCP, "Not enough space in ptr\n"); - return -1; - } - - found = find_msg_pointers(msg, ptr, size); - - if (found < 3) { - DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found); - return -1; - } - - /* - * replace the space with \0. the main method gurantess that - * we still have + 1 for null termination - */ - msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0'; - msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0'; - msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0'; - msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0'; - - if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0 - || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) { - DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n", - (const char *)&msg->l3h[ptr[3].start], - (const char *)&msg->l3h[ptr[2].start]); - return -1; - } - - *transaction_id = (const char *)&msg->l3h[ptr[0].start]; - *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]); - return *endp == NULL; -} - -static int verify_call_id(const struct mgcp_endpoint *endp, - const char *callid) -{ - if (strcmp(endp->callid, callid) != 0) { - DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n", - ENDPOINT_NUMBER(endp), endp->callid, callid); - return -1; - } - - return 0; -} - -static int verify_ci(const struct mgcp_endpoint *endp, - const char *ci) -{ - if (atoi(ci) != endp->ci) { - DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n", - ENDPOINT_NUMBER(endp), endp->ci, ci); - return -1; - } - - return 0; -} - -static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source) -{ - struct mgcp_msg_ptr data_ptrs[6]; - int found, response; - const char *trans_id; - struct mgcp_endpoint *endp; - - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); - if (found != 0) - response = 500; - else - response = 200; - - return send_response(response, "AUEP", trans_id, source); -} - -static int parse_conn_mode(const char* msg, int *conn_mode) -{ - int ret = 0; - if (strcmp(msg, "recvonly") == 0) - *conn_mode = MGCP_CONN_RECV_ONLY; - else if (strcmp(msg, "sendrecv") == 0) - *conn_mode = MGCP_CONN_RECV_SEND; - else { - DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg); - ret = -1; - } - - return ret; -} - -static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) -{ - struct mgcp_msg_ptr data_ptrs[6]; - int found, i, line_start; - const char *trans_id; - struct mgcp_endpoint *endp; - int error_code = 500; - - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); - if (found != 0) - return send_response(500, "CRCX", trans_id, source); - - if (endp->ci != CI_UNUSED) { - DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(500, "CRCX", trans_id, source); - } - - /* parse CallID C: and LocalParameters L: */ - MSG_TOKENIZE_START - switch (msg->l3h[line_start]) { - case 'L': - endp->local_options = talloc_strdup(endpoints, - (const char *)&msg->l3h[line_start + 3]); - break; - case 'C': - endp->callid = talloc_strdup(endpoints, - (const char *)&msg->l3h[line_start + 3]); - break; - case 'M': - if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], - &endp->conn_mode) != 0) { - error_code = 517; - goto error2; - } - break; - default: - DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", - msg->l3h[line_start], msg->l3h[line_start], - ENDPOINT_NUMBER(endp)); - break; - } - MSG_TOKENIZE_END - - /* initialize */ - endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; - - /* set to zero until we get the info */ - memset(&endp->remote, 0, sizeof(endp->remote)); - - /* bind to the port now */ - endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); - if (!early_bind && bind_rtp(endp) != 0) - goto error2; - - /* assign a local call identifier or fail */ - endp->ci = generate_call_id(); - if (endp->ci == CI_UNUSED) - goto error2; - - DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n", - ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); - return send_with_sdp(endp, "CRCX", trans_id, source); -error: - DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", - hexdump(msg->l3h, msgb_l3len(msg)), - ENDPOINT_NUMBER(endp), line_start, i); - return send_response(error_code, "CRCX", trans_id, source); - -error2: - DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(error_code, "CRCX", trans_id, source); -} - -static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source) -{ - struct mgcp_msg_ptr data_ptrs[6]; - int found, i, line_start; - const char *trans_id; - struct mgcp_endpoint *endp; - int error_code = 500; - - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); - if (found != 0) - return send_response(error_code, "MDCX", trans_id, source); - - if (endp->ci == CI_UNUSED) { - DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(error_code, "MDCX", trans_id, source); - } - - MSG_TOKENIZE_START - switch (msg->l3h[line_start]) { - case 'C': { - if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) - goto error3; - break; - } - case 'I': { - if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) - goto error3; - break; - } - case 'L': - /* skip */ - break; - case 'M': - if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], - &endp->conn_mode) != 0) { - error_code = 517; - goto error3; - } - break; - case '\0': - /* SDP file begins */ - break; - case 'a': - case 'o': - case 's': - case 't': - case 'v': - /* skip these SDP attributes */ - break; - case 'm': { - int port; - const char *param = (const char *)&msg->l3h[line_start]; - - if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { - endp->net_rtp = htons(port); - endp->net_rtcp = htons(port + 1); - } - break; - } - case 'c': { - char ipv4[16]; - const char *param = (const char *)&msg->l3h[line_start]; - - if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) { - inet_aton(ipv4, &endp->remote); - } - break; - } - default: - DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", - msg->l3h[line_start], msg->l3h[line_start], - ENDPOINT_NUMBER(endp)); - break; - } - MSG_TOKENIZE_END - - /* modify */ - DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", - ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); - return send_with_sdp(endp, "MDCX", trans_id, source); - -error: - DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", - hexdump(msg->l3h, msgb_l3len(msg)), - ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); - return send_response(error_code, "MDCX", trans_id, source); - -error3: - return send_response(error_code, "MDCX", trans_id, source); -} - -static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source) -{ - struct mgcp_msg_ptr data_ptrs[6]; - int found, i, line_start; - const char *trans_id; - struct mgcp_endpoint *endp; - int error_code = 500; - - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); - if (found != 0) - return send_response(error_code, "DLCX", trans_id, source); - - if (endp->ci == CI_UNUSED) { - DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(error_code, "DLCX", trans_id, source); - } - - MSG_TOKENIZE_START - switch (msg->l3h[line_start]) { - case 'C': { - if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) - goto error3; - break; - } - case 'I': { - if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) - goto error3; - break; - } - default: - DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", - msg->l3h[line_start], msg->l3h[line_start], - ENDPOINT_NUMBER(endp)); - break; - } - MSG_TOKENIZE_END - - - /* free the connection */ - DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); - endp->ci= CI_UNUSED; - talloc_free(endp->callid); - talloc_free(endp->local_options); - - if (!early_bind) { - bsc_unregister_fd(&endp->local_rtp); - bsc_unregister_fd(&endp->local_rtcp); - } - - endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; - - return send_response(250, "DLCX", trans_id, source); - -error: - DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", - hexdump(msg->l3h, msgb_l3len(msg)), - ENDPOINT_NUMBER(endp), line_start, i); - return send_response(error_code, "DLCX", trans_id, source); - -error3: - return send_response(error_code, "DLCX", trans_id, source); -} +unsigned int rtp_base_port = RTP_PORT_DEFAULT; static void print_help() { @@ -882,234 +123,24 @@ static int read_call_agent(struct bsc_fd *fd, unsigned int what) if (first_request) { first_request = 0; - send_rsip(&addr); + mgcp_send_rsip(bfd.fd, &addr); return 0; } /* handle message now */ msg->l2h = msgb_put(msg, rc); - handle_message(msg, &addr); + mgcp_handle_message(bfd.fd, msg, &addr); msgb_reset(msg); return 0; } -/* - * vty code for mgcp below - */ -struct cmd_node mgcp_node = { - MGCP_NODE, - "%s(mgcp)#", - 1, -}; - -static int config_write_mgcp(struct vty *vty) -{ - vty_out(vty, "mgcp%s", VTY_NEWLINE); - if (local_ip) - vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); - if (bts_ip) - vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); - vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); - vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); - vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE); - vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE); - vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE); - vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); - vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); - vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); - if (forward_ip) - vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE); - if (forward_port != 0) - vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", - SHOW_STR "Display information about the MGCP Media Gateway") -{ - int i; - - vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE); - for (i = 1; i < number_endpoints; ++i) { - struct mgcp_endpoint *endp = &endpoints[i]; - vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", - i, endp->ci, - ntohs(endp->net_rtp), ntohs(endp->net_rtcp), - ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp, - cfg_mgcp_cmd, - "mgcp", - "Configure the MGCP") -{ - vty->node = MGCP_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_local_ip, - cfg_mgcp_local_ip_cmd, - "local ip IP", - "Set the IP to be used in SDP records") -{ - local_ip = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bts_ip, - cfg_mgcp_bts_ip_cmd, - "bts ip IP", - "Set the IP of the BTS for RTP forwarding") -{ - bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]); - inet_aton(bts_ip, &bts_in); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bind_ip, - cfg_mgcp_bind_ip_cmd, - "bind ip IP", - "Bind the MGCP to this local addr") -{ - source_addr = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bind_port, - cfg_mgcp_bind_port_cmd, - "bind port <0-65534>", - "Bind the MGCP to this port") -{ - unsigned int port = atoi(argv[0]); - if (port > 65534) { - vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - source_port = port; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bind_early, - cfg_mgcp_bind_early_cmd, - "bind early (0|1)", - "Bind all RTP ports early") -{ - unsigned int bind = atoi(argv[0]); - if (bind != 0 && bind != 1) { - vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - early_bind = bind == 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_rtp_base_port, - cfg_mgcp_rtp_base_port_cmd, - "rtp base <0-65534>", - "Base port to use") -{ - unsigned int port = atoi(argv[0]); - if (port > 65534) { - vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - rtp_base_port = port; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_sdp_payload_number, - cfg_mgcp_sdp_payload_number_cmd, - "sdp audio payload number <1-255>", - "Set the audio codec to use") -{ - unsigned int payload = atoi(argv[0]); - if (payload > 255) { - vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - audio_payload = payload; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_sdp_payload_name, - cfg_mgcp_sdp_payload_name_cmd, - "sdp audio payload name NAME", - "Set the audio name to use") -{ - audio_name = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_loop, - cfg_mgcp_loop_cmd, - "loop (0|1)", - "Loop the audio") -{ - audio_loop = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_number_endp, - cfg_mgcp_number_endp_cmd, - "number endpoints <0-65534>", - "The number of endpoints to allocate. This is not dynamic.") -{ - /* + 1 as we start counting at one */ - number_endpoints = atoi(argv[0]) + 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_forward_ip, - cfg_mgcp_forward_ip_cmd, - "forward audio ip IP", - "Forward packets from and to the IP. This disables most of the MGCP feature.") -{ - if (forward_ip) - talloc_free(forward_ip); - forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_forward_port, - cfg_mgcp_forward_port_cmd, - "forward audio port <1-15000>", - "Forward packets from and to the port. This disables most of the MGCP feature.") -{ - forward_port = atoi(argv[0]); - return CMD_SUCCESS; -} int bsc_vty_init(struct gsm_network *dummy) { cmd_init(1); vty_init(); - install_element(VIEW_NODE, &show_mgcp_cmd); - - - install_element(CONFIG_NODE, &cfg_mgcp_cmd); - install_node(&mgcp_node, config_write_mgcp); - install_default(MGCP_NODE); - install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd); - install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); - install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); - install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); - install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); - install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); - install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd); + mgcp_vty_init(); return 0; } @@ -1117,7 +148,7 @@ int main(int argc, char** argv) { struct gsm_network dummy_network; struct sockaddr_in addr; - int on = 1, i, rc; + int on = 1, rc; struct debug_target *stderr_target; tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent"); @@ -1130,61 +161,13 @@ int main(int argc, char** argv) handle_options(argc, argv); telnet_init(&dummy_network, 4243); - rc = vty_read_config_file(config_file); - if (rc < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + rc = mgcp_parse_config(config_file, &dummy_network); + if (rc < 0) return rc; - } - if (!bts_ip) - fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n"); - - endpoints = _talloc_zero_array(tall_bsc_ctx, - sizeof(struct mgcp_endpoint), - number_endpoints, "endpoints"); - if (!endpoints) { - fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints); - return -1; - } - - /* Initialize all endpoints */ - for (i = 0; i < number_endpoints; ++i) { - endpoints[i].local_rtp.fd = -1; - endpoints[i].local_rtcp.fd = -1; - endpoints[i].ci = CI_UNUSED; - } - - /* - * This application supports two modes. - * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX - * 2.) plain forwarding of RTP packets on the endpoints. - * both modes are mutual exclusive - */ - if (forward_ip) { - int port = rtp_base_port; - if (forward_port != 0) - port = forward_port; - - if (!early_bind) { - DEBUGP(DMGCP, "Forwarding requires early bind.\n"); - return -1; - } - - /* - * Store the forward IP and assign a ci. For early bind - * the sockets will be created after this. - */ - for (i = 1; i < number_endpoints; ++i) { - struct mgcp_endpoint *endp = &endpoints[i]; - inet_aton(forward_ip, &endp->remote); - endp->ci = CI_UNUSED + 23; - endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port)); - endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1); - } - - DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); - } else { + /* we need to bind a socket */ + if (rc == 0) { bfd.when = BSC_FD_READ; bfd.cb = read_call_agent; bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); @@ -1223,16 +206,6 @@ int main(int argc, char** argv) /* initialisation */ srand(time(NULL)); - /* early bind */ - if (early_bind) { - for (i = 1; i < number_endpoints; ++i) { - struct mgcp_endpoint *endp = &endpoints[i]; - endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); - if (bind_rtp(endp) != 0) - return -1; - } - } - /* main loop */ while (1) { bsc_select_main(0); diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c new file mode 100644 index 000000000..fe82fb510 --- /dev/null +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -0,0 +1,1114 @@ +/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ +/* The protocol implementation */ + +/* + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by on-waves.com + * 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 + +#warning "Make use of the rtp proxy code" + +static int source_port = 2427; +static const char *local_ip = NULL; +static const char *source_addr = "0.0.0.0"; +static unsigned int number_endpoints = 0; +static const char *bts_ip = NULL; +static struct in_addr bts_in; +static const char *audio_name = "GSM-EFR/8000"; +static int audio_payload = 97; +static int audio_loop = 0; +static int early_bind = 0; + +static char *forward_ip = NULL; +static int forward_port = 0; + +enum mgcp_connection_mode { + MGCP_CONN_NONE = 0, + MGCP_CONN_RECV_ONLY = 1, + MGCP_CONN_SEND_ONLY = 2, + MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, +}; + +enum { + DEST_NETWORK = 0, + DEST_BTS = 1, +}; + +enum { + PROTO_RTP, + PROTO_RTCP, +}; + +#define CI_UNUSED 0 +static unsigned int last_call_id = 0; + +struct mgcp_endpoint { + int ci; + char *callid; + char *local_options; + int conn_mode; + + /* the local rtp port we are binding to */ + int rtp_port; + + /* + * RTP mangling: + * - we get RTP and RTCP to us and need to forward to the BTS + * - we get RTP and RTCP from the BTS and forward to the network + */ + struct bsc_fd local_rtp; + struct bsc_fd local_rtcp; + + struct in_addr remote; + struct in_addr bts; + + /* in network byte order */ + int net_rtp, net_rtcp; + int bts_rtp, bts_rtcp; +}; + +static struct mgcp_endpoint *endpoints = NULL; +#define ENDPOINT_NUMBER(endp) abs(endp - endpoints) + +/** + * Macro for tokenizing MGCP messages and SDP in one go. + * + */ +#define MSG_TOKENIZE_START \ + line_start = 0; \ + for (i = 0; i < msgb_l3len(msg); ++i) { \ + /* we have a line end */ \ + if (msg->l3h[i] == '\n') { \ + /* skip the first line */ \ + if (line_start == 0) { \ + line_start = i + 1; \ + continue; \ + } \ + \ + /* check if we have a proper param */ \ + if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \ + } else if (i - line_start > 2 \ + && islower(msg->l3h[line_start]) \ + && msg->l3h[line_start + 1] == '=') { \ + } else if (i - line_start < 3 \ + || msg->l3h[line_start + 1] != ':' \ + || msg->l3h[line_start + 2] != ' ') \ + goto error; \ + \ + msg->l3h[i] = '\0'; \ + if (msg->l3h[i-1] == '\r') \ + msg->l3h[i-1] = '\0'; + +#define MSG_TOKENIZE_END \ + line_start = i + 1; \ + } \ + } + + +struct mgcp_msg_ptr { + unsigned int start; + unsigned int length; +}; + +struct mgcp_request { + char *name; + int (*handle_request) (int fd, struct msgb *msg, struct sockaddr_in *source); + char *debug_name; +}; + +#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \ + { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME }, + +static int handle_audit_endpoint(int fd, struct msgb *msg, struct sockaddr_in *source); +static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *source); +static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *source); +static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *source); + +static int generate_call_id() +{ + int i; + + /* use the call id */ + ++last_call_id; + + /* handle wrap around */ + if (last_call_id == CI_UNUSED) + ++last_call_id; + + /* callstack can only be of size number_of_endpoints */ + /* verify that the call id is free, e.g. in case of overrun */ + for (i = 1; i < number_endpoints; ++i) + if (endpoints[i].ci == last_call_id) + return generate_call_id(); + + return last_call_id; +} + +/* FIXIME/TODO: need to have a list of pending transactions and check that */ +static unsigned int generate_transaction_id() +{ + return abs(rand()); +} + +static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len) +{ + struct sockaddr_in out; + out.sin_family = AF_INET; + out.sin_port = port; + memcpy(&out.sin_addr, addr, sizeof(*addr)); + + return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out)); +} + +/* + * There is data coming. We will have to figure out if it + * came from the BTS or the MediaGateway of the MSC. On top + * of that we need to figure out if it was RTP or RTCP. + * + * Currently we do not communicate with the BSC so we have + * no idea where the BTS is listening for RTP and need to + * do the classic routing trick. Wait for the first packet + * from the BTS and then go ahead. + */ +static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) +{ + char buf[4096]; + struct sockaddr_in addr; + socklen_t slen = sizeof(addr); + struct mgcp_endpoint *endp; + int rc, dest, proto; + + endp = (struct mgcp_endpoint *) fd->data; + + rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, + (struct sockaddr *) &addr, &slen); + if (rc < 0) { + DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n", + ENDPOINT_NUMBER(endp)); + return -1; + } + + /* do not forward aynthing... maybe there is a packet from the bts */ + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); + return -1; + } + + /* + * Figure out where to forward it to. This code assumes that we + * have received the Connection Modify and know who is a legitimate + * partner. According to the spec we could attempt to forward even + * after the Create Connection but we will not as we are not really + * able to tell if this is legitimate. + */ + #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." + dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 && + (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) + ? DEST_BTS : DEST_NETWORK; + proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; + + /* We have no idea who called us, maybe it is the BTS. */ + if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) { + /* it was the BTS... */ + if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { + if (fd == &endp->local_rtp) { + endp->bts_rtp = addr.sin_port; + } else { + endp->bts_rtcp = addr.sin_port; + } + + endp->bts = addr.sin_addr; + DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", + ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); + } + } + + /* dispatch */ + if (audio_loop) + dest = !dest; + + if (dest == DEST_NETWORK) { + return udp_send(fd->fd, &endp->remote, + proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, + buf, rc); + } else { + return udp_send(fd->fd, &endp->bts, + proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, + buf, rc); + } +} + +static int create_bind(struct bsc_fd *fd, int port) +{ + struct sockaddr_in addr; + int on = 1; + + fd->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd->fd < 0) + return -1; + + setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_aton(source_addr, &addr.sin_addr); + + if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + return -1; + + return 0; +} + +static int bind_rtp(struct mgcp_endpoint *endp) +{ + if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { + DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", + endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup0; + } + + if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) { + DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n", + endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup1; + } + + endp->local_rtp.cb = rtp_data_cb; + endp->local_rtp.data = endp; + endp->local_rtp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtp) != 0) { + DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n", + endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup2; + } + + endp->local_rtcp.cb = rtp_data_cb; + endp->local_rtcp.data = endp; + endp->local_rtcp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtcp) != 0) { + DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n", + endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup3; + } + + return 0; + +cleanup3: + bsc_unregister_fd(&endp->local_rtp); +cleanup2: + close(endp->local_rtcp.fd); + endp->local_rtcp.fd = -1; +cleanup1: + close(endp->local_rtp.fd); + endp->local_rtp.fd = -1; +cleanup0: + return -1; +} + +/* + * array of function pointers for handling various + * messages. In the future this might be binary sorted + * for performance reasons. + */ +static const struct mgcp_request mgcp_requests [] = { + MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint") + MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection") + MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection") + MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection") +}; + +static int send_response_with_data(int fd, int code, const char *msg, const char *trans, + const char *data, struct sockaddr_in *source) +{ + char buf[4096]; + int len; + + if (data) { + len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data); + } else { + len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans); + } + DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg); + + if (source) + return sendto(fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source)); + else + return write(fd, buf, len); +} + +static int send_response(int fd, int code, const char *msg, + const char *trans, struct sockaddr_in *source) +{ + return send_response_with_data(fd, code, msg, trans, NULL, source); +} + +static int send_with_sdp(int fd, struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source) +{ + const char *addr = local_ip; + char sdp_record[4096]; + + if (!addr) + addr = source_addr; + + snprintf(sdp_record, sizeof(sdp_record) - 1, + "I: %d\n\n" + "v=0\r\n" + "c=IN IP4 %s\r\n" + "m=audio %d RTP/AVP %d\r\n" + "a=rtpmap:%d %s\r\n", + endp->ci, addr, endp->rtp_port, + audio_payload, audio_payload, audio_name); + return send_response_with_data(fd, 200, msg, trans_id, sdp_record, source); +} + +/* send a static record */ +int mgcp_send_rsip(int fd, struct sockaddr_in *source) +{ + char reset[4096]; + int len, rc; + + len = snprintf(reset, sizeof(reset) - 1, + "RSIP %u *@mgw MGCP 1.0\n" + "RM: restart\n", generate_transaction_id()); + if (source) + rc = sendto(fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source)); + else + rc = write(fd, reset, len); + + if (rc < 0) { + DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc); + } + + return rc; +} + +/* + * handle incoming messages: + * - this can be a command (four letters, space, transaction id) + * - or a response (three numbers, space, transaction id) + */ +int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source) +{ + int code; + + if (msg->len < 4) { + DEBUGP(DMGCP, "mgs too short: %d\n", msg->len); + return -1; + } + + /* attempt to treat it as a response */ + if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) { + DEBUGP(DMGCP, "Response: Code: %d\n", code); + } else { + int i, handled = 0; + msg->l3h = &msg->l2h[4]; + for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) + if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) { + handled = 1; + mgcp_requests[i].handle_request(fd, msg, source); + } + if (!handled) { + DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]); + } + } + + return 0; +} + +/* string tokenizer for the poor */ +static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length) +{ + int i, found = 0; + + int whitespace = 1; + for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) { + /* if we have a space we found an end */ + if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { + if (!whitespace) { + ++found; + whitespace = 1; + ptrs->length = i - ptrs->start - 1; + ++ptrs; + --ptrs_length; + } else { + /* skip any number of whitespace */ + } + + /* line end... stop */ + if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') + break; + } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { + /* line end, be done */ + break; + } else if (whitespace) { + whitespace = 0; + ptrs->start = i; + } + } + + if (ptrs_length == 0) + return -1; + return found; +} + +static struct mgcp_endpoint *find_endpoint(const char *mgcp) +{ + char *endptr = NULL; + unsigned int gw = INT_MAX; + + gw = strtoul(mgcp, &endptr, 16); + if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) { + DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp); + return NULL; + } + + return &endpoints[gw]; +} + +static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, + const char **transaction_id, struct mgcp_endpoint **endp) +{ + int found; + + if (size < 3) { + DEBUGP(DMGCP, "Not enough space in ptr\n"); + return -1; + } + + found = find_msg_pointers(msg, ptr, size); + + if (found < 3) { + DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found); + return -1; + } + + /* + * replace the space with \0. the main method gurantess that + * we still have + 1 for null termination + */ + msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0'; + msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0'; + msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0'; + msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0'; + + if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0 + || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) { + DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n", + (const char *)&msg->l3h[ptr[3].start], + (const char *)&msg->l3h[ptr[2].start]); + return -1; + } + + *transaction_id = (const char *)&msg->l3h[ptr[0].start]; + *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]); + return *endp == NULL; +} + +static int verify_call_id(const struct mgcp_endpoint *endp, + const char *callid) +{ + if (strcmp(endp->callid, callid) != 0) { + DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n", + ENDPOINT_NUMBER(endp), endp->callid, callid); + return -1; + } + + return 0; +} + +static int verify_ci(const struct mgcp_endpoint *endp, + const char *ci) +{ + if (atoi(ci) != endp->ci) { + DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n", + ENDPOINT_NUMBER(endp), endp->ci, ci); + return -1; + } + + return 0; +} + +static int handle_audit_endpoint(int fd, struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, response; + const char *trans_id; + struct mgcp_endpoint *endp; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + response = 500; + else + response = 200; + + return send_response(fd, response, "AUEP", trans_id, source); +} + +static int parse_conn_mode(const char* msg, int *conn_mode) +{ + int ret = 0; + if (strcmp(msg, "recvonly") == 0) + *conn_mode = MGCP_CONN_RECV_ONLY; + else if (strcmp(msg, "sendrecv") == 0) + *conn_mode = MGCP_CONN_RECV_SEND; + else { + DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg); + ret = -1; + } + + return ret; +} + +static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(fd, 500, "CRCX", trans_id, source); + + if (endp->ci != CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(fd, 500, "CRCX", trans_id, source); + } + + /* parse CallID C: and LocalParameters L: */ + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'L': + endp->local_options = talloc_strdup(endpoints, + (const char *)&msg->l3h[line_start + 3]); + break; + case 'C': + endp->callid = talloc_strdup(endpoints, + (const char *)&msg->l3h[line_start + 3]); + break; + case 'M': + if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], + &endp->conn_mode) != 0) { + error_code = 517; + goto error2; + } + break; + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + /* initialize */ + endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + + /* set to zero until we get the info */ + memset(&endp->remote, 0, sizeof(endp->remote)); + + /* bind to the port now */ + endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); + if (!early_bind && bind_rtp(endp) != 0) + goto error2; + + /* assign a local call identifier or fail */ + endp->ci = generate_call_id(); + if (endp->ci == CI_UNUSED) + goto error2; + + DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n", + ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); + return send_with_sdp(fd, endp, "CRCX", trans_id, source); +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i); + return send_response(fd, error_code, "CRCX", trans_id, source); + +error2: + DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(fd, error_code, "CRCX", trans_id, source); +} + +static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(fd, error_code, "MDCX", trans_id, source); + + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(fd, error_code, "MDCX", trans_id, source); + } + + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'C': { + if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'I': { + if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'L': + /* skip */ + break; + case 'M': + if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], + &endp->conn_mode) != 0) { + error_code = 517; + goto error3; + } + break; + case '\0': + /* SDP file begins */ + break; + case 'a': + case 'o': + case 's': + case 't': + case 'v': + /* skip these SDP attributes */ + break; + case 'm': { + int port; + const char *param = (const char *)&msg->l3h[line_start]; + + if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { + endp->net_rtp = htons(port); + endp->net_rtcp = htons(port + 1); + } + break; + } + case 'c': { + char ipv4[16]; + const char *param = (const char *)&msg->l3h[line_start]; + + if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) { + inet_aton(ipv4, &endp->remote); + } + break; + } + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + /* modify */ + DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", + ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); + return send_with_sdp(fd, endp, "MDCX", trans_id, source); + +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); + return send_response(fd, error_code, "MDCX", trans_id, source); + +error3: + return send_response(fd, error_code, "MDCX", trans_id, source); +} + +static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(fd, error_code, "DLCX", trans_id, source); + + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(fd, error_code, "DLCX", trans_id, source); + } + + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'C': { + if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'I': { + if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + + /* free the connection */ + DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); + endp->ci= CI_UNUSED; + talloc_free(endp->callid); + talloc_free(endp->local_options); + + if (!early_bind) { + bsc_unregister_fd(&endp->local_rtp); + bsc_unregister_fd(&endp->local_rtcp); + } + + endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + + return send_response(fd, 250, "DLCX", trans_id, source); + +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i); + return send_response(fd, error_code, "DLCX", trans_id, source); + +error3: + return send_response(fd, error_code, "DLCX", trans_id, source); +} + +/* + * vty code for mgcp below + */ +struct cmd_node mgcp_node = { + MGCP_NODE, + "%s(mgcp)#", + 1, +}; + +static int config_write_mgcp(struct vty *vty) +{ + vty_out(vty, "mgcp%s", VTY_NEWLINE); + if (local_ip) + vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); + if (bts_ip) + vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); + vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); + vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); + vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE); + vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE); + vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE); + vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); + vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); + vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); + if (forward_ip) + vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE); + if (forward_port != 0) + vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", + SHOW_STR "Display information about the MGCP Media Gateway") +{ + int i; + + vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE); + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", + i, endp->ci, + ntohs(endp->net_rtp), ntohs(endp->net_rtcp), + ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp, + cfg_mgcp_cmd, + "mgcp", + "Configure the MGCP") +{ + vty->node = MGCP_NODE; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_local_ip, + cfg_mgcp_local_ip_cmd, + "local ip IP", + "Set the IP to be used in SDP records") +{ + local_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bts_ip, + cfg_mgcp_bts_ip_cmd, + "bts ip IP", + "Set the IP of the BTS for RTP forwarding") +{ + bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + inet_aton(bts_ip, &bts_in); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_ip, + cfg_mgcp_bind_ip_cmd, + "bind ip IP", + "Bind the MGCP to this local addr") +{ + source_addr = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_port, + cfg_mgcp_bind_port_cmd, + "bind port <0-65534>", + "Bind the MGCP to this port") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + source_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_early, + cfg_mgcp_bind_early_cmd, + "bind early (0|1)", + "Bind all RTP ports early") +{ + unsigned int bind = atoi(argv[0]); + if (bind != 0 && bind != 1) { + vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + early_bind = bind == 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_rtp_base_port, + cfg_mgcp_rtp_base_port_cmd, + "rtp base <0-65534>", + "Base port to use") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + rtp_base_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_number, + cfg_mgcp_sdp_payload_number_cmd, + "sdp audio payload number <1-255>", + "Set the audio codec to use") +{ + unsigned int payload = atoi(argv[0]); + if (payload > 255) { + vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + audio_payload = payload; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_name, + cfg_mgcp_sdp_payload_name_cmd, + "sdp audio payload name NAME", + "Set the audio name to use") +{ + audio_name = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_loop, + cfg_mgcp_loop_cmd, + "loop (0|1)", + "Loop the audio") +{ + audio_loop = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_number_endp, + cfg_mgcp_number_endp_cmd, + "number endpoints <0-65534>", + "The number of endpoints to allocate. This is not dynamic.") +{ + /* + 1 as we start counting at one */ + number_endpoints = atoi(argv[0]) + 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_forward_ip, + cfg_mgcp_forward_ip_cmd, + "forward audio ip IP", + "Forward packets from and to the IP. This disables most of the MGCP feature.") +{ + if (forward_ip) + talloc_free(forward_ip); + forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_forward_port, + cfg_mgcp_forward_port_cmd, + "forward audio port <1-15000>", + "Forward packets from and to the port. This disables most of the MGCP feature.") +{ + forward_port = atoi(argv[0]); + return CMD_SUCCESS; +} + +int mgcp_vty_init(void) +{ + install_element(VIEW_NODE, &show_mgcp_cmd); + + install_element(CONFIG_NODE, &cfg_mgcp_cmd); + install_node(&mgcp_node, config_write_mgcp); + install_default(MGCP_NODE); + install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); + install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); + install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); + install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd); + return 0; +} + +int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network) +{ + int i, rc; + + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + + if (!bts_ip) + fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n"); + + endpoints = _talloc_zero_array(tall_bsc_ctx, + sizeof(struct mgcp_endpoint), + number_endpoints, "endpoints"); + if (!endpoints) { + fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints); + return -1; + } + + /* Initialize all endpoints */ + for (i = 0; i < number_endpoints; ++i) { + endpoints[i].local_rtp.fd = -1; + endpoints[i].local_rtcp.fd = -1; + endpoints[i].ci = CI_UNUSED; + } + + /* + * This application supports two modes. + * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX + * 2.) plain forwarding of RTP packets on the endpoints. + * both modes are mutual exclusive + */ + if (forward_ip) { + int port = rtp_base_port; + if (forward_port != 0) + port = forward_port; + + if (!early_bind) { + DEBUGP(DMGCP, "Forwarding requires early bind.\n"); + return -1; + } + + /* + * Store the forward IP and assign a ci. For early bind + * the sockets will be created after this. + */ + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + inet_aton(forward_ip, &endp->remote); + endp->ci = CI_UNUSED + 23; + endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port)); + endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1); + } + + DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); + } + + /* early bind */ + if (early_bind) { + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); + if (bind_rtp(endp) != 0) + return -1; + } + } + + return !!forward_ip; +} From 2ada71de6465def08867c522dc955ff61907c116 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 3 Feb 2010 09:13:10 +0100 Subject: [PATCH 362/365] [mgcp] Replace DEBUGP with the LOGP statement * Classify messages as LOGL_INFO or LOGL_ERROR --- openbsc/src/mgcp/mgcp_protocol.c | 83 +++++++++++++++++--------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index fe82fb510..763dadbcc 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -221,14 +221,14 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, (struct sockaddr *) &addr, &slen); if (rc < 0) { - DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n", + LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n", ENDPOINT_NUMBER(endp)); return -1; } /* do not forward aynthing... maybe there is a packet from the bts */ if (endp->ci == CI_UNUSED) { - DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); return -1; } @@ -256,7 +256,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) } endp->bts = addr.sin_addr; - DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", + LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n", ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); } } @@ -282,8 +282,10 @@ static int create_bind(struct bsc_fd *fd, int port) int on = 1; fd->fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd->fd < 0) + if (fd->fd < 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n"); return -1; + } setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); memset(&addr, 0, sizeof(addr)); @@ -291,8 +293,9 @@ static int create_bind(struct bsc_fd *fd, int port) addr.sin_port = htons(port); inet_aton(source_addr, &addr.sin_addr); - if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { return -1; + } return 0; } @@ -300,14 +303,14 @@ static int create_bind(struct bsc_fd *fd, int port) static int bind_rtp(struct mgcp_endpoint *endp) { if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { - DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", - endp->rtp_port, ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n", + source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp)); goto cleanup0; } if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) { - DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n", - endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n", + source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); goto cleanup1; } @@ -315,7 +318,7 @@ static int bind_rtp(struct mgcp_endpoint *endp) endp->local_rtp.data = endp; endp->local_rtp.when = BSC_FD_READ; if (bsc_register_fd(&endp->local_rtp) != 0) { - DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n", + LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n", endp->rtp_port, ENDPOINT_NUMBER(endp)); goto cleanup2; } @@ -324,7 +327,7 @@ static int bind_rtp(struct mgcp_endpoint *endp) endp->local_rtcp.data = endp; endp->local_rtcp.when = BSC_FD_READ; if (bsc_register_fd(&endp->local_rtcp) != 0) { - DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n", + LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n", endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); goto cleanup3; } @@ -366,7 +369,7 @@ static int send_response_with_data(int fd, int code, const char *msg, const char } else { len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans); } - DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg); + LOGP(DMGCP, LOGL_NOTICE, "Sending response: code: %d for '%s'\n", code, msg); if (source) return sendto(fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source)); @@ -414,7 +417,7 @@ int mgcp_send_rsip(int fd, struct sockaddr_in *source) rc = write(fd, reset, len); if (rc < 0) { - DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc); + LOGP(DMGCP, LOGL_ERROR, "Failed to send RSIP: %d\n", rc); } return rc; @@ -430,13 +433,13 @@ int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source) int code; if (msg->len < 4) { - DEBUGP(DMGCP, "mgs too short: %d\n", msg->len); + LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len); return -1; } /* attempt to treat it as a response */ if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) { - DEBUGP(DMGCP, "Response: Code: %d\n", code); + LOGP(DMGCP, LOGL_NOTICE, "Response: Code: %d\n", code); } else { int i, handled = 0; msg->l3h = &msg->l2h[4]; @@ -446,7 +449,7 @@ int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source) mgcp_requests[i].handle_request(fd, msg, source); } if (!handled) { - DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]); + LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->data[0]); } } @@ -496,7 +499,7 @@ static struct mgcp_endpoint *find_endpoint(const char *mgcp) gw = strtoul(mgcp, &endptr, 16); if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) { - DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp); + LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp); return NULL; } @@ -509,14 +512,14 @@ static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, int found; if (size < 3) { - DEBUGP(DMGCP, "Not enough space in ptr\n"); + LOGP(DMGCP, LOGL_ERROR, "Not enough space in ptr\n"); return -1; } found = find_msg_pointers(msg, ptr, size); if (found < 3) { - DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found); + LOGP(DMGCP, LOGL_ERROR, "Gateway: Not enough params. Found: %d\n", found); return -1; } @@ -531,7 +534,7 @@ static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0 || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) { - DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n", + LOGP(DMGCP, LOGL_ERROR, "Wrong MGCP version. Not handling: '%s' '%s'\n", (const char *)&msg->l3h[ptr[3].start], (const char *)&msg->l3h[ptr[2].start]); return -1; @@ -546,7 +549,7 @@ static int verify_call_id(const struct mgcp_endpoint *endp, const char *callid) { if (strcmp(endp->callid, callid) != 0) { - DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n", + LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n", ENDPOINT_NUMBER(endp), endp->callid, callid); return -1; } @@ -558,7 +561,7 @@ static int verify_ci(const struct mgcp_endpoint *endp, const char *ci) { if (atoi(ci) != endp->ci) { - DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n", + LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n", ENDPOINT_NUMBER(endp), endp->ci, ci); return -1; } @@ -590,7 +593,7 @@ static int parse_conn_mode(const char* msg, int *conn_mode) else if (strcmp(msg, "sendrecv") == 0) *conn_mode = MGCP_CONN_RECV_SEND; else { - DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg); + LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg); ret = -1; } @@ -610,7 +613,7 @@ static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *sourc return send_response(fd, 500, "CRCX", trans_id, source); if (endp->ci != CI_UNUSED) { - DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); return send_response(fd, 500, "CRCX", trans_id, source); } @@ -633,7 +636,7 @@ static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *sourc } break; default: - DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n", msg->l3h[line_start], msg->l3h[line_start], ENDPOINT_NUMBER(endp)); break; @@ -656,17 +659,17 @@ static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *sourc if (endp->ci == CI_UNUSED) goto error2; - DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n", + LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n", ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); return send_with_sdp(fd, endp, "CRCX", trans_id, source); error: - DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); return send_response(fd, error_code, "CRCX", trans_id, source); error2: - DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); return send_response(fd, error_code, "CRCX", trans_id, source); } @@ -683,7 +686,7 @@ static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *sourc return send_response(fd, error_code, "MDCX", trans_id, source); if (endp->ci == CI_UNUSED) { - DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); return send_response(fd, error_code, "MDCX", trans_id, source); } @@ -739,7 +742,7 @@ static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *sourc break; } default: - DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n", msg->l3h[line_start], msg->l3h[line_start], ENDPOINT_NUMBER(endp)); break; @@ -747,12 +750,12 @@ static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *sourc MSG_TOKENIZE_END /* modify */ - DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", + LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); return send_with_sdp(fd, endp, "MDCX", trans_id, source); error: - DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", + LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); return send_response(fd, error_code, "MDCX", trans_id, source); @@ -774,7 +777,7 @@ static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *sourc return send_response(fd, error_code, "DLCX", trans_id, source); if (endp->ci == CI_UNUSED) { - DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); return send_response(fd, error_code, "DLCX", trans_id, source); } @@ -791,7 +794,7 @@ static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *sourc break; } default: - DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n", msg->l3h[line_start], msg->l3h[line_start], ENDPOINT_NUMBER(endp)); break; @@ -800,7 +803,7 @@ static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *sourc /* free the connection */ - DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); + LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); endp->ci= CI_UNUSED; talloc_free(endp->callid); talloc_free(endp->local_options); @@ -815,7 +818,7 @@ static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *sourc return send_response(fd, 250, "DLCX", trans_id, source); error: - DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); return send_response(fd, error_code, "DLCX", trans_id, source); @@ -1081,7 +1084,7 @@ int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network port = forward_port; if (!early_bind) { - DEBUGP(DMGCP, "Forwarding requires early bind.\n"); + LOGP(DMGCP, LOGL_NOTICE, "Forwarding requires early bind.\n"); return -1; } @@ -1097,7 +1100,7 @@ int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1); } - DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); + LOGP(DMGCP, LOGL_NOTICE, "Configured for Audio Forwarding.\n"); } /* early bind */ @@ -1105,8 +1108,10 @@ int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network for (i = 1; i < number_endpoints; ++i) { struct mgcp_endpoint *endp = &endpoints[i]; endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); - if (bind_rtp(endp) != 0) + if (bind_rtp(endp) != 0) { + LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", endp->rtp_port); return -1; + } } } From 77f7afe08e2529ff7be301f6cf5298207370807f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 3 Feb 2010 09:54:43 +0100 Subject: [PATCH 363/365] [mgcp] Prepare the in process MGCP handling by adding callbacks * Call a callback when the endpoint was created, modified or deleted. This can be used by the BSC MUX to send a MGCP packet over TCP to the right the BSC to allocate the endpoint there with the right data, or it can be used in the BSC to send the right commands to the BTS. --- openbsc/include/openbsc/mgcp.h | 8 ++++++++ openbsc/src/mgcp/mgcp_protocol.c | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 17dd2ec4f..114b39546 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -52,3 +52,11 @@ int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source); int mgcp_send_rsip(int fd, struct sockaddr_in *source); int mgcp_vty_init(void); + +/* endpoint managed */ +#define MGCP_ENDP_CRCX 1 +#define MGCP_ENDP_DLCX 2 +#define MGCP_ENDP_MDCX 3 + +typedef int (*mgcp_change)(int endpoint, int state, int local_rtp, void *); +void mgcp_set_change_cb(mgcp_change cb, void *data); diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index 763dadbcc..d09615743 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -162,6 +162,9 @@ static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *sourc static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *source); static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *source); +static mgcp_change change_cb; +static void *change_cb_data; + static int generate_call_id() { int i; @@ -661,6 +664,9 @@ static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *sourc LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n", ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); + if (change_cb) + change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port, change_cb_data); + return send_with_sdp(fd, endp, "CRCX", trans_id, source); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", @@ -752,6 +758,8 @@ static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *sourc /* modify */ LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); + if (change_cb) + change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port, change_cb_data); return send_with_sdp(fd, endp, "MDCX", trans_id, source); error: @@ -814,6 +822,8 @@ static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *sourc } endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + if (change_cb) + change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port, change_cb_data); return send_response(fd, 250, "DLCX", trans_id, source); @@ -1117,3 +1127,9 @@ int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network return !!forward_ip; } + +void mgcp_set_change_cb(mgcp_change cb, void *data) +{ + change_cb = cb; + change_cb_data = data; +} From 62e836c53394acccc83283ba6b11d462ba8e8483 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 3 Feb 2010 11:03:45 +0100 Subject: [PATCH 364/365] [mgcp] Make the mgcp_protocol generate a struct msgb* Do not directly send data from inside the mgcp_protocol.c implementation. Instead allocate and return a struct msgb*. The caller can then either wrap that into the IPA protcol or directly send it over the UDP socket. --- openbsc/include/openbsc/mgcp.h | 12 ++- openbsc/src/mgcp/mgcp_main.c | 16 +++- openbsc/src/mgcp/mgcp_protocol.c | 125 +++++++++++++++++-------------- 3 files changed, 91 insertions(+), 62 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 114b39546..ee721d88d 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -21,6 +21,11 @@ * */ +#ifndef OPENBSC_MGCP_H +#define OPENBSC_MGCP_H + +#include "msgb.h" + #define RTP_PORT_DEFAULT 4000 extern unsigned int rtp_base_port; @@ -49,8 +54,9 @@ static inline int rtp_calculate_port(int multiplex, int base) } int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network); -int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source); -int mgcp_send_rsip(int fd, struct sockaddr_in *source); + +struct msgb *mgcp_handle_message(struct msgb *msg); +struct msgb *mgcp_create_rsip(void); int mgcp_vty_init(void); /* endpoint managed */ @@ -60,3 +66,5 @@ int mgcp_vty_init(void); typedef int (*mgcp_change)(int endpoint, int state, int local_rtp, void *); void mgcp_set_change_cb(mgcp_change cb, void *data); + +#endif diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c index 134148c62..6d8b3e9c6 100644 --- a/openbsc/src/mgcp/mgcp_main.c +++ b/openbsc/src/mgcp/mgcp_main.c @@ -106,6 +106,7 @@ static int read_call_agent(struct bsc_fd *fd, unsigned int what) struct sockaddr_in addr; socklen_t slen = sizeof(addr); struct msgb *msg; + struct msgb *resp; msg = (struct msgb *) fd->data; @@ -123,14 +124,25 @@ static int read_call_agent(struct bsc_fd *fd, unsigned int what) if (first_request) { first_request = 0; - mgcp_send_rsip(bfd.fd, &addr); + resp = mgcp_create_rsip(); + + if (resp) { + sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0, + (struct sockaddr *) &addr, sizeof(addr)); + msgb_free(resp); + } return 0; } /* handle message now */ msg->l2h = msgb_put(msg, rc); - mgcp_handle_message(bfd.fd, msg, &addr); + resp = mgcp_handle_message(msg); msgb_reset(msg); + + if (resp) { + sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr)); + msgb_free(resp); + } return 0; } diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index d09615743..55edb00bf 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -150,17 +150,17 @@ struct mgcp_msg_ptr { struct mgcp_request { char *name; - int (*handle_request) (int fd, struct msgb *msg, struct sockaddr_in *source); + struct msgb *(*handle_request) (struct msgb *msg); char *debug_name; }; #define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \ { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME }, -static int handle_audit_endpoint(int fd, struct msgb *msg, struct sockaddr_in *source); -static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *source); -static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *source); -static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *source); +static struct msgb *handle_audit_endpoint(struct msgb *msg); +static struct msgb *handle_create_con(struct msgb *msg); +static struct msgb *handle_delete_con(struct msgb *msg); +static struct msgb *handle_modify_con(struct msgb *msg); static mgcp_change change_cb; static void *change_cb_data; @@ -361,32 +361,43 @@ static const struct mgcp_request mgcp_requests [] = { MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection") }; -static int send_response_with_data(int fd, int code, const char *msg, const char *trans, - const char *data, struct sockaddr_in *source) +static struct msgb *mgcp_msgb_alloc(void) +{ + struct msgb *msg; + msg = msgb_alloc_headroom(4096, 128, "MGCP msg"); + if (!msg) + LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n"); + + return msg; +} + +static struct msgb *send_response_with_data(int code, const char *msg, const char *trans, + const char *data) { - char buf[4096]; int len; + struct msgb *res; + + res = mgcp_msgb_alloc(); + if (!res) + return NULL; if (data) { - len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data); + len = snprintf((char *) res->data, 2048, "%d %s\n%s", code, trans, data); } else { - len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans); + len = snprintf((char *) res->data, 2048, "%d %s\n", code, trans); } - LOGP(DMGCP, LOGL_NOTICE, "Sending response: code: %d for '%s'\n", code, msg); - if (source) - return sendto(fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source)); - else - return write(fd, buf, len); + res->l2h = msgb_put(res, len); + LOGP(DMGCP, LOGL_NOTICE, "Sending response: code: %d for '%s'\n", code, res->l2h); + return res; } -static int send_response(int fd, int code, const char *msg, - const char *trans, struct sockaddr_in *source) +static struct msgb *send_response(int code, const char *msg, const char *trans) { - return send_response_with_data(fd, code, msg, trans, NULL, source); + return send_response_with_data(code, msg, trans, NULL); } -static int send_with_sdp(int fd, struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source) +static struct msgb *send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id) { const char *addr = local_ip; char sdp_record[4096]; @@ -402,28 +413,24 @@ static int send_with_sdp(int fd, struct mgcp_endpoint *endp, const char *msg, co "a=rtpmap:%d %s\r\n", endp->ci, addr, endp->rtp_port, audio_payload, audio_payload, audio_name); - return send_response_with_data(fd, 200, msg, trans_id, sdp_record, source); + return send_response_with_data(200, msg, trans_id, sdp_record); } /* send a static record */ -int mgcp_send_rsip(int fd, struct sockaddr_in *source) +struct msgb *mgcp_create_rsip(void) { - char reset[4096]; - int len, rc; + struct msgb *msg; + int len; - len = snprintf(reset, sizeof(reset) - 1, + msg = mgcp_msgb_alloc(); + if (!msg) + return NULL; + + len = snprintf((char *) msg->data, 2048, "RSIP %u *@mgw MGCP 1.0\n" "RM: restart\n", generate_transaction_id()); - if (source) - rc = sendto(fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source)); - else - rc = write(fd, reset, len); - - if (rc < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to send RSIP: %d\n", rc); - } - - return rc; + msg->l2h = msgb_put(msg, len); + return msg; } /* @@ -431,13 +438,14 @@ int mgcp_send_rsip(int fd, struct sockaddr_in *source) * - this can be a command (four letters, space, transaction id) * - or a response (three numbers, space, transaction id) */ -int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source) +struct msgb *mgcp_handle_message(struct msgb *msg) { int code; + struct msgb *resp = NULL; if (msg->len < 4) { LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len); - return -1; + return NULL; } /* attempt to treat it as a response */ @@ -449,14 +457,15 @@ int mgcp_handle_message(int fd, struct msgb *msg, struct sockaddr_in *source) for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) { handled = 1; - mgcp_requests[i].handle_request(fd, msg, source); + resp = mgcp_requests[i].handle_request(msg); + break; } if (!handled) { LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->data[0]); } } - return 0; + return resp; } /* string tokenizer for the poor */ @@ -572,7 +581,7 @@ static int verify_ci(const struct mgcp_endpoint *endp, return 0; } -static int handle_audit_endpoint(int fd, struct msgb *msg, struct sockaddr_in *source) +static struct msgb *handle_audit_endpoint(struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, response; @@ -585,7 +594,7 @@ static int handle_audit_endpoint(int fd, struct msgb *msg, struct sockaddr_in *s else response = 200; - return send_response(fd, response, "AUEP", trans_id, source); + return send_response(response, "AUEP", trans_id); } static int parse_conn_mode(const char* msg, int *conn_mode) @@ -603,7 +612,7 @@ static int parse_conn_mode(const char* msg, int *conn_mode) return ret; } -static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *source) +static struct msgb *handle_create_con(struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; @@ -613,11 +622,11 @@ static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *sourc found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) - return send_response(fd, 500, "CRCX", trans_id, source); + return send_response(500, "CRCX", trans_id); if (endp->ci != CI_UNUSED) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(fd, 500, "CRCX", trans_id, source); + return send_response(500, "CRCX", trans_id); } /* parse CallID C: and LocalParameters L: */ @@ -667,19 +676,19 @@ static int handle_create_con(int fd, struct msgb *msg, struct sockaddr_in *sourc if (change_cb) change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port, change_cb_data); - return send_with_sdp(fd, endp, "CRCX", trans_id, source); + return send_with_sdp(endp, "CRCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); - return send_response(fd, error_code, "CRCX", trans_id, source); + return send_response(error_code, "CRCX", trans_id); error2: LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(fd, error_code, "CRCX", trans_id, source); + return send_response(error_code, "CRCX", trans_id); } -static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *source) +static struct msgb *handle_modify_con(struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; @@ -689,11 +698,11 @@ static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *sourc found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) - return send_response(fd, error_code, "MDCX", trans_id, source); + return send_response(error_code, "MDCX", trans_id); if (endp->ci == CI_UNUSED) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(fd, error_code, "MDCX", trans_id, source); + return send_response(error_code, "MDCX", trans_id); } MSG_TOKENIZE_START @@ -760,19 +769,19 @@ static int handle_modify_con(int fd, struct msgb *msg, struct sockaddr_in *sourc ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); if (change_cb) change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port, change_cb_data); - return send_with_sdp(fd, endp, "MDCX", trans_id, source); + return send_with_sdp(endp, "MDCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); - return send_response(fd, error_code, "MDCX", trans_id, source); + return send_response(error_code, "MDCX", trans_id); error3: - return send_response(fd, error_code, "MDCX", trans_id, source); + return send_response(error_code, "MDCX", trans_id); } -static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *source) +static struct msgb *handle_delete_con(struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; @@ -782,11 +791,11 @@ static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *sourc found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) - return send_response(fd, error_code, "DLCX", trans_id, source); + return send_response(error_code, "DLCX", trans_id); if (endp->ci == CI_UNUSED) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(fd, error_code, "DLCX", trans_id, source); + return send_response(error_code, "DLCX", trans_id); } MSG_TOKENIZE_START @@ -825,16 +834,16 @@ static int handle_delete_con(int fd, struct msgb *msg, struct sockaddr_in *sourc if (change_cb) change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port, change_cb_data); - return send_response(fd, 250, "DLCX", trans_id, source); + return send_response(250, "DLCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); - return send_response(fd, error_code, "DLCX", trans_id, source); + return send_response(error_code, "DLCX", trans_id); error3: - return send_response(fd, error_code, "DLCX", trans_id, source); + return send_response(error_code, "DLCX", trans_id); } /* From 92026f1cef5d8c187302e1ad2103a4826584ec1d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 3 Feb 2010 18:10:07 +0100 Subject: [PATCH 365/365] [mgcp] Refer to the right Company in the Copyright/Copyleft line Use On-Waves instead of the name I made up from the domain name. --- openbsc/include/openbsc/mgcp.h | 2 +- openbsc/src/mgcp/mgcp_main.c | 2 +- openbsc/src/mgcp/mgcp_protocol.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index ee721d88d..5b4aa3eec 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -2,7 +2,7 @@ /* * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by on-waves.com + * (C) 2009 by On-Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c index 6d8b3e9c6..7d318b191 100644 --- a/openbsc/src/mgcp/mgcp_main.c +++ b/openbsc/src/mgcp/mgcp_main.c @@ -3,7 +3,7 @@ /* * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by on-waves.com + * (C) 2009 by On-Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index 55edb00bf..53573f3b2 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -3,7 +3,7 @@ /* * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by on-waves.com + * (C) 2009 by On-Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify