From holger at freyther.de Mon Nov 2 10:33:50 2015 From: holger at freyther.de (Holger Freyther) Date: Mon, 2 Nov 2015 11:33:50 +0100 Subject: [PATCH 5/6] gsup/oap: add OAP to GSUP client. In-Reply-To: <1444643858-15149-6-git-send-email-nhofmeyr@sysmocom.de> References: <1444643858-15149-1-git-send-email-nhofmeyr@sysmocom.de> <1444643858-15149-6-git-send-email-nhofmeyr@sysmocom.de> Message-ID: > On 12 Oct 2015, at 11:57, Neels Hofmeyr wrote: Dear Neels, > diff --git a/openbsc/src/gprs/gprs_gsup_client.c b/openbsc/src/gprs/gprs_gsup_client.c > index 1f9e34c..a332fa7 100644 > --- a/openbsc/src/gprs/gprs_gsup_client.c > +++ b/openbsc/src/gprs/gprs_gsup_client.c > > static int gsup_client_read_cb(struct ipa_client_conn *link, struct msgb *msg) > { > > - OSMO_ASSERT(gsupc->read_cb != NULL); > - gsupc->read_cb(gsupc, msg); > + if (he->proto == IPAC_PROTO_EXT_GSUP) { > + OSMO_ASSERT(gsupc->read_cb != NULL); > + gsupc->read_cb(gsupc, msg); > + /* expecting read_cb() to free msg */ > + } > + else > + if (he->proto == IPAC_PROTO_EXT_OAP) { > + return gsup_client_oap_handle(gsupc, msg); > + /* gsup_client_oap_handle frees msg */ > + } > + else > + goto invalid; the coding style would not have else and if on two different lines. I will fix this myself right now. cheers holger From suraev at alumni.ntnu.no Mon Nov 2 11:18:36 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Mon, 2 Nov 2015 12:18:36 +0100 Subject: CDR-like logs Message-ID: <5637468C.20002@alumni.ntnu.no> Hi. If I enable detailed-enough logs of OpenBSC I can get data regarding call and sms transactions: new state INITIATED -> MO_CALL_PROC, 1 active transactions new state MO_CALL_PROC -> CONNECT_IND, 1 active transactions new state CONNECT_IND -> ACTIVE, 1 active transactions new state ACTIVE -> DISCONNECT_IND, 1 active transactions new state DISCONNECT_IND -> RELEASE_REQ, 1 active transactions new state RELEASE_REQ -> NULL, 0 active transactions However there's no information regarding which mobile is participating in the transaction. Is there some way to get CDR-like data from OpenBSC? Smth like imsi=123 call_to 35345345 duration 12 imsi=53 sms_from 234234 ... cheers, Max. From holger at freyther.de Mon Nov 2 12:40:55 2015 From: holger at freyther.de (Holger Freyther) Date: Mon, 2 Nov 2015 13:40:55 +0100 Subject: [PATCH 2/4] Rename gtp_dublicate, cosmetic. In-Reply-To: <1444651222-27697-3-git-send-email-nhofmeyr@sysmocom.de> References: <1444651222-27697-1-git-send-email-nhofmeyr@sysmocom.de> <1444651222-27697-3-git-send-email-nhofmeyr@sysmocom.de> Message-ID: > On 12 Oct 2015, at 14:00, Neels Hofmeyr wrote: Hi! > Fix spelling dublicate -> duplicate in comments and in (apparently only > statically used) gtp_dublicate(). > > Add two TODO comments. > > Fix other spelling/punctuation and one numbering in comments. > > Remove an opening brace from a comment to not mix up cindent in vim. > > Break a long line. I am sorry to be picky in this regard. If the subject of the change is to fix the typo in comments, code and function names, then please limit yourself to such a fix. Is sed -i s,dublicate,duplicate,g enough for the first round? > --- > gtp/gtp.c | 38 ++++++++++++++++++++------------------ > gtp/gtp.h | 4 ++-- > > -int gtp_dublicate(struct gsn_t *gsn, int version, > +int gtp_duplicate(struct gsn_t *gsn, int version, > struct sockaddr_in *peer, uint16_t seq) > { > - if (!gtp_dublicate(gsn, version, peer, seq)) > + /* TODO describe what this is all about: */ > + if (!gtp_duplicate(gsn, version, peer, seq)) > return 0; > > pdp = &pdp_buf; > memset(pdp, 0, sizeof(struct pdp_t)); > > if (version == 0) { > + /* TODO code dup: get_tid() */ > uint64_t tid = be64toh(((union gtp_packet *)pack)->gtp0.h.tid); > > diff --git a/gtp/gtp.h b/gtp/gtp.h > index 76c967b..7f8ec91 100644 > --- a/gtp/gtp.h > +++ b/gtp/gtp.h > @@ -147,7 +147,7 @@ struct ul16_t; > > struct gtp0_header { /* Descriptions from 3GPP 09.60 */ > uint8_t flags; /* 01 bitfield, with typical values */ > - /* 000..... Version: 1 (0) */ > + /* 000..... Version: 0 */ > > diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c > index 5b56751..13692e0 100644 > --- a/sgsnemu/sgsnemu.c > +++ b/sgsnemu/sgsnemu.c > @@ -1569,7 +1569,7 @@ int main(int argc, char **argv) > 512 = Flat rate, 256 = Hot billing */ > > /* Create context */ > - /* We send this of once. Retransmissions are handled by gtplib */ > + /* We send this off once. Retransmissions are handled by gtplib */ > > - /******************************************************************/ > + /******************************************************************/ > /* Main select loop */ > - /******************************************************************/ > + /******************************************************************/ > > while ((0 != state) && (5 != state)) { > > @@ -1613,7 +1613,7 @@ int main(int argc, char **argv) > state = 3; > } > > - /* Send off disconnect */ > + /* Send disconnect */ > if (3 == state) { > state = 4; > stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */ > @@ -1628,17 +1628,23 @@ int main(int argc, char **argv) > } > } > > - /* Send of ping packets */ > + /* Send ping packets */ > diff = 0; > while ((diff <= 0) && > /* Send off an ICMP ping packet */ > - /*if ( */ (options.pinghost.s_addr) && (2 == state) && > + /*if */ (options.pinghost.s_addr) && (2 == state) && > ((pingseq < options.pingcount) > || (options.pingcount == 0))) { > + > if (!pingseq) > gettimeofday(&firstping, &tz); /* Set time of first ping */ > gettimeofday(&tv, &tz); > - diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */ > + > + /* Microseconds safe up to 500 sec */ > + diff = 1e6 / options.pingrate * pingseq > + - 1e6 * (tv.tv_sec - firstping.tv_sec) > + - (tv.tv_usec - firstping.tv_usec); > + > if (diff <= 0) { > if (options.debug) > printf("Create_ping %d\n", diff); > -- > 2.1.4 > From nhofmeyr at sysmocom.de Mon Nov 2 14:06:29 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 2 Nov 2015 15:06:29 +0100 Subject: [PATCH 5/6] gsup/oap: add OAP to GSUP client. In-Reply-To: References: <1444643858-15149-1-git-send-email-nhofmeyr@sysmocom.de> <1444643858-15149-6-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20151102140629.GA1241@dub5> On Mon, Nov 02, 2015 at 11:33:50AM +0100, Holger Freyther wrote: > > static int gsup_client_read_cb(struct ipa_client_conn *link, struct msgb *msg) > > { > > > > - OSMO_ASSERT(gsupc->read_cb != NULL); > > - gsupc->read_cb(gsupc, msg); > > + if (he->proto == IPAC_PROTO_EXT_GSUP) { > > + OSMO_ASSERT(gsupc->read_cb != NULL); > > + gsupc->read_cb(gsupc, msg); > > + /* expecting read_cb() to free msg */ > > + } > > + else > > + if (he->proto == IPAC_PROTO_EXT_OAP) { > > + return gsup_client_oap_handle(gsupc, msg); > > + /* gsup_client_oap_handle frees msg */ > > + } > > + else > > + goto invalid; > > the coding style would not have else and if on two different lines. I will fix this myself > right now. Yes, indeed. I'm doing that on purpose... the logical idea is that the if conditions all start on the same column. That's my personal dialect where I'm puzzled that no-one else seems to do it this way. IMHO it's the only way to do it nicely ;) that said ... do I really have to lose that bit of personal dialect? Admitted, in a bunch of code where I'm editing, I should always adhere to the local style. But my question is also for the gtphub development. Sure it's nice to have all styles match in osmo code ... I guess I need someone to push me to write "else if" on the same line. Against the styles in openggsn, this style deviation is harmless ... right?? ;) ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Nov 2 18:18:21 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 2 Nov 2015 19:18:21 +0100 Subject: [PATCH 5/6] gsup/oap: add OAP to GSUP client. In-Reply-To: <20151102140629.GA1241@dub5> References: <1444643858-15149-1-git-send-email-nhofmeyr@sysmocom.de> <1444643858-15149-6-git-send-email-nhofmeyr@sysmocom.de> <20151102140629.GA1241@dub5> Message-ID: <20151102181821.GA1678@dub5> On Mon, Nov 02, 2015 at 03:06:29PM +0100, Neels Hofmeyr wrote: > On Mon, Nov 02, 2015 at 11:33:50AM +0100, Holger Freyther wrote: > > > static int gsup_client_read_cb(struct ipa_client_conn *link, struct msgb *msg) > > > { > > > > > > - OSMO_ASSERT(gsupc->read_cb != NULL); > > > - gsupc->read_cb(gsupc, msg); > > > + if (he->proto == IPAC_PROTO_EXT_GSUP) { > > > + OSMO_ASSERT(gsupc->read_cb != NULL); > > > + gsupc->read_cb(gsupc, msg); > > > + /* expecting read_cb() to free msg */ > > > + } > > > + else > > > + if (he->proto == IPAC_PROTO_EXT_OAP) { > > > + return gsup_client_oap_handle(gsupc, msg); > > > + /* gsup_client_oap_handle frees msg */ > > > + } > > > + else > > > + goto invalid; > > > > the coding style would not have else and if on two different lines. I will fix this myself > > right now. > > Yes, indeed. I'm doing that on purpose... the logical idea is that the if > conditions all start on the same column. Now that I'm actually looking at the commit, let's name it: I wrote: if (a) { frizziply(); } else if (b) { frobnicate(); } else goto invalid; and you committed if (a) { frizziply(); } else if (b) { frobnicate(); } else goto invalid; I personally find it mildly ugly, but let's avoid the discussion. To reiterate, I'd like to know whether gtphub should/really must ;) be changed to the latter style. ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Mon Nov 2 19:20:39 2015 From: holger at freyther.de (Holger Freyther) Date: Mon, 2 Nov 2015 20:20:39 +0100 Subject: [PATCH 5/6] gsup/oap: add OAP to GSUP client. In-Reply-To: <20151102181821.GA1678@dub5> References: <1444643858-15149-1-git-send-email-nhofmeyr@sysmocom.de> <1444643858-15149-6-git-send-email-nhofmeyr@sysmocom.de> <20151102140629.GA1241@dub5> <20151102181821.GA1678@dub5> Message-ID: <6A5B69AF-2A84-4901-92EF-DCD8C4DC8A0E@freyther.de> > On 02 Nov 2015, at 19:18, Neels Hofmeyr wrote: > > > > I personally find it mildly ugly, but let's avoid the discussion. > > To reiterate, I'd like to know whether gtphub should/really must ;) be > changed to the latter style. yes. From nhofmeyr at sysmocom.de Wed Nov 4 01:56:21 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 4 Nov 2015 02:56:21 +0100 Subject: [PATCH] gtphub collapsed patch (aka bomb) Message-ID: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> I can talk all day about atomic commits, but chunks of gtphub have transformed twice over (that's me figuring out how to map and resolve GTP data elements), so that half the patches are obsoleted by later ones, in a hard-to-rebase way. So here is a joint patch of gtphub for review. If anyone requests it, I will gladly separate it into a handful of patches adding each subsection / family of API at a time, to better show where each part reaches. Just ask... Many thanks for any reviews! ~Neels Neels Hofmeyr (1): Add GTP hub (code bomb). openbsc/.gitignore | 2 + openbsc/configure.ac | 1 + openbsc/include/openbsc/Makefile.am | 1 + openbsc/include/openbsc/debug.h | 1 + openbsc/include/openbsc/gtphub.h | 345 +++++ openbsc/include/openbsc/vty.h | 1 + openbsc/src/gprs/Makefile.am | 6 + openbsc/src/gprs/gtphub.c | 1794 +++++++++++++++++++++++ openbsc/src/gprs/gtphub_main.c | 283 ++++ openbsc/src/gprs/gtphub_sep.c | 26 + openbsc/src/gprs/gtphub_vty.c | 258 ++++ openbsc/tests/Makefile.am | 2 +- openbsc/tests/gtphub/Makefile.am | 20 + openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf | 5 + openbsc/tests/gtphub/gtphub_nc_test.ok | 7 + openbsc/tests/gtphub/gtphub_nc_test.sh | 85 ++ openbsc/tests/gtphub/gtphub_test.c | 675 +++++++++ openbsc/tests/gtphub/gtphub_test.ok | 3 + openbsc/tests/gtphub/hex2bin.py | 13 + openbsc/tests/testsuite.at | 12 + 20 files changed, 3539 insertions(+), 1 deletion(-) create mode 100644 openbsc/include/openbsc/gtphub.h create mode 100644 openbsc/src/gprs/gtphub.c create mode 100644 openbsc/src/gprs/gtphub_main.c create mode 100644 openbsc/src/gprs/gtphub_sep.c create mode 100644 openbsc/src/gprs/gtphub_vty.c create mode 100644 openbsc/tests/gtphub/Makefile.am create mode 100644 openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf create mode 100644 openbsc/tests/gtphub/gtphub_nc_test.ok create mode 100755 openbsc/tests/gtphub/gtphub_nc_test.sh create mode 100644 openbsc/tests/gtphub/gtphub_test.c create mode 100644 openbsc/tests/gtphub/gtphub_test.ok create mode 100755 openbsc/tests/gtphub/hex2bin.py -- 2.1.4 From nhofmeyr at sysmocom.de Wed Nov 4 01:56:22 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 4 Nov 2015 02:56:22 +0100 Subject: [PATCH] Add GTP hub (code bomb). In-Reply-To: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1446602182-32618-2-git-send-email-nhofmeyr@sysmocom.de> First steps towards a new GTP hub. The aim is to mux GTP connections, so that multiple SGSN <--> GGSN links can pass through a single point. Background: allow having more than one SGSN, possibly in various remote locations. The recent addition of OAP to GSUP is related to the same background idea. (This is a collapsed patch of various changes that do not make sense to review in chronological order anymore, since a lot of it has thorougly transmorphed after it was first committed.) Sponsored-by: On-Waves ehf --- openbsc/.gitignore | 2 + openbsc/configure.ac | 1 + openbsc/include/openbsc/Makefile.am | 1 + openbsc/include/openbsc/debug.h | 1 + openbsc/include/openbsc/gtphub.h | 345 +++++ openbsc/include/openbsc/vty.h | 1 + openbsc/src/gprs/Makefile.am | 6 + openbsc/src/gprs/gtphub.c | 1794 +++++++++++++++++++++++ openbsc/src/gprs/gtphub_main.c | 283 ++++ openbsc/src/gprs/gtphub_sep.c | 26 + openbsc/src/gprs/gtphub_vty.c | 258 ++++ openbsc/tests/Makefile.am | 2 +- openbsc/tests/gtphub/Makefile.am | 20 + openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf | 5 + openbsc/tests/gtphub/gtphub_nc_test.ok | 7 + openbsc/tests/gtphub/gtphub_nc_test.sh | 85 ++ openbsc/tests/gtphub/gtphub_test.c | 675 +++++++++ openbsc/tests/gtphub/gtphub_test.ok | 3 + openbsc/tests/gtphub/hex2bin.py | 13 + openbsc/tests/testsuite.at | 12 + 20 files changed, 3539 insertions(+), 1 deletion(-) create mode 100644 openbsc/include/openbsc/gtphub.h create mode 100644 openbsc/src/gprs/gtphub.c create mode 100644 openbsc/src/gprs/gtphub_main.c create mode 100644 openbsc/src/gprs/gtphub_sep.c create mode 100644 openbsc/src/gprs/gtphub_vty.c create mode 100644 openbsc/tests/gtphub/Makefile.am create mode 100644 openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf create mode 100644 openbsc/tests/gtphub/gtphub_nc_test.ok create mode 100755 openbsc/tests/gtphub/gtphub_nc_test.sh create mode 100644 openbsc/tests/gtphub/gtphub_test.c create mode 100644 openbsc/tests/gtphub/gtphub_test.ok create mode 100755 openbsc/tests/gtphub/hex2bin.py diff --git a/openbsc/.gitignore b/openbsc/.gitignore index ca73db6..fc3d0bf 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -53,6 +53,7 @@ src/utils/isdnsync src/nat/bsc_nat src/gprs/osmo-sgsn src/gprs/osmo-gbproxy +src/gprs/osmo-gtphub src/osmo-bsc_nat/osmo-bsc_nat #tests @@ -78,6 +79,7 @@ tests/mgcp/mgcp_transcoding_test tests/sgsn/sgsn_test tests/subscr/subscr_test tests/oap/oap_test +tests/gtphub/gtphub_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 8b7ce62..098e5b4 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -210,6 +210,7 @@ AC_OUTPUT( tests/sgsn/Makefile tests/subscr/Makefile tests/oap/Makefile + tests/gtphub/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 8a074c2..15c38d1 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,6 +18,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ gprs_gb_parse.h smpp.h meas_feed.h gprs_gsup_messages.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h + gtphub.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 19d8fc2..189ca47 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -33,6 +33,7 @@ enum { DCTRL, DSMPP, DFILTER, + DGTPHUB, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/gtphub.h b/openbsc/include/openbsc/gtphub.h new file mode 100644 index 0000000..ebd4058 --- /dev/null +++ b/openbsc/include/openbsc/gtphub.h @@ -0,0 +1,345 @@ +/* GTP Hub Implementation */ + +/* (C) 2015 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include +#include + + +/* support */ + +/* TODO move to osmocom/core/socket.c ? */ +#include /* for IPPROTO_* etc */ +struct osmo_sockaddr { + struct sockaddr_storage a; + socklen_t l; +}; + +/* TODO move to osmocom/core/socket.c ? */ +/*! \brief Initialize a sockaddr + * \param[out] addr Valid osmo_sockaddr pointer to write result to + * \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC + * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM + * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP + * \param[in] host Remote host name or IP address in string form + * \param[in] port Remote port number in host byte order + * \returns 0 on success, otherwise an error code (from getaddrinfo()). + * + * Copy the first result from a getaddrinfo() call with the given parameters to + * *addr and *addr_len. On error, do not change *addr and return nonzero. + */ +int osmo_sockaddr_init(struct osmo_sockaddr *addr, + uint16_t family, uint16_t type, uint8_t proto, + const char *host, uint16_t port); + +/* Conveniently pass AF_UNSPEC, SOCK_DGRAM and IPPROTO_UDP to + * osmo_sockaddr_init(). */ +static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr, + const char *host, uint16_t port) +{ + return osmo_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host, port); +} + +/*! \brief convert sockaddr to human readable string. + * \param[out] addr_str Valid pointer to a buffer of length addr_str_len. + * \param[in] addr_str_len Size of buffer addr_str points at. + * \param[out] port_str Valid pointer to a buffer of length port_str_len. + * \param[in] port_str_len Size of buffer port_str points at. + * \param[in] addr Binary representation as returned by osmo_sockaddr_init(). + * \param[in] flags flags as passed to getnameinfo(). + * \returns 0 on success, an error code on error. + * + * Return the IPv4 or IPv6 address string and the port (a.k.a. service) string + * representations of the given struct osmo_sockaddr in two caller provided + * char buffers. Flags of (NI_NUMERICHOST | NI_NUMERICSERV) return numeric + * address and port. Either one of addr_str or port_str may be NULL, in which + * case nothing is returned there. + * + * See also osmo_sockaddr_to_str() (less flexible, but much more convenient). */ +int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len, + char *port_str, size_t port_str_len, + const struct osmo_sockaddr *addr, + int flags); + + +/*! \brief conveniently concatenate the parts returned by osmo_sockaddr_to_strs(). + * \param[in] addr Binary representation as returned by osmo_sockaddr_init(). + * \param[in] buf A buffer to use for string operations. + * \param[in] buf_len Length of the buffer. + * \returns Address string (in buffer). + * + * Compose a string of the numeric IP-address and port represented by *addr of + * the form " port ". The returned string is valid until the + * next invocation of this function. + */ +const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr, + char *buf, size_t buf_len); + +/*! \brief conveniently return osmo_sockaddr_to_strb() in a static buffer. + * \param[in] addr Binary representation as returned by osmo_sockaddr_init(). + * \returns Address string in static buffer. + * + * See osmo_sockaddr_to_strb(). + * + * Note: only one osmo_sockaddr_to_str() call will work per print/log + * statement. For two or more, use osmo_sockaddr_to_strb() with a separate + * buffer each. + */ +const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr); + +/*! \brief compare two osmo_sockaddr. + * \param[in] a The first address to compare. + * \param[in] b The other address to compare. + * \returns 0 if equal, otherwise -1 or 1. + */ +int osmo_sockaddr_cmp(const struct osmo_sockaddr *a, const struct osmo_sockaddr *b); + +/*! \brief Overwrite *dst with *src. + * Like memcpy(), but copy only the valid bytes. */ +void osmo_sockaddr_copy(struct osmo_sockaddr *dst, const struct osmo_sockaddr *src); + + +/* general */ + +enum gtphub_port_idx { + GTPH_PORT_CTRL = 0, + GTPH_PORT_USER = 1, + GTPH_PORT_N +}; + +extern const char* const gtphub_port_idx_names[GTPH_PORT_N]; + + +/* A number map assigns a "random" mapped number to each user provided number. + * If the same number is requested multiple times, the same mapped number is + * returned. + * + * Number maps plug into possibly shared pools and expiry queues, for example: + * + * mapA -----------+-> pool1 <-+-- mapB + * {10->1, 11->5} | {1, 2, 3, ...} | {10->2, 11->3} + * | | + * | | + * /-> \-> expiry1 <-/ + * | (30 seconds) + * | + * mapC -------+-----> pool2 <-+-- mapD + * {10->1, 11->3} {1, 2, 3, ...} | {10->2, 11->5} + * | + * expiry2 <-/ + * (60 seconds) + * + * A map contains mappings ("10->1"). Each map needs a number pool, which can + * be shared with other maps. Each new mapping receives a number from the pool, + * which is then unavailable to any other map using the same pool. + * + * A map may point at an expiry queue, in which case all mappings added to it + * are also appended to the expiry queue (using a separate llist entry in the + * mapping). Any number of maps may submit to the same expiry queue, if they + * desire the same expiry timeout. An expiry queue stores the mappings in + * chronological order, so that expiry checking is needed only from the start + * of the queue; hence only mappings with identical expiry timeout can be added + * to the same expiry queue. Upon expiry, a mapping is dropped from the map it + * was submitted at. nr_map_expiry_tick() needs to be called regularly for + * each expiry queue. + * + * A nr_mapping can be embedded in a larger struct: each mapping can have a + * distinct destructor (del_cb), and each del_cb can figure out the container + * struct's address and free that upon expiry or manual deletion. So in expiry + * queues (and even maps), mappings of different container types can be mixed. + * This can help to drastically reduce the amount of unnecessary visits during + * expiry checking, for the case that no expiry is pending. An expiry queue + * always knows which mappings to expire next, because they are right at the + * start of its list. + * + * Mapping allocation and a del_cb are provided by the caller. If del_cb is + * NULL, no deallocation will be done (allowing statically allocated entries). + */ +/* TODO at some point I thought the allocation & del_cb complexity was + * needed/helpful, but by now it seems like overkill. Maybe lose that again. */ + +typedef int nr_t; + +/* Generator for unused numbers. So far this counts upwards from zero, but the + * implementation may change in the future. Treat this like an opaque struct. + * If this becomes random, the tests need to be fixed. */ +struct nr_pool { + nr_t last_nr; + /* TODO add min, max, for safe wrapping */ +}; + +struct nr_mapping; +typedef void (*nr_mapping_del_cb_t)(struct nr_mapping *); + +struct nr_mapping { + struct llist_head entry; + struct llist_head expiry_entry; + time_t expiry; + + void *origin; + nr_t orig; + nr_t repl; + + nr_mapping_del_cb_t del_cb; +}; + +struct nr_map_expiry { + int expiry_in_seconds; + struct llist_head mappings; +}; + +struct nr_map { + struct nr_pool *pool; /* multiple nr_maps can share a nr_pool. */ + struct nr_map_expiry *expiry; + struct llist_head mappings; +}; + + +void nr_pool_init(struct nr_pool *pool); + +/* Return the next unused number from the nr_pool. */ +nr_t nr_pool_next(struct nr_pool *pool); + +/* Initialize the nr_mapping to zero/empty values. */ +void nr_mapping_init(struct nr_mapping *mapping); + +/* Remove the given mapping from its parent map and expiry queue, and call + * mapping->del_cb, if set. */ +void nr_mapping_del(struct nr_mapping *mapping); + +/* Initialize an expiry queue exq. */ +void nr_map_expiry_init(struct nr_map_expiry *exq, int expiry_in_seconds); + +/* Add a new mapping, or restart the expiry timeout for an already listed mapping. */ +void nr_map_expiry_add(struct nr_map_expiry *exq, struct nr_mapping *mapping, time_t now); + +/* Carry out due expiry of mappings. Must be invoked regularly. + * 'now' is the current clock count in seconds and must correspond to the clock + * count passed to nr_map_add(). A monotonous clock counter should be used. */ +int nr_map_expiry_tick(struct nr_map_expiry *exq, time_t now); + +/* Initialize an (already allocated) nr_map, and set the map's number pool. + * Multiple nr_map instances may use the same nr_pool. Set the nr_map's expiry + * queue to exq, so that all added mappings are automatically expired after the + * time configured in exq. exq may be NULL to disable automatic expiry. */ +void nr_map_init(struct nr_map *map, struct nr_pool *pool, + struct nr_map_expiry *exq); + +/* Add a new entry to the map. mapping->orig, mapping->origin and + * mapping->del_cb must be set before calling this function. The remaining + * fields of *mapping will be overwritten. mapping->repl is set to the next + * available mapped number from map->pool. 'now' is the current clock count in + * seconds; if no map->expiry is used, just pass 0 for 'now'. */ +void nr_map_add(struct nr_map *map, struct nr_mapping *mapping, + time_t now); + +/* Return a known mapping from nr_orig and the given origin. If nr_orig is + * unknown, return NULL. */ +struct nr_mapping *nr_map_get(const struct nr_map *map, + void *origin, nr_t nr_orig); + +/* Return a known mapping to nr_repl. If nr_repl is unknown, return NULL. */ +struct nr_mapping *nr_map_get_inv(const struct nr_map *map, nr_t nr_repl); + +/* Remove all mappings from map. */ +void nr_map_clear(struct nr_map *map); + +/* Return 1 if map has no entries, 0 otherwise. */ +int nr_map_empty(const struct nr_map *map); + + +/* config */ + +static const int GTPH_SEQ_MAPPING_EXPIRY_SECS = 30; /* TODO is there a spec for this? */ +static const int GTPH_TEI_MAPPING_EXPIRY_MINUTES = 6 * 60; /* TODO is there a spec for this? */ + +struct gtphub_cfg_addr { + const char *addr_str; + uint16_t port; +}; + +struct gtphub_cfg_bind { + struct gtphub_cfg_addr bind; +}; + +struct gtphub_cfg { + struct gtphub_cfg_bind to_sgsns[GTPH_PORT_N]; + struct gtphub_cfg_bind to_ggsns[GTPH_PORT_N]; + struct gtphub_cfg_addr sgsn_proxy[GTPH_PORT_N]; + struct gtphub_cfg_addr ggsn_proxy[GTPH_PORT_N]; +}; + + +/* state */ + +struct gtphub_peer { + struct llist_head entry; + + struct osmo_sockaddr addr; + struct nr_map tei_map; + struct nr_pool seq_pool; + struct nr_map seq_map; + unsigned int ref_count; /* references from other peers' seq_maps */ + struct gtphub_peer *association[GTPH_PORT_N]; /* One points to "this" */ +}; + +struct gtphub_bind { + struct osmo_fd ofd; + struct nr_pool tei_pool; + + /* list of struct gtphub_peer */ + struct llist_head peers; +}; + +struct gtphub { + struct gtphub_bind to_sgsns[GTPH_PORT_N]; + struct gtphub_bind to_ggsns[GTPH_PORT_N]; + + /* pointers to an entry of to_sgsns[x].peers */ + struct gtphub_peer *sgsn_proxy[GTPH_PORT_N]; + + /* pointers to an entry of to_ggsns[x].peers */ + struct gtphub_peer *ggsn_proxy[GTPH_PORT_N]; + + struct osmo_timer_list gc_timer; + struct nr_map_expiry expire_seq_maps; + struct nr_map_expiry expire_tei_maps; +}; + +struct gtp_packet_desc; + + +/* api */ + +int gtphub_vty_init(void); +int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file); + +/* Initialize and start gtphub: bind to ports, run expiry timers. */ +int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg); + +time_t gtphub_now(void); + +/* Remove expired items, empty peers, ... */ +void gtphub_gc(struct gtphub *hub, time_t now); diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h index 818a20e..bc30e23 100644 --- a/openbsc/include/openbsc/vty.h +++ b/openbsc/include/openbsc/vty.h @@ -36,6 +36,7 @@ enum bsc_vty_node { BSC_NODE, SMPP_NODE, SMPP_ESME_NODE, + GTPHUB_NODE, }; extern int bsc_vty_is_config_node(struct vty *vty, int node); diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index c8e3696..b2d1774 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -11,6 +11,7 @@ noinst_HEADERS = gprs_sndcp.h bin_PROGRAMS = osmo-gbproxy if HAVE_LIBGTP +bin_PROGRAMS += osmo-gtphub if HAVE_LIBCARES bin_PROGRAMS += osmo-sgsn endif @@ -33,3 +34,8 @@ osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \ $(LIBCRYPTO_LIBS) -lrt + +osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sep.c gtphub_vty.c +osmo_gtphub_LDADD = \ + $(top_builddir)/src/libcommon/libcommon.a \ + -lgtp $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) -lrt diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c new file mode 100644 index 0000000..19246e2 --- /dev/null +++ b/openbsc/src/gprs/gtphub.c @@ -0,0 +1,1794 @@ +/* GTP Hub Implementation */ + +/* (C) 2015 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#define GTPHUB_DEBUG 1 + +static const int GTPH_GC_TICK_SECONDS = 1; + +void *osmo_gtphub_ctx; + +#define LOGERR(fmt, args...) \ + LOGP(DGTPHUB, LOGL_ERROR, fmt, ##args) + +#define LOG(fmt, args...) \ + LOGP(DGTPHUB, LOGL_NOTICE, fmt, ##args) + +#define ZERO_STRUCT(struct_pointer) memset(struct_pointer, '\0', sizeof(*(struct_pointer))) + +/* TODO move this to osmocom/core/select.h ? */ +typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what); + +/* TODO move this to osmocom/core/linuxlist.h ? */ +#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next) +#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry) + +/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */ + +enum gtp_rc { + GTP_RC_UNKNOWN = 0, + GTP_RC_TINY = 1, /* no IEs (like ping/pong) */ + GTP_RC_PDU = 2, /* a real packet with IEs */ + + GTP_RC_TOOSHORT = -1, + GTP_RC_UNSUPPORTED_VERSION = -2, + GTP_RC_INVALID_IE = -3, +}; + +struct gtp_packet_desc { + union gtp_packet *data; + int data_len; + int header_len; + int version; + int rc; /* enum gtp_rc */ + unsigned int port_idx; + union gtpie_member *ie[GTPIE_SIZE]; +}; + +/* Validate GTP version 0 data; analogous to validate_gtp1_header(), see there. + */ +void validate_gtp0_header(struct gtp_packet_desc *p) +{ + const struct gtp0_header *pheader = &(p->data->gtp0.h); + p->rc = GTP_RC_UNKNOWN; + p->header_len = 0; + + OSMO_ASSERT(p->data_len >= 1); + OSMO_ASSERT(p->version == 0); + + if (p->data_len < GTP0_HEADER_SIZE) { + LOGERR("GTP0 packet too short: %d\n", p->data_len); + p->rc = GTP_RC_TOOSHORT; + return; + } + + if (p->data_len == GTP0_HEADER_SIZE) { + p->rc = GTP_RC_TINY; + p->header_len = GTP0_HEADER_SIZE; + return; + } + + /* Check packet length field versus length of packet */ + if (p->data_len != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) { + LOGERR("GTP packet length field (%d + %d) does not match" + " actual length (%d)\n", + GTP0_HEADER_SIZE, (int)ntoh16(pheader->length), + p->data_len); + p->rc = GTP_RC_TOOSHORT; + return; + } + + LOG("GTP v0 TID = %" PRIu64 "\n", pheader->tid); + p->header_len = GTP0_HEADER_SIZE; + p->rc = GTP_RC_PDU; +} + +/* Validate GTP version 1 data, and update p->rc with the result, as well as + * p->header_len in case of a valid header. */ +void validate_gtp1_header(struct gtp_packet_desc *p) +{ + const struct gtp1_header_long *pheader = &(p->data->gtp1l.h); + p->rc = GTP_RC_UNKNOWN; + p->header_len = 0; + + OSMO_ASSERT(p->data_len >= 1); + OSMO_ASSERT(p->version == 1); + + if ((p->data_len < GTP1_HEADER_SIZE_LONG) + && (p->data_len != GTP1_HEADER_SIZE_SHORT)){ + LOGERR("GTP packet too short: %d\n", p->data_len); + p->rc = GTP_RC_TOOSHORT; + return; + } + + LOG("|GTPv1\n"); + LOG("| type = %" PRIu8 " 0x%02" PRIx8 "\n", + pheader->type, pheader->type); + LOG("| length = %" PRIu16 " 0x%04" PRIx16 "\n", + ntoh16(pheader->length), ntoh16(pheader->length)); + LOG("| TEI = %" PRIu32 " 0x%08" PRIx32 "\n", + ntoh32(pheader->tei), ntoh32(pheader->tei)); + LOG("| seq = %" PRIu16 " 0x%04" PRIx16 "\n", + ntoh16(pheader->seq), ntoh16(pheader->seq)); + LOG("| npdu = %" PRIu8 " 0x%02" PRIx8 "\n", + pheader->npdu, pheader->npdu); + LOG("| next = %" PRIu8 " 0x%02" PRIx8 "\n", + pheader->next, pheader->next); + + if (p->data_len <= GTP1_HEADER_SIZE_LONG) { + p->rc = GTP_RC_TINY; + p->header_len = GTP1_HEADER_SIZE_SHORT; + return; + } + + /* Check packet length field versus length of packet */ + if (p->data_len != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { + LOGERR("GTP packet length field (%d + %d) does not match" + " actual length (%d)\n", + GTP1_HEADER_SIZE_SHORT, (int)ntoh16(pheader->length), + p->data_len); + p->rc = GTP_RC_TOOSHORT; + return; + } + + p->rc = GTP_RC_PDU; + p->header_len = GTP1_HEADER_SIZE_LONG; +} + +/* Examine whether p->data of size p->data_len has a valid GTP header. Set + * p->version, p->rc and p->header_len. On error, p->rc <= 0 (see enum + * gtp_rc). p->data must point at a buffer with p->data_len set. */ +void validate_gtp_header(struct gtp_packet_desc *p) +{ + p->rc = GTP_RC_UNKNOWN; + + /* Need at least 1 byte in order to check version */ + if (p->data_len < 1) { + LOGERR("Discarding packet - too small: %d\n", p->data_len); + p->rc = GTP_RC_TOOSHORT; + return; + } + + p->version = p->data->flags >> 5; + + switch (p->version) { + case 0: + validate_gtp0_header(p); + break; + case 1: + validate_gtp1_header(p); + break; + default: + LOGERR("Unsupported GTP version: %d\n", p->version); + p->rc = GTP_RC_UNSUPPORTED_VERSION; + break; + } +} + + +/* Return the value of the i'th IMSI IEI by copying to *imsi. + * The first IEI is reached by passing i = 0. + * imsi must point at allocated space of (at least) 8 bytes. + * Return 1 on success, or 0 if not found. */ +static int get_ie_imsi(union gtpie_member *ie[], uint8_t *imsi, int i) +{ + return gtpie_gettv0(ie, GTPIE_IMSI, i, imsi, 8) == 0; +} + +/* Analogous to get_ie_imsi(). nsapi must point at a single uint8_t. */ +static int get_ie_nsapi(union gtpie_member *ie[], uint8_t *nsapi, int i) +{ + return gtpie_gettv1(ie, GTPIE_NSAPI, i, nsapi) == 0; +} + +static char imsi_digit_to_char(uint8_t nibble) +{ + nibble &= 0x0f; + if (nibble > 9) + return (nibble == 0x0f) ? '\0' : '?'; + return '0' + nibble; +} + +/* Return a human readable IMSI string, in a static buffer. + * imsi must point at 8 octets of IMSI IE encoded IMSI data. */ +static const char *imsi_to_str(uint8_t *imsi) +{ + static char str[17]; + int i; + + for (i = 0; i < 8; i++) { + str[2*i] = imsi_digit_to_char(imsi[i]); + str[2*i + 1] = imsi_digit_to_char(imsi[i] >> 4); + } + str[16] = '\0'; + return str; +} + +/* Validate header, and index information elements. Write decoded packet + * information to *res. res->data will point at the given data buffer. On + * error, p->rc is set <= 0 (see enum gtp_rc). */ +static void gtp_decode(const uint8_t *data, int data_len, + unsigned int from_port_idx, + struct gtp_packet_desc *res) +{ + ZERO_STRUCT(res); + res->data = (union gtp_packet*)data; + res->data_len = data_len; + res->port_idx = from_port_idx; + + validate_gtp_header(res); + + if (res->rc <= 0) { + LOGERR("INVALID: dropping GTP packet.\n"); + return; + } + + LOG("Valid GTP header (v%d)\n", res->version); + + if (res->rc != GTP_RC_PDU) { + LOG("no IEs in this GTP packet\n"); + return; + } + + if (gtpie_decaps(res->ie, res->version, + (void*)(data + res->header_len), + res->data_len - res->header_len) != 0) { + res->rc = GTP_RC_INVALID_IE; + return; + } + +#if GTPHUB_DEBUG + int i; + + for (i = 0; i < 10; i++) { + uint8_t imsi[8]; + if (!get_ie_imsi(res->ie, imsi, i)) + break; + LOG("| IMSI %s\n", imsi_to_str(imsi)); + } + + for (i = 0; i < 10; i++) { + uint8_t nsapi; + if (!get_ie_nsapi(res->ie, &nsapi, i)) + break; + LOG("| NSAPI %d\n", (int)nsapi); + } + + for (i = 0; i < 10; i++) { + unsigned int addr_len; + struct in_addr addr; + if (gtpie_gettlv(res->ie, GTPIE_GSN_ADDR, i, &addr_len, &addr, + sizeof(addr)) != 0) + break; + LOG("| addr %s\n", inet_ntoa(addr)); + } + + for (i = 0; i < 10; i++) { + uint32_t tei; + if (gtpie_gettv4(res->ie, GTPIE_TEI_DI, i, &tei) != 0) + break; + LOG("| TEI DI (USER) %" PRIu32 " 0x%08" PRIx32 "\n", + tei, tei); + } + + for (i = 0; i < 10; i++) { + uint32_t tei; + if (gtpie_gettv4(res->ie, GTPIE_TEI_C, i, &tei) != 0) + break; + LOG("| TEI (CTRL) %" PRIu32 " 0x%08" PRIx32 "\n", + tei, tei); + } +#endif +} + + +/* general */ + +const char* const gtphub_port_idx_names[GTPH_PORT_N] = { + "CTRL", + "USER", +}; + +time_t gtphub_now(void) +{ + struct timespec now_tp; + OSMO_ASSERT(clock_gettime(CLOCK_MONOTONIC, &now_tp) >= 0); + return now_tp.tv_sec; +} + + +/* nr_map, nr_pool */ + +void nr_pool_init(struct nr_pool *pool) +{ + *pool = (struct nr_pool){}; +} + +nr_t nr_pool_next(struct nr_pool *pool) +{ + pool->last_nr ++; + + OSMO_ASSERT(pool->last_nr > 0); + /* TODO: gracefully handle running out of TEIs. */ + /* TODO: random TEIs. */ + + return pool->last_nr; +} + +void nr_map_init(struct nr_map *map, struct nr_pool *pool, + struct nr_map_expiry *exq) +{ + ZERO_STRUCT(map); + map->pool = pool; + map->expiry = exq; + INIT_LLIST_HEAD(&map->mappings); +} + +void nr_mapping_init(struct nr_mapping *m) +{ + ZERO_STRUCT(m); + INIT_LLIST_HEAD(&m->entry); + INIT_LLIST_HEAD(&m->expiry_entry); +} + +void nr_map_add(struct nr_map *map, struct nr_mapping *mapping, time_t now) +{ + /* Generate a mapped number */ + mapping->repl = nr_pool_next(map->pool); + + /* Add to the tail to always yield a list sorted by expiry, in + * ascending order. */ + llist_add_tail(&mapping->entry, &map->mappings); + if (map->expiry) + nr_map_expiry_add(map->expiry, mapping, now); +} + +void nr_map_clear(struct nr_map *map) +{ + struct nr_mapping *m; + struct nr_mapping *n; + llist_for_each_entry_safe(m, n, &map->mappings, entry) { + nr_mapping_del(m); + } +} + +int nr_map_empty(const struct nr_map *map) +{ + return llist_empty(&map->mappings); +} + +struct nr_mapping *nr_map_get(const struct nr_map *map, + void *origin, nr_t nr_orig) +{ + struct nr_mapping *mapping; + llist_for_each_entry(mapping, &map->mappings, entry) { + if ((mapping->origin == origin) + && (mapping->orig == nr_orig)) + return mapping; + } + /* Not found. */ + return NULL; +} + +struct nr_mapping *nr_map_get_inv(const struct nr_map *map, nr_t nr_repl) +{ + struct nr_mapping *mapping; + llist_for_each_entry(mapping, &map->mappings, entry) { + if (mapping->repl == nr_repl) { + return mapping; + } + } + /* Not found. */ + return NULL; +} + +void nr_mapping_del(struct nr_mapping *mapping) +{ + OSMO_ASSERT(mapping); + llist_del(&mapping->entry); + llist_del(&mapping->expiry_entry); + if (mapping->del_cb) + (mapping->del_cb)(mapping); +} + +void nr_map_expiry_init(struct nr_map_expiry *exq, int expiry_in_seconds) +{ + ZERO_STRUCT(exq); + exq->expiry_in_seconds = expiry_in_seconds; + INIT_LLIST_HEAD(&exq->mappings); +} + +void nr_map_expiry_add(struct nr_map_expiry *exq, struct nr_mapping *mapping, + time_t now) +{ + mapping->expiry = now + exq->expiry_in_seconds; + + /* Add/move to the tail to always sort by expiry, ascending. */ + llist_del(&mapping->expiry_entry); + llist_add_tail(&mapping->expiry_entry, &exq->mappings); +} + +int nr_map_expiry_tick(struct nr_map_expiry *exq, time_t now) +{ + int expired = 0; + struct nr_mapping *m; + struct nr_mapping *n; + llist_for_each_entry_safe(m, n, &exq->mappings, expiry_entry) { + if (m->expiry <= now) { + nr_mapping_del(m); + expired ++; + } + else { + /* The items are added sorted by expiry. So when we hit + * an unexpired entry, only more unexpired ones will + * follow. */ + break; + } + } + return expired; +} + + +/* gtphub */ + +/* Remove a gtphub_peer from its list and free it. */ +static void gtphub_peer_del(struct gtphub_peer *peer); + +/* From the information in the gtp_packet_desc, return the address of a GGSN. + * Return -1 on error. */ +static struct gtphub_peer *gtphub_resolve_ggsn(struct gtphub *hub, + struct gtp_packet_desc *p, + unsigned int port_idx); + +/* (wrapped by unit test) */ +int gtphub_resolve_ggsn_addr(struct gtphub *hub, + struct osmo_sockaddr *result, + struct gtp_packet_desc *p); + +/* comment: see at definition */ +static struct gtphub_peer *gtphub_peer_new(struct gtphub *hub, + struct gtphub_bind bind[], + unsigned int port_idx, + const char *addr_str, + uint16_t port, + const char *other_addr_str, + uint16_t other_port); + +static struct gtphub_peer *gtphub_peer_new_from_sockaddr(struct gtphub *hub, + struct gtphub_bind bind[], + unsigned int port_idx, + const struct osmo_sockaddr *addr, + int port_override); + +static void gtphub_zero(struct gtphub *hub) +{ + ZERO_STRUCT(hub); +} + +static int gtphub_sock_init(struct osmo_fd *ofd, + const struct gtphub_cfg_addr *addr, + osmo_fd_cb_t cb, + void *data, + int ofd_id) +{ + if (!addr->addr_str) { + LOGERR("Cannot bind: empty address.\n"); + return -1; + } + if (!addr->port) { + LOGERR("Cannot bind: zero port not permitted.\n"); + return -1; + } + + ofd->when = BSC_FD_READ; + ofd->cb = cb; + ofd->data = data; + ofd->priv_nr = ofd_id; + + int rc; + rc = osmo_sock_init_ofd(ofd, + AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, + addr->addr_str, addr->port, + OSMO_SOCK_F_BIND); + if (rc < 1) { + LOGERR("Cannot bind to %s port %d (rc %d)\n", + addr->addr_str, (int)addr->port, rc); + return -1; + } + + return 0; +} + +static void gtphub_gtp_bind_init(struct gtphub_bind *b) +{ + ZERO_STRUCT(b); + + nr_pool_init(&b->tei_pool); + INIT_LLIST_HEAD(&b->peers); +} + +static int gtphub_gtp_bind_start(struct gtphub_bind *b, + const struct gtphub_cfg_bind *cfg, + osmo_fd_cb_t cb, void *cb_data, + unsigned int ofd_id) +{ + if (gtphub_sock_init(&b->ofd, &cfg->bind, cb, cb_data, ofd_id) != 0) + return -1; + return 0; +} + +/* Recv datagram from from->fd, optionally write sender's address to *from_addr. + * Return the number of bytes read, zero on error. */ +static int gtphub_read(const struct osmo_fd *from, + struct osmo_sockaddr *from_addr, + uint8_t *buf, size_t buf_len) +{ + /* recvfrom requires the available length to be set in *from_addr_len. */ + if (from_addr) + from_addr->l = sizeof(from_addr->a); + + errno = 0; + ssize_t received = recvfrom(from->fd, buf, buf_len, 0, + (struct sockaddr*)&from_addr->a, &from_addr->l); + /* TODO use recvmsg and get a MSG_TRUNC flag to make sure the message + * is not truncated. Then maybe reduce buf's size. */ + + if (received <= 0) { + if (errno != EAGAIN) + LOGERR("error: %s\n", strerror(errno)); + return 0; + } + + if (from_addr) { + LOG("from %s\n", osmo_sockaddr_to_str(from_addr)); + } + + if (received <= 0) { + LOGERR("error: %s\n", strerror(errno)); + return 0; + } + + LOG("Received %d\n%s\n", (int)received, osmo_hexdump(buf, received)); + return received; +} + +inline void gtphub_peer_ref_count_inc(struct gtphub_peer *p) +{ + OSMO_ASSERT(p->ref_count < UINT_MAX); + p->ref_count++; +} + +inline void gtphub_peer_ref_count_dec(struct gtphub_peer *p) +{ + OSMO_ASSERT(p->ref_count > 0); + p->ref_count--; +} + +inline uint16_t get_seq(struct gtp_packet_desc *p) +{ + OSMO_ASSERT(p->version == 1); + return ntoh16(p->data->gtp1l.h.seq); +} + +inline void set_seq(struct gtp_packet_desc *p, uint16_t seq) +{ + OSMO_ASSERT(p->version == 1); + p->data->gtp1l.h.seq = hton16(seq); +} + +inline uint32_t get_tei(struct gtp_packet_desc *p) +{ + OSMO_ASSERT(p->version == 1); + return ntoh32(p->data->gtp1l.h.tei); +} + +inline void set_tei(struct gtp_packet_desc *p, uint32_t tei) +{ + OSMO_ASSERT(p->version == 1); + p->data->gtp1l.h.tei = hton32(tei); +} + +static void gtphub_mapping_del_cb(struct nr_mapping *nrm); + +static struct nr_mapping *gtphub_mapping_new() +{ + struct nr_mapping *nrm; + nrm = talloc_zero(osmo_gtphub_ctx, struct nr_mapping); + OSMO_ASSERT(nrm); + + nr_mapping_init(nrm); + nrm->del_cb = gtphub_mapping_del_cb; + return nrm; +} + +static void gtphub_mapping_del_cb(struct nr_mapping *nrm) +{ + struct gtphub_peer *from = nrm->origin; + OSMO_ASSERT(from); + LOG("expired: %d: nr mapping from %s: %d->%d\n", + (int)nrm->expiry, + osmo_sockaddr_to_str(&from->addr), + (int)nrm->orig, (int)nrm->repl); + + gtphub_peer_ref_count_dec(from); + talloc_free(nrm); +} + +static struct nr_mapping *gtphub_mapping_have(struct nr_map *map, + struct gtphub_peer *from, + uint16_t orig_nr) +{ + struct nr_mapping *nrm; + + nrm = nr_map_get(map, from, orig_nr); + + if (!nrm) { + nrm = gtphub_mapping_new(); + nrm->orig = orig_nr; + nrm->origin = from; + nr_map_add(map, nrm, gtphub_now()); + gtphub_peer_ref_count_inc(from); + LOG("peer %p: MAP %d --> %d\n", from, (int)(nrm->orig), (int)(nrm->repl)); + } + else { + /* restart expiry timeout */ + nr_map_expiry_add(map->expiry, nrm, gtphub_now()); + } + + OSMO_ASSERT(nrm); + return nrm; +} + +static int gtphub_map_seq(struct gtp_packet_desc *p, + struct gtphub_peer *from_peer, struct gtphub_peer *to_peer) +{ + /* Store a mapping in to_peer's map, so when we later receive a GTP + * packet back from to_peer, the seq nr can be unmapped back to its + * origin (from_peer here). */ + struct nr_mapping *nrm; + nrm = gtphub_mapping_have(&to_peer->seq_map, from_peer, get_seq(p)); + + /* Change the GTP packet to yield the new, mapped seq nr */ + set_seq(p, nrm->repl); + + return 0; +} + +static struct gtphub_peer *gtphub_unmap_seq(struct gtp_packet_desc *p, + struct gtphub_peer *responding_peer) +{ + OSMO_ASSERT(p->version == 1); + struct nr_mapping *nrm = nr_map_get_inv(&responding_peer->seq_map, + get_seq(p)); + if (!nrm) + return NULL; + LOG("peer %p: UNMAP %d <-- %d\n", nrm->origin, (int)(nrm->orig), (int)(nrm->repl)); + set_seq(p, nrm->orig); + return nrm->origin; +} + +static void gtphub_check_restart_counter(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *from) +{ + /* TODO */ + /* If the peer is sending a Recovery IE (7.7.11) with a restart counter + * that doesn't match the peer's previously sent restart counter, clear + * that peer and cancel PDP contexts. */ +} + +static void gtphub_map_restart_counter(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *from, + struct gtphub_peer *to) +{ + /* TODO */ +} + +/* gtphub_map_ie_teis() and gtphub_unmap_header_tei(): + * + * TEI mapping must happen symmetrically. An SGSN contacts gtphub instead of N + * GGSNs, and a GGSN replies to gtphub for N SGSNs. From either end, TEIs may + * collide: two GGSNs picking the same TEIs, or two SGSNs picking the same + * TEIs. Since the opposite side sees the sender address being gtphub's + * address, TEIs among the SGSNs, and among the GGSNs, must not overlap. If a + * peer sends a TEI already sent before from a peer of the same side, gtphub + * replaces it with a TEI not yet seen from that side and remembers the + * mapping. + * + * Consider two SGSNs A and B contacting two GGSNs C and D thru gtphub. + * + * A: Create PDP Ctx, I have TEI 1. + * ---> gtphub: A has TEI 1, sending 1 for C. + * ---> C: gtphub has TEI 1. + * <--- C: Reponse to TEI 1: I have TEI 11. + * <--- gtphub: ok, telling A: 11. + * A: gtphub's first TEI is 11. (1) + * + * B: Create PDP Ctx, I have TEIs 1. + * ---> gtphub: 1 already taken for C, sending 2 for B. (map) + * ---> C: gtphub also has 2. + * <--- C: Reponse to TEI 2: I have TEI 12. + * <--- gtphub: ok, TEI 2 is actually B with TEI 1. (unmap) + * B: gtphub's first TEI is 12, as far as I can tell. + * + * Now the second GGSN comes into play: + * + * A: Create PDP Ctx, I have TEI 2. + * ---> gtphub: A also has TEI 2, but for D, sending 1. (2) + * ---> D: gtphub has 1. + * <--- D: Reponse to TEI 1: I have TEI 11. + * <--- gtphub: from D, 1 is A. 11 already taken by C, sending 13. (3) + * A: gtphub also has TEI 13. (4) + * + * And some messages routed through: + * + * A: message to TEI 11, see (1). + * ---> gtphub: ok, telling C with TEI 11. + * ---> C: I see, 11 means reply with 1. + * <--- C: Response to TEI 1 + * <--- gtphub: 1 from C is actually for A with TEI 1. + * A: ah, my TEI 1, thanks! + * + * A: message to TEI 13, see (4). + * ---> gtphub: ok, but not 13, D wanted TEI 11 instead, see (3). + * ---> D: I see, 11 means reply with 1. + * <--- D: Response to TEI 1 + * <--- gtphub: 1 from D is actually for A with TEI 2, see (2). + * A: ah, my TEI 2, thanks! + * + * What if a GGSN initiates a request: + * + * <--- D: Request to gtphub TEI 1 + * <--- gtphub: 1 from D is for A with 2, see (2). + * A: my TEI 2 means reply with 13. + * ---> gtphub: 13 was D with 11, see (3). + * ---> D: 11 from gtphub: a reply to my request for TEI 1. + * + * Note that usually, it's the sequence numbers that route a response back to + * the requesting peer. Nevertheless, the TEI mappings must be carried out to + * replace the TEIs in the GTP packet that is relayed. + * + * Also note: the TEI in the GTP header is "reversed" from the TEI in the IEs: + * the TEI in the header is used to send something *to* a peer, while the TEI + * in e.g. a Create PDP Context Request's IE is for routing messages *back* + * later. */ + +static int gtphub_unmap_header_tei(struct gtphub_peer **to_peer_p, + struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *from_peer) +{ + OSMO_ASSERT(p->version == 1); + + struct nr_mapping *nrm; + uint32_t tei; + + *to_peer_p = NULL; + + /* If the header's TEI is zero, no PDP context has been established + * yet. If nonzero, a mapping should actually already exist for this + * TEI, since it must have been announced in a PDP context creation. */ + tei = get_tei(p); + + if (!tei) + return 0; + + /* to_peer has previously announced a TEI, which was stored and + * mapped in from_peer's tei_map. */ + nrm = nr_map_get_inv(&from_peer->tei_map, tei); + if (!nrm) { + LOGERR("Received unknown TEI %" PRIu32 " from %s\n", + tei, osmo_sockaddr_to_str(&from_peer->addr)); + return -1; + } + + struct gtphub_peer *to_peer = nrm->origin; + uint32_t unmapped_tei = nrm->orig; + set_tei(p, unmapped_tei); + + char buf[256]; + LOG("Unmapped TEI coming from %p %s: %d -> %d (to %s)\n", + from_peer, osmo_sockaddr_to_str(&from_peer->addr), tei, + unmapped_tei, osmo_sockaddr_to_strb(&to_peer->addr, buf, sizeof(buf))); + + *to_peer_p = to_peer; + return 0; +} + +/* In a packet coming from from_peer, find TEI IE with type number ie_type. If + * it does not exist yet, create a mapping for the TEI in to_peer's map. A + * message coming from to_peer can then be addressed to the (new) mapped TEI, + * and will trace back to from_peer and the TEI in this p's IE. + * + * Also replace the TEI with a mapped TEI in the GTP packet's data buffer. The + * buffer can then be sent on to to_peer. */ +static int gtphub_map_tei_ie(struct gtp_packet_desc *p, + uint8_t ie_type, int mandatory, + struct gtphub_peer *from_peer, + struct gtphub_peer *to_peer, + unsigned int port_idx) +{ + int ie_idx; + uint32_t tei; + uint32_t mapped_tei; + + OSMO_ASSERT(from_peer); + OSMO_ASSERT(to_peer); + + from_peer = from_peer->association[port_idx]; + to_peer = to_peer->association[port_idx]; + + if (!(from_peer && to_peer)) { + LOGERR("Missing peer in %s plane /" + " missing Create PDP Context Request\n", + gtphub_port_idx_names[port_idx]); + return -1; + } + + ie_idx = gtpie_getie(p->ie, ie_type, 0); + if (ie_idx < 0) { + if (! mandatory) + return 0; + + LOGERR("Create PDP Context Request: Invalid: missing IE %d\n", ie_type); + return -1; + } + tei = ntoh32(p->ie[ie_idx]->tv4.v); + /* When to_peer later sends the mapped tei for this tei, we + * want to obtain this tei and from_peer. */ + struct nr_mapping *nrm; + nrm = gtphub_mapping_have(&to_peer->tei_map, + from_peer, tei); + + mapped_tei = nrm->repl; + p->ie[ie_idx]->tv4.v = hton32(mapped_tei); + + char buf[256]; + LOG("Storing new %s TEI in peer %p %s's map: (from %s, TEI %d) -> TEI %d\n", + gtphub_port_idx_names[port_idx], + to_peer, + osmo_sockaddr_to_str(&to_peer->addr), + osmo_sockaddr_to_strb(&from_peer->addr, buf, sizeof(buf)), + tei, mapped_tei); + + return 0; +} + +/* The responding peer does not know that it is going to be the responding peer + * yet, but it must already be resolved and initialized. The GTP packet is + * coming from requesting_peer.*/ +static int gtphub_handle_create_pdp_req(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *requesting_peer, + struct gtphub_peer *responding_peer) +{ + /* This is a Create PDP Context Request. Expecting this + * to come from the SGSN side. */ + /* TODO enforce? */ + int rc; + + rc = gtphub_map_tei_ie(p, GTPIE_TEI_DI, 1, + requesting_peer, responding_peer, + GTPH_PORT_USER); + if (rc < 0) + return rc; + + rc = gtphub_map_tei_ie(p, GTPIE_TEI_C, 1, + requesting_peer, responding_peer, + GTPH_PORT_CTRL); + return rc; +} + +/* The GTP packet is coming from responding_peer; "responding peer" in the + * sense of the Create PDP Context messages. requesting_peer will have been + * figured out from sequence number and/or header TEI. */ +static int gtphub_handle_create_pdp_resp(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *responding_peer, + struct gtphub_peer *requesting_peer) +{ + /* This is a Create PDP Context Response. Expecting this + * to come from the GGSN side. */ + /* TODO enforce? */ + int rc; + + rc = gtphub_map_tei_ie(p, GTPIE_TEI_DI, 0, + responding_peer, requesting_peer, + GTPH_PORT_USER); + if (rc < 0) + return rc; + + rc = gtphub_map_tei_ie(p, GTPIE_TEI_C, 0, + responding_peer, requesting_peer, + GTPH_PORT_CTRL); + return rc; +} + +static int gtphub_map_ie_teis(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *from_peer, + struct gtphub_peer *to_peer) +{ + OSMO_ASSERT(p->version == 1); + struct gtp1_header_long *h = &p->data->gtp1l.h; + uint8_t type = ntoh8(h->type); + + switch (type) { + case GTP_CREATE_PDP_REQ: + gtphub_handle_create_pdp_req(hub, p, from_peer, to_peer); + break; + + case GTP_CREATE_PDP_RSP: + gtphub_handle_create_pdp_resp(hub, p, from_peer, to_peer); + break; + + default: + break; + } + return 0; +} + +static void gtphub_replace_addresses(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *from, + struct gtphub_bind *from_bind, + struct gtphub_peer *to, + struct gtphub_bind *to_bind) +{ + /* TODO */ +} + +static int gtphub_write(struct osmo_fd *to, + struct osmo_sockaddr *to_addr, + uint8_t *buf, size_t buf_len) +{ + errno = 0; + ssize_t sent = sendto(to->fd, buf, buf_len, 0, + (struct sockaddr*)&to_addr->a, to_addr->l); + + if (to_addr) { + LOG("to %s\n", osmo_sockaddr_to_str(to_addr)); + } + + if (sent == -1) { + LOGERR("error: %s\n", strerror(errno)); + return -EINVAL; + } + + if (sent != buf_len) + LOGERR("sent(%d) != data_len(%d)\n", (int)sent, (int)buf_len); + else + LOG("Sent %d\n%s\n", (int)sent, osmo_hexdump(buf, sent)); + + return 0; +} + +int gtphub_from_ggsns_handle_buf(struct gtphub *hub, + unsigned int port_idx, + const struct osmo_sockaddr *from_addr, + uint8_t *buf, + size_t received, + struct osmo_fd **to_ofd, + struct osmo_sockaddr **to_addr); + +static struct gtphub_peer *gtphub_peer_find(const struct gtphub_bind *bind, + const struct osmo_sockaddr *addr); + +static int from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what) +{ + unsigned int port_idx = from_ggsns_ofd->priv_nr; + OSMO_ASSERT(port_idx < GTPH_PORT_N); + LOG("\n\n=== reading from GGSN (%s)\n", gtphub_port_idx_names[port_idx]); + if (!(what & BSC_FD_READ)) + return 0; + + struct gtphub *hub = from_ggsns_ofd->data; + + static uint8_t buf[4096]; + struct osmo_sockaddr from_addr; + struct osmo_sockaddr *to_addr; + struct osmo_fd *to_ofd; + size_t len; + + len = gtphub_read(from_ggsns_ofd, &from_addr, buf, sizeof(buf)); + if (len < 1) + return 0; + + len = gtphub_from_ggsns_handle_buf(hub, port_idx, &from_addr, buf, len, + &to_ofd, &to_addr); + if (len < 1) + return 0; + + return gtphub_write(to_ofd, to_addr, buf, len); +} + +static int gtphub_unmap(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer *from, + struct gtphub_peer *to_proxy, + struct gtphub_peer **final_unmapped, + struct gtphub_peer **unmapped_from_seq, + struct gtphub_peer **unmapped_from_tei) +{ + /* Always (try to) unmap sequence and TEI numbers, which need to be + * replaced in the packet. Either way, give precedence to the proxy, if + * configured. */ + + struct gtphub_peer *from_seq = NULL; + struct gtphub_peer *from_tei = NULL; + struct gtphub_peer *unmapped = NULL; + + if (unmapped_from_seq) + *unmapped_from_seq = from_seq; + if (unmapped_from_tei) + *unmapped_from_tei = from_tei; + if (final_unmapped) + *final_unmapped = unmapped; + + from_seq = gtphub_unmap_seq(p, from); + + if (gtphub_unmap_header_tei(&from_tei, hub, p, from) < 0) + return -1; + + if (from_seq && from_tei && (from_seq != from_tei)) { + char b0[256]; + char b1[256]; + LOGERR("Seq unmap and TEI unmap yield two different peers. Using seq unmap." + "(from %s %s: seq %d yields %s, tei %u yields %s)\n", + gtphub_port_idx_names[p->port_idx], + osmo_sockaddr_to_str(&from->addr), + (int)get_seq(p), + osmo_sockaddr_to_strb(&from_seq->addr, b0, sizeof(b0)), + (int)get_tei(p), + osmo_sockaddr_to_strb(&from_tei->addr, b1, sizeof(b1)) + ); + } + unmapped = (from_seq? from_seq : from_tei); + + if (unmapped && to_proxy && (unmapped != to_proxy)) { + char buf[256]; + LOGERR("Unmap yields a different peer than the configured proxy. Using proxy." + " unmapped: %s proxy: %s\n", + osmo_sockaddr_to_str(&unmapped->addr), + osmo_sockaddr_to_strb(&to_proxy->addr, buf, sizeof(buf)) + ); + } + unmapped = (to_proxy? to_proxy : unmapped); + + if (!unmapped) { + /* Return no error, but returned pointers are all NULL. */ + return 0; + } + + LOG("from seq %p; from tei %p; unmapped => %p\n", + from_seq, from_tei, unmapped); + + if (unmapped_from_seq) + *unmapped_from_seq = from_seq; + if (unmapped_from_tei) + *unmapped_from_tei = from_tei; + if (final_unmapped) + *final_unmapped = unmapped; + return 0; +} + +/* Parse buffer as GTP packet, replace elements in-place and return the ofd and + * address to forward to. Return the number of bytes to forward, 0 or less on + * failure. Return the fd and address to forward to in to_ofd and to_addr. */ +int gtphub_from_ggsns_handle_buf(struct gtphub *hub, + unsigned int port_idx, + const struct osmo_sockaddr *from_addr, + uint8_t *buf, + size_t received, + struct osmo_fd **to_ofd, + struct osmo_sockaddr **to_addr) +{ + LOG("<- rx from GGSN %s\n", osmo_sockaddr_to_str(from_addr)); + + static struct gtp_packet_desc p; + gtp_decode(buf, received, port_idx, &p); + + if (p.rc <= 0) + return -1; + + /* If a GGSN proxy is configured, check that it's indeed that proxy + * talking to us. */ + struct gtphub_peer *ggsn = hub->ggsn_proxy[port_idx]; + if (ggsn && (osmo_sockaddr_cmp(&ggsn->addr, from_addr) != 0)) { + char buf[256]; + LOGERR("Rejecting: GGSN proxy configured, but GTP packet" + " received on GGSN bind is from another sender:" + " proxy: %s sender: %s\n", + osmo_sockaddr_to_str(&ggsn->addr), + osmo_sockaddr_to_strb(from_addr, buf, sizeof(buf))); + return -1; + } + + if (!ggsn) { + /* If any PDP context has been created, we already have an + * entry for this GGSN. If we don't have an entry, the GGSN has + * nothing to tell us about. */ + ggsn = gtphub_peer_find(&hub->to_ggsns[port_idx], from_addr); + LOG("Found peer %p for %s\n", ggsn, osmo_sockaddr_to_str(from_addr)); + } + + if (!ggsn) { + LOGERR("no ggsn\n"); + return -1; + } + + struct gtphub_peer *sgsn_from_seq; + struct gtphub_peer *sgsn; + if (gtphub_unmap(hub, &p, ggsn, + hub->sgsn_proxy[port_idx], + &sgsn, &sgsn_from_seq, NULL) + != 0) { + return -1; + } + + if (!sgsn) { + LOGERR("No SGSN to send to. Dropping packet.\n"); + return -1; + } + + gtphub_check_restart_counter(hub, &p, ggsn); + gtphub_map_restart_counter(hub, &p, ggsn, sgsn); + gtphub_replace_addresses(hub, &p, + ggsn, &hub->to_ggsns[port_idx], + sgsn, &hub->to_sgsns[port_idx]); + + /* If the GGSN is replying to an SGSN request, the sequence nr has + * already been unmapped above (sgsn_from_seq != NULL), and we need not + * create a new mapping. */ + if (!sgsn_from_seq) + gtphub_map_seq(&p, ggsn, sgsn); + + /* If IEs announce new TEIs, map those. */ + if (gtphub_map_ie_teis(hub, &p, ggsn, sgsn) < 0) { + LOGERR("Dropping invalid packet\n"); + return -1; + } + + *to_ofd = &hub->to_sgsns[port_idx].ofd; + *to_addr = &sgsn->addr; + + return received; +} + +int gtphub_from_sgsns_handle_buf(struct gtphub *hub, + unsigned int port_idx, + const struct osmo_sockaddr *from_addr, + uint8_t *buf, + size_t received, + struct osmo_fd **to_ofd, + struct osmo_sockaddr **to_addr); + +static int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what) +{ + unsigned int port_idx = from_sgsns_ofd->priv_nr; + OSMO_ASSERT(port_idx < GTPH_PORT_N); + LOG("\n\n=== reading from SGSN (%s)\n", gtphub_port_idx_names[port_idx]); + + if (!(what & BSC_FD_READ)) + return 0; + + struct gtphub *hub = from_sgsns_ofd->data; + + static uint8_t buf[4096]; + struct osmo_sockaddr from_addr; + struct osmo_sockaddr *to_addr; + struct osmo_fd *to_ofd; + size_t len; + + len = gtphub_read(from_sgsns_ofd, &from_addr, buf, sizeof(buf)); + if (len < 1) + return 0; + + len = gtphub_from_sgsns_handle_buf(hub, port_idx, &from_addr, buf, len, + &to_ofd, &to_addr); + if (len < 1) + return 0; + + return gtphub_write(to_ofd, to_addr, buf, len); +} + +/* Parse buffer as GTP packet, replace elements in-place and return the ofd and + * address to forward to. Return the number of bytes to forward, 0 or less on + * failure. Return the fd and address to forward to in to_ofd and to_addr. */ +int gtphub_from_sgsns_handle_buf(struct gtphub *hub, + unsigned int port_idx, + const struct osmo_sockaddr *from_addr, + uint8_t *buf, + size_t received, + struct osmo_fd **to_ofd, + struct osmo_sockaddr **to_addr) +{ + LOG("-> rx from SGSN %s\n", osmo_sockaddr_to_str(from_addr)); + + static struct gtp_packet_desc p; + gtp_decode(buf, received, port_idx, &p); + + if (p.rc <= 0) + return -1; + + /* If an SGSN proxy is configured, check that it's indeed that proxy + * talking to us. */ + struct gtphub_peer *sgsn = hub->sgsn_proxy[port_idx]; + if (sgsn && (osmo_sockaddr_cmp(&sgsn->addr, from_addr) != 0)) { + char buf[256]; + LOGERR("Rejecting: SGSN proxy configured, but GTP packet" + " received on SGSN bind is from another sender: " + "proxy: %s sender: %s\n", + osmo_sockaddr_to_str(from_addr), + osmo_sockaddr_to_strb(&sgsn->addr, buf, sizeof(buf))); + return -1; + } + + if (!sgsn) { + /* TODO this is a worthless hack to test things. Instead: + sgsn = gtphub_sgsn_get(hub, ...); */ + sgsn = llist_first(&hub->to_sgsns[port_idx].peers, + struct gtphub_peer, entry); + if (!sgsn) { + sgsn = gtphub_peer_new_from_sockaddr(hub, + hub->to_sgsns, + port_idx, + from_addr, + -1); + if (!sgsn) { + LOG("Packet dropped by preliminary debug code.\n"); + return -1; + } + LOG("Created peer %p\n", sgsn); + } + + if (osmo_sockaddr_cmp(&sgsn->addr, from_addr) != 0) { + char buf[256]; + LOG("SGSN changed its address from %s to %s\n", + osmo_sockaddr_to_str(&sgsn->addr), + osmo_sockaddr_to_strb(from_addr, buf, sizeof(buf))); + memcpy(&sgsn->addr, from_addr, sizeof(sgsn->addr)); + } + LOG("Peer %p = %s\n", sgsn, osmo_sockaddr_to_str(&sgsn->addr)); + } + + struct gtphub_peer *ggsn_from_seq; + struct gtphub_peer *ggsn; + if (gtphub_unmap(hub, &p, sgsn, + hub->ggsn_proxy[port_idx], + &ggsn, &ggsn_from_seq, NULL) + != 0) { + return -1; + } + + /* See what our GGSN guess would be from the packet data per se. */ + /* TODO maybe not do this always? */ + struct gtphub_peer *ggsn_from_packet; + ggsn_from_packet = gtphub_resolve_ggsn(hub, &p, port_idx); + + if (ggsn_from_packet && ggsn + && (ggsn_from_packet != ggsn)) { + char buf[256]; + LOGERR("GGSN implied from packet does not match unmapped" + " GGSN, using unmapped GGSN:" + " from packet: %s unmapped: %s\n", + osmo_sockaddr_to_str(&ggsn_from_packet->addr), + osmo_sockaddr_to_strb(&ggsn_from_packet->addr, + buf, sizeof(buf))); + /* TODO return -1; ? */ + } + + if (!ggsn) + ggsn = ggsn_from_packet; + + if (!ggsn) { + LOGERR("No GGSN to send to. Dropping packet.\n"); + return -1; + } + + gtphub_check_restart_counter(hub, &p, sgsn); + gtphub_map_restart_counter(hub, &p, sgsn, ggsn); + gtphub_replace_addresses(hub, &p, + sgsn, &hub->to_sgsns[port_idx], + ggsn, &hub->to_ggsns[port_idx]); + + /* If the SGSN is replying to a GGSN request, the sequence nr has + * already been unmapped above (unmap_ggsn != NULL), and we need not + * create a new outgoing sequence map. */ + if (!ggsn_from_seq) + gtphub_map_seq(&p, sgsn, ggsn); + + /* If IEs announce new TEIs, map those. */ + if (gtphub_map_ie_teis(hub, &p, sgsn, ggsn) < 0) { + LOGERR("Dropping invalid packet\n"); + return -1; + } + + *to_ofd = &hub->to_ggsns[port_idx].ofd; + *to_addr = &ggsn->addr; + + return received; +} + +static void gtphub_gc_bind(struct gtphub *hub, struct gtphub_bind *b) +{ + struct gtphub_peer *p, *n; + llist_for_each_entry_safe(p, n, &b->peers, entry) { + + if ((!p->ref_count) + && nr_map_empty(&p->seq_map)) { + + LOG("expired: peer %s\n", + osmo_sockaddr_to_str(&p->addr)); + gtphub_peer_del(p); + } + } +} + +void gtphub_gc(struct gtphub *hub, time_t now) +{ + int expired; + expired = nr_map_expiry_tick(&hub->expire_seq_maps, now); + expired += nr_map_expiry_tick(&hub->expire_tei_maps, now); + + /* ... */ + + if (expired) { + int i; + for (i = 0; i < GTPH_PORT_N; i++) { + gtphub_gc_bind(hub, &hub->to_sgsns[i]); + gtphub_gc_bind(hub, &hub->to_ggsns[i]); + } + } +} + +static void gtphub_gc_cb(void *data) +{ + struct gtphub *hub = data; + gtphub_gc(hub, gtphub_now()); + osmo_timer_schedule(&hub->gc_timer, GTPH_GC_TICK_SECONDS, 0); +} + +static void gtphub_gc_start(struct gtphub *hub) +{ + hub->gc_timer.cb = gtphub_gc_cb; + hub->gc_timer.data = hub; + + osmo_timer_schedule(&hub->gc_timer, GTPH_GC_TICK_SECONDS, 0); +} + +/* called by unit tests */ +void gtphub_init(struct gtphub *hub) +{ + gtphub_zero(hub); + + nr_map_expiry_init(&hub->expire_seq_maps, GTPH_SEQ_MAPPING_EXPIRY_SECS); + nr_map_expiry_init(&hub->expire_tei_maps, GTPH_TEI_MAPPING_EXPIRY_MINUTES * 60); + + int port_idx; + for (port_idx = 0; port_idx < GTPH_PORT_N; port_idx++) { + gtphub_gtp_bind_init(&hub->to_ggsns[port_idx]); + gtphub_gtp_bind_init(&hub->to_sgsns[port_idx]); + } +} + +int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg) +{ + int rc; + + gtphub_init(hub); + + int port_idx; + for (port_idx = 0; port_idx < GTPH_PORT_N; port_idx++) { + rc = gtphub_gtp_bind_start(&hub->to_ggsns[port_idx], + &cfg->to_ggsns[port_idx], + from_ggsns_read_cb, hub, port_idx); + if (rc) { + LOGERR("Failed to bind for GGSNs (%s)\n", + gtphub_port_idx_names[port_idx]); + return rc; + } + + rc = gtphub_gtp_bind_start(&hub->to_sgsns[port_idx], + &cfg->to_sgsns[port_idx], + from_sgsns_read_cb, hub, port_idx); + if (rc) { + LOGERR("Failed to bind for SGSNs (%s)\n", + gtphub_port_idx_names[port_idx]); + return rc; + } + } + + /* SGSN proxy. Trigger only on the control port address. */ + if (cfg->sgsn_proxy[GTPH_PORT_CTRL].addr_str) { + struct gtphub_cfg_addr *addr_c = &cfg->sgsn_proxy[GTPH_PORT_CTRL]; + struct gtphub_cfg_addr *addr_u = &cfg->sgsn_proxy[GTPH_PORT_USER]; + + struct gtphub_peer *sgsn_c; + struct gtphub_peer *sgsn_u; + sgsn_c = gtphub_peer_new(hub, hub->to_sgsns, GTPH_PORT_CTRL, + addr_c->addr_str, addr_c->port, + addr_u->addr_str, addr_u->port); + sgsn_u = sgsn_c->association[GTPH_PORT_USER]; + + hub->sgsn_proxy[GTPH_PORT_CTRL] = sgsn_c; + hub->sgsn_proxy[GTPH_PORT_USER] = sgsn_u; + + /* This is *the* proxy SGSN. Make sure it is never expired. */ + gtphub_peer_ref_count_inc(sgsn_c); + gtphub_peer_ref_count_inc(sgsn_u); + + LOG("Using SGSN %s proxy %s port %d\n", + gtphub_port_idx_names[GTPH_PORT_CTRL], + addr_c->addr_str, + (int)addr_c->port); + LOG("Using SGSN %s proxy %s port %d\n", + gtphub_port_idx_names[GTPH_PORT_USER], + addr_u->addr_str, + (int)addr_u->port); + } + + /* GGSN proxy. Trigger only on the control port address. */ + if (cfg->ggsn_proxy[GTPH_PORT_CTRL].addr_str) { + struct gtphub_cfg_addr *addr_c = &cfg->ggsn_proxy[GTPH_PORT_CTRL]; + struct gtphub_cfg_addr *addr_u = &cfg->ggsn_proxy[GTPH_PORT_USER]; + + struct gtphub_peer *ggsn_c; + struct gtphub_peer *ggsn_u; + ggsn_c = gtphub_peer_new(hub, hub->to_ggsns, GTPH_PORT_CTRL, + addr_c->addr_str, addr_c->port, + addr_u->addr_str, addr_u->port); + ggsn_u = ggsn_c->association[GTPH_PORT_USER]; + + hub->ggsn_proxy[GTPH_PORT_CTRL] = ggsn_c; + hub->ggsn_proxy[GTPH_PORT_USER] = ggsn_u; + + /* This is *the* proxy GGSN. Make sure it is never expired. */ + gtphub_peer_ref_count_inc(ggsn_c); + gtphub_peer_ref_count_inc(ggsn_u); + + LOG("Using GGSN %s proxy %s port %d\n", + gtphub_port_idx_names[GTPH_PORT_CTRL], + addr_c->addr_str, + (int)addr_c->port); + LOG("Using GGSN %s proxy %s port %d\n", + gtphub_port_idx_names[GTPH_PORT_USER], + addr_u->addr_str, + (int)addr_u->port); + } + + gtphub_gc_start(hub); + return 0; +} + +static struct gtphub_peer *_gtphub_peer_new(struct gtphub *hub, + struct gtphub_bind bind[], + unsigned int port_idx, + const char *addr_str, + uint16_t port) +{ + struct gtphub_peer *n = talloc_zero(osmo_gtphub_ctx, struct gtphub_peer); + + nr_map_init(&n->tei_map, &bind[port_idx].tei_pool, &hub->expire_tei_maps); + + nr_pool_init(&n->seq_pool); + nr_map_init(&n->seq_map, &n->seq_pool, &hub->expire_seq_maps); + + /* TODO use something random to pick the initial sequence nr. + 0x6d31 produces the ASCII character sequence 'm1', currently used in + gtphub_nc_test.sh. */ + n->seq_pool.last_nr = 0x6d31 - 1; + + llist_add(&n->entry, &bind[port_idx].peers); + + if (!port) { + port = (port_idx == GTPH_PORT_USER)? GTP1U_PORT : GTP1C_PORT; + } + + LOG("New peer: %s %s %d\n", gtphub_port_idx_names[port_idx], addr_str, + (int)port); + + if (osmo_sockaddr_init_udp(&n->addr, addr_str, port) != 0) { + LOGERR("Cannot resolve '%s port %d'\n", + addr_str, (int)port); + talloc_free(n); + return NULL; + } + + return n; +} + +/* Create two new gtphub_peer instances added to bind[CTRL]->peers and + * bind[USER]->peers. + * Initialize: + * - point association[port_idx]es to the respective instances, + * - resolve the provided addresses, + * - set default port numbers for the respective planes, if a given port is 0. + * addr_str and port define the peer for the GTP plane indicated by port_idx. + * other_addr_str and other_port are used to initialize the peer on the + * respective other plane (if port_idx is GTPH_PORT_CTRL, other_addr_str and + * other_port are for the User plane). other_addr_str may be NULL, in which + * case addr_str is used for both planes. One or both ports may be 0, in which + * case the default port for that plane is used. Return a pointer to the new + * instance in the plane, or NULL on error. */ +static struct gtphub_peer *gtphub_peer_new(struct gtphub *hub, + struct gtphub_bind bind[], + unsigned int port_idx, + const char *addr_str, + uint16_t port, + const char *other_addr_str, + uint16_t other_port) +{ + if (!other_addr_str) + other_addr_str = addr_str; + + const char *addr_str_c; + const char *addr_str_u; + uint16_t port_c; + uint16_t port_u; + if (port_idx == GTPH_PORT_CTRL) { + addr_str_c = addr_str; + addr_str_u = other_addr_str; + port_c = port; + port_u = other_port; + } + else { + OSMO_ASSERT(port_idx == GTPH_PORT_USER); + addr_str_u = addr_str; + addr_str_c = other_addr_str; + port_u = port; + port_c = other_port; + } + + struct gtphub_peer *c = _gtphub_peer_new(hub, bind, GTPH_PORT_CTRL, + addr_str_c, port_c); + struct gtphub_peer *u = _gtphub_peer_new(hub, bind, GTPH_PORT_USER, + addr_str_u, port_u); + + c->association[GTPH_PORT_CTRL] = u->association[GTPH_PORT_CTRL] = c; + c->association[GTPH_PORT_USER] = u->association[GTPH_PORT_USER] = u; + + return c->association[port_idx]; +} + +/* port_override: -1: use port from addr; 0: use plane's default port; >0: use + * this number as port. */ +static struct gtphub_peer *gtphub_peer_new_from_sockaddr(struct gtphub *hub, + struct gtphub_bind bind[], + unsigned int port_idx, + const struct osmo_sockaddr *addr, + int port_override) +{ + char addr_str[256]; + char port_str[6]; + + if (osmo_sockaddr_to_strs(addr_str, sizeof(addr_str), + port_str, sizeof(port_str), + addr, + (NI_NUMERICHOST | NI_NUMERICSERV)) + != 0) { + return NULL; + } + + uint16_t port = port_override < 0? atoi(port_str) : port_override; + + return gtphub_peer_new(hub, bind, port_idx, addr_str, port, NULL, 0); +} + +static void gtphub_peer_del(struct gtphub_peer *peer) +{ + nr_map_clear(&peer->seq_map); + llist_del(&peer->entry); + talloc_free(peer); +} + +static struct gtphub_peer *gtphub_peer_find(const struct gtphub_bind *bind, + const struct osmo_sockaddr *addr) +{ + struct gtphub_peer *peer; + llist_for_each_entry(peer, &bind->peers, entry) { + if (osmo_sockaddr_cmp(addr, &peer->addr) == 0) + return peer; + } + return NULL; +} + +static struct gtphub_peer *gtphub_have_ggsn(struct gtphub *hub, + struct osmo_sockaddr *addr, + unsigned int port_idx) +{ + struct gtphub_peer *peer; + peer = gtphub_peer_find(&hub->to_ggsns[port_idx], addr); + if (peer) + return peer; + + /* Not found, create one. */ + peer = gtphub_peer_new_from_sockaddr(hub, hub->to_ggsns, port_idx, addr, -1); + return peer; +} + +static struct gtphub_peer *gtphub_resolve_ggsn(struct gtphub *hub, + struct gtp_packet_desc *p, + unsigned int port_idx) +{ + int rc; + + struct osmo_sockaddr addr; + + rc = gtphub_resolve_ggsn_addr(hub, &addr, p); + if (rc < 0) + return NULL; + + return gtphub_have_ggsn(hub, &addr, port_idx); +} + + +/* TODO move to osmocom/core/socket.c ? */ +/* The caller is required to call freeaddrinfo(*result), iff zero is returned. */ +/* use this in osmo_sock_init() to remove dup. */ +static int _osmo_getaddrinfo(struct addrinfo **result, + uint16_t family, uint16_t type, uint8_t proto, + const char *host, uint16_t port) +{ + struct addrinfo hints; + char portbuf[16]; + + sprintf(portbuf, "%u", port); + memset(&hints, '\0', sizeof(struct addrinfo)); + hints.ai_family = family; + if (type == SOCK_RAW) { + /* Workaround for glibc, that returns EAI_SERVICE (-8) if + * SOCK_RAW and IPPROTO_GRE is used. + */ + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + } else { + hints.ai_socktype = type; + hints.ai_protocol = proto; + } + + return getaddrinfo(host, portbuf, &hints, result); +} + +/* TODO move to osmocom/core/socket.c ? */ +int osmo_sockaddr_init(struct osmo_sockaddr *addr, + uint16_t family, uint16_t type, uint8_t proto, + const char *host, uint16_t port) +{ + struct addrinfo *res; + int rc; + rc = _osmo_getaddrinfo(&res, family, type, proto, host, port); + + if (rc != 0) { + LOGERR("getaddrinfo returned error %d\n", (int)rc); + return -EINVAL; + } + + OSMO_ASSERT(res->ai_addrlen <= sizeof(addr->a)); + memcpy(&addr->a, res->ai_addr, res->ai_addrlen); + addr->l = res->ai_addrlen; + freeaddrinfo(res); + + return 0; +} + +int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len, + char *port_str, size_t port_str_len, + const struct osmo_sockaddr *addr, + int flags) +{ + int rc; + + if ((addr->l < 1) || (addr->l > sizeof(addr->a))) { + LOGP(DGTPHUB, LOGL_ERROR, "Invalid address size: %d\n", addr->l); + return -1; + } + + if (addr->l > sizeof(addr->a)) { + LOGP(DGTPHUB, LOGL_ERROR, "Invalid address: too long: %d\n", addr->l); + return -1; + } + + rc = getnameinfo((struct sockaddr*)&addr->a, addr->l, + addr_str, addr_str_len, + port_str, port_str_len, + flags); + + if (rc) + LOGP(DGTPHUB, LOGL_ERROR, "Invalid address: %s: %s\n", gai_strerror(rc), + osmo_hexdump((uint8_t*)&addr->a, addr->l)); + + return rc; +} + +const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr, + char *buf, size_t buf_len) +{ + const int portbuf_len = 6; + OSMO_ASSERT(buf_len > portbuf_len); + char *portbuf = buf + buf_len - portbuf_len; + buf_len -= portbuf_len; + if (osmo_sockaddr_to_strs(buf, buf_len, + portbuf, portbuf_len, + addr, + NI_NUMERICHOST | NI_NUMERICSERV)) + return NULL; + + char *pos = buf + strnlen(buf, buf_len-1); + size_t len = buf_len - (pos - buf); + + snprintf(pos, len, " port %s", portbuf); + buf[buf_len-1] = '\0'; + + return buf; +} + +const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr) +{ + static char buf[256]; + const char *result = osmo_sockaddr_to_strb(addr, buf, sizeof(buf)); + if (! result) + return "(invalid)"; + return result; +} + +int osmo_sockaddr_cmp(const struct osmo_sockaddr *a, const struct osmo_sockaddr *b) +{ + if (a->l != b->l) { + /* Lengths are not the same, but determine the order. Will + * anyone ever sort a list by osmo_sockaddr though...? */ + int cmp = memcmp(&a->a, &b->a, (a->l < b->l)? a->l : b->l); + if (cmp == 0) { + if (a->l < b->l) + return -1; + else + return 1; + } + return cmp; + } + return memcmp(&a->a, &b->a, a->l); +} + +void osmo_sockaddr_copy(struct osmo_sockaddr *dst, const struct osmo_sockaddr *src) +{ + OSMO_ASSERT(src->l <= sizeof(dst->a)); + memcpy(&dst->a, &src->a, src->l); + dst->l = src->l; +} diff --git a/openbsc/src/gprs/gtphub_main.c b/openbsc/src/gprs/gtphub_main.c new file mode 100644 index 0000000..84c7969 --- /dev/null +++ b/openbsc/src/gprs/gtphub_main.c @@ -0,0 +1,283 @@ +/* GTP Hub main program */ + +/* (C) 2015 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "../../bscconfig.h" + +#define LOGERR(fmt, args...) \ + LOGP(DGTPHUB, LOGL_ERROR, fmt, ##args) + +#define LOG(fmt, args...) \ + LOGP(DGTPHUB, LOGL_NOTICE, fmt, ##args) + +#ifndef OSMO_VTY_PORT_GTPHUB +/* should come from libosmocore */ +#define OSMO_VTY_PORT_GTPHUB 4253 +#endif + +extern void *osmo_gtphub_ctx; + + +const char *gtphub_copyright = + "Copyright (C) 2015 sysmocom s.f.m.c GmbH \r\n" + "License AGPLv3+: GNU AGPL version 2 or later \r\n" + "This is free software: you are free to change and redistribute it.\r\n" + "There is NO WARRANTY, to the extent permitted by law.\r\n"; + +static struct log_info_cat gtphub_categories[] = { + [DGTPHUB] = { + .name = "DGTPHUB", + .description = "GTP Hub", + .color = "\033[1;33m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, +}; + +int gtphub_log_filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 0; +} + +static const struct log_info gtphub_log_info = { + .filter_fn = gtphub_log_filter_fn, + .cat = gtphub_categories, + .num_cat = ARRAY_SIZE(gtphub_categories), +}; + +void log_cfg(struct gtphub_cfg *cfg) +{ + struct gtphub_cfg_addr *a; + a = &cfg->to_sgsns[GTPH_PORT_CTRL].bind; + LOG("to-SGSNs bind, Control: %s port %d\n", + a->addr_str, a->port); + a = &cfg->to_sgsns[GTPH_PORT_USER].bind; + LOG("to-SGSNs bind, User: %s port %d\n", + a->addr_str, a->port); + a = &cfg->to_ggsns[GTPH_PORT_CTRL].bind; + LOG("to-GGSNs bind, Control: %s port %d\n", + a->addr_str, a->port); + a = &cfg->to_ggsns[GTPH_PORT_USER].bind; + LOG("to-GGSNs bind, User: %s port %d\n", + a->addr_str, a->port); +} + +static void signal_handler(int signal) +{ + fprintf(stdout, "signal %u received\n", signal); + + switch (signal) { + case SIGINT: + osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); + sleep(1); + exit(0); + break; + 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: + case SIGUSR2: + talloc_report_full(osmo_gtphub_ctx, stderr); + break; + default: + break; + } +} + +extern int bsc_vty_go_parent(struct vty *vty); + +static struct vty_app_info vty_info = { + .name = "OsmoGTPhub", + .version = PACKAGE_VERSION, + .go_parent_cb = bsc_vty_go_parent, + .is_config_node = bsc_vty_is_config_node, +}; + +struct cmdline_cfg { + const char *config_file; + int daemonize; +}; + +static void print_help(struct cmdline_cfg *ccfg) +{ + printf("gtphub commandline options\n"); + printf(" -h --help This text.\n"); + printf(" -D --daemonize Fork the process into a background daemon.\n"); + printf(" -d,--debug Enable Debugging for this category.\n"); + printf(" Pass '-d list' to get a category listing.\n"); + printf(" -s --disable-color"); + printf(" -c --config-file The config file to use [%s].\n", ccfg->config_file); + printf(" -e,--log-level Set a global log level.\n"); +} + +static void list_categories(void) +{ + printf("Avaliable debug categories:\n"); + int i; + for (i = 0; i < gtphub_log_info.num_cat; ++i) { + if (!gtphub_log_info.cat[i].name) + continue; + + printf("%s\n", gtphub_log_info.cat[i].name); + } +} + +static void handle_options(struct cmdline_cfg *ccfg, int argc, char **argv) +{ + while (1) { + int option_index = 0, c; + static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"debug", 1, 0, 'd'}, + {"daemonize", 0, 0, 'D'}, + {"config-file", 1, 0, 'c'}, + {"disable-color", 0, 0, 's'}, + {"timestamp", 0, 0, 'T'}, + {"log-level", 1, 0, 'e'}, + {NULL, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "hd:Dc:sTe:", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + //print_usage(); + print_help(ccfg); + exit(0); + case 's': + log_set_use_color(osmo_stderr_target, 0); + break; + case 'd': + if (strcmp("list", optarg) == 0) { + list_categories(); + exit(0); + } + else + log_parse_category_mask(osmo_stderr_target, optarg); + break; + case 'D': + ccfg->daemonize = 1; + break; + case 'c': + ccfg->config_file = optarg; + break; + case 'T': + log_set_print_timestamp(osmo_stderr_target, 1); + break; + case 'e': + log_set_log_level(osmo_stderr_target, atoi(optarg)); + break; + default: + /* ignore */ + break; + } + } +} + +int main(int argc, char **argv) +{ + int rc; + + osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub"); + + signal(SIGINT, &signal_handler); + signal(SIGABRT, &signal_handler); + signal(SIGUSR1, &signal_handler); + signal(SIGUSR2, &signal_handler); + osmo_init_ignore_signals(); + + osmo_init_logging(>phub_log_info); + + vty_info.copyright = gtphub_copyright; + vty_init(&vty_info); + logging_vty_add_cmds(>phub_log_info); + gtphub_vty_init(); + + rate_ctr_init(osmo_gtphub_ctx); + rc = telnet_init(osmo_gtphub_ctx, 0, OSMO_VTY_PORT_GTPHUB); + if (rc < 0) + exit(1); + + struct cmdline_cfg _ccfg; + struct cmdline_cfg *ccfg = &_ccfg; + memset(ccfg, '\0', sizeof(*ccfg)); + ccfg->config_file = "./gtphub.conf"; + + struct gtphub_cfg _cfg; + struct gtphub_cfg *cfg = &_cfg; + memset(cfg, '\0', sizeof(*cfg)); + + struct gtphub _hub; + struct gtphub *hub = &_hub; + + handle_options(ccfg, argc, argv); + + rc = gtphub_cfg_read(cfg, ccfg->config_file); + if (rc < 0) { + LOGP(DGTPHUB, LOGL_FATAL, "Cannot parse config file '%s'\n", ccfg->config_file); + exit(2); + } + + if (gtphub_start(hub, cfg) != 0) + return -1; + + log_cfg(cfg); + + if (ccfg->daemonize) { + rc = osmo_daemonize(); + if (rc < 0) { + LOGERR("Error during daemonize"); + exit(1); + } + } + + while (1) { + rc = osmo_select_main(0); + if (rc < 0) + exit(3); + } + + /* not reached */ + exit(0); +} diff --git a/openbsc/src/gprs/gtphub_sep.c b/openbsc/src/gprs/gtphub_sep.c new file mode 100644 index 0000000..bb31834 --- /dev/null +++ b/openbsc/src/gprs/gtphub_sep.c @@ -0,0 +1,26 @@ +/* This file is kept separate so that these functions can be wrapped for + * gtphub_test.c. When a function and its callers are in the same compilational + * unit, the wrappability may be optimized away. */ +#include + +#include +#include + +#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next) +#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry) + +int gtphub_resolve_ggsn_addr(struct gtphub *hub, + struct osmo_sockaddr *result, + struct gtp_packet_desc *p) +{ + /* TODO This is just hardcodedly returning the first known address. + * Should resolve from actual subscriber data. */ + struct gtphub_peer *ggsn = llist_first(&hub->to_ggsns[GTPH_PORT_CTRL].peers, + struct gtphub_peer, entry); + if (!ggsn) + return -1; + + memcpy(result, &ggsn->addr, sizeof(struct osmo_sockaddr)); + return 0; +} + diff --git a/openbsc/src/gprs/gtphub_vty.c b/openbsc/src/gprs/gtphub_vty.c new file mode 100644 index 0000000..2227d48 --- /dev/null +++ b/openbsc/src/gprs/gtphub_vty.c @@ -0,0 +1,258 @@ +/* (C) 2015 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include + +#include +#include + +static struct gtphub_cfg *g_cfg = 0; + +static struct cmd_node gtphub_node = { + GTPHUB_NODE, + "%s(config-gtphub)# ", + 1, +}; + +#define GTPH_DEFAULT_CONTROL_PORT 2123 +#define GTPH_DEFAULT_USER_PORT 2152 + +static void write_addrs(struct vty *vty, const char *name, + struct gtphub_cfg_addr *c, struct gtphub_cfg_addr *u) +{ + if ((c->port == GTPH_DEFAULT_CONTROL_PORT) + && (u->port == GTPH_DEFAULT_USER_PORT) + && (strcmp(c->addr_str, u->addr_str) == 0)) { + /* Default port numbers and same IP address: write "short" + * variant. */ + vty_out(vty, " %s %s%s", + name, + c->addr_str, + VTY_NEWLINE); + return; + } + + vty_out(vty, " %s ctrl %s %d user %s %d%s", + name, + c->addr_str, (int)c->port, + u->addr_str, (int)u->port, + VTY_NEWLINE); +} + +static int config_write_gtphub(struct vty *vty) +{ + vty_out(vty, "gtphub%s", VTY_NEWLINE); + + write_addrs(vty, "bind-to-sgsns", + &g_cfg->to_sgsns[GTPH_PORT_CTRL].bind, + &g_cfg->to_sgsns[GTPH_PORT_USER].bind); + + write_addrs(vty, "bind-to-ggsns", + &g_cfg->to_ggsns[GTPH_PORT_CTRL].bind, + &g_cfg->to_ggsns[GTPH_PORT_USER].bind); + + if (g_cfg->ggsn_proxy[GTPH_PORT_CTRL].addr_str) { + write_addrs(vty, "ggsn-proxy", + &g_cfg->ggsn_proxy[GTPH_PORT_CTRL], + &g_cfg->ggsn_proxy[GTPH_PORT_USER]); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_gtphub, cfg_gtphub_cmd, + "gtphub", + "Configure the GTP hub") +{ + vty->node = GTPHUB_NODE; + return CMD_SUCCESS; +} + +#define BIND_ARGS "ctrl ADDR <0-65535> user ADDR <0-65535>" +#define BIND_DOCS \ + "Set GTP-C bind\n" \ + "GTP-C local IP address (v4 or v6)\n" \ + "GTP-C local port\n" \ + "Set GTP-U bind\n" \ + "GTP-U local IP address (v4 or v6)\n" \ + "GTP-U local port\n" + + +DEFUN(cfg_gtphub_bind_to_sgsns_short, cfg_gtphub_bind_to_sgsns_short_cmd, + "bind-to-sgsns ADDR", + "GTP Hub Parameters\n" + "Set the local bind address to listen for SGSNs, for both GTP-C and GTP-U\n" + "Local IP address (v4 or v6)\n" + ) +{ + int i; + for (i = 0; i < GTPH_PORT_N; i++) + g_cfg->to_sgsns[i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->to_sgsns[GTPH_PORT_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT; + g_cfg->to_sgsns[GTPH_PORT_USER].bind.port = GTPH_DEFAULT_USER_PORT; + return CMD_SUCCESS; +} + +DEFUN(cfg_gtphub_bind_to_ggsns_short, cfg_gtphub_bind_to_ggsns_short_cmd, + "bind-to-ggsns ADDR", + "GTP Hub Parameters\n" + "Set the local bind address to listen for GGSNs, for both GTP-C and GTP-U\n" + "Local IP address (v4 or v6)\n" + ) +{ + int i; + for (i = 0; i < GTPH_PORT_N; i++) + g_cfg->to_ggsns[i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->to_ggsns[GTPH_PORT_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT; + g_cfg->to_ggsns[GTPH_PORT_USER].bind.port = GTPH_DEFAULT_USER_PORT; + return CMD_SUCCESS; +} + + +static int handle_binds(struct gtphub_cfg_bind *b, const char **argv) +{ + b[GTPH_PORT_CTRL].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + b[GTPH_PORT_CTRL].bind.port = atoi(argv[1]); + b[GTPH_PORT_USER].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[2]); + b[GTPH_PORT_USER].bind.port = atoi(argv[3]); + return CMD_SUCCESS; +} + +DEFUN(cfg_gtphub_bind_to_sgsns, cfg_gtphub_bind_to_sgsns_cmd, + "bind-to-sgsns " BIND_ARGS, + "GTP Hub Parameters\n" + "Set the local bind addresses and ports to listen for SGSNs\n" + BIND_DOCS + ) +{ + return handle_binds(g_cfg->to_sgsns, argv); +} + +DEFUN(cfg_gtphub_bind_to_ggsns, cfg_gtphub_bind_to_ggsns_cmd, + "bind-to-ggsns " BIND_ARGS, + "GTP Hub Parameters\n" + "Set the local bind addresses and ports to listen for GGSNs\n" + BIND_DOCS + ) +{ + return handle_binds(g_cfg->to_ggsns, argv); +} + +DEFUN(cfg_gtphub_ggsn_proxy_short, cfg_gtphub_ggsn_proxy_short_cmd, + "ggsn-proxy ADDR", + "GTP Hub Parameters\n" + "Redirect all GGSN bound traffic to default ports on this address (another gtphub)\n" + "Remote IP address (v4 or v6)\n" + ) +{ + g_cfg->ggsn_proxy[GTPH_PORT_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->ggsn_proxy[GTPH_PORT_CTRL].port = GTPH_DEFAULT_CONTROL_PORT; + g_cfg->ggsn_proxy[GTPH_PORT_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->ggsn_proxy[GTPH_PORT_USER].port = GTPH_DEFAULT_USER_PORT; + return CMD_SUCCESS; +} + +DEFUN(cfg_gtphub_ggsn_proxy, cfg_gtphub_ggsn_proxy_cmd, + "ggsn-proxy " BIND_ARGS, + "GTP Hub Parameters\n" + "Redirect all GGSN bound traffic to these addresses and ports (another gtphub)\n" + BIND_DOCS + ) +{ + g_cfg->ggsn_proxy[GTPH_PORT_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->ggsn_proxy[GTPH_PORT_CTRL].port = atoi(argv[1]); + g_cfg->ggsn_proxy[GTPH_PORT_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]); + g_cfg->ggsn_proxy[GTPH_PORT_USER].port = atoi(argv[3]); + return CMD_SUCCESS; +} + +DEFUN(cfg_gtphub_sgsn_proxy_short, cfg_gtphub_sgsn_proxy_short_cmd, + "sgsn-proxy ADDR", + "GTP Hub Parameters\n" + "Redirect all SGSN bound traffic to default ports on this address (another gtphub)\n" + "Remote IP address (v4 or v6)\n" + ) +{ + g_cfg->sgsn_proxy[GTPH_PORT_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->sgsn_proxy[GTPH_PORT_CTRL].port = GTPH_DEFAULT_CONTROL_PORT; + g_cfg->sgsn_proxy[GTPH_PORT_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->sgsn_proxy[GTPH_PORT_USER].port = GTPH_DEFAULT_USER_PORT; + return CMD_SUCCESS; +} + +DEFUN(cfg_gtphub_sgsn_proxy, cfg_gtphub_sgsn_proxy_cmd, + "sgsn-proxy " BIND_ARGS, + "GTP Hub Parameters\n" + "Redirect all SGSN bound traffic to these addresses and ports (another gtphub)\n" + BIND_DOCS + ) +{ + g_cfg->sgsn_proxy[GTPH_PORT_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); + g_cfg->sgsn_proxy[GTPH_PORT_CTRL].port = atoi(argv[1]); + g_cfg->sgsn_proxy[GTPH_PORT_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]); + g_cfg->sgsn_proxy[GTPH_PORT_USER].port = atoi(argv[3]); + return CMD_SUCCESS; +} + +DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub", + SHOW_STR "Display information about the GTP hub") +{ + vty_out(vty, "gtphub has nothing to say yet%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + + +int gtphub_vty_init(void) +{ + install_element_ve(&show_gtphub_cmd); + + install_element(CONFIG_NODE, &cfg_gtphub_cmd); + install_node(>phub_node, config_write_gtphub); + vty_install_default(GTPHUB_NODE); + + install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_short_cmd); + install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_cmd); + install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_short_cmd); + install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_cmd); + install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_short_cmd); + install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_cmd); + install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_short_cmd); + install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_cmd); + + return 0; +} + +int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file) +{ + int rc; + + g_cfg = cfg; + + rc = vty_read_config_file(config_file, NULL); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + return 0; +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 1b557d4..aacfe0b 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr oap +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau subscr oap gtphub if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/gtphub/Makefile.am b/openbsc/tests/gtphub/Makefile.am new file mode 100644 index 0000000..ecc6d62 --- /dev/null +++ b/openbsc/tests/gtphub/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) + +EXTRA_DIST = \ + gtphub_test.ok \ + gtphub_nc_test.sh \ + gtphub_nc_test.ok \ + hex2bin.py + +noinst_PROGRAMS = gtphub_test + +gtphub_test_SOURCES = gtphub_test.c +gtphub_test_LDFLAGS = \ + -Wl,--wrap=gtphub_resolve_ggsn_addr + +gtphub_test_LDADD = \ + $(top_builddir)/src/gprs/gtphub.o \ + $(LIBOSMOCORE_LIBS) \ + -lgtp -lrt + diff --git a/openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf b/openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf new file mode 100644 index 0000000..17cc756 --- /dev/null +++ b/openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf @@ -0,0 +1,5 @@ +gtphub + bind-to-sgsns ctrl 127.0.0.1 21231 user 127.0.0.1 21521 + bind-to-ggsns ctrl 127.0.0.1 21232 user 127.0.0.1 21522 + ggsn-proxy 127.0.0.1 +end diff --git a/openbsc/tests/gtphub/gtphub_nc_test.ok b/openbsc/tests/gtphub/gtphub_nc_test.ok new file mode 100644 index 0000000..6a6db53 --- /dev/null +++ b/openbsc/tests/gtphub/gtphub_nc_test.ok @@ -0,0 +1,7 @@ +--- recv_server: +32 01 00 04 00 00 00 00 6d 31 00 00 +OK +--- recv_client: +32 02 00 06 00 00 00 00 7c 00 00 00 0e 01 +OK +done diff --git a/openbsc/tests/gtphub/gtphub_nc_test.sh b/openbsc/tests/gtphub/gtphub_nc_test.sh new file mode 100755 index 0000000..febb5a7 --- /dev/null +++ b/openbsc/tests/gtphub/gtphub_nc_test.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# gtphub_nc_test.sh + +# TODO does this work with all relevant netcat implementations? +# TODO skip if netcat not found? +# TODO use only 127.0.0.1 once gtphub is configurable. + +dump() { + # echo result to strip trailing space + echo $(hexdump -v -e '/1 "%02x "' $@) +} + +sendhex() { + hex="$1" + from_port="$2" + to_port="$3" + echo "$hex" | ./hex2bin.py | nc --send-only -u -s 127.0.0.1 -p "$from_port" 127.0.0.1 "$to_port" +} + +gtphub_bin="./osmo-gtphub" +if [ ! -x "$gtphub_bin" ]; then + echo "executable not found: $gtphub_bin" + exit 1; +fi + +# client osmo-gtphub gtp server +# 127.0.0.1:9876 <--> 127.0.0.1:21231 | 127.0.0.1:21232 <--> 127.0.0.1 2123 +# (netcat) ($gtphub_bin) (netcat) + +# start gtphub relay +"$gtphub_bin" -c gtphub.conf & +sleep 0.1 + +# log what reaches client and server +nc --recv-only -u -l -p 9876 -s 127.0.0.1 > recv_client & +nc --recv-only -u -l -p 2123 -s 127.0.0.1 > recv_server & +sleep .1 + +# send test messages, both ways... +# When sending the ping, the sequence number gets mapped (7c00 -> 6d31). +# In the pong, the mapped sequence nr is sent and gets mapped backwards. +gtp_ping_seq1="32 01 00 04 00 00 00 00 7c 00 00 00" +gtp_ping_seq2="32 01 00 04 00 00 00 00 6d 31 00 00" +gtp_pong_seq2="32 02 00 06 00 00 00 00 6d 31 00 00 0e 01" +gtp_pong_seq1="32 02 00 06 00 00 00 00 7c 00 00 00 0e 01" + +sendhex "$gtp_ping_seq1" 9876 21231 + +# server sends reply with the mapped sequence nr., but wrong sender in terms of +# the configured GGSN proxy address. +sendhex "$gtp_pong_seq2" 7777 21232 + +# server sends reply with the mapped sequence nr., correct sender +sendhex "$gtp_pong_seq2" 2123 21232 + +sleep .1 +kill %1 %2 %3 + +# log what has reached the server and client ends, matched against +# gtphub_nc_test.ok +retval=0 +rx_srv="$(dump recv_server)" +echo "--- recv_server:" +echo "$rx_srv" + +if [ "$rx_srv" = "$gtp_ping_seq2" ]; then + echo "OK" +else + echo "*** FAILURE" + retval=1 +fi + +rx_clt="$(dump recv_client)" +echo "--- recv_client:" +echo "$rx_clt" + +if [ "$rx_clt" = "$gtp_pong_seq1" ]; then + echo "OK" +else + echo "*** FAILURE" + retval=2 +fi + +echo "done" +exit "$retval" diff --git a/openbsc/tests/gtphub/gtphub_test.c b/openbsc/tests/gtphub/gtphub_test.c new file mode 100644 index 0000000..5a5c4d1 --- /dev/null +++ b/openbsc/tests/gtphub/gtphub_test.c @@ -0,0 +1,675 @@ +/* Test the GTP hub */ + +/* (C) 2015 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#define EXPIRE_ALL (gtphub_now() + (60 * GTPH_TEI_MAPPING_EXPIRY_MINUTES) + 1) + +/* Make non-public API accessible */ + +void gtphub_init(struct gtphub *hub); + +int gtphub_from_sgsns_handle_buf(struct gtphub *hub, + unsigned int port_idx, + const struct osmo_sockaddr *from_addr, + uint8_t *buf, + size_t received, + struct osmo_fd **to_ofd, + struct osmo_sockaddr **to_addr); + +int gtphub_from_ggsns_handle_buf(struct gtphub *hub, + unsigned int port_idx, + const struct osmo_sockaddr *from_addr, + uint8_t *buf, + size_t received, + struct osmo_fd **to_ofd, + struct osmo_sockaddr **to_addr); + +void *osmo_gtphub_ctx; + +/* TODO copied from libosmo-abis/src/subchan_demux.c, remove dup */ +static int llist_len(struct llist_head *head) +{ + struct llist_head *entry; + int i = 0; + + llist_for_each(entry, head) + i++; + + return i; +} + +static void nr_mapping_free(struct nr_mapping *m) +{ + talloc_free(m); +} + +static struct nr_mapping *nr_mapping_alloc(void) +{ + struct nr_mapping *m; + m = talloc(osmo_gtphub_ctx, struct nr_mapping); + nr_mapping_init(m); + m->del_cb = nr_mapping_free; + return m; +} + +static struct nr_mapping *nr_map_have(struct nr_map *map, void *origin, nr_t orig, time_t now) +{ + struct nr_mapping *mapping; + + mapping = nr_map_get(map, origin, orig); + if (!mapping) { + mapping = nr_mapping_alloc(); + mapping->origin = origin; + mapping->orig = orig; + nr_map_add(map, mapping, now); + } + + return mapping; +} + +static nr_t nr_map_verify(const struct nr_map *map, void *origin, nr_t orig, nr_t expect_repl) +{ + struct nr_mapping *m; + m = nr_map_get(map, origin, orig); + + if (!m) { + printf("mapping not found for %p %d\n", origin, orig); + return 0; + } + + if (m->repl != expect_repl) { + printf("mapping found, but nr mismatches: expect %d, got %d\n", + (int)expect_repl, (int)m->repl); + return 0; + } + + return 1; +} + +static int nr_map_verify_inv(const struct nr_map *map, nr_t repl, + void *expect_origin, nr_t expect_orig) +{ + struct nr_mapping *m; + m = nr_map_get_inv(map, repl); + if (!m) { + printf("mapping not found for %d\n", (int)repl); + return 0; + } + + if (m->origin != expect_origin) { + printf("mapping found, but origin mismatches: expect %p, got %p\n", + expect_origin, m->origin); + return 0; + } + + if (m->orig != expect_orig) { + printf("mapping found, but nr mismatches: expect %d, got %d\n", + (int)expect_orig, (int)m->orig); + return 0; + } + + return 1; +} + + +static void test_nr_map_basic(void) +{ + struct nr_pool _pool; + struct nr_pool *pool = &_pool; + struct nr_map _map; + struct nr_map *map = &_map; + + nr_pool_init(pool); + nr_map_init(map, pool, NULL); + + OSMO_ASSERT(llist_empty(&map->mappings)); + +#define TEST_N_HALF 100 +#define TEST_N (2*TEST_N_HALF) +#define TEST_I 123 + uint32_t i, check_i; + uint32_t m[TEST_N]; + struct nr_mapping *mapping; + + /* create half of TEST_N mappings from one origin */ + void *origin1 = (void*)0x1234; + for (i = 0; i < TEST_N_HALF; i++) { + nr_t orig = TEST_I + i; + mapping = nr_map_have(map, origin1, orig, 0); + m[i] = mapping->repl; + OSMO_ASSERT(m[i] != 0); + OSMO_ASSERT(llist_len(&map->mappings) == (i+1)); + for (check_i = 0; check_i < i; check_i++) + OSMO_ASSERT(m[check_i] != m[i]); + } + OSMO_ASSERT(llist_len(&map->mappings) == TEST_N_HALF); + + /* create another TEST_N mappings with the same original numbers, but + * from a different origin */ + void *origin2 = (void*)0x5678; + for (i = 0; i < TEST_N_HALF; i++) { + int i2 = TEST_N_HALF + i; + nr_t orig = TEST_I + i; + mapping = nr_map_have(map, origin2, orig, 0); + m[i2] = mapping->repl; + OSMO_ASSERT(m[i2] != 0); + OSMO_ASSERT(llist_len(&map->mappings) == (i2+1)); + for (check_i = 0; check_i < i2; check_i++) + OSMO_ASSERT(m[check_i] != m[i2]); + } + OSMO_ASSERT(llist_len(&map->mappings) == TEST_N); + + /* verify mappings */ + for (i = 0; i < TEST_N_HALF; i++) { + nr_t orig = TEST_I + i; + { + OSMO_ASSERT(nr_map_verify(map, origin1, orig, m[i])); + OSMO_ASSERT(nr_map_verify_inv(map, m[i], origin1, orig)); + } + { + int i2 = TEST_N_HALF + i; + OSMO_ASSERT(nr_map_verify(map, origin2, orig, m[i2])); + OSMO_ASSERT(nr_map_verify_inv(map, m[i2], origin2, orig)); + } + } + + /* remove all mappings */ + for (i = 0; i < TEST_N_HALF; i++) { + OSMO_ASSERT(llist_len(&map->mappings) == (TEST_N - 2*i)); + + nr_t orig = TEST_I + i; + nr_mapping_del(nr_map_get(map, origin1, orig)); + nr_mapping_del(nr_map_get(map, origin2, orig)); + } + OSMO_ASSERT(llist_empty(&map->mappings)); +#undef TEST_N +#undef TEST_I +} + +static int seqmap_is(struct nr_map *map, const char *str) +{ + static char buf[4096]; + char *pos = buf; + size_t len = sizeof(buf); + struct nr_mapping *m; + llist_for_each_entry(m, &map->mappings, entry) { + size_t wrote = snprintf(pos, len, "(%d->%d@%d), ", + (int)m->orig, + (int)m->repl, + (int)m->expiry); + OSMO_ASSERT(wrote < len); + pos += wrote; + len -= wrote; + } + *pos = '\0'; + + if (strncmp(buf, str, sizeof(buf)) != 0) { + printf("FAILURE: seqmap_is() mismatches expected value:\n" + "expected: %s\n" + "is: %s\n", + str, buf); + return 0; + } + return 1; +} + +static void test_nr_map_expiry(void) +{ + struct nr_map_expiry expiry; + struct nr_pool pool; + struct nr_map map; + int i; + + nr_map_expiry_init(&expiry, 30); + nr_pool_init(&pool); + nr_map_init(&map, &pool, &expiry); + OSMO_ASSERT(seqmap_is(&map, "")); + + /* tick on empty map */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10000) == 0); + OSMO_ASSERT(seqmap_is(&map, "")); + +#define MAP1 \ + "(10->1 at 10040), " \ + "" + +#define MAP2 \ + "(20->2 at 10050), " \ + "(21->3 at 10051), " \ + "(22->4 at 10052), " \ + "(23->5 at 10053), " \ + "(24->6 at 10054), " \ + "(25->7 at 10055), " \ + "(26->8 at 10056), " \ + "(27->9 at 10057), " \ + "" + +#define MAP3 \ + "(420->10 at 10072), " \ + "(421->11 at 10072), " \ + "(422->12 at 10072), " \ + "(423->13 at 10072), " \ + "(424->14 at 10072), " \ + "(425->15 at 10072), " \ + "(426->16 at 10072), " \ + "(427->17 at 10072), " \ + "" + + /* add mapping at time 10010. */ + nr_map_have(&map, 0, 10, 10010); + OSMO_ASSERT(seqmap_is(&map, MAP1)); + + /* tick on unexpired item. */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10010) == 0); + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10011) == 0); + OSMO_ASSERT(seqmap_is(&map, MAP1)); + + /* Spread mappings at 10020, 10021, ... 10027. */ + for (i = 0; i < 8; i++) + nr_map_have(&map, 0, 20 + i, 10020 + i); + OSMO_ASSERT(seqmap_is(&map, MAP1 MAP2)); + + /* tick on unexpired items. */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10030) == 0); + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10039) == 0); + OSMO_ASSERT(seqmap_is(&map, MAP1 MAP2)); + + /* expire the first item (from 10010). */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10010 + 30) == 1); + OSMO_ASSERT(seqmap_is(&map, MAP2)); + + /* again nothing to expire */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10041) == 0); + OSMO_ASSERT(seqmap_is(&map, MAP2)); + + /* Mappings all at the same time. */ + for (i = 0; i < 8; i++) + nr_map_have(&map, 0, 420 + i, 10042); + OSMO_ASSERT(seqmap_is(&map, MAP2 MAP3)); + + /* Eight to expire, were added further above to be chronologically + * correct, at 10020..10027. */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10027 + 30) == 8); + OSMO_ASSERT(seqmap_is(&map, MAP3)); + + /* again nothing to expire */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10027 + 30) == 0); + OSMO_ASSERT(seqmap_is(&map, MAP3)); + + /* Eight to expire, from 10042. Now at 10042 + 30: */ + OSMO_ASSERT(nr_map_expiry_tick(&expiry, 10042 + 30) == 8); + OSMO_ASSERT(seqmap_is(&map, "")); + +#undef MAP1 +#undef MAP2 +#undef MAP3 +} + + + +/* override, requires '-Wl,--wrap=gtphub_resolve_ggsn_addr' */ +int __real_gtphub_resolve_ggsn_addr(struct gtphub *hub, + struct osmo_sockaddr *result, + struct gtp_packet_desc *p); + +struct osmo_sockaddr resolved_ggsn_addr = {.l = 0}; +int __wrap_gtphub_resolve_ggsn_addr(struct gtphub *hub, + struct osmo_sockaddr *result, + struct gtp_packet_desc *p) +{ + osmo_sockaddr_copy(result, &resolved_ggsn_addr); + printf("Wrap: returning GGSN addr: %s\n", + osmo_sockaddr_to_str(result)); + return (resolved_ggsn_addr.l != 0)? 0 : -1; +} + +#define buf_len 1024 +static uint8_t buf[buf_len]; + +static unsigned int msg(const char *hex) +{ + unsigned int l = osmo_hexparse(hex, buf, buf_len); + OSMO_ASSERT(l > 0); + return l; +} + +/* Compare static buf to given string constant. The amount of bytes is obtained + * from parsing the GTP header in buf. hex must match an osmo_hexdump() of the + * desired message. Return 1 if size and content match. */ +#define msg_is(MSG) _msg_is(MSG, __FILE__, __LINE__) +static int _msg_is(const char *hex, const char *file, int line) +{ + struct gtp1_header_long *h = (void*)buf; + int len = ntoh16(h->length) + 8; + const char *dump = osmo_hexdump_nospc(buf, len); + int cmp = strcmp(dump, hex); + + if (cmp != 0) { + printf("\n%s:%d: msg_is(): MISMATCH\n" + " expecting:\n'%s'\n" + " got:\n'%s'\n", + file, + line, + hex, dump); + int i; + int l = strlen(hex); + int m = strlen(dump); + if (m < l) + l = m; + for (i = 0; i < l; i++) { + if (hex[i] != dump[i]) { + printf("First mismatch at position %d:\n" + " %s\n %s\n", i, hex + i, dump + i); + break; + } + } + } + return cmp == 0; +} + +#define same_addr(GOT, EXPECTED) _same_addr((GOT),(EXPECTED), __FILE__, __LINE__) +static int _same_addr(const struct osmo_sockaddr *got, + const struct osmo_sockaddr *expected, + const char *file, int line) +{ + int cmp = osmo_sockaddr_cmp(got, expected); + if (!cmp) + return 1; + char buf[256]; + printf("\n%s:%d: addr_is(): MISMATCH\n" + " expecting: '%s'\n" + " got: '%s'\n", + file, line, + osmo_sockaddr_to_str(expected), + osmo_sockaddr_to_strb(got, buf, sizeof(buf))); + return 0; +} + +static void test_echo(void) +{ + struct gtphub _hub; + struct gtphub *hub = &_hub; + + gtphub_init(hub); + + const char *gtp_ping_from_sgsn = + "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */ + "01" /* type 01: Echo request */ + "0004" /* length of 4 after header TEI */ + "00000000" /* header TEI == 0 in Echo */ + "abcd" /* some 16 octet sequence nr */ + "0000" /* N-PDU 0, no extension header (why is this here?) */ + ; + + /* Same with mapped sequence number */ + const char *gtp_ping_to_ggsn = + "32" "01" "0004" "00000000" + "6d31" /* mapped seq */ + "00" "00"; + + const char *gtp_pong_from_ggsn = + "32" + "02" /* type 02: Echo response */ + "0006" /* len */ + "00000000" /* tei */ + "6d31" /* mapped seq */ + "0000" /* ext */ + "0e01" /* 0e: Recovery, val == 1 */ + ; + /* Same with unmapped sequence number */ + const char *gtp_pong_to_sgsn = + "32" "02" "0006" "00000000" + "abcd" /* unmapped seq */ + "00" "00" "0e01"; + + /* Set the GGSN address that gtphub is forced to resolve to. */ + OSMO_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_addr, + "192.168.43.34", 434) + == 0); + + /* according to spec, we'd always send to port 2123 instead... + struct osmo_sockaddr ggsn_standard_port; + OSMO_ASSERT(osmo_sockaddr_init_udp(&ggsn_standard_port, + "192.168.43.34", 2123) + == 0); + */ + + struct osmo_sockaddr orig_sgsn_addr; + OSMO_ASSERT(osmo_sockaddr_init(&orig_sgsn_addr, + AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, + "192.168.42.23", 423) == 0); + struct osmo_fd *ggsn_ofd = NULL; + struct osmo_sockaddr *ggsn_addr = NULL; + int send; + send = gtphub_from_sgsns_handle_buf(hub, GTPH_PORT_CTRL, &orig_sgsn_addr, + buf, msg(gtp_ping_from_sgsn), + &ggsn_ofd, &ggsn_addr); + OSMO_ASSERT(send > 0); + OSMO_ASSERT(ggsn_addr); + OSMO_ASSERT(same_addr(ggsn_addr, &resolved_ggsn_addr)); + OSMO_ASSERT(msg_is(gtp_ping_to_ggsn)); + + struct osmo_fd *sgsn_ofd; + struct osmo_sockaddr *sgsn_addr; + send = gtphub_from_ggsns_handle_buf(hub, GTPH_PORT_CTRL, ggsn_addr, + buf, msg(gtp_pong_from_ggsn), + &sgsn_ofd, &sgsn_addr); + OSMO_ASSERT(send > 0); + OSMO_ASSERT(sgsn_addr); + OSMO_ASSERT(same_addr(sgsn_addr, &orig_sgsn_addr)); + OSMO_ASSERT(msg_is(gtp_pong_to_sgsn)); + + gtphub_gc(hub, EXPIRE_ALL); +} + +static void test_create_pdp_ctx(void) +{ + struct gtphub _hub; + struct gtphub *hub = &_hub; + + gtphub_init(hub); + + /* This is copied from a packet that sgsnemu sends. */ + const char *gtp_req_from_sgsn = + "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */ + "10" /* type 16: Create PDP Context Request */ + "0067" /* length = 8 + 103 */ + "00000000" /* No TEI yet */ + "abcd" /* Sequence nr */ + "00" /* N-PDU 0 */ + "00" /* No extensions */ + /* IEs */ + "02" /* 2 = IMSI */ + "42000121436587f9" + "0e" "60" /* 14: Recovery = 96 */ + "0f01" /* 15: Selection mode = MS provided APN, subscription not verified*/ + "10" /* 16: TEI Data I */ + "00000123" + "11" /* 17: TEI Control Plane */ + "00000321" + "1400" /* 20: NSAPI = 0*/ + "1a" /* 26: Charging Characteristics */ + "0800" + "80" /* 128: End User Address */ + "0002" /* length = 2: empty PDP Address */ + "f121" /* spare 0xf0, PDP organization 1, PDP type number 0x21 = 33 */ + "83" /* 131: Access Point Name */ + "0008" /* length = 8 */ + "696e7465726e6574" /* "internet" */ + "84" /* 132: Protocol Configuration Options */ + "0015" /* length = 21 */ + "80c0231101010011036d69670868656d6d656c6967" + "85" /* 133: GSN Address */ + "0004" /* length */ + "7f000001" + "85" /* 133: GSN Address (second entry) */ + "0004" /* length */ + "7f000001" + "86" /* 134: MS International PSTN/ISDN Number (MSISDN) */ + "0007" /* length */ + "916407123254f6" /* 1946702123456(f) */ + "87" /* 135: Quality of Service (QoS) Profile */ + "0004" /* length */ + "00" /* priority */ + "0b921f" /* QoS profile data */ + ; + + const char *gtp_req_to_ggsn = + "32" "10" "0067" "00000000" + "6d31" /* mapped seq ("abcd") */ + "00" "00" "02" "42000121436587f9" "0e60" "0f01" + "10" "00000001" /* mapped TEI Data I ("123") */ + "11" "00000001" /* mapped TEI Control ("321") */ + "1400" "1a" "0800" "80" "0002" "f121" "83" + "0008" "696e7465726e6574" "84" "0015" + "80c0231101010011036d69670868656d6d656c6967" "85" "0004" + "7f000001" "85" "0004" "7f000001" "86" "0007" "916407123254f6" + "87" "0004" "00" "0b921f" + ; + + const char *gtp_resp_from_ggsn = + "32" + "11" /* Create PDP Context Response */ + "004e" /* length = 78 + 8 */ + "00000001" /* destination TEI (sent in req above) */ + "6d31" /* mapped seq */ + "00" "00" + /* IEs */ + "01" /* 1: Cause */ + "80" /* value = 0b10000000 = response, no rejection. */ + "08" /* 8: Reordering Required */ + "00" /* not required. */ + "0e" "01" /* 14: Recovery = 1 */ + "10" /* 16: TEI Data I */ + "00000567" + "11" /* 17: TEI Control */ + "00000765" + "7f" /* 127: Charging ID */ + "00000001" + "80" /* 128: End User Address */ + "0006" /* length = 6 */ + "f121" /* spare 0xf0, PDP organization 1, PDP type number 0x21 = 33 */ + "7f000002" + "84" /* 132: Protocol Configuration Options */ + "0014" /* len = 20 */ + "8080211002000010810608080808830600000000" + "85" /* 133: GSN Address */ + "0004" /* length */ + "7f000002" + "85" /* 133: GSN Address (again) */ + "0004" /* length */ + "7f000002" + "87" /* 135: Quality of Service (QoS) Profile */ + "0004" /* length */ + "00" /* priority */ + "0b921f" /* QoS profile data */ + ; + + const char *gtp_resp_to_sgsn = + "32" "11" "004e" + "00000321" /* unmapped TEI ("001") */ + "abcd" /* unmapped seq ("6d31") */ + "00" "00" "01" "80" "08" "00" "0e" "01" + "10" "00000001" /* mapped TEI from GGSN ("567") */ + "11" "00000001" /* mapped TEI from GGSN ("765") */ + "7f" "00000001" "80" "0006" "f121" "7f000002" "84" "0014" + "8080211002000010810608080808830600000000" "85" "0004" + "7f000002" "85" "0004" "7f000002" "87" "0004" "00" "0b921f" + ; + + /* Set the GGSN address that gtphub is forced to resolve to. */ + OSMO_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_addr, + "192.168.43.34", 434) + == 0); + + struct osmo_sockaddr orig_sgsn_addr; + OSMO_ASSERT(osmo_sockaddr_init(&orig_sgsn_addr, + AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, + "192.168.42.23", 423) == 0); + struct osmo_fd *ggsn_ofd = NULL; + struct osmo_sockaddr *ggsn_addr = NULL; + int send; + send = gtphub_from_sgsns_handle_buf(hub, GTPH_PORT_CTRL, &orig_sgsn_addr, + buf, msg(gtp_req_from_sgsn), + &ggsn_ofd, &ggsn_addr); + OSMO_ASSERT(send > 0); + OSMO_ASSERT(ggsn_addr); + OSMO_ASSERT(same_addr(ggsn_addr, &resolved_ggsn_addr)); + OSMO_ASSERT(msg_is(gtp_req_to_ggsn)); + + struct osmo_fd *sgsn_ofd; + struct osmo_sockaddr *sgsn_addr; + send = gtphub_from_ggsns_handle_buf(hub, GTPH_PORT_CTRL, ggsn_addr, + buf, msg(gtp_resp_from_ggsn), + &sgsn_ofd, &sgsn_addr); + OSMO_ASSERT(send > 0); + OSMO_ASSERT(sgsn_addr); + OSMO_ASSERT(same_addr(sgsn_addr, &orig_sgsn_addr)); + OSMO_ASSERT(msg_is(gtp_resp_to_sgsn)); + + gtphub_gc(hub, EXPIRE_ALL); +} + +static struct log_info_cat gtphub_categories[] = { + [DGTPHUB] = { + .name = "DGTPHUB", + .description = "GTP Hub", + .color = "\033[1;33m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, +}; + +static struct log_info info = { + .cat = gtphub_categories, + .num_cat = ARRAY_SIZE(gtphub_categories), +}; + +int main(int argc, char **argv) +{ + osmo_init_logging(&info); + osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub"); + + test_nr_map_basic(); + test_nr_map_expiry(); + test_echo(); + test_create_pdp_ctx(); + printf("Done\n"); + + talloc_report_full(osmo_gtphub_ctx, stderr); + OSMO_ASSERT(talloc_total_blocks(osmo_gtphub_ctx) == 1); + return 0; +} + diff --git a/openbsc/tests/gtphub/gtphub_test.ok b/openbsc/tests/gtphub/gtphub_test.ok new file mode 100644 index 0000000..7be13fe --- /dev/null +++ b/openbsc/tests/gtphub/gtphub_test.ok @@ -0,0 +1,3 @@ +Wrap: returning GGSN addr: 192.168.43.34 port 434 +Wrap: returning GGSN addr: 192.168.43.34 port 434 +Done diff --git a/openbsc/tests/gtphub/hex2bin.py b/openbsc/tests/gtphub/hex2bin.py new file mode 100755 index 0000000..6a906b1 --- /dev/null +++ b/openbsc/tests/gtphub/hex2bin.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import sys + +blob = [] + +for l in sys.stdin.readlines(): + l = ''.join(c for c in l if not c.isspace()) + + for i in range(0, len(l), 2): + h = l[i:i+2] + sys.stdout.write(chr(int(h, 16))) + diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 78aa47e..3a5883e 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -110,3 +110,15 @@ AT_CHECK([test "$enable_oap_test" != no || exit 77]) cat $abs_srcdir/oap/oap_test.ok > expout AT_CHECK([$abs_top_builddir/tests/oap/oap_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([gtphub]) +AT_KEYWORDS([gtphub]) +AT_CHECK([test "$enable_gtphub_test" != no || exit 77]) +cat $abs_srcdir/gtphub/gtphub_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/gtphub/gtphub_test], [], [expout], [ignore]) +cat $abs_srcdir/gtphub/gtphub_nc_test.ok > expout +cat $abs_srcdir/gtphub/gtphub_nc_test.gtphub.conf > gtphub.conf +ln -s $abs_srcdir/gtphub/hex2bin.py . +ln -s $abs_top_builddir/src/gprs/osmo-gtphub . +AT_CHECK([$abs_top_builddir/tests/gtphub/gtphub_nc_test.sh], [], [expout], [ignore]) +AT_CLEANUP -- 2.1.4 From nhofmeyr at sysmocom.de Wed Nov 4 02:01:22 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 4 Nov 2015 03:01:22 +0100 Subject: [PATCH] Add GTP hub (code bomb). In-Reply-To: <1446602182-32618-2-git-send-email-nhofmeyr@sysmocom.de> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> <1446602182-32618-2-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20151104020122.GA32132@dub5> On Mon, Nov 02, 2015 at 08:20:39PM +0100, Holger Freyther wrote: > > To reiterate, I'd like to know whether gtphub should/really must ;) be > > changed to the latter style. > > yes. ok, the patch I just sent still uses my style though. I'll modify it later. And also I'm aware that my special LOG() makros are still in there, too. Not forgotten. Hope that doesn't harm reviews. ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From amber_sarosh at hotmail.com Wed Nov 4 06:32:59 2015 From: amber_sarosh at hotmail.com (Amber and Sarosh) Date: Wed, 4 Nov 2015 11:32:59 +0500 Subject: Changing Configuration Parameters Dynamically - OpenBSC Message-ID: Hi,Can someone inform us if the VTY configuration commands to change parameters e.g. cell id, location area code, MS power etc. that are run on OpenBSC VTY telnet interface take effect on next restart of the OpenBSC session or during the same session? If former is the case, is there any way to dynamically change Cell ID, LAC, MS TX power etc i.e. without restarting the OpenBSC session? Regards, Amber & Sarosh -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.chemeris at gmail.com Wed Nov 4 08:20:15 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Wed, 4 Nov 2015 11:20:15 +0300 Subject: CDR-like logs In-Reply-To: <5637468C.20002@alumni.ntnu.no> References: <5637468C.20002@alumni.ntnu.no> Message-ID: Max, You can connect it to FreeSWITCH or any other VoIP PBX and generate logs of pretty much any format. Please excuse typos. Written with a touchscreen keyboard. -- Regards, Alexander Chemeris CEO Fairwaves, Inc. https://fairwaves.co On Nov 2, 2015 14:27, "Suraev" wrote: > Hi. > > If I enable detailed-enough logs of OpenBSC I can get data regarding call > and sms > transactions: > > new state INITIATED -> MO_CALL_PROC, 1 active transactions > new state MO_CALL_PROC -> CONNECT_IND, 1 active transactions > new state CONNECT_IND -> ACTIVE, 1 active transactions > new state ACTIVE -> DISCONNECT_IND, 1 active transactions > new state DISCONNECT_IND -> RELEASE_REQ, 1 active transactions > new state RELEASE_REQ -> NULL, 0 active transactions > > However there's no information regarding which mobile is participating in > the > transaction. > > Is there some way to get CDR-like data from OpenBSC? Smth like > imsi=123 call_to 35345345 duration 12 > imsi=53 sms_from 234234 > ... > > cheers, > Max. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From sipos.csaba at kvk.uni-obuda.hu Wed Nov 4 09:18:06 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Wed, 4 Nov 2015 10:18:06 +0100 (CET) Subject: Meas_web and meas_json In-Reply-To: <213728024.5449223.1445896264483.JavaMail.zimbra@kvk.uni-obuda.hu> References: <1510240027.5443523.1445891932058.JavaMail.zimbra@kvk.uni-obuda.hu> <1010582984.5443937.1445892326559.JavaMail.zimbra@kvk.uni-obuda.hu> <213728024.5449223.1445896264483.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <687363025.6773365.1446628686520.JavaMail.zimbra@kvk.uni-obuda.hu> Dear Alexander, I am playing with the meas_web utility, and I finally have the missing informations for the README to make the installation process more complete, will sending a new copy for you soon. Altough I experienced some problems: 1. I noticed that the "Type" and "Channel" parameters are not shown on the web interface, but if I run "show lchan" in the BSC console, I got the correct results for both parameters. I checked the temporary files which stores the meas_feed data, and it seems these data parts are not even there, and this is the reason the web interface is not displaying them. 2. Is there a way to set a time after the inactive old subscribers are deleted from the web interface? On my end the subscribers are just keep coming (a lot of rejected LOC updates) and when they reach the "maximum item number" count the web interface just crashes. Would be lovely to have a timeout value next to the "max item number" to set the amount of time of which the inactive subscribers would disappear from the web interface. And the web interface should not crash even if there is more transactions than the maximum item number :-) Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Sipos Csaba" C?mzett: "Alexander Chemeris" M?solatot kap: "OpenBSC Mailing List" Elk?ld?tt ?zenetek: H?tf?, 2015. Okt?ber 26. 22:51:04 T?rgy: Re: Meas_web and meas_json Dear Alexander, > Do you mind contributing to the documentation? I don't mind at all :-) In fact I have some points which was a littlebit to brief and we might want to put some more details. For example the fact that the meas_json utility is not part of the master and where can it be found :-) What would be nice is to make it work with the PCU to get and display the GPRS/EDGE meas data too. Will put up some wiki (or at least further detail the readme) and send it to you when I have the time, but first I want to finish the B200/B210 (and potentionally UmTRX) wiki page which you can find here: http://openbsc.osmocom.org/trac/wiki/Ettus_USRP_B2xx_family Its not finished yet, but most of the nasty stuff is up and it works, but here and there some more details will be needed for newbies. If you, or anyone else find any problems, have some questions or suggestions, please tell me so I can correct it :-) Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Alexander Chemeris" C?mzett: "Sipos Csaba" M?solatot kap: "OpenBSC Mailing List" Elk?ld?tt ?zenetek: H?tf?, 2015. Okt?ber 26. 22:15:30 T?rgy: Re: Meas_web and meas_json Hi Sipos, On Mon, Oct 26, 2015 at 11:45 PM, Sipos Csaba wrote: > Just wanted to thank you for the web version of meas_vis utility, and wanted to confirm that it works very well with Nokia Site family (E1 based) and the USRP B200 too :-) Glad someone found it useful and was even able to get it working. :) Do you mind contributing to the documentation? It would be great to have a brief page about it at the wiki and some more details for the installation instructions, but we never got to write it :( > It would make life easier if the meas_json utility would make it to the master branch: > > http://cgit.osmocom.org/openbsc/log/?h=achemeris/meas_json > > Is there a reason it is not being merged? I guess the primary reason is that I've never submitted it. I still plan on doing that, just need to find some time to do that. -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From aschultz at tpip.net Wed Nov 4 09:20:45 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Wed, 4 Nov 2015 10:20:45 +0100 Subject: [PATCH] gtphub collapsed patch (aka bomb) In-Reply-To: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <5639CDED.3060406@tpip.net> Hi Neels, I'm trying to understand how you handle a PDP Create Context message where the SGSN Address for control plane and an SGSN address for user traffic differ from the sender IP? Background: 3GPP TS 29.060 version 12.9.0 Release 12, Section 7.3.2 Create PDP Context Request has this to say about the SGSN Addresses: > The SGSN shall include an SGSN Address for control plane and an SGSN address > for user traffic, which may differ from that provided by the underlying network > service (e.g. IP). To me the implies that a maximum of four IP's need to handled per PDP Context. Those are the two GTP-C/U sender IP's the SGSN uses to talk to us and the two GTP-C/U IP's we are supposed to use when talking to the SGSN. The same applies to the GGSN connection. Any thoughts on this? Andreas On 11/04/2015 02:56 AM, Neels Hofmeyr wrote: > I can talk all day about atomic commits, but chunks of gtphub have transformed > twice over (that's me figuring out how to map and resolve GTP data elements), > so that half the patches are obsoleted by later ones, in a hard-to-rebase way. > > So here is a joint patch of gtphub for review. If anyone requests it, I will > gladly separate it into a handful of patches adding each subsection / family of > API at a time, to better show where each part reaches. Just ask... > > Many thanks for any reviews! > > ~Neels > > > Neels Hofmeyr (1): > Add GTP hub (code bomb). > > openbsc/.gitignore | 2 + > openbsc/configure.ac | 1 + > openbsc/include/openbsc/Makefile.am | 1 + > openbsc/include/openbsc/debug.h | 1 + > openbsc/include/openbsc/gtphub.h | 345 +++++ > openbsc/include/openbsc/vty.h | 1 + > openbsc/src/gprs/Makefile.am | 6 + > openbsc/src/gprs/gtphub.c | 1794 +++++++++++++++++++++++ > openbsc/src/gprs/gtphub_main.c | 283 ++++ > openbsc/src/gprs/gtphub_sep.c | 26 + > openbsc/src/gprs/gtphub_vty.c | 258 ++++ > openbsc/tests/Makefile.am | 2 +- > openbsc/tests/gtphub/Makefile.am | 20 + > openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf | 5 + > openbsc/tests/gtphub/gtphub_nc_test.ok | 7 + > openbsc/tests/gtphub/gtphub_nc_test.sh | 85 ++ > openbsc/tests/gtphub/gtphub_test.c | 675 +++++++++ > openbsc/tests/gtphub/gtphub_test.ok | 3 + > openbsc/tests/gtphub/hex2bin.py | 13 + > openbsc/tests/testsuite.at | 12 + > 20 files changed, 3539 insertions(+), 1 deletion(-) > create mode 100644 openbsc/include/openbsc/gtphub.h > create mode 100644 openbsc/src/gprs/gtphub.c > create mode 100644 openbsc/src/gprs/gtphub_main.c > create mode 100644 openbsc/src/gprs/gtphub_sep.c > create mode 100644 openbsc/src/gprs/gtphub_vty.c > create mode 100644 openbsc/tests/gtphub/Makefile.am > create mode 100644 openbsc/tests/gtphub/gtphub_nc_test.gtphub.conf > create mode 100644 openbsc/tests/gtphub/gtphub_nc_test.ok > create mode 100755 openbsc/tests/gtphub/gtphub_nc_test.sh > create mode 100644 openbsc/tests/gtphub/gtphub_test.c > create mode 100644 openbsc/tests/gtphub/gtphub_test.ok > create mode 100755 openbsc/tests/gtphub/hex2bin.py > From suraev at alumni.ntnu.no Wed Nov 4 09:58:17 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Wed, 4 Nov 2015 10:58:17 +0100 Subject: CDR-like logs In-Reply-To: References: <5637468C.20002@alumni.ntnu.no> Message-ID: <5639D6B9.4020208@alumni.ntnu.no> I've hoped to skip this extra step :-) 04.11.2015 09:20, Alexander Chemeris ?????: > Max, > > You can connect it to FreeSWITCH or any other VoIP PBX and generate logs of pretty > much any format. > > Please excuse typos. Written with a touchscreen keyboard. > > -- > Regards, > Alexander Chemeris > CEO Fairwaves, Inc. > https://fairwaves.co > > On Nov 2, 2015 14:27, "Suraev" > > wrote: > > Hi. > > If I enable detailed-enough logs of OpenBSC I can get data regarding call and sms > transactions: > > new state INITIATED -> MO_CALL_PROC, 1 active transactions > new state MO_CALL_PROC -> CONNECT_IND, 1 active transactions > new state CONNECT_IND -> ACTIVE, 1 active transactions > new state ACTIVE -> DISCONNECT_IND, 1 active transactions > new state DISCONNECT_IND -> RELEASE_REQ, 1 active transactions > new state RELEASE_REQ -> NULL, 0 active transactions > > However there's no information regarding which mobile is participating in the > transaction. > > Is there some way to get CDR-like data from OpenBSC? Smth like > imsi=123 call_to 35345345 duration 12 > imsi=53 sms_from 234234 > ... > > cheers, > Max. > From holger at freyther.de Wed Nov 4 10:14:15 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 4 Nov 2015 11:14:15 +0100 Subject: CDR-like logs In-Reply-To: <5639D6B9.4020208@alumni.ntnu.no> References: <5637468C.20002@alumni.ntnu.no> <5639D6B9.4020208@alumni.ntnu.no> Message-ID: > On 04 Nov 2015, at 10:58, Suraev wrote: > > I've hoped to skip this extra step :-) Have a look at the SGSN, then look at the BCSM for camel and then add signals during the call for the BCSM state changes and finally you can write a CDR module that will register to these events and do the logging. :) holger From suraev at alumni.ntnu.no Wed Nov 4 12:54:39 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Wed, 4 Nov 2015 13:54:39 +0100 Subject: CDR-like logs In-Reply-To: References: <5637468C.20002@alumni.ntnu.no> <5639D6B9.4020208@alumni.ntnu.no> Message-ID: <563A000F.4070207@alumni.ntnu.no> That's the most compelling argument for installing SIP server I've ever heard :-D 04.11.2015 11:14, Holger Freyther ?????: > >> On 04 Nov 2015, at 10:58, Suraev wrote: >> >> I've hoped to skip this extra step :-) > > Have a look at the SGSN, then look at the BCSM for camel and then add > signals during the call for the BCSM state changes and finally you can write > a CDR module that will register to these events and do the logging. :) > > > holger > From sipos.csaba at kvk.uni-obuda.hu Wed Nov 4 14:36:17 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Wed, 4 Nov 2015 15:36:17 +0100 (CET) Subject: PySIM: SW match failed In-Reply-To: <1940417519.6857089.1446647154167.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <983547764.6859205.1446647777849.JavaMail.zimbra@kvk.uni-obuda.hu> Dear Holger, Alexander, list In the last couple of weeks we experiencing an issue programmin the SJS1 USIm cards with PySIM. We can read them, but during programming, a lot of us got the following error: root at D6420:~/pysim# root at D6420:~/pysim# ./pySim-read.py -p 0 Reading ... ICCID: 8988211000000073729 IMSI: 901700000007372 SMSP: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ACC: 0004 MSISDN: Not available Done ! root at D6420:~/pysim# ./pySim-prog.py -p 0 -t sysmoUSIM-SJS1 -i 208920000000001 -s 8988211000000073729 -x 208 -y 92 --op=11111111111111111111111111111111 -k 8BAF473F2F8FD09487CCCBD7097C6862 -a 55127679 Insert card now (or CTRL-C to cancel) Generated card parameters : > Name : Magic > SMSP : e1ffffffffffffffffffffffff0581005155f5ffffffffffff000000 > ICCID : 8988211000000073729 > MCC/MNC : 208/92 > IMSI : 208920000000001 > Ki : 8BAF473F2F8FD09487CCCBD7097C6862 > OPC : 8e27b6af0e692e750f32667a3b14605d > ACC : None Programming ... Traceback (most recent call last): File "./pySim-prog.py", line 626, in card.program(cp) File "/root/pysim/pySim/cards.py", line 438, in program r = self._scc.select_file(['3f00']) File "/root/pysim/pySim/commands.py", line 44, in select_file data, sw = self._tp.send_apdu_checksw(self.cla_byte + "a4000002" + i) File "/root/pysim/pySim/transport/__init__.py", line 87, in send_apdu_checksw raise RuntimeError("SW match failed ! Expected %s and got %s." % (sw.lower(), rv[1])) RuntimeError: SW match failed ! Expected 9000 and got 6a86. root at D6420:~/pysim# Please note that in this particular case I was trying to reprogram an SJS1 card with a card reader (and the exact command) that was worked in the past, and yet its not working now. I don't think this is a PySIM error, but more likely a Pyscard or PCSC-lite problem. I tried several Pyscard versions (1.6.10, 1.6.12, 1.6.16. 1.7.0 and 1.9.0) and the it was all the same. At this point I don't have any more ideas what to try, if anyone would have any suggestions I would apreciate it. I am certainly not alone with this issue, several folks from OpenAIR and OpenLTE are also having the very same problem. Regards, Csaba From nhofmeyr at sysmocom.de Wed Nov 4 15:24:33 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 4 Nov 2015 16:24:33 +0100 Subject: [PATCH] gtphub collapsed patch (aka bomb) In-Reply-To: <5639CDED.3060406@tpip.net> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> <5639CDED.3060406@tpip.net> Message-ID: <20151104152433.GA1486@dub5> On Wed, Nov 04, 2015 at 10:20:45AM +0100, Andreas Schultz wrote: > Hi Neels, > > I'm trying to understand how you handle a PDP Create Context message where > the SGSN Address for control plane and an SGSN address for user traffic differ > from the sender IP? That part is ultimately still missing, as may be visible from the PDP Context unit test. So far it's recording only the actual originating address as returned by the socket read. It's my plan for today. But the internal storage is ready. gtphub will examine the IEs SGSN Address for signalling SGSN Address for user traffic and GGSN Address for Control Plane GGSN Address for user traffic and store these addresses for future use. The addresses are stored separately, with association pointers from one to the other. There's a bit of a handwavy situation there, e.g. if an SGSN sends a PDP Create request from 1.2.3.4, but the address in the IE is 5.6.7.8. gtphub later on needs to find the proper peer record; if I stored a peer for 5.6.7.8 and the SGSN again were to send from 1.2.3.4, gtphub would not be able to match that up. I will so far only store the IE's address (5.6.7.8), and expect the SGSN to continue sending ctrl messages for this PDP context from 5.6.7.8 from then on. After all that's what it told me to use. The user plane is not affected, because the only place to find the user address is in the IE from a Create PDP Context message, sent on the ctrl plane, so there's no mismatch situation arising. If any GSN in practice actually wanted to send all ctrl messages from 1.2.3.4 but expected the returned ctrl responses to come back on 5.6.7.8, then gtphub would have to store the sender's address 1.2.3.4 as well. Concerning the ports, we've discussed before that the proper way according to spec is to always use the standard port number for the respective plane when sending out a packet to a peer. gtphub can manage both (sender's port or override with standard port), but when the IE's address mismatches the sender's address, and if I henceforth want use the IE's address, I have no port information for that one (see 7.7.32 in 29.060 and 5.1 in 23.003). The sender's port is actually not relevant at all, so I will semantically have to use the default port number. gtphub would also be able to manage "return to sender", if that's what we need (that's what it's doing now, preliminarily). Thinkable configs: - Use exclusively the address from the IEs. - Disallow mismatch of CTRL sender and address in CTRL IE. - When addresses match, use sender's port (ugly, but OpenGGSN seems to use the sender's port, so maybe there's something to it; yet I don't trust OpenGGSN by now). I'm handling IPv4 and v6 transparently, BTW. The difference in the IE is only detectable from the IE length, as 7.7.32 doesn't include the GSN address' type field. Let's hope IPv8 will have the same length as IPv6 :P Does that answer your question? And as always, please let me know if you find any dent in my reasoning :) ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From aschultz at tpip.net Wed Nov 4 15:46:41 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Wed, 4 Nov 2015 16:46:41 +0100 Subject: [PATCH] gtphub collapsed patch (aka bomb) In-Reply-To: <20151104152433.GA1486@dub5> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> <5639CDED.3060406@tpip.net> <20151104152433.GA1486@dub5> Message-ID: <563A2861.8020003@tpip.net> On 11/04/2015 04:24 PM, Neels Hofmeyr wrote: > On Wed, Nov 04, 2015 at 10:20:45AM +0100, Andreas Schultz wrote: >> Hi Neels, >> >> I'm trying to understand how you handle a PDP Create Context message where >> the SGSN Address for control plane and an SGSN address for user traffic differ >> from the sender IP? > > That part is ultimately still missing, as may be visible from the PDP > Context unit test. So far it's recording only the actual originating > address as returned by the socket read. It's my plan for today. > > But the internal storage is ready. gtphub will examine the IEs > SGSN Address for signalling > SGSN Address for user traffic > and > GGSN Address for Control Plane > GGSN Address for user traffic > and store these addresses for future use. The addresses are stored > separately, with association pointers from one to the other. > > There's a bit of a handwavy situation there, e.g. if an SGSN sends a PDP > Create request from 1.2.3.4, but the address in the IE is 5.6.7.8. gtphub > later on needs to find the proper peer record; if I stored a peer for > 5.6.7.8 and the SGSN again were to send from 1.2.3.4, gtphub would not be > able to match that up. I will so far only store the IE's address > (5.6.7.8), and expect the SGSN to continue sending ctrl messages for this > PDP context from 5.6.7.8 from then on. After all that's what it told me to > use. The user plane is not affected, because the only place to find the > user address is in the IE from a Create PDP Context message, sent on the > ctrl plane, so there's no mismatch situation arising. > > If any GSN in practice actually wanted to send all ctrl messages from > 1.2.3.4 but expected the returned ctrl responses to come back on 5.6.7.8, > then gtphub would have to store the sender's address 1.2.3.4 as well. The above doesn't seem right. The specs say to send replies to the IP and port where the request originated. The GSN control plan address is only to be used when we want to send a request to the other side. So, shouldn't this work like this: * for each request, cache the source IP+Port and forward the reply back to that, * for each PDP context, remember the ctrl and data IP as requested by the GSN, forward requests to that I had some fun trying to understand how path management is supposed to work when control source IP != GSN control IP. I still don't get how the restart counter in the Recovery IE is supposed to be match to the GSN. > Concerning the ports, we've discussed before that the proper way according to > spec is to always use the standard port number for the respective plane when > sending out a packet to a peer. That would apply to requests only, replies go back to the original source. Note: in GTPv2 this is getting even more complicated with triggered messages. > gtphub can manage both (sender's port or > override with standard port), but when the IE's address mismatches the sender's > address, and if I henceforth want use the IE's address, I have no port > information for that one (see 7.7.32 in 29.060 and 5.1 in 23.003). The sender's > port is actually not relevant at all, so I will semantically have to use the > default port number. gtphub would also be able to manage "return to sender", if > that's what we need (that's what it's doing now, preliminarily). > > Thinkable configs: > - Use exclusively the address from the IEs. > - Disallow mismatch of CTRL sender and address in CTRL IE. Seems like the reasonable thing to do. > - When addresses match, use sender's port (ugly, but OpenGGSN seems to use the > sender's port, so maybe there's something to it; yet I don't trust OpenGGSN > by now). Replies should always go back to the request source IP. Only requests got to the GSN control plane IP. > I'm handling IPv4 and v6 transparently, BTW. The difference in the IE is only > detectable from the IE length, as 7.7.32 doesn't include the GSN address' type > field. Let's hope IPv8 will have the same length as IPv6 :P Lets hope all peers you are talking to are on the same IP version. Mixing IPv4 and IPv6 peer will be fun (see the Alternative GGSN Address). > Does that answer your question? > > And as always, please let me know if you find any dent in my reasoning :) I'm still trying to understand some of the finer points of GTP myself. - Andreas > > ~Neels From nhofmeyr at sysmocom.de Wed Nov 4 22:47:07 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 4 Nov 2015 23:47:07 +0100 Subject: [PATCH] gtphub collapsed patch (aka bomb) In-Reply-To: <563A2861.8020003@tpip.net> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> <5639CDED.3060406@tpip.net> <20151104152433.GA1486@dub5> <563A2861.8020003@tpip.net> Message-ID: <20151104224707.GB1486@dub5> On Wed, Nov 04, 2015 at 04:46:41PM +0100, Andreas Schultz wrote: > The specs say to send replies to the IP and port where the request > originated. The GSN control plan address is only to be used when we > want to send a request to the other side. Goodness, really? > * for each request, cache the source IP+Port and forward the reply back > to that, Let's consider IP address and port separately. - IP address: The only time when the sender IP *can* even differ is during Create PDP Context messages. The only question is, where does the response to a Create PDP Context Request go. All other cases are clear. (For Update, only the Response can have differing IP address, but that's already the reply.) And even there it doesn't really make sense to have different addresses: the Create PDP Context Response coming back from the GGSN is explicitly addressed to the TEI that was declared in the Request. Why then would it be sent to a different IP address than the one that was also declared in the Request, explicitly to negotiate that TEI for that IP address? Like, for one more reply, the TEI belongs to the sender address, and just after that it belongs to the negotiated address? If this is used in practice, can anyone illustrate for what situation it is useful to negotiate a PDP context where the sender differs from the negotiated Ctrl address? Load balancing for User, yes, but Ctrl?? In the user plane the entire ambiguity does not exist at all. Messages are sent to the address that was in the Create PDP Context request, period. So I actually assume the ctrl plane works the same. OpenGGSN does actually reply to the same IP *and* port it received from, always. It also replies to the same IP address even if the IE's address in the Create Context Request differs. This may just disprove all my points. > >- Disallow mismatch of CTRL sender and address in CTRL IE. > > Seems like the reasonable thing to do. In that case, the SGSN sender address and the CTRL address in the Create PDP Context Request must be identical and all the awkwardness is cut out. And wouldn't work if someone tried to do that, of course. Does anyone? - Port: Ports can differ all the time. Any port number can be used as sender to send to a standard port of a peer. This becomes weird as soon as we're talking GTP packets that contain a nonzero destination TEI to send to. Echos send no TEI (zero), but they also don't require any resolution or tracing of peers: just reply, done. They go back to where they came from: 29.060 10.1.2.2: "NOTE: The source IP address of the Echo Response message shall be the same as the destination IP address of the Echo Request message." To see this "NOTE"d as loudly makes me assume that Echo is an exception in that way. If I'm sending a message for a specific TEI, sending it to a different port feels wrong. The TEI was negotiated as part of a Create PDP Context for an IP address, with no port information attached. The TEI hence, at least in my head, resolves to an IP address with the standard port. No matter if it's a request or a response. That was my first guess... But again OpenGGSN always replies to the sender. Say different ports are used, what is the scope for TEI, recovery and sequence number? Does an IP address share these across all its ports, or does each port have a separate set of TEIs? In case two separate ports know about the same TEIs, how then is it a problem if replies only ever go back to the default port? gtphub implementation wise, a known sequence number can be used to trace back to the sender port, and the TEI can then be ignored. Once an unknown sequence number arises, the TEI resolves to the default port. Having to manage ports per request seems unneccessary, on top of all the TEI business. Is there a benefit? Load balancing is done on the IP address level already, right? Is this ever used in the field? > I'm still trying to understand some of the finer points of GTP myself. If anyone can enlighten us with hard facts from the daily grunge of actual GTP usage, that would be appreciated :) We could examine some traces and check... - whether sender addresses ever differ from PDP Context message IE addresses, and where responses go. - whether port numbers are ever nonstandard, - where responses go, and - how TEIs and seq nrs seem to scope. > >I'm handling IPv4 and v6 transparently, BTW. The difference in the IE is only > >detectable from the IE length, as 7.7.32 doesn't include the GSN address' type > >field. Let's hope IPv8 will have the same length as IPv6 :P > > Lets hope all peers you are talking to are on the same IP version. Mixing IPv4 > and IPv6 peer will be fun (see the Alternative GGSN Address). Hmm yes, I just noticed that, too. Shall this and shall that. According to spec, you can't run a v6 GSN without also supplying alternative v4 addresses. I'll just let v6 tag along until it becomes relevant... Thanks again, this discussion helps a lot! ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Nov 4 23:29:34 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 5 Nov 2015 00:29:34 +0100 Subject: [PATCH 5/6] gsup/oap: add OAP to GSUP client. In-Reply-To: <6A5B69AF-2A84-4901-92EF-DCD8C4DC8A0E@freyther.de> References: <1444643858-15149-1-git-send-email-nhofmeyr@sysmocom.de> <1444643858-15149-6-git-send-email-nhofmeyr@sysmocom.de> <20151102140629.GA1241@dub5> <20151102181821.GA1678@dub5> <6A5B69AF-2A84-4901-92EF-DCD8C4DC8A0E@freyther.de> Message-ID: <20151104232934.GC1486@dub5> On Mon, Nov 02, 2015 at 08:20:39PM +0100, Holger Freyther wrote: > > > On 02 Nov 2015, at 19:18, Neels Hofmeyr wrote: > > > > > > > > I personally find it mildly ugly, but let's avoid the discussion. > > > > To reiterate, I'd like to know whether gtphub should/really must ;) be > > changed to the latter style. > > yes. heh, was actually just four places in gtphub. And the script fixed five others elsewhere while at it, sent in a separate patch mail. ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Nov 4 23:28:58 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 5 Nov 2015 00:28:58 +0100 Subject: [PATCH] fix some 'else' indenting styles Message-ID: <1446679738-22264-1-git-send-email-nhofmeyr@sysmocom.de> --- openbsc/src/gprs/gprs_sgsn.c | 2 +- openbsc/src/libbsc/bsc_vty.c | 3 +-- openbsc/src/libmsc/gsm_04_08.c | 9 +++------ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index c4dc9d7..982fb92 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -576,7 +576,7 @@ static void drop_one_pdp(struct sgsn_pdp_ctx *pdp) { if (pdp->mm->mm_state == GMM_REGISTERED_NORMAL) gsm48_tx_gsm_deact_pdp_req(pdp, GSM_CAUSE_NET_FAIL); - else { + else { /* FIXME: GPRS paging in case MS is SUSPENDED */ LOGPDPCTXP(LOGL_NOTICE, pdp, "Hard-dropping PDP ctx due to GGSN " "recovery\n"); diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 24bae97..8141b21 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -2174,8 +2174,7 @@ DEFUN(cfg_bts_rach_ac_class, cfg_bts_rach_ac_class_cmd, bts->si_common.rach_control.t3 &= ~(0x1 << control_class); else bts->si_common.rach_control.t3 |= (0x1 << control_class); - else - if (allowed) + else if (allowed) bts->si_common.rach_control.t2 &= ~(0x1 << (control_class - 8)); else bts->si_common.rach_control.t2 |= (0x1 << (control_class - 8)); diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 7db7586..c8aea06 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -806,8 +806,7 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) ptr8[7] = bcdify(tzunits); /* Set negative time */ ptr8[7] |= 0x08; - } - else { + } else { tzunits = bts->tz.hr*4; tzunits = tzunits + (bts->tz.mn/15); ptr8[7] = bcdify(tzunits); @@ -815,8 +814,7 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) /* Convert DST value */ if (bts->tz.dst >= 0 && bts->tz.dst <= 2) dst = bts->tz.dst; - } - else { + } else { /* Need to get GSM offset and convert into 15 min units */ /* This probably breaks if gmtoff returns a value not evenly divisible by 15? */ local_time = localtime(&cur_t); @@ -831,8 +829,7 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) ptr8[7] = bcdify(tzunits); /* Flip it to negative */ ptr8[7] |= 0x08; - } - else + } else ptr8[7] = bcdify(tzunits); /* Does not support DST +2 */ -- 2.1.4 From nhofmeyr at sysmocom.de Thu Nov 5 00:27:52 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 5 Nov 2015 01:27:52 +0100 Subject: GTP peers Message-ID: <20151105002752.GD1486@dub5> I've just noticed that my code cannot handle the same GSN's Ctrl address handing out differing User plane addresses to various other GSNs. That's the point of load balancing, after all. So far I've paired up a Ctrl and a User peer 1:1, that won't do. That and the reply-to-same-port will make the structures a bit more complex still: - Each User address has its one managing Ctrl address, but the same Ctrl address may be used for several User addresses. - One address can have several ports, and a sequence number that came from a given port should get its reply with the same sequence number back to that port (discussion pending?). ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From laforge at gnumonks.org Thu Nov 5 09:06:50 2015 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 5 Nov 2015 10:06:50 +0100 Subject: CDR-like logs In-Reply-To: <563A000F.4070207@alumni.ntnu.no> References: <5637468C.20002@alumni.ntnu.no> <5639D6B9.4020208@alumni.ntnu.no> <563A000F.4070207@alumni.ntnu.no> Message-ID: <20151105090650.GB9183@nataraja> On Wed, Nov 04, 2015 at 01:54:39PM +0100, Suraev wrote: > That's the most compelling argument for installing SIP server I've ever heard :-D well, if you prefer to do that than to contribute some lines of code for the benefit of you and every other user, that's your decision to make. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Thu Nov 5 09:05:15 2015 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 5 Nov 2015 10:05:15 +0100 Subject: PySIM: SW match failed In-Reply-To: <983547764.6859205.1446647777849.JavaMail.zimbra@kvk.uni-obuda.hu> References: <1940417519.6857089.1446647154167.JavaMail.zimbra@kvk.uni-obuda.hu> <983547764.6859205.1446647777849.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <20151105090515.GA9183@nataraja> On Wed, Nov 04, 2015 at 03:36:17PM +0100, Sipos Csaba wrote: > RuntimeError: SW match failed ! Expected 9000 and got 6a86. According to ISO 7816-4, this 6a86 means 'incorrect P1 or P2 parameter'. > At this point I don't have any more ideas what to try, if anyone would have any suggestions I would apreciate it. Please activate (or hack some code for) tracing the actual APDUs that pySim excahnges with the card. IIRC, pySim already has that option. Once you see the raw APDUs, you can compare their encoding (particularly P1/P2) with those described in the relevant ETSI/3GPP (U)SIM specifications. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Thu Nov 5 09:13:53 2015 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 5 Nov 2015 10:13:53 +0100 Subject: EGPRS(EDGE) data rate is not stable? In-Reply-To: References: Message-ID: <20151105091353.GC9183@nataraja> On Wed, Oct 14, 2015 at 08:46:08AM +0800, wangpalm wrote: > With phone attached to my configured EGPRS, sometimes it has a data > rate around 200kbps (which is near optimal), while frequently it has a > intolerablly slow data rate. Is it a common problem, or it's due to > incorrect configrations or hardware problems? I run a gsm test > system with nanobts, and the libosmocore, openbsc, openggsn codes are > based on the version around end of April 2015. The configuration is > made accorrding to the instruction from openbsc web. The correction in > fc_queue_timer_cfg has also been made according to Jacob Erlbeck. You are running a complex setup (a GSM/EGPRS network), and there can be many reasons. * Have you excluded RF interference? In order to do that, you could connect your EGPRS capable MS over coaxial cable, duplexer and attenuators directly without any antenna to the BTS. This way you exclude any RF side interference. you also exclude the possibility that any other phones not part of your test setup are meanwhile attempting to register or use services of the network Next point is to obtain protocol traces (pcap) with synchronized time-stamps on * the MS side (the IP you get out of your MS) * the Gb side betwene BTS and SGSN * the IP side of the GGSN Recording those pcap files and looking at what happens where in the timeline can be very useful. * Have you studied the protocol traces on the Gb level? Looking at them it should be easy to determine if flow control was an issue at the time you experience low througput. * Have you studied the IP level protocol traces on MS side or on the GGSN side? What does a TCP sequence number / RTT analysis give you for those traces? When are packets lost? * you could use OsmocomBB + bust_ind + gprsdecode to obtain air-interface protocol traces to further analyze that interface. * finally, the nanoBTS telnet debug interface might be of help to provide you some insight into what is happening in the (closed source) PCU at the time you experience problems. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From suraev at alumni.ntnu.no Thu Nov 5 12:27:48 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Thu, 5 Nov 2015 13:27:48 +0100 Subject: CDR-like logs In-Reply-To: <20151105090650.GB9183@nataraja> References: <5637468C.20002@alumni.ntnu.no> <5639D6B9.4020208@alumni.ntnu.no> <563A000F.4070207@alumni.ntnu.no> <20151105090650.GB9183@nataraja> Message-ID: <563B4B44.7010708@alumni.ntnu.no> Grasping camel will take orders of magnitude more time than getting logs out of SIP server. Sadly, I'm time-constrained with regards to this feature. 05.11.2015 10:06, Harald Welte ?????: > On Wed, Nov 04, 2015 at 01:54:39PM +0100, Suraev wrote: >> That's the most compelling argument for installing SIP server I've ever heard :-D > > well, if you prefer to do that than to contribute some lines of code for > the benefit of you and every other user, that's your decision to make. > From aschultz at tpip.net Fri Nov 6 09:43:38 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Fri, 6 Nov 2015 10:43:38 +0100 (CET) Subject: [PATCH] gtphub collapsed patch (aka bomb) In-Reply-To: <20151104224707.GB1486@dub5> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> <5639CDED.3060406@tpip.net> <20151104152433.GA1486@dub5> <563A2861.8020003@tpip.net> <20151104224707.GB1486@dub5> Message-ID: <819890475.865025.1446803018892.JavaMail.zimbra@tpip.net> ----- Original Message ----- > From: "Neels Hofmeyr" > To: "Andreas Schultz" > Cc: openbsc at lists.osmocom.org > Sent: Wednesday, November 4, 2015 11:47:07 PM > Subject: Re: [PATCH] gtphub collapsed patch (aka bomb) > On Wed, Nov 04, 2015 at 04:46:41PM +0100, Andreas Schultz wrote: >> The specs say to send replies to the IP and port where the request >> originated. The GSN control plan address is only to be used when we >> want to send a request to the other side. > > Goodness, really? > >> * for each request, cache the source IP+Port and forward the reply back >> to that, > > Let's consider IP address and port separately. > > - IP address: > > The only time when the sender IP *can* even differ is during Create PDP > Context messages. The only question is, where does the response to a Create > PDP Context Request go. All other cases are clear. > (For Update, only the Response can have differing IP address, but that's > already the reply.) I think you are over complicating thinks. Lets take this step by step. The simplest case is a reply. It will *always* be sent to the source IP and port of the request. The source of the response should be the destination IP and port of the request the triggered the response. So, you basically just reverse source and destination and be done. The GSN arguments in the request do not change that. The GSN arguments are only used when you have to send a request to the other side after the initial request. So, for any new PDP context, the initial request from the SGNS will go to the GGSN address that you AAA told you use. Any follow up request will go to the IP that the GGSN told you to use. If the GGSN needs to send a request to the SGSN it will use the IP the GGSN told it to use. Thinks get interesting when you look at the Echo requests. For our GGSN implementation, I decided to only use the IP's from the GSN information elements. > And even there it doesn't really make sense to have different addresses: > the Create PDP Context Response coming back from the GGSN is explicitly > addressed to the TEI that was declared in the Request. Why then would it > be sent to a different IP address than the one that was also declared in > the Request, explicitly to negotiate that TEI for that IP address? The reply will be sent back to the source in any case. TEI's belong to the GSN IP's from the IE, not to the source IP. > Like, for one more reply, the TEI belongs to the sender address, and just > after that it belongs to the negotiated address? > > If this is used in practice, can anyone illustrate for what situation it > is useful to negotiate a PDP context where the sender differs from the > negotiated Ctrl address? Load balancing for User, yes, but Ctrl?? > > In the user plane the entire ambiguity does not exist at all. Messages > are sent to the address that was in the Create PDP Context request, > period. So I actually assume the ctrl plane works the same. > > OpenGGSN does actually reply to the same IP *and* port it received from, > always. It also replies to the same IP address even if the IE's address in > the Create Context Request differs. This may just disprove all my points. For the reply, that is absolutely correct. What does it do with any follow up request? Would it use the IP from the IE or the original source IP? >> >- Disallow mismatch of CTRL sender and address in CTRL IE. >> >> Seems like the reasonable thing to do. > > In that case, the SGSN sender address and the CTRL address in the Create > PDP Context Request must be identical and all the awkwardness is cut out. > And wouldn't work if someone tried to do that, of course. Does anyone? I have played only with Cisco (CSR 1000v) and there you can't configure the source IP to differ from the ctrl IP. Andreas > > > - Port: > > Ports can differ all the time. Any port number can be used as sender to > send to a standard port of a peer. > > This becomes weird as soon as we're talking GTP packets that contain > a nonzero destination TEI to send to. > > Echos send no TEI (zero), but they also don't require any resolution or > tracing of peers: just reply, done. They go back to where they came from: > 29.060 10.1.2.2: "NOTE: The source IP address of the Echo Response > message shall be the same as the destination IP address of the Echo > Request message." > To see this "NOTE"d as loudly makes me assume that Echo is an exception in > that way. > > If I'm sending a message for a specific TEI, sending it to a different > port feels wrong. The TEI was negotiated as part of a Create PDP Context > for an IP address, with no port information attached. The TEI hence, at > least in my head, resolves to an IP address with the standard port. No > matter if it's a request or a response. That was my first guess... > > But again OpenGGSN always replies to the sender. > > Say different ports are used, what is the scope for TEI, recovery and > sequence number? Does an IP address share these across all its ports, or > does each port have a separate set of TEIs? > > In case two separate ports know about the same TEIs, how then is it a > problem if replies only ever go back to the default port? > > gtphub implementation wise, a known sequence number can be used to trace > back to the sender port, and the TEI can then be ignored. Once an unknown > sequence number arises, the TEI resolves to the default port. > > Having to manage ports per request seems unneccessary, on top of all the > TEI business. Is there a benefit? Load balancing is done on the IP address > level already, right? Is this ever used in the field? > > >> I'm still trying to understand some of the finer points of GTP myself. > > If anyone can enlighten us with hard facts from the daily grunge of actual > GTP usage, that would be appreciated :) > > We could examine some traces and check... > - whether sender addresses ever differ from PDP Context message IE > addresses, and where responses go. > - whether port numbers are ever nonstandard, > - where responses go, and > - how TEIs and seq nrs seem to scope. > > >> >I'm handling IPv4 and v6 transparently, BTW. The difference in the IE is only >> >detectable from the IE length, as 7.7.32 doesn't include the GSN address' type >> >field. Let's hope IPv8 will have the same length as IPv6 :P >> >> Lets hope all peers you are talking to are on the same IP version. Mixing IPv4 >> and IPv6 peer will be fun (see the Alternative GGSN Address). > > Hmm yes, I just noticed that, too. Shall this and shall that. According to > spec, you can't run a v6 GSN without also supplying alternative v4 > addresses. I'll just let v6 tag along until it becomes relevant... > > > Thanks again, this discussion helps a lot! > > ~Neels From suraev at alumni.ntnu.no Fri Nov 6 15:08:44 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Fri, 6 Nov 2015 16:08:44 +0100 Subject: abis flapping Message-ID: <563CC27C.8090401@alumni.ntnu.no> Hi. I've enabled extra logging for BTS <-> BSC communication and I can see following neverending cycle - see attachement. Is th constant flow of "Set Chan Attr" and channel state alternating between Enabled and Disabled states an expected thing or it's some sort of misconfiguration on my part? regards, Max. -------------- next part -------------- A non-text attachment was scrubbed... Name: bscbts.log Type: text/x-log Size: 12465 bytes Desc: not available URL: From alexander.huemer at xx.vu Fri Nov 6 19:48:20 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:48:20 +0100 Subject: Some patches Message-ID: <20151106194820.GC30339@yade.xx.vu> Hi, here are some patches that I produced while compiling some osmocom projects and its dependencies on a new box. Most of them are trivialities that prevent compiler warnings. The patch for openbsc though fixes a bug that prevents the build when libgtp from openggsn is not present on the system. Kind regards, -Alex From alexander.huemer at xx.vu Fri Nov 6 19:55:23 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:55:23 +0100 Subject: [PATCH 0/2] libosmocore In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <1446839725-21682-1-git-send-email-alexander.huemer@xx.vu> src/stat_item.c | 2 +- utils/osmo-sim-test.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) From alexander.huemer at xx.vu Fri Nov 6 19:55:24 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:55:24 +0100 Subject: [PATCH 1/2] osmo-sim-test: add missing include In-Reply-To: <1446839725-21682-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839725-21682-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839725-21682-2-git-send-email-alexander.huemer@xx.vu> --- utils/osmo-sim-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/osmo-sim-test.c b/utils/osmo-sim-test.c index 9d1b481..d6299e9 100644 --- a/utils/osmo-sim-test.c +++ b/utils/osmo-sim-test.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:55:25 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:55:25 +0100 Subject: [PATCH 2/2] src/stat_item.c: fix cast In-Reply-To: <1446839725-21682-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839725-21682-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839725-21682-3-git-send-email-alexander.huemer@xx.vu> --- src/stat_item.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stat_item.c b/src/stat_item.c index 0545ea0..7017523 100644 --- a/src/stat_item.c +++ b/src/stat_item.c @@ -81,7 +81,7 @@ struct osmo_stat_item_group *osmo_stat_item_group_alloc(void *ctx, size = (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1); /* Store offsets into the item array */ - group->items[item_idx] = (void *)items_size; + group->items[item_idx] = (struct osmo_stat_item *)items_size; items_size += size; } -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:56:28 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:56:28 +0100 Subject: [PATCH 0/1] libosmo-abis In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <1446839789-26954-1-git-send-email-alexander.huemer@xx.vu> include/osmocom/abis/lapd.h | 2 ++ 1 file changed, 2 insertions(+) From alexander.huemer at xx.vu Fri Nov 6 19:56:29 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:56:29 +0100 Subject: [PATCH] export lapd_tei_alloc(), used in libosmo-netif In-Reply-To: <1446839789-26954-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839789-26954-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839789-26954-2-git-send-email-alexander.huemer@xx.vu> --- include/osmocom/abis/lapd.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/osmocom/abis/lapd.h b/include/osmocom/abis/lapd.h index 2457cde..2987633 100644 --- a/include/osmocom/abis/lapd.h +++ b/include/osmocom/abis/lapd.h @@ -50,6 +50,8 @@ enum lapd_recv_errors { __LAPD_ERR_MAX }; +struct lapd_tei *lapd_tei_alloc(struct lapd_instance *li, uint8_t tei); + int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error); void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi, -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:57:22 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:57:22 +0100 Subject: [PATCH 0/1] libosmo-netif In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <1446839843-30904-1-git-send-email-alexander.huemer@xx.vu> examples/lapd-over-datagram-network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) From alexander.huemer at xx.vu Fri Nov 6 19:57:23 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:57:23 +0100 Subject: [PATCH] teip is a pointer, not an int In-Reply-To: <1446839843-30904-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839843-30904-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839843-30904-2-git-send-email-alexander.huemer@xx.vu> --- examples/lapd-over-datagram-network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/lapd-over-datagram-network.c b/examples/lapd-over-datagram-network.c index 74bba74..8d3fbde 100644 --- a/examples/lapd-over-datagram-network.c +++ b/examples/lapd-over-datagram-network.c @@ -129,7 +129,7 @@ void lapd_rx_cb(struct osmo_dlsap_prim *dp, uint8_t tei, uint8_t sapi, int main(int argc, char *argv[]) { - int teip; + struct lapd_tei *teip; tall_test = talloc_named_const(NULL, 1, "lapd_test"); @@ -159,7 +159,7 @@ int main(int argc, char *argv[]) } teip = lapd_tei_alloc(lapd, tei); - if (teip == 0) { + if (teip == NULL) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot assign TEI\n"); exit(EXIT_FAILURE); } -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:58:11 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:58:11 +0100 Subject: [PATCH 0/1] openbsc In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <1446839892-2266-1-git-send-email-alexander.huemer@xx.vu> openbsc/tests/oap/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) From alexander.huemer at xx.vu Fri Nov 6 19:58:12 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:58:12 +0100 Subject: [PATCH] tests/oap: depend on libgtp In-Reply-To: <1446839892-2266-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839892-2266-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839892-2266-2-git-send-email-alexander.huemer@xx.vu> exclude logic copied from src/gprs/Makefile.am --- openbsc/tests/oap/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/tests/oap/Makefile.am b/openbsc/tests/oap/Makefile.am index e160902..3a76b11 100644 --- a/openbsc/tests/oap/Makefile.am +++ b/openbsc/tests/oap/Makefile.am @@ -3,7 +3,11 @@ AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) EXTRA_DIST = oap_test.ok +if HAVE_LIBGTP +if HAVE_LIBCARES noinst_PROGRAMS = oap_test +endif +endif oap_test_SOURCES = oap_test.c -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:58:58 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:58:58 +0100 Subject: [PATCH 0/3] openggsn In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <1446839941-5156-1-git-send-email-alexander.huemer@xx.vu> Makefile.am | 1 + configure.in => configure.ac | 0 gtp/gtp.c | 11 ++++++----- gtp/pdp.c | 7 ++++--- 4 files changed, 11 insertions(+), 8 deletions(-) From alexander.huemer at xx.vu Fri Nov 6 19:58:59 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:58:59 +0100 Subject: [PATCH 1/3] configure.in -> configure.ac In-Reply-To: <1446839941-5156-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839941-5156-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839941-5156-2-git-send-email-alexander.huemer@xx.vu> --- configure.in => configure.ac | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename configure.in => configure.ac (100%) diff --git a/configure.in b/configure.ac similarity index 100% rename from configure.in rename to configure.ac -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:59:00 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:59:00 +0100 Subject: [PATCH 2/3] Makefile.am: define ACLOCAL_AMFLAGS, include directory m4 In-Reply-To: <1446839941-5156-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839941-5156-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839941-5156-3-git-send-email-alexander.huemer@xx.vu> --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 960ca07..78b83f1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,5 @@ ## Process this file with automake to produce Makefile.in +ACLOCAL_AMFLAGS = -I m4 SUBDIRS = lib gtp ggsn sgsnemu doc pkgconfigdir = $(libdir)/pkgconfig -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:59:01 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:59:01 +0100 Subject: [PATCH 3/3] fix some format specifiers In-Reply-To: <1446839941-5156-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839941-5156-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839941-5156-4-git-send-email-alexander.huemer@xx.vu> --- gtp/gtp.c | 11 ++++++----- gtp/pdp.c | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/gtp/gtp.c b/gtp/gtp.c index 4436336..a3772ff 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -2676,7 +2677,7 @@ int gtp_decaps0(struct gsn_t *gsn) return 0; gsn->err_readfrom++; LOGP(DLGTP, LOGL_ERROR, - "recvfrom(fd0=%d, buffer=%lx, len=%d) failed: status = %d error = %s\n", + "recvfrom(fd0=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n", gsn->fd0, (unsigned long)buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); return -1; @@ -2821,7 +2822,7 @@ int gtp_decaps1c(struct gsn_t *gsn) return 0; gsn->err_readfrom++; LOGP(DLGTP, LOGL_ERROR, - "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s\n", + "recvfrom(fd=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n", fd, (unsigned long)buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); return -1; @@ -2996,7 +2997,7 @@ int gtp_decaps1u(struct gsn_t *gsn) return 0; gsn->err_readfrom++; LOGP(DLGTP, LOGL_ERROR, - "recvfrom(fd1u=%d, buffer=%lx, len=%d) failed: status = %d error = %s\n", + "recvfrom(fd1u=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n", gsn->fd1u, (unsigned long)buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); @@ -3129,7 +3130,7 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len) if (len > sizeof(union gtp_packet) - sizeof(struct gtp0_header)) { gsn->err_memcpy++; LOGP(DLGTP, LOGL_ERROR, - "Memcpy failed: %d > %d\n", len, + "Memcpy failed: %u > %zu\n", len, sizeof(union gtp_packet) - sizeof(struct gtp0_header)); return EOF; @@ -3152,7 +3153,7 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len) sizeof(struct gtp1_header_long)) { gsn->err_memcpy++; LOGP(DLGTP, LOGL_ERROR, - "Memcpy failed: %d > %d\n", len, + "Memcpy failed: %u > %zu\n", len, sizeof(union gtp_packet) - sizeof(struct gtp0_header)); return EOF; diff --git a/gtp/pdp.c b/gtp/pdp.c index e28ffac..f0d6adf 100644 --- a/gtp/pdp.c +++ b/gtp/pdp.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "pdp.h" #include "lookupa.h" @@ -211,7 +212,7 @@ int pdp_tidset(struct pdp_t *pdp, uint64_t tid) int hash = pdp_tidhash(tid); struct pdp_t *pdp2; struct pdp_t *pdp_prev = NULL; - DEBUGP(DLGTP, "Begin pdp_tidset tid = %llx\n", tid); + DEBUGP(DLGTP, "Begin pdp_tidset tid = %"PRIx64"\n", tid); pdp->tidnext = NULL; pdp->tid = tid; for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) @@ -229,7 +230,7 @@ int pdp_tiddel(struct pdp_t *pdp) int hash = pdp_tidhash(pdp->tid); struct pdp_t *pdp2; struct pdp_t *pdp_prev = NULL; - DEBUGP(DLGTP, "Begin pdp_tiddel tid = %llx\n", pdp->tid); + DEBUGP(DLGTP, "Begin pdp_tiddel tid = %"PRIx64"\n", pdp->tid); for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { if (pdp2 == pdp) { if (!pdp_prev) @@ -249,7 +250,7 @@ int pdp_tidget(struct pdp_t **pdp, uint64_t tid) { int hash = pdp_tidhash(tid); struct pdp_t *pdp2; - DEBUGP(DLGTP, "Begin pdp_tidget tid = %llx\n", tid); + DEBUGP(DLGTP, "Begin pdp_tidget tid = %"PRIx64"\n", tid); for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { if (pdp2->tid == tid) { *pdp = pdp2; -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:59:49 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:59:49 +0100 Subject: [PATCH 0/2] osmo-bts In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <1446839991-8820-1-git-send-email-alexander.huemer@xx.vu> src/common/bts_ctrl_lookup.c | 1 + src/common/l1sap.c | 1 + src/common/msg_utils.c | 6 +++--- src/common/rsl.c | 1 + src/common/vty.c | 5 +++-- tests/agch/agch_test.c | 9 +++++---- 6 files changed, 14 insertions(+), 9 deletions(-) From alexander.huemer at xx.vu Fri Nov 6 19:59:50 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:59:50 +0100 Subject: [PATCH 1/2] fix some format specifiers In-Reply-To: <1446839991-8820-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839991-8820-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839991-8820-2-git-send-email-alexander.huemer@xx.vu> --- src/common/msg_utils.c | 6 +++--- src/common/vty.c | 5 +++-- tests/agch/agch_test.c | 9 +++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c index 22a3012..841ffe6 100644 --- a/src/common/msg_utils.c +++ b/src/common/msg_utils.c @@ -96,7 +96,7 @@ int msg_verify_ipa_structure(struct msgb *msg) if (msgb_l1len(msg) < sizeof(struct ipaccess_head)) { LOGP(DL1C, LOGL_ERROR, - "Ipa header insufficient space %d %d\n", + "Ipa header insufficient space %d %zu\n", msgb_l1len(msg), sizeof(struct ipaccess_head)); return -1; } @@ -105,7 +105,7 @@ int msg_verify_ipa_structure(struct msgb *msg) if (ntohs(hh->len) != msgb_l1len(msg) - sizeof(struct ipaccess_head)) { LOGP(DL1C, LOGL_ERROR, - "Incorrect ipa header msg size %d %d\n", + "Incorrect ipa header msg size %d %zu\n", ntohs(hh->len), msgb_l1len(msg) - sizeof(struct ipaccess_head)); return -1; } @@ -142,7 +142,7 @@ int msg_verify_oml_structure(struct msgb *msg) struct abis_om_hdr *omh; if (msgb_l2len(msg) < sizeof(*omh)) { - LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %d\n", + LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %zu\n", msgb_l2len(msg), sizeof(*omh)); return -1; } diff --git a/src/common/vty.c b/src/common/vty.c index 0d52dd7..08ad5d4 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -21,6 +21,7 @@ #include "btsconfig.h" +#include #include #include #include @@ -577,8 +578,8 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) paging_get_queue_max(btsb->paging_state), paging_queue_length(btsb->paging_state), paging_get_lifetime(btsb->paging_state), VTY_NEWLINE); vty_out(vty, " AGCH: Queue limit %u, occupied %d, " - "dropped %llu, merged %llu, rejected %llu, " - "ag-res %llu, non-res %llu%s", + "dropped %"PRIu64", merged %"PRIu64", rejected %"PRIu64", " + "ag-res %"PRIu64", non-res %"PRIu64"%s", btsb->agch_max_queue_length, btsb->agch_queue_length, btsb->agch_queue_dropped_msgs, btsb->agch_queue_merged_msgs, btsb->agch_queue_rejected_msgs, btsb->agch_queue_agch_msgs, diff --git a/tests/agch/agch_test.c b/tests/agch/agch_test.c index 24fa847..4175bdd 100644 --- a/tests/agch/agch_test.c +++ b/tests/agch/agch_test.c @@ -25,6 +25,7 @@ #include #include +#include #include static struct gsm_bts *bts; @@ -143,8 +144,8 @@ static void test_agch_queue(void) printf("AGCH filled: count %u, imm.ass %d, imm.ass.rej %d (refs %d), " "queue limit %u, occupied %d, " - "dropped %llu, merged %llu, rejected %llu, " - "ag-res %llu, non-res %llu\n", + "dropped %"PRIu64", merged %"PRIu64", rejected %"PRIu64", " + "ag-res %"PRIu64", non-res %"PRIu64"\n", count, imm_ass_count, imm_ass_rej_count, imm_ass_rej_ref_count, btsb->agch_max_queue_length, btsb->agch_queue_length, btsb->agch_queue_dropped_msgs, btsb->agch_queue_merged_msgs, @@ -182,8 +183,8 @@ static void test_agch_queue(void) printf("AGCH drained: multiframes %u, imm.ass %d, imm.ass.rej %d (refs %d), " "queue limit %u, occupied %d, " - "dropped %llu, merged %llu, rejected %llu, " - "ag-res %llu, non-res %llu\n", + "dropped %"PRIu64", merged %"PRIu64", rejected %"PRIu64", " + "ag-res %"PRIu64", non-res %"PRIu64"\n", multiframes, imm_ass_count, imm_ass_rej_count, imm_ass_rej_ref_count, btsb->agch_max_queue_length, btsb->agch_queue_length, btsb->agch_queue_dropped_msgs, btsb->agch_queue_merged_msgs, -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 19:59:51 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 20:59:51 +0100 Subject: [PATCH 2/2] add some missing includes In-Reply-To: <1446839991-8820-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839991-8820-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446839991-8820-3-git-send-email-alexander.huemer@xx.vu> --- src/common/bts_ctrl_lookup.c | 1 + src/common/l1sap.c | 1 + src/common/rsl.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/common/bts_ctrl_lookup.c b/src/common/bts_ctrl_lookup.c index e693718..3857ec3 100644 --- a/src/common/bts_ctrl_lookup.c +++ b/src/common/bts_ctrl_lookup.c @@ -26,6 +26,7 @@ #include #include #include +#include extern vector ctrl_node_vec; diff --git a/src/common/l1sap.c b/src/common/l1sap.c index d5dd8a6..894d659 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -45,6 +45,7 @@ #include #include #include +#include static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); diff --git a/src/common/rsl.c b/src/common/rsl.c index a225155..f2f63f8 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -47,6 +47,7 @@ #include #include #include +#include //#define FAKE_CIPH_MODE_COMPL -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 20:00:32 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 21:00:32 +0100 Subject: [PATCH 0/2] osmo-pcu In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <1446840034-11954-1-git-send-email-alexander.huemer@xx.vu> .gitignore | 2 ++ Makefile.am | 1 + configure.ac | 2 ++ m4/DUMMY | 0 src/pcu_vty_functions.cpp | 7 ++++--- 5 files changed, 9 insertions(+), 3 deletions(-) From alexander.huemer at xx.vu Fri Nov 6 20:00:33 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 21:00:33 +0100 Subject: [PATCH 1/2] buildsystem: follow libtoolize suggestions In-Reply-To: <1446840034-11954-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446840034-11954-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446840034-11954-2-git-send-email-alexander.huemer@xx.vu> --- .gitignore | 2 ++ Makefile.am | 1 + configure.ac | 2 ++ m4/DUMMY | 0 4 files changed, 5 insertions(+) create mode 100644 m4/DUMMY diff --git a/.gitignore b/.gitignore index 6cc9aa5..93bd908 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,8 @@ install-sh missing libtool ltmain.sh +m4/*.m4 +compile core core.* diff --git a/Makefile.am b/Makefile.am index 4cbc114..80ecaac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,4 @@ +ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 SUBDIRS = src examples tests diff --git a/configure.ac b/configure.ac index 876f7d4..eabb2e7 100644 --- a/configure.ac +++ b/configure.ac @@ -16,6 +16,8 @@ AC_PROG_CXX AC_PROG_INSTALL LT_INIT +AC_CONFIG_MACRO_DIR([m4]) + dnl checks for header files AC_HEADER_STDC diff --git a/m4/DUMMY b/m4/DUMMY new file mode 100644 index 0000000..e69de29 -- 2.6.2 From alexander.huemer at xx.vu Fri Nov 6 20:00:34 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 21:00:34 +0100 Subject: [PATCH 2/2] fix some format specifiers In-Reply-To: <1446840034-11954-1-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446840034-11954-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446840034-11954-3-git-send-email-alexander.huemer@xx.vu> --- src/pcu_vty_functions.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp index d2a3641..df24171 100644 --- a/src/pcu_vty_functions.cpp +++ b/src/pcu_vty_functions.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "pcu_vty_functions.h" #include "bts.h" #include "gprs_ms_storage.h" @@ -47,7 +48,7 @@ int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data) llist_for_each(ms_iter, &bts->ms_store().ms_list()) { GprsMs *ms = ms_iter->entry(); - vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%d, CS-DL=%d, LLC=%d, " + vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%d, CS-DL=%d, LLC=%zu, " "IMSI=%s%s", ms->tlli(), ms->ta(), ms->current_cs_ul(), ms->current_cs_dl(), @@ -70,9 +71,9 @@ static int show_ms(struct vty *vty, GprsMs *ms) vty_out(vty, " Coding scheme downlink: CS-%d%s", ms->current_cs_dl(), VTY_NEWLINE); vty_out(vty, " MS class: %d%s", ms->ms_class(), VTY_NEWLINE); - vty_out(vty, " LLC queue length: %d%s", ms->llc_queue()->size(), + vty_out(vty, " LLC queue length: %zu%s", ms->llc_queue()->size(), VTY_NEWLINE); - vty_out(vty, " LLC queue octets: %d%s", ms->llc_queue()->octets(), + vty_out(vty, " LLC queue octets: %zu%s", ms->llc_queue()->octets(), VTY_NEWLINE); if (ms->l1_meas()->have_rssi) vty_out(vty, " RSSI: %d dBm%s", -- 2.6.2 From holger at freyther.de Fri Nov 6 20:09:25 2015 From: holger at freyther.de (Holger Freyther) Date: Fri, 6 Nov 2015 21:09:25 +0100 Subject: Some patches In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: > On 06 Nov 2015, at 20:48, Alexander Huemer wrote: > > Hi, > > here are some patches that I produced while compiling some osmocom > projects and its dependencies on a new box. > Most of them are trivialities that prevent compiler warnings. > The patch for openbsc though fixes a bug that prevents the build when > libgtp from openggsn is not present on the system. ah cool! I will try to have a look this weekend. holger From alexander.huemer at xx.vu Fri Nov 6 20:24:40 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 21:24:40 +0100 Subject: Some patches In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <20151106202440.GF30339@yade.xx.vu> Hi, while fixing some trivial compiler warnings in openbsc I stumbled over this: > Making all in abis > CC abis_test.o > abis_test.c: In function ?test_simple_sw_config?: > abis_test.c:68:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > printf("Start: %u len: %zu\n", descr[0].start - simple_config, descr[0].len); > ^ > abis_test.c: In function ?test_dual_sw_config?: > abis_test.c:111:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > printf("Start: %u len: %zu\n", descr[0].start - dual_config, descr[0].len); > ^ > abis_test.c:115:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > printf("Start: %u len: %zu\n", descr[1].start - dual_config, descr[1].len); > ^ > abis_test.c: In function ?test_sw_selection?: > abis_test.c:132:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > printf("Start: %u len: %zu\n", descr[0].start - load_config, descr[0].len); > ^ > abis_test.c:136:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > printf("Start: %u len: %zu\n", descr[1].start - load_config, descr[1].len); The relevant expression is: descr[1].start - load_config and variations thereof. descr[1].start is declared include/openbsc/abis_nm.h as: const uint8_t *start; simple_config is declared as: static const uint8_t simple_config[] So an address is taken and the first element (implicitly) of an uint8 array is substracted from it. Maybe I just don't get the beauty of this, for me this looks wrong. Kind regards, -Alex From alexander.huemer at xx.vu Fri Nov 6 20:35:33 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Fri, 6 Nov 2015 21:35:33 +0100 Subject: Some patches In-Reply-To: <20151106194820.GC30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> Message-ID: <20151106203533.GG30339@yade.xx.vu> Hi, gcc-5.2.1 from Debian stretch refuses to build osmo-pcu. > bts.cpp:86:1: error: invalid conversion from 'const rate_ctr_desc*' to > 'unsigned int' [-fpermissive] > }; The relevant piece of code from bts.cpp is: static const struct rate_ctr_group_desc bts_ctrg_desc = { "bts", "BTS Statistics", ARRAY_SIZE(bts_ctr_description), bts_ctr_description, }; This structure comes from libosmocore, osmocom/core/rate_ctr.h, without comments: struct rate_ctr_group_desc { const char *group_name_prefix; const char *group_description; int class_id; const unsigned int num_ctr; const struct rate_ctr_desc *ctr_desc; }; It seems like the class_id is missing. Since the initialization is done in the classic, ordered way, the last three fields are initialized to unintened values, at least that's what I make of this. For me that looks like a real bug. Kind regards, -Alex From holger at freyther.de Fri Nov 6 20:57:43 2015 From: holger at freyther.de (Holger Freyther) Date: Fri, 6 Nov 2015 21:57:43 +0100 Subject: Some patches In-Reply-To: <20151106203533.GG30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <20151106203533.GG30339@yade.xx.vu> Message-ID: <342301C4-4B0D-4486-BF56-14783A120EA0@freyther.de> > On 06 Nov 2015, at 21:35, Alexander Huemer wrote: > > Hi, > > For me that looks like a real bug. real bug! and fails to compiler with earlier GCC as well (as on our jenkins). I wonder if there is momentum for Gerrit+Jenkins or Gitlab/Github+Travis to catch these things before we merge/integrate changes. :) From nhofmeyr at sysmocom.de Sat Nov 7 02:42:55 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sat, 7 Nov 2015 03:42:55 +0100 Subject: Some patches In-Reply-To: <20151106202440.GF30339@yade.xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <20151106202440.GF30339@yade.xx.vu> Message-ID: <20151107024255.GB5717@dub5> On Fri, Nov 06, 2015 at 09:24:40PM +0100, Alexander Huemer wrote: > Hi, > > while fixing some trivial compiler warnings in openbsc I stumbled over > this: > > > Making all in abis > > CC abis_test.o > > abis_test.c: In function ?test_simple_sw_config?: > > abis_test.c:68:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > > printf("Start: %u len: %zu\n", descr[0].start - simple_config, descr[0].len); > > ^ > > abis_test.c: In function ?test_dual_sw_config?: > > abis_test.c:111:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > > printf("Start: %u len: %zu\n", descr[0].start - dual_config, descr[0].len); > > ^ > > abis_test.c:115:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > > printf("Start: %u len: %zu\n", descr[1].start - dual_config, descr[1].len); > > ^ > > abis_test.c: In function ?test_sw_selection?: > > abis_test.c:132:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > > printf("Start: %u len: %zu\n", descr[0].start - load_config, descr[0].len); > > ^ > > abis_test.c:136:9: warning: format ?%u? expects argument of type ?unsigned int?, but argument 2 has type ?long int? [-Wformat=] > > printf("Start: %u len: %zu\n", descr[1].start - load_config, descr[1].len); > > The relevant expression is: > > descr[1].start - load_config > > and variations thereof. > descr[1].start is declared include/openbsc/abis_nm.h as: > > const uint8_t *start; > > simple_config is declared as: > > static const uint8_t simple_config[] > > So an address is taken and the first element (implicitly) of an uint8 > array is substracted from it. No, not at all :) simple_config, a uint8_t*, is passed to abis_nm_parse_sw_config. After that, uint8_t *start is actually pointing at a byte within simple_config. It's a subtraction of two uint8_t* from each other to get a byte offset: Subtract simple_config's address (the start of the data) from the "start" pointer's address value, and the result is a byte offset to get from simple_config to where "start" is pointing. The declaration static const uint8_t simple_config[] yields a uint8_t*, but declaring it with [] allows initializing a static array. (Also, simple_config == &simple_config == &simple_config[0], all uint8_t*, which spaces me out every time I come across it.) Also note the slight counter intuitiveness of subtracting pointers to get byte offsets: (T*)a - (T*)b == ((uint)a - (uint)b))/sizeof(T), so this case gives byte offsets precisely because sizeof(uint8_t) == 1... ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Sat Nov 7 11:30:07 2015 From: holger at freyther.de (Holger Freyther) Date: Sat, 7 Nov 2015 12:30:07 +0100 Subject: [PATCH 2/2] src/stat_item.c: fix cast In-Reply-To: <1446839725-21682-3-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446839725-21682-1-git-send-email-alexander.huemer@xx.vu> <1446839725-21682-3-git-send-email-alexander.huemer@xx.vu> Message-ID: <80AD3955-AFB0-43AD-ACB4-8C63A025EF5B@freyther.de> > On 06 Nov 2015, at 20:55, Alexander Huemer wrote: Hi Jacob, > src/stat_item.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/src/stat_item.c b/src/stat_item.c > index 0545ea0..7017523 100644 > --- a/src/stat_item.c > +++ b/src/stat_item.c > @@ -81,7 +81,7 @@ struct osmo_stat_item_group *osmo_stat_item_group_alloc(void *ctx, > size = (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1); > > /* Store offsets into the item array */ > - group->items[item_idx] = (void *)items_size; > + group->items[item_idx] = (struct osmo_stat_item *)items_size; This will silence the warning but I think we could change the code to be more direct at the cost of recalculating the offset twice but staying with the pointers of the right type? From holger at freyther.de Sat Nov 7 11:45:33 2015 From: holger at freyther.de (Holger Freyther) Date: Sat, 7 Nov 2015 12:45:33 +0100 Subject: [PATCH 1/2] buildsystem: follow libtoolize suggestions In-Reply-To: <1446840034-11954-2-git-send-email-alexander.huemer@xx.vu> References: <20151106194820.GC30339@yade.xx.vu> <1446840034-11954-1-git-send-email-alexander.huemer@xx.vu> <1446840034-11954-2-git-send-email-alexander.huemer@xx.vu> Message-ID: > On 06 Nov 2015, at 21:00, Alexander Huemer wrote: > Well, we don't have any m4 macros ourselves and just creating an empty directory doesn't look like a good idea. Have you considered asking on the libtool/autoconf list where this warning is coming from and what to do about it? thanks holger From alexander.huemer at xx.vu Sat Nov 7 12:39:41 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Sat, 7 Nov 2015 13:39:41 +0100 Subject: Some patches In-Reply-To: <20151107024255.GB5717@dub5> References: <20151106194820.GC30339@yade.xx.vu> <20151106202440.GF30339@yade.xx.vu> <20151107024255.GB5717@dub5> Message-ID: <20151107123941.GA26613@yade.xx.vu> Hi! On Sat, Nov 07, 2015 at 03:42:55AM +0100, Neels Hofmeyr wrote: > On Fri, Nov 06, 2015 at 09:24:40PM +0100, Alexander Huemer wrote: > > The relevant expression is: > > > > descr[1].start - load_config > > > > and variations thereof. > > descr[1].start is declared include/openbsc/abis_nm.h as: > > > > const uint8_t *start; > > > > simple_config is declared as: > > > > static const uint8_t simple_config[] > > > > So an address is taken and the first element (implicitly) of an uint8 > > array is substracted from it. > > No, not at all :) > > simple_config, a uint8_t*, is passed to abis_nm_parse_sw_config. After > that, uint8_t *start is actually pointing at a byte within simple_config. > It's a subtraction of two uint8_t* from each other to get a byte offset: > > Subtract simple_config's address (the start of the data) from the "start" > pointer's address value, and the result is a byte offset to get from > simple_config to where "start" is pointing. > > The declaration > > static const uint8_t simple_config[] > > yields a uint8_t*, but declaring it with [] allows initializing a static > array. (Also, simple_config == &simple_config == &simple_config[0], all > uint8_t*, which spaces me out every time I come across it.) > > Also note the slight counter intuitiveness of subtracting pointers to get > byte offsets: (T*)a - (T*)b == ((uint)a - (uint)b))/sizeof(T), so this case > gives byte offsets precisely because sizeof(uint8_t) == 1... Yes, indeed, thanks for the clarification. So what happens here is pointer arithmetic. I misinterpreted the right side of the '-'. Sorry for the noise. Kind regards, -Alex From alexander.huemer at xx.vu Sat Nov 7 13:00:51 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Sat, 7 Nov 2015 14:00:51 +0100 Subject: [PATCH 0/1] A patch for openbsc In-Reply-To: <20151107123941.GA26613@yade.xx.vu> References: <20151107123941.GA26613@yade.xx.vu> Message-ID: <1446901252-5264-1-git-send-email-alexander.huemer@xx.vu> Hi, so I guess the right format specifier to use here is "%td", since the expression is (something like) a ptrdiff_t. At least this fixes the warning and `make check` still passes the abis test. Kind regards, -Alex From alexander.huemer at xx.vu Sat Nov 7 13:00:52 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Sat, 7 Nov 2015 14:00:52 +0100 Subject: [PATCH] tests/abis: fix format specifiers In-Reply-To: <1446901252-5264-1-git-send-email-alexander.huemer@xx.vu> References: <20151107123941.GA26613@yade.xx.vu> <1446901252-5264-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <1446901252-5264-2-git-send-email-alexander.huemer@xx.vu> --- openbsc/tests/abis/abis_test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/tests/abis/abis_test.c b/openbsc/tests/abis/abis_test.c index 53e8a4c..496267f 100644 --- a/openbsc/tests/abis/abis_test.c +++ b/openbsc/tests/abis/abis_test.c @@ -65,7 +65,7 @@ static void test_simple_sw_config(void) abort(); } - printf("Start: %u len: %zu\n", descr[0].start - simple_config, descr[0].len); + printf("Start: %td len: %zu\n", descr[0].start - simple_config, descr[0].len); printf("file_id: %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len)); printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len)); } @@ -108,11 +108,11 @@ static void test_dual_sw_config(void) abort(); } - printf("Start: %u len: %zu\n", descr[0].start - dual_config, descr[0].len); + printf("Start: %td len: %zu\n", descr[0].start - dual_config, descr[0].len); printf("file_id: %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len)); printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len)); - printf("Start: %u len: %zu\n", descr[1].start - dual_config, descr[1].len); + printf("Start: %td len: %zu\n", descr[1].start - dual_config, descr[1].len); printf("file_id: %s\n", osmo_hexdump(descr[1].file_id, descr[1].file_id_len)); printf("file_ver: %s\n", osmo_hexdump(descr[1].file_ver, descr[1].file_ver_len)); } @@ -129,11 +129,11 @@ static void test_sw_selection(void) abort(); } - printf("Start: %u len: %zu\n", descr[0].start - load_config, descr[0].len); + printf("Start: %td len: %zu\n", descr[0].start - load_config, descr[0].len); printf("file_id: %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len)); printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len)); - printf("Start: %u len: %zu\n", descr[1].start - load_config, descr[1].len); + printf("Start: %td len: %zu\n", descr[1].start - load_config, descr[1].len); printf("file_id: %s\n", osmo_hexdump(descr[1].file_id, descr[1].file_id_len)); printf("file_ver: %s\n", osmo_hexdump(descr[1].file_ver, descr[1].file_ver_len)); -- 2.6.2 From alexander.huemer at xx.vu Sat Nov 7 13:07:32 2015 From: alexander.huemer at xx.vu (Alexander Huemer) Date: Sat, 7 Nov 2015 14:07:32 +0100 Subject: [PATCH 1/2] buildsystem: follow libtoolize suggestions In-Reply-To: References: <20151106194820.GC30339@yade.xx.vu> <1446840034-11954-1-git-send-email-alexander.huemer@xx.vu> <1446840034-11954-2-git-send-email-alexander.huemer@xx.vu> Message-ID: <20151107130732.GB26613@yade.xx.vu> Hi! On Sat, Nov 07, 2015 at 12:45:33PM +0100, Holger Freyther wrote: > > On 06 Nov 2015, at 21:00, Alexander Huemer wrote: > > Well, we don't have any m4 macros ourselves and just creating an empty directory doesn't > look like a good idea. Have you considered asking on the libtool/autoconf list where this > warning is coming from and what to do about it? Are you sure this approach is wrong? In libosmocore the same was done in commit b2eb83fa95b209fb01de2996a1382c944fc265fe of 2010, I actually took the filename from there. If you prefer I can check with the autotools people. Kind regards, -Alex From pablo at gnumonks.org Sat Nov 7 16:56:27 2015 From: pablo at gnumonks.org (Pablo Neira Ayuso) Date: Sat, 7 Nov 2015 17:56:27 +0100 Subject: [PATCH 0/6] gtp: compat and build updates In-Reply-To: <1446118742-22809-1-git-send-email-aschultz@tpip.net> References: <1446118742-22809-1-git-send-email-aschultz@tpip.net> Message-ID: <20151107165627.GA1477@salvia> On Thu, Oct 29, 2015 at 12:38:56PM +0100, Andreas Schultz wrote: > Hi, > > This is the first series of my gtp kernel updates. > > It contains mostly the removal of Linux version ifdefs. After this the > module builds only on 4.3+. The goal here is the preparation for main > line inclusion. > > The other small change is a update to the Makefile for simpler out-of-tree > build Series applied, thanks Andreas. From laforge at gnumonks.org Mon Nov 9 00:38:06 2015 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 9 Nov 2015 01:38:06 +0100 Subject: Nov 11, 8pm / Osmocom Berlin Meeting Message-ID: <20151109003806.GD4643@nataraja> Hi all! This is the announcement for the re-incarnation of our bi-weekly Osmocom Berlin Meeting. Nov 11, 8pm @ CCC Berlin, Marienstr. 11, 10117 Berlin There is no formal presentation this time, but * there will be SDR equipment, antenna and a working/tested setup of a gnuradio based MPT1327 decoder * there will be SIMtrace equipment in case somebody wants to play with it there will be a sysmoBTS with OsmoBTS, OsmoPCU, OsmoNITB, OsmoSGSN and OpenGGSN if somebody wants to play with it * there will be Huawei Femtocells to play with * Harald would like to discuss OpenBSC website / documentation improvements The meeting is open to anyone interested in mobile communications. You do not have to be involved with the Osmocom projects in order to attend. Anyone interested in mobile communications protocols is welcome. If you are interested to show up, feel free to do so. The meeting is "free as in free beer", despite no actual free beer being around ;) More information can be found at http://openbsc.osmocom.org/trac/wiki/OsmocomMeeting/Berlin Regards, Harald -- - Harald Welte ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Mon Nov 9 13:40:15 2015 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 9 Nov 2015 14:40:15 +0100 Subject: [PATCH] gbproxy: Count more GSM 04.08 messages Message-ID: <1447076415-90027-1-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther Extend the ul/dl counting to count the usual messages on the Gb interface. Add counters for the attach, routing area update, pdp context activation and deactivation procedures. Update the test result with the new counters. --- openbsc/include/openbsc/gb_proxy.h | 14 + openbsc/src/gprs/gb_proxy.c | 39 +++ openbsc/src/gprs/gb_proxy_peer.c | 15 + openbsc/tests/gbproxy/gbproxy_test.ok | 576 ++++++++++++++++++++++++++++++++++ 4 files changed, 644 insertions(+) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index ff35a39..3141325 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -48,8 +48,22 @@ enum gbproxy_peer_ctr { GBPROX_PEER_CTR_PATCH_ERR, GBPROX_PEER_CTR_ATTACH_REQS, GBPROX_PEER_CTR_ATTACH_REJS, + GBPROX_PEER_CTR_ATTACH_ACKS, + GBPROX_PEER_CTR_ATTACH_COMPL, + GBPROX_PEER_CTR_RA_UPD_REQS, + GBPROX_PEER_CTR_RA_UPD_ACKS, + GBPROX_PEER_CTR_RA_UPD_REJS, + GBPROX_PEER_CTR_RA_UPD_COMPL, + GBPROX_PEER_CTR_DETACH_REQS, + GBPROX_PEER_CTR_DETACH_ACKS, + GBPROX_PEER_CTR_PDP_ACT_REQS, + GBPROX_PEER_CTR_PDP_ACT_ACKS, + GBPROX_PEER_CTR_PDP_ACT_REJS, + GBPROX_PEER_CTR_PDP_DEACT_REQS, + GBPROX_PEER_CTR_PDP_DEACT_ACKS, GBPROX_PEER_CTR_TLLI_UNKNOWN, GBPROX_PEER_CTR_TLLI_CACHE_SIZE, + GBPROX_PEER_CTR_LAST, }; enum gbproxy_keep_mode { diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 8cdf9a4..4f5bbac 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -593,6 +593,24 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg, case GSM48_MT_GMM_ATTACH_REQ: rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REQS]); break; + case GSM48_MT_GMM_DETACH_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_DETACH_REQS]); + break; + case GSM48_MT_GMM_ATTACH_COMPL: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_COMPL]); + break; + case GSM48_MT_GMM_RA_UPD_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_REQS]); + break; + case GSM48_MT_GMM_RA_UPD_COMPL: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_COMPL]); + break; + case GSM48_MT_GSM_ACT_PDP_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_REQS]); + break; + case GSM48_MT_GSM_DEACT_PDP_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_DEACT_REQS]); + break; default: break; @@ -678,9 +696,30 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, if (parse_ctx.g48_hdr) { switch (parse_ctx.g48_hdr->msg_type) { + case GSM48_MT_GMM_ATTACH_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_ACKS]); + break; case GSM48_MT_GMM_ATTACH_REJ: rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REJS]); break; + case GSM48_MT_GMM_DETACH_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_DETACH_ACKS]); + break; + case GSM48_MT_GMM_RA_UPD_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_ACKS]); + break; + case GSM48_MT_GMM_RA_UPD_REJ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_REJS]); + break; + case GSM48_MT_GSM_ACT_PDP_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_ACKS]); + break; + case GSM48_MT_GSM_ACT_PDP_REJ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_REJS]); + break; + case GSM48_MT_GSM_DEACT_PDP_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_DEACT_ACKS]); + break; default: break; diff --git a/openbsc/src/gprs/gb_proxy_peer.c b/openbsc/src/gprs/gb_proxy_peer.c index b65fc17..f467d76 100644 --- a/openbsc/src/gprs/gb_proxy_peer.c +++ b/openbsc/src/gprs/gb_proxy_peer.c @@ -51,10 +51,25 @@ static const struct rate_ctr_desc peer_ctr_description[] = { { "mod-err", "Patch error: other " }, { "attach-reqs", "Attach Request count " }, { "attach-rejs", "Attach Reject count " }, + { "attach-acks", "Attach Accept count " }, + { "attach-cpls", "Attach Completed count " }, + { "ra-upd-reqs", "RoutingArea Update Request count" }, + { "ra-upd-rejs", "RoutingArea Update Reject count " }, + { "ra-upd-acks", "RoutingArea Update Accept count " }, + { "ra-upd-cpls", "RoutingArea Update Compltd count" }, + { "detach-reqs", "Detach Request count " }, + { "detach-acks", "Detach Accept count " }, + { "pdp-act-reqs", "PDP Activation Request count " }, + { "pdp-act-rejs", "PDP Activation Reject count " }, + { "pdp-act-acks", "PDP Activation Accept count " }, + { "pdp-deact-reqs","PDP Deactivation Request count " }, + { "pdp-deact-acks","PDP Deactivation Accept count " }, { "tlli-unknown", "TLLI from SGSN unknown " }, { "tlli-cache", "TLLI cache size " }, }; +osmo_static_assert(ARRAY_SIZE(peer_ctr_description) == GBPROX_PEER_CTR_LAST, everything_described); + static const struct rate_ctr_group_desc peer_ctrg_desc = { .group_name_prefix = "gbproxy.peer", .group_description = "GBProxy Peer Statistics", diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index bbb6820..ba2f385 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1670,6 +1670,7 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/efe2b700 -> 8000dead/efe2b700, IMSI 12131415161718, AGE 0 @@ -1688,6 +1689,8 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/efe2b700 -> 8000dead/efe2b700, IMSI 12131415161718, AGE 0 @@ -1706,6 +1709,8 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -1726,6 +1731,8 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 8000beef, IMSI (none), AGE 0 @@ -1745,6 +1752,8 @@ result (IDENT REQUEST) = 27 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 8000beef, IMSI (none), AGE 0 @@ -1764,6 +1773,8 @@ result (IDENT RESPONSE) = 44 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 8000beef, IMSI 12199999961718, AGE 0 @@ -1783,6 +1794,8 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000beef/efe2b700 -> 8000beef/efe2b700, IMSI 12199999961718, AGE 0 @@ -1801,6 +1814,8 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000beef/efe2b700 -> 8000beef/efe2b700, IMSI 12199999961718, AGE 0 @@ -1819,6 +1834,8 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12199999961718, AGE 0 @@ -2086,6 +2103,9 @@ Peers: RAID patched (SGSN): 2 APN patched : 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + PDP Activation Request count : 3 TLLI from SGSN unknown : 1 TLLI cache size : 1 TLLI-Cache: 1 @@ -2120,6 +2140,11 @@ Peers: RAID patched (SGSN): 2 APN patched : 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 + PDP Activation Request count : 3 TLLI from SGSN unknown : 1 TLLI-Cache: 0 --- RA update --- @@ -2166,6 +2191,13 @@ Peers: RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 + PDP Activation Request count : 4 TLLI from SGSN unknown : 1 TLLI cache size : 1 TLLI-Cache: 1 @@ -2189,6 +2221,13 @@ Peers: RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 1 + PDP Activation Request count : 4 TLLI from SGSN unknown : 1 TLLI-Cache: 0 --- Bad cases --- @@ -2240,6 +2279,13 @@ Peers: RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 1 + PDP Activation Request count : 5 TLLI from SGSN unknown : 1 TLLI cache size : 2 TLLI-Cache: 2 @@ -2442,6 +2488,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -2465,6 +2512,8 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -2488,6 +2537,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -2512,6 +2563,9 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -2572,6 +2626,9 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -2608,6 +2665,11 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01/c0dead02 -> efe2b700/e0987654, IMSI 12131415161718, AGE 0 @@ -2644,6 +2706,11 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01/c0dead03 -> efe2b700/e0543210, IMSI 12131415161718, AGE 0 @@ -2680,6 +2747,12 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2704,6 +2777,12 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2728,6 +2807,12 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2752,6 +2837,12 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2776,6 +2867,12 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2868,6 +2965,13 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + RoutingArea Update Compltd count: 1 + Detach Request count : 1 + PDP Activation Request count : 1 TLLI from SGSN unknown : 2 TLLI cache size : 1 TLLI-Cache: 1 @@ -2894,6 +2998,14 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Reject count : 2 + RoutingArea Update Compltd count: 1 + Detach Request count : 1 + Detach Accept count : 1 + PDP Activation Request count : 1 TLLI from SGSN unknown : 2 TLLI-Cache: 0 Gbproxy global: @@ -3096,6 +3208,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3119,6 +3232,7 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3142,6 +3256,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3165,6 +3281,8 @@ Peers: TLLI patched (SGSN): 4 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3188,6 +3306,9 @@ Peers: TLLI patched (SGSN): 4 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 + Detach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3211,6 +3332,10 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI-Cache: 0 Gbproxy global: === test_gbproxy_imsi_acquisition === @@ -3429,6 +3554,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3452,6 +3578,8 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3475,6 +3603,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3534,6 +3664,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3557,6 +3689,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3580,6 +3714,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3603,6 +3739,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3626,6 +3764,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3695,6 +3835,9 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3718,6 +3861,10 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI-Cache: 0 PROCESSING RA UPD REQ from 0x01020304:1111 00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 @@ -3751,6 +3898,11 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead -> 78dead02, IMSI 12131415161718, AGE 0 @@ -3774,6 +3926,12 @@ Peers: TLLI patched (SGSN): 10 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead03 -> 78dead02/efe2b700, IMSI 12131415161718, AGE 0 @@ -3797,6 +3955,12 @@ Peers: TLLI patched (SGSN): 10 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead03 -> 78dead02/efe2b700, IMSI 12131415161718, AGE 0 @@ -3820,6 +3984,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 2 TLLI-Cache: 0 PROCESSING ATTACH REQUEST from 0x01020304:1111 00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 b6 bb @@ -3865,6 +4035,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 3 + Detach Accept count : 2 TLLI-Cache: 0 PROCESSING DETACH REQ (unknown TLLI) from 0x01020304:1111 00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 2d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 0d 30 0d @@ -3886,6 +4062,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 4 + Detach Accept count : 2 TLLI-Cache: 0 PROCESSING RA UPD REQ from 0x01020304:1111 00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 31 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 d8 cf d8 @@ -3931,6 +4113,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 3 + RoutingArea Update Reject count : 1 + Detach Request count : 5 + Detach Accept count : 2 TLLI-Cache: 0 Gbproxy global: Invalid Routing Area Identifier : 1 @@ -4264,6 +4452,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4287,6 +4476,8 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4310,6 +4501,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4369,6 +4562,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4392,6 +4587,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4415,6 +4612,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4438,6 +4637,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4461,6 +4662,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4486,6 +4689,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress, SGSN NSEI 65535 @@ -4510,6 +4715,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4534,6 +4741,8 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4558,6 +4767,8 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4582,6 +4793,8 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef/c0dead03 -> 78dead02/e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4606,6 +4819,8 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef/c0dead03 -> 78dead02/e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4630,6 +4845,8 @@ Peers: TLLI patched (SGSN): 10 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4690,6 +4907,8 @@ Peers: TLLI patched (SGSN): 12 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4714,6 +4933,8 @@ Peers: TLLI patched (SGSN): 12 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4738,6 +4959,8 @@ Peers: TLLI patched (SGSN): 13 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4762,6 +4985,8 @@ Peers: TLLI patched (SGSN): 13 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4786,6 +5011,8 @@ Peers: TLLI patched (SGSN): 14 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4812,6 +5039,8 @@ Peers: TLLI patched (SGSN): 14 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress, SGSN NSEI 65535 @@ -4837,6 +5066,8 @@ Peers: TLLI patched (SGSN): 14 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4862,6 +5093,8 @@ Peers: TLLI patched (SGSN): 15 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4887,6 +5120,8 @@ Peers: TLLI patched (SGSN): 15 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4912,6 +5147,8 @@ Peers: TLLI patched (SGSN): 16 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed/c0dead05 -> 78dead04/efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4937,6 +5174,8 @@ Peers: TLLI patched (SGSN): 16 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed/c0dead05 -> 78dead04/efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4962,6 +5201,8 @@ Peers: TLLI patched (SGSN): 17 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 TLLI cache size : 3 TLLI-Cache: 3 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4989,6 +5230,9 @@ Peers: TLLI patched (SGSN): 17 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 TLLI cache size : 3 TLLI-Cache: 3 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -5014,6 +5258,10 @@ Peers: TLLI patched (SGSN): 18 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5041,6 +5289,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5066,6 +5318,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 2 + Detach Accept count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5092,6 +5348,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 3 + Detach Accept count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5116,6 +5376,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 3 + Detach Accept count : 3 TLLI-Cache: 0 Gbproxy global: Invalid BVC Identifier : 1 @@ -5322,6 +5586,7 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5340,6 +5605,8 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5358,6 +5625,8 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5376,6 +5645,9 @@ result (DETACH REQ) = 48 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5394,6 +5666,10 @@ result (DETACH ACC) = 71 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5412,6 +5688,10 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5430,6 +5710,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5448,6 +5732,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5466,6 +5754,10 @@ result (DETACH REQ (re-attach)) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5484,6 +5776,10 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5502,6 +5798,10 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5520,6 +5820,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5538,6 +5842,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5556,6 +5864,10 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5574,6 +5886,10 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5592,6 +5908,10 @@ result (ATTACH REQUEST (IMSI)) = 82 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5610,6 +5930,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5628,6 +5952,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5646,6 +5974,10 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5664,6 +5996,10 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5682,6 +6018,10 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5700,6 +6040,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 5 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5718,6 +6062,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 5 + Attach Completed count : 5 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5748,6 +6096,12 @@ result (RA UDP REJ) = 72 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 5 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5766,6 +6120,12 @@ result (ATTACH REQUEST) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 5 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -5785,6 +6145,12 @@ result (IDENT RESPONSE) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 5 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5803,6 +6169,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5821,6 +6193,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5839,6 +6217,12 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5857,6 +6241,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5875,6 +6265,12 @@ result (ATTACH REQUEST (local TLLI)) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5893,6 +6289,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5911,6 +6313,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5929,6 +6337,12 @@ result (DETACH REQ (re-attach)) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5947,6 +6361,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5965,6 +6385,12 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5983,6 +6409,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 8 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6001,6 +6433,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 8 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6019,6 +6457,12 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 8 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6037,6 +6481,12 @@ result (ATTACH REQUEST (unexpected, IMSI)) = 82 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 8 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6055,6 +6505,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6073,6 +6529,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6091,6 +6553,12 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6109,6 +6577,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -6127,6 +6601,12 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6145,6 +6625,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 10 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6163,6 +6649,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 10 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6181,6 +6673,12 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 10 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6199,6 +6697,12 @@ result (ATTACH REQUEST (unexpected)) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 10 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6217,6 +6721,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6235,6 +6745,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6253,6 +6769,12 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6271,6 +6793,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -6289,6 +6817,12 @@ result (ATTACH REQUEST) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 12 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -6307,6 +6841,12 @@ result (IDENT RESPONSE) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 12 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6326,6 +6866,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 12 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -6345,6 +6891,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 13 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -6364,6 +6916,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 13 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI-Cache: 0 PROCESSING ATTACH REQUEST from 0x01020304:1111 00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 99 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 88 49 82 @@ -6381,6 +6939,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 14 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -6400,6 +6964,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 14 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0, STORED 1, IMSI acquisition in progress @@ -6423,6 +6993,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 14 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -- 2.6.0 From holger at freyther.de Mon Nov 9 14:10:57 2015 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 9 Nov 2015 15:10:57 +0100 Subject: [PATCH] gbproxy: Count more GSM 04.08 messages Message-ID: <1447078257-90248-1-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther Extend the ul/dl counting to count the usual messages on the Gb interface. Add counters for the attach, routing area update, pdp context activation and deactivation procedures. Update the test result with the new counters. --- openbsc/include/openbsc/gb_proxy.h | 15 + openbsc/src/gprs/gb_proxy.c | 42 +++ openbsc/src/gprs/gb_proxy_peer.c | 16 + openbsc/tests/gbproxy/gbproxy_test.ok | 576 ++++++++++++++++++++++++++++++++++ 4 files changed, 649 insertions(+) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index ff35a39..153d962 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -48,8 +48,23 @@ enum gbproxy_peer_ctr { GBPROX_PEER_CTR_PATCH_ERR, GBPROX_PEER_CTR_ATTACH_REQS, GBPROX_PEER_CTR_ATTACH_REJS, + GBPROX_PEER_CTR_ATTACH_ACKS, + GBPROX_PEER_CTR_ATTACH_COMPLS, + GBPROX_PEER_CTR_RA_UPD_REQS, + GBPROX_PEER_CTR_RA_UPD_REJS, + GBPROX_PEER_CTR_RA_UPD_ACKS, + GBPROX_PEER_CTR_RA_UPD_COMPLS, + GBPROX_PEER_CTR_GMM_STATUS, + GBPROX_PEER_CTR_DETACH_REQS, + GBPROX_PEER_CTR_DETACH_ACKS, + GBPROX_PEER_CTR_PDP_ACT_REQS, + GBPROX_PEER_CTR_PDP_ACT_REJS, + GBPROX_PEER_CTR_PDP_ACT_ACKS, + GBPROX_PEER_CTR_PDP_DEACT_REQS, + GBPROX_PEER_CTR_PDP_DEACT_ACKS, GBPROX_PEER_CTR_TLLI_UNKNOWN, GBPROX_PEER_CTR_TLLI_CACHE_SIZE, + GBPROX_PEER_CTR_LAST, }; enum gbproxy_keep_mode { diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 8cdf9a4..5e6c0b4 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -593,6 +593,27 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg, case GSM48_MT_GMM_ATTACH_REQ: rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REQS]); break; + case GSM48_MT_GMM_DETACH_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_DETACH_REQS]); + break; + case GSM48_MT_GMM_ATTACH_COMPL: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_COMPLS]); + break; + case GSM48_MT_GMM_RA_UPD_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_REQS]); + break; + case GSM48_MT_GMM_RA_UPD_COMPL: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_COMPLS]); + break; + case GSM48_MT_GMM_STATUS: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_GMM_STATUS]); + break; + case GSM48_MT_GSM_ACT_PDP_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_REQS]); + break; + case GSM48_MT_GSM_DEACT_PDP_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_DEACT_REQS]); + break; default: break; @@ -678,9 +699,30 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, if (parse_ctx.g48_hdr) { switch (parse_ctx.g48_hdr->msg_type) { + case GSM48_MT_GMM_ATTACH_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_ACKS]); + break; case GSM48_MT_GMM_ATTACH_REJ: rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REJS]); break; + case GSM48_MT_GMM_DETACH_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_DETACH_ACKS]); + break; + case GSM48_MT_GMM_RA_UPD_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_ACKS]); + break; + case GSM48_MT_GMM_RA_UPD_REJ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_REJS]); + break; + case GSM48_MT_GSM_ACT_PDP_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_ACKS]); + break; + case GSM48_MT_GSM_ACT_PDP_REJ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_REJS]); + break; + case GSM48_MT_GSM_DEACT_PDP_ACK: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_DEACT_ACKS]); + break; default: break; diff --git a/openbsc/src/gprs/gb_proxy_peer.c b/openbsc/src/gprs/gb_proxy_peer.c index b65fc17..3018bbf 100644 --- a/openbsc/src/gprs/gb_proxy_peer.c +++ b/openbsc/src/gprs/gb_proxy_peer.c @@ -51,10 +51,26 @@ static const struct rate_ctr_desc peer_ctr_description[] = { { "mod-err", "Patch error: other " }, { "attach-reqs", "Attach Request count " }, { "attach-rejs", "Attach Reject count " }, + { "attach-acks", "Attach Accept count " }, + { "attach-cpls", "Attach Completed count " }, + { "ra-upd-reqs", "RoutingArea Update Request count" }, + { "ra-upd-rejs", "RoutingArea Update Reject count " }, + { "ra-upd-acks", "RoutingArea Update Accept count " }, + { "ra-upd-cpls", "RoutingArea Update Compltd count" }, + { "gmm-status", "GMM Status count " }, + { "detach-reqs", "Detach Request count " }, + { "detach-acks", "Detach Accept count " }, + { "pdp-act-reqs", "PDP Activation Request count " }, + { "pdp-act-rejs", "PDP Activation Reject count " }, + { "pdp-act-acks", "PDP Activation Accept count " }, + { "pdp-deact-reqs","PDP Deactivation Request count " }, + { "pdp-deact-acks","PDP Deactivation Accept count " }, { "tlli-unknown", "TLLI from SGSN unknown " }, { "tlli-cache", "TLLI cache size " }, }; +osmo_static_assert(ARRAY_SIZE(peer_ctr_description) == GBPROX_PEER_CTR_LAST, everything_described); + static const struct rate_ctr_group_desc peer_ctrg_desc = { .group_name_prefix = "gbproxy.peer", .group_description = "GBProxy Peer Statistics", diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index bbb6820..0ef976f 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1670,6 +1670,7 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/efe2b700 -> 8000dead/efe2b700, IMSI 12131415161718, AGE 0 @@ -1688,6 +1689,8 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/efe2b700 -> 8000dead/efe2b700, IMSI 12131415161718, AGE 0 @@ -1706,6 +1709,8 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -1726,6 +1731,8 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 8000beef, IMSI (none), AGE 0 @@ -1745,6 +1752,8 @@ result (IDENT REQUEST) = 27 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 8000beef, IMSI (none), AGE 0 @@ -1764,6 +1773,8 @@ result (IDENT RESPONSE) = 44 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 8000beef, IMSI 12199999961718, AGE 0 @@ -1783,6 +1794,8 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000beef/efe2b700 -> 8000beef/efe2b700, IMSI 12199999961718, AGE 0 @@ -1801,6 +1814,8 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000beef/efe2b700 -> 8000beef/efe2b700, IMSI 12199999961718, AGE 0 @@ -1819,6 +1834,8 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12199999961718, AGE 0 @@ -2086,6 +2103,9 @@ Peers: RAID patched (SGSN): 2 APN patched : 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + PDP Activation Request count : 3 TLLI from SGSN unknown : 1 TLLI cache size : 1 TLLI-Cache: 1 @@ -2120,6 +2140,11 @@ Peers: RAID patched (SGSN): 2 APN patched : 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 + PDP Activation Request count : 3 TLLI from SGSN unknown : 1 TLLI-Cache: 0 --- RA update --- @@ -2166,6 +2191,13 @@ Peers: RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 + PDP Activation Request count : 4 TLLI from SGSN unknown : 1 TLLI cache size : 1 TLLI-Cache: 1 @@ -2189,6 +2221,13 @@ Peers: RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 1 + PDP Activation Request count : 4 TLLI from SGSN unknown : 1 TLLI-Cache: 0 --- Bad cases --- @@ -2240,6 +2279,13 @@ Peers: RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 1 + PDP Activation Request count : 5 TLLI from SGSN unknown : 1 TLLI cache size : 2 TLLI-Cache: 2 @@ -2442,6 +2488,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -2465,6 +2512,8 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -2488,6 +2537,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -2512,6 +2563,9 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -2572,6 +2626,9 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -2608,6 +2665,11 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01/c0dead02 -> efe2b700/e0987654, IMSI 12131415161718, AGE 0 @@ -2644,6 +2706,11 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01/c0dead03 -> efe2b700/e0543210, IMSI 12131415161718, AGE 0 @@ -2680,6 +2747,12 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2704,6 +2777,12 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2728,6 +2807,12 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2752,6 +2837,12 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 3 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2776,6 +2867,12 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + RoutingArea Update Compltd count: 1 + PDP Activation Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 @@ -2868,6 +2965,13 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + RoutingArea Update Compltd count: 1 + Detach Request count : 1 + PDP Activation Request count : 1 TLLI from SGSN unknown : 2 TLLI cache size : 1 TLLI-Cache: 1 @@ -2894,6 +2998,14 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 4 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 2 + RoutingArea Update Accept count : 2 + RoutingArea Update Compltd count: 1 + Detach Request count : 1 + Detach Accept count : 1 + PDP Activation Request count : 1 TLLI from SGSN unknown : 2 TLLI-Cache: 0 Gbproxy global: @@ -3096,6 +3208,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3119,6 +3232,7 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3142,6 +3256,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3165,6 +3281,8 @@ Peers: TLLI patched (SGSN): 4 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3188,6 +3306,9 @@ Peers: TLLI patched (SGSN): 4 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 + Detach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3211,6 +3332,10 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 2 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI-Cache: 0 Gbproxy global: === test_gbproxy_imsi_acquisition === @@ -3429,6 +3554,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3452,6 +3578,8 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 @@ -3475,6 +3603,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3534,6 +3664,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3557,6 +3689,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3580,6 +3714,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3603,6 +3739,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3626,6 +3764,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3695,6 +3835,9 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -3718,6 +3861,10 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI-Cache: 0 PROCESSING RA UPD REQ from 0x01020304:1111 00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 @@ -3751,6 +3898,11 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead -> 78dead02, IMSI 12131415161718, AGE 0 @@ -3774,6 +3926,12 @@ Peers: TLLI patched (SGSN): 10 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead03 -> 78dead02/efe2b700, IMSI 12131415161718, AGE 0 @@ -3797,6 +3955,12 @@ Peers: TLLI patched (SGSN): 10 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead03 -> 78dead02/efe2b700, IMSI 12131415161718, AGE 0 @@ -3820,6 +3984,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 2 + Detach Accept count : 2 TLLI-Cache: 0 PROCESSING ATTACH REQUEST from 0x01020304:1111 00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 b6 bb @@ -3865,6 +4035,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 3 + Detach Accept count : 2 TLLI-Cache: 0 PROCESSING DETACH REQ (unknown TLLI) from 0x01020304:1111 00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 2d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 0d 30 0d @@ -3886,6 +4062,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 1 + RoutingArea Update Accept count : 1 + Detach Request count : 4 + Detach Accept count : 2 TLLI-Cache: 0 PROCESSING RA UPD REQ from 0x01020304:1111 00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 31 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 d8 cf d8 @@ -3931,6 +4113,12 @@ Peers: TLLI patched (SGSN): 11 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 1 + Attach Completed count : 1 + RoutingArea Update Request count: 3 + RoutingArea Update Accept count : 1 + Detach Request count : 5 + Detach Accept count : 2 TLLI-Cache: 0 Gbproxy global: Invalid Routing Area Identifier : 1 @@ -4264,6 +4452,7 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4287,6 +4476,8 @@ Peers: TLLI patched (SGSN): 2 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4310,6 +4501,8 @@ Peers: TLLI patched (SGSN): 3 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4369,6 +4562,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4392,6 +4587,8 @@ Peers: TLLI patched (SGSN): 5 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4415,6 +4612,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4438,6 +4637,8 @@ Peers: TLLI patched (SGSN): 6 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4461,6 +4662,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -4486,6 +4689,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress, SGSN NSEI 65535 @@ -4510,6 +4715,8 @@ Peers: TLLI patched (SGSN): 7 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4534,6 +4741,8 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4558,6 +4767,8 @@ Peers: TLLI patched (SGSN): 8 P-TMSI patched (SGSN): 1 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4582,6 +4793,8 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef/c0dead03 -> 78dead02/e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4606,6 +4819,8 @@ Peers: TLLI patched (SGSN): 9 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI 8000beef/c0dead03 -> 78dead02/e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4630,6 +4845,8 @@ Peers: TLLI patched (SGSN): 10 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4690,6 +4907,8 @@ Peers: TLLI patched (SGSN): 12 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4714,6 +4933,8 @@ Peers: TLLI patched (SGSN): 12 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4738,6 +4959,8 @@ Peers: TLLI patched (SGSN): 13 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4762,6 +4985,8 @@ Peers: TLLI patched (SGSN): 13 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4786,6 +5011,8 @@ Peers: TLLI patched (SGSN): 14 P-TMSI patched (SGSN): 2 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4812,6 +5039,8 @@ Peers: TLLI patched (SGSN): 14 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress, SGSN NSEI 65535 @@ -4837,6 +5066,8 @@ Peers: TLLI patched (SGSN): 14 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4862,6 +5093,8 @@ Peers: TLLI patched (SGSN): 15 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4887,6 +5120,8 @@ Peers: TLLI patched (SGSN): 15 P-TMSI patched (SGSN): 2 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4912,6 +5147,8 @@ Peers: TLLI patched (SGSN): 16 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 2 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed/c0dead05 -> 78dead04/efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4937,6 +5174,8 @@ Peers: TLLI patched (SGSN): 16 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 TLLI cache size : 3 TLLI-Cache: 3 TLLI 8000feed/c0dead05 -> 78dead04/efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4962,6 +5201,8 @@ Peers: TLLI patched (SGSN): 17 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 TLLI cache size : 3 TLLI-Cache: 3 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -4989,6 +5230,9 @@ Peers: TLLI patched (SGSN): 17 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 TLLI cache size : 3 TLLI-Cache: 3 TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 @@ -5014,6 +5258,10 @@ Peers: TLLI patched (SGSN): 18 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5041,6 +5289,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5066,6 +5318,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 2 + Detach Accept count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5092,6 +5348,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 3 + Detach Accept count : 2 TLLI cache size : 1 TLLI-Cache: 1 TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 @@ -5116,6 +5376,10 @@ Peers: P-TMSI patched (BSS ): 1 P-TMSI patched (SGSN): 3 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 3 + Detach Accept count : 3 TLLI-Cache: 0 Gbproxy global: Invalid BVC Identifier : 1 @@ -5322,6 +5586,7 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5340,6 +5605,8 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5358,6 +5625,8 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5376,6 +5645,9 @@ result (DETACH REQ) = 48 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5394,6 +5666,10 @@ result (DETACH ACC) = 71 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 1 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5412,6 +5688,10 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 1 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5430,6 +5710,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5448,6 +5732,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5466,6 +5754,10 @@ result (DETACH REQ (re-attach)) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5484,6 +5776,10 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 2 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5502,6 +5798,10 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 2 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5520,6 +5820,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 2 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5538,6 +5842,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5556,6 +5864,10 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5574,6 +5886,10 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 3 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5592,6 +5908,10 @@ result (ATTACH REQUEST (IMSI)) = 82 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 3 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5610,6 +5930,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 3 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5628,6 +5952,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5646,6 +5974,10 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5664,6 +5996,10 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 4 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5682,6 +6018,10 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 4 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5700,6 +6040,10 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 5 + Attach Completed count : 4 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5718,6 +6062,10 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 5 + Attach Completed count : 5 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5748,6 +6096,12 @@ result (RA UDP REJ) = 72 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 5 + Attach Accept count : 5 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5766,6 +6120,12 @@ result (ATTACH REQUEST) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 5 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 2 TLLI-Cache: 2 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -5785,6 +6145,12 @@ result (IDENT RESPONSE) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 5 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5803,6 +6169,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 5 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5821,6 +6193,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -5839,6 +6217,12 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5857,6 +6241,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 6 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5875,6 +6265,12 @@ result (ATTACH REQUEST (local TLLI)) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 6 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5893,6 +6289,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 6 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5911,6 +6313,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5929,6 +6337,12 @@ result (DETACH REQ (re-attach)) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -5947,6 +6361,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 7 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -5965,6 +6385,12 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 7 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -5983,6 +6409,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 8 + Attach Completed count : 7 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6001,6 +6433,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 8 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6019,6 +6457,12 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 8 + Attach Accept count : 8 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6037,6 +6481,12 @@ result (ATTACH REQUEST (unexpected, IMSI)) = 82 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 8 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6055,6 +6505,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 8 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6073,6 +6529,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6091,6 +6553,12 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6109,6 +6577,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 9 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -6127,6 +6601,12 @@ result (ATTACH REQUEST) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 9 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6145,6 +6625,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 10 + Attach Completed count : 9 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6163,6 +6649,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 10 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6181,6 +6673,12 @@ result (GMM INFO) = 70 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 10 + Attach Accept count : 10 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6199,6 +6697,12 @@ result (ATTACH REQUEST (unexpected)) = 79 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 10 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6217,6 +6721,12 @@ result (ATTACH ACCEPT) = 92 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 10 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6235,6 +6745,12 @@ result (ATTACH COMPLETE) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 @@ -6253,6 +6769,12 @@ result (DETACH REQ) = 73 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 @@ -6271,6 +6793,12 @@ result (DETACH ACC) = 35 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 11 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -6289,6 +6817,12 @@ result (ATTACH REQUEST) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 12 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -6307,6 +6841,12 @@ result (IDENT RESPONSE) = 0 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 12 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 @@ -6326,6 +6866,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 12 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED @@ -6345,6 +6891,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 13 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 1 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -6364,6 +6916,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 13 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI-Cache: 0 PROCESSING ATTACH REQUEST from 0x01020304:1111 00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 99 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 88 49 82 @@ -6381,6 +6939,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 14 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress @@ -6400,6 +6964,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 14 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0, STORED 1, IMSI acquisition in progress @@ -6423,6 +6993,12 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 Attach Request count : 14 Attach Reject count : 1 + Attach Accept count : 11 + Attach Completed count : 11 + RoutingArea Update Request count: 1 + RoutingArea Update Reject count : 1 + Detach Request count : 2 + Detach Accept count : 1 TLLI cache size : 1 TLLI-Cache: 1 TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -- 2.6.0 From jskarvad at redhat.com Tue Nov 10 09:56:23 2015 From: jskarvad at redhat.com (Jaroslav Skarvada) Date: Tue, 10 Nov 2015 04:56:23 -0500 (EST) Subject: libosmocore minor issues In-Reply-To: <1195163689.6803559.1447087336065.JavaMail.zimbra@redhat.com> References: <1195163689.6803559.1447087336065.JavaMail.zimbra@redhat.com> Message-ID: <1096145625.7613757.1447149383640.JavaMail.zimbra@redhat.com> Hi, I am working on getting libosmocom package into Fedora, there is review request in [1]. During the packaging I found following minor issues: - Incorrect FSF addresses in source code, e.g. there is written in the sources: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. But the correct address is (as taken from the https://www.gnu.org/licenses/gpl-2.0.html): 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - exit call in the library: /usr/lib64/libosmovty.so.3.0.0 exit at GLIBC_2.2.5 libraries shouldn't generally call exit. thanks & regards Jaroslav [1] https://bugzilla.redhat.com/show_bug.cgi?id=1279527 From laforge at gnumonks.org Tue Nov 10 19:50:52 2015 From: laforge at gnumonks.org (Harald Welte) Date: Tue, 10 Nov 2015 20:50:52 +0100 Subject: Changing Configuration Parameters Dynamically - OpenBSC In-Reply-To: References: Message-ID: <20151110195052.GV8473@nataraja> On Wed, Nov 04, 2015 at 11:32:59AM +0500, Amber and Sarosh wrote: > Hi,Can someone inform us if the VTY configuration commands to change > parameters e.g. cell id, location area code, MS power etc. that are > run on OpenBSC VTY telnet interface take effect on next restart of > the OpenBSC session or during the same session? If former is the case, > is there any way to dynamically change Cell ID, LAC, MS TX power etc > i.e. without restarting the OpenBSC session? * you don't need to restart openbsc to change any parameter * some parameters (almost all under the bts/trx/ts nodes) are communicated via A-bis OML at BTS connection time. Those parameters are not becoming effective until the BTS re-connects and thus goes throug OML initialization. There is a vty command that you can use to drop the a-bis OML connection for a specific BTS. * other parameters (affecting OpenBSC behavior directly) become effectively immediately. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Tue Nov 10 19:48:40 2015 From: laforge at gnumonks.org (Harald Welte) Date: Tue, 10 Nov 2015 20:48:40 +0100 Subject: libosmocore minor issues In-Reply-To: <1096145625.7613757.1447149383640.JavaMail.zimbra@redhat.com> References: <1195163689.6803559.1447087336065.JavaMail.zimbra@redhat.com> <1096145625.7613757.1447149383640.JavaMail.zimbra@redhat.com> Message-ID: <20151110194840.GU8473@nataraja> Hi Jaroslav, On Tue, Nov 10, 2015 at 04:56:23AM -0500, Jaroslav Skarvada wrote: > I am working on getting libosmocom package into Fedora, there is > review request in [1]. Thanks for this! > During the packaging I found following minor issues: > - Incorrect FSF addresses in source code This is easy to fix. Do you already have a patch to fix all occurrences? I'd happily apply that. > - exit call in the library: /usr/lib64/libosmovty.so.3.0.0 exit at GLIBC_2.2.5 > libraries shouldn't generally call exit. libosmovty started as a fork of the VTY (telnet command line interface) code of GNU zebra. So the code was not written as a library to begin with, but was part of zebra itself. In any case, addressing those issues is not particularly easy, as said functions should never fail at this point, but they don't have a way to return an error code, or their callers simply assume they always succeed. So the best we can do without breaking API and ABI (and modifying all users of the library) is to change the exit(1) calls into an assert. Would that be better? -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From jskarvad at redhat.com Wed Nov 11 15:23:11 2015 From: jskarvad at redhat.com (Jaroslav Skarvada) Date: Wed, 11 Nov 2015 10:23:11 -0500 (EST) Subject: libosmocore minor issues In-Reply-To: <20151110194840.GU8473@nataraja> References: <1195163689.6803559.1447087336065.JavaMail.zimbra@redhat.com> <1096145625.7613757.1447149383640.JavaMail.zimbra@redhat.com> <20151110194840.GU8473@nataraja> Message-ID: <1076717592.8478548.1447255391492.JavaMail.zimbra@redhat.com> ----- Original Message ----- > Hi Jaroslav, > > On Tue, Nov 10, 2015 at 04:56:23AM -0500, Jaroslav Skarvada wrote: > > I am working on getting libosmocom package into Fedora, there is > > review request in [1]. > > Thanks for this! > > > During the packaging I found following minor issues: > > - Incorrect FSF addresses in source code > > This is easy to fix. Do you already have a patch to fix all > occurrences? I'd happily apply that. > Patch attempting to fix it is attached. > > - exit call in the library: /usr/lib64/libosmovty.so.3.0.0 exit at GLIBC_2.2.5 > > libraries shouldn't generally call exit. > > libosmovty started as a fork of the VTY (telnet command line interface) > code of GNU zebra. So the code was not written as a library to begin > with, but was part of zebra itself. > > In any case, addressing those issues is not particularly easy, as said > functions should never fail at this point, but they don't have a way to > return an error code, or their callers simply assume they always > succeed. > > So the best we can do without breaking API and ABI (and modifying all > users of the library) is to change the exit(1) calls into an assert. > Would that be better? Nice, thanks. Please note, this is not something that blocks Fedora review, I just wanted to point it out, e.g. to consider it for next API update sometimes in the future thanks & regards Jaroslav -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-fix-FSF-address-in-sources-headers.patch Type: text/x-patch Size: 5552 bytes Desc: not available URL: From laforge at gnumonks.org Wed Nov 11 23:58:57 2015 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 12 Nov 2015 00:58:57 +0100 Subject: Can we drop osmo-pcu OpenBTS support? Message-ID: <20151111235857.GR8473@nataraja> Dear all, as far as I understand, the TCP socket interface between osmo-bts and OpenBSC only existed in a particular branch/fork of OpenBTS created by Fairwaves, and it was created at a point where no public release of OpenBTS included any GPRS support. As the world has moved on (OpenBTS including their own GRPS code with something of a unified PCU, SGSN and GGSN; Fairwaves using OsmoBTS), I'm wondering how much sense it makes to still keep this code in the osmo-pcu repository. Particularly, it doesn't seem to make sense to keep it as the compile default. A default should be applicable to most users / configurations of a software, shouldn't it? Any input on thi is appreciated. My argument would be to drop that code. If not, then at least make it the non-default case. Or even compile both an osmo-pcu-osmobts and an osmo-pcu-openbts binary by the default makefile target and do away with any compile-time switching between the two. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Thu Nov 12 12:50:40 2015 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 12 Nov 2015 13:50:40 +0100 Subject: libosmocore minor issues In-Reply-To: <1076717592.8478548.1447255391492.JavaMail.zimbra@redhat.com> References: <1195163689.6803559.1447087336065.JavaMail.zimbra@redhat.com> <1096145625.7613757.1447149383640.JavaMail.zimbra@redhat.com> <20151110194840.GU8473@nataraja> <1076717592.8478548.1447255391492.JavaMail.zimbra@redhat.com> Message-ID: <20151112125040.GX8473@nataraja> Hi Jaroslav, On Wed, Nov 11, 2015 at 10:23:11AM -0500, Jaroslav Skarvada wrote: > > > During the packaging I found following minor issues: > > > - Incorrect FSF addresses in source code > > > Patch attempting to fix it is attached. Patch applied, thanks. > > > - exit call in the library: /usr/lib64/libosmovty.so.3.0.0 exit at GLIBC_2.2.5 > > > libraries shouldn't generally call exit. > > > > So the best we can do without breaking API and ABI (and modifying all > > users of the library) is to change the exit(1) calls into an assert. > > Would that be better? > > Nice, thanks. Please note, this is not something that blocks Fedora > review, I just wanted to point it out, e.g. to consider it for > next API update sometimes in the future Thanks. I've just applied a patch to change the exit() calls into OSMO_ASSERT() instead, which is a better and more generic way to do this anyway. The VTY code doesn't get much love from us, we simply adapted it from Zebra back in the early days of OpenBSC, and it sits there without much review/improvement/change. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From suraev at alumni.ntnu.no Thu Nov 12 14:05:05 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Thu, 12 Nov 2015 15:05:05 +0100 Subject: libosmocore minor issues In-Reply-To: <20151112125040.GX8473@nataraja> References: <1195163689.6803559.1447087336065.JavaMail.zimbra@redhat.com> <1096145625.7613757.1447149383640.JavaMail.zimbra@redhat.com> <20151110194840.GU8473@nataraja> <1076717592.8478548.1447255391492.JavaMail.zimbra@redhat.com> <20151112125040.GX8473@nataraja> Message-ID: <56449C91.6050508@alumni.ntnu.no> 12.11.2015 13:50, Harald Welte ?????: > > The VTY code doesn't get much love from us, we simply adapted it from > Zebra back in the early days of OpenBSC, and it sits there without much > review/improvement/change. > Speaking of which - upstream (quagga, successor to zebra) would welcome if anyone could abstract their vty code and split it into separate library. See https://bugzilla.quagga.net/show_bug.cgi?id=847 for details. cheers, Max. From alexander.chemeris at gmail.com Thu Nov 12 17:56:57 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Thu, 12 Nov 2015 09:56:57 -0800 Subject: Can we drop osmo-pcu OpenBTS support? In-Reply-To: <20151111235857.GR8473@nataraja> References: <20151111235857.GR8473@nataraja> Message-ID: Hi Harald, On Wed, Nov 11, 2015 at 3:58 PM, Harald Welte wrote: > My argument would be to drop that code. Yes, we can drop it. -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From aschultz at tpip.net Fri Nov 13 14:57:37 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Fri, 13 Nov 2015 15:57:37 +0100 Subject: [PATCH] convert literal APN name to protocol encoded version before use Message-ID: <1447426657-17954-1-git-send-email-aschultz@tpip.net> The definition of the APN field format in GTPv1 is hidden in a chain of documents. 3GPP TS 29.060 (the GTPv1-C specification) Section 7.7.30: > The Access Point Name contains a logical name (see 3GPP TS 23.060 [4]). > It is coded as in the value part defined in 3GPP TS 24.008 3GPP TS 24.008 Section 10.5.6.1: > The value part is defined in 3GPP TS 23.003. 3GPP TS 23.003 Section 9.1: > The APN consists of one or more labels. Each label is coded as a one > octet length field followed by that number of octets coded as 8 bit > ASCII characters This converts a literal APN (e.g. Label1.Label2.Label3) to a structured field (e.g. \006Label1\006Label2\006Label3) Signed-off-by: Andreas Schultz --- sgsnemu/sgsnemu.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index 5b56751..832bd97 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -231,6 +231,7 @@ int process_options(int argc, char **argv) char *type; char *mcc; char *mnc; + char *tok, *apn; char *lac; int lac_d; char *rest; @@ -534,10 +535,19 @@ int process_options(int argc, char **argv) printf("Invalid APN\n"); return -1; } - options.apn.l = strlen(args_info.apn_arg); - strncpy((char *)options.apn.v, args_info.apn_arg, - sizeof(options.apn.v)); - options.apn.v[sizeof(options.apn.v) - 1] = 0; + options.apn.l = strlen(args_info.apn_arg) + 1; + + apn = (char *)options.apn.v; + for (tok = strtok(args_info.apn_arg, "."); + tok != NULL; + tok = strtok(NULL, ".")) { + size_t len = strlen(tok); + + *apn++ = (char)len; + strncpy(apn, tok, len); + apn += len; + } + printf("Using APN: %s\n", args_info.apn_arg); /* selmode */ -- 2.5.0 From laforge at gnumonks.org Fri Nov 13 16:16:40 2015 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 13 Nov 2015 17:16:40 +0100 Subject: [PATCH] convert literal APN name to protocol encoded version before use In-Reply-To: <1447426657-17954-1-git-send-email-aschultz@tpip.net> References: <1447426657-17954-1-git-send-email-aschultz@tpip.net> Message-ID: <20151113161640.GY4687@nataraja> On Fri, Nov 13, 2015 at 03:57:37PM +0100, Andreas Schultz wrote: > This converts a literal APN (e.g. Label1.Label2.Label3) to a structured > field (e.g. \006Label1\006Label2\006Label3) thanks, applied to my local tree, will push soon. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From suraev at alumni.ntnu.no Sat Nov 14 12:29:37 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Sat, 14 Nov 2015 13:29:37 +0100 Subject: channel availability Message-ID: <56472931.9070807@alumni.ntnu.no> Hi. While trying to debug issue with osmo-pcu failing to allocate tfi due to pdch unavailability I've noticed that regular connection attempts are also failing with imm. ass. reject due to channel unavailability. I do not see rach flood so it feels like misconfiguration or maybe hw issue. MY question is - how to troubleshoot this? Where can I look as to which channels are available, which are occupied and by whom? thanks, Max. From laforge at gnumonks.org Sat Nov 14 20:20:01 2015 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 14 Nov 2015 21:20:01 +0100 Subject: channel availability In-Reply-To: <56472931.9070807@alumni.ntnu.no> References: <56472931.9070807@alumni.ntnu.no> Message-ID: <20151114202001.GU4687@nataraja> On Sat, Nov 14, 2015 at 01:29:37PM +0100, Suraev wrote: > MY question is - how to troubleshoot this? Where can I look as to > which channels are available, which are occupied and by whom? 'show lchan' shows you the state of currently allocated logical channels. 'by whom' doesn't really work unless we have received an identity of the subscirber already. You don't know at the time of RACH request. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From anas.abubaker at port.ac.uk Sun Nov 15 20:26:45 2015 From: anas.abubaker at port.ac.uk (Anas Abubaker) Date: Sun, 15 Nov 2015 20:26:45 +0000 Subject: Testing with openbsc Message-ID: I am trying to insert some code to openBSC, and after studying the GSM network, I decided to test with SMS payload without changing the headers, the best place for it is in the MSC before the SMS is stored in the SMSC, can anyone direct me to the source file for it, I've tried to look in Libsmocore and Openbsc source files but with no success. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jerlbeck at sysmocom.de Mon Nov 16 08:46:58 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 16 Nov 2015 09:46:58 +0100 Subject: [PATCH] convert literal APN name to protocol encoded version before use In-Reply-To: <1447426657-17954-1-git-send-email-aschultz@tpip.net> References: <1447426657-17954-1-git-send-email-aschultz@tpip.net> Message-ID: <56499802.8010703@sysmocom.de> Hi, On 13.11.2015 15:57, Andreas Schultz wrote: > >> The APN consists of one or more labels. Each label is coded as a one >> octet length field followed by that number of octets coded as 8 bit >> ASCII characters > > This converts a literal APN (e.g. Label1.Label2.Label3) to a structured > field (e.g. \006Label1\006Label2\006Label3) We already have gprs_apn_to_str and gprs_str_to_apn in openbsc/src/gprs/gprs_utils.c (along with test cases) which are probably good candidates (among other functions in that file) to be moved to libosmocore, which sgsnemu is using already. Nevertheless most of the basic GPRS stuff (e.g. gsm_04_08_gprs.c which is on a similar level) is still in openbsc, so I would like to have more of a concept (gsm, gb, or a new gprs lib? Name prefix?) before starting refactoring. Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From jerlbeck at sysmocom.de Mon Nov 16 09:35:56 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 16 Nov 2015 10:35:56 +0100 Subject: [PATCH] convert literal APN name to protocol encoded version before use In-Reply-To: <20151116085923.GJ4687@nataraja> References: <1447426657-17954-1-git-send-email-aschultz@tpip.net> <56499802.8010703@sysmocom.de> <20151116085923.GJ4687@nataraja> Message-ID: <5649A37C.8070505@sysmocom.de> Hi Harald, On 16.11.2015 09:59, Harald Welte wrote: > I would argue to put more things into libosmogsm. We already have > plenty of libraries and I think there's not much point to have even more > fragmentation. I mean, we're not talking about hundreds of megabyte of > boost-enabled C++ code, but some amount of helper functions here. > > libosmogb should stay related specific to the Gb (NS/BSSGP) interface, I > think that's a pretty clean/clear split. Agreed. > In terms of prefixing: libosmogsm uses gsm* where * is for the reduced > spec number, and some gprs_* symbols. I think it's hard to come up with > a detailed rule, but I'd say as long as it fits within that scheme it is > fine. > > Starting now to prefix eveything with osmo_ seems a bit ridiculous, with > all the existing other-prefixed symbols. but let's kepe the nubmer of > prefixes limited ;) I just came across gsm/apn.c (which seems to be a sensible place to put the conversion functions) where are currently definitions of osmo_apn_qualify and osmo_apn_qualify_from_imsi. So for the sake of consistency I can move the function there as osmo_apn_from_str/to_str. Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From royal_angel2009 at hotmail.com Tue Nov 3 08:43:09 2015 From: royal_angel2009 at hotmail.com (Rehab Khan) Date: Tue, 3 Nov 2015 13:43:09 +0500 Subject: No subject Message-ID: Hey All, I have configured osmocom openbsc.Everything runs fine.But the configurations do not change in real time,everytime the system needs to be restarted as changing lac or cellid in openbsc.cfg file after running the entire setup halts the osmo-nitb log.I want to change cellid,lac and some other configuration parameters in runtime as such in openbts so, can you provide some assistance in this regard? Any help will be greatly appreciated. -------------- next part -------------- An HTML attachment was scrubbed... URL: From royal_angel2009 at hotmail.com Tue Nov 3 08:44:37 2015 From: royal_angel2009 at hotmail.com (Rehab Khan) Date: Tue, 3 Nov 2015 13:44:37 +0500 Subject: openbsc_configuration Message-ID: I have configured osmocom openbsc.Everything runs fine.But the configurations do not change in real time,everytime the system needs to be restarted as changing lac or cellid in openbsc.cfg file after running the entire setup halts the osmo-nitb log.I want to change cellid,lac and some other configuration parameters in runtime as such in openbts so, can you provide some assistance in this regard? Any help will be greatly appreciated. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hwelte at sysmocom.de Mon Nov 16 08:59:23 2015 From: hwelte at sysmocom.de (Harald Welte) Date: Mon, 16 Nov 2015 09:59:23 +0100 Subject: [PATCH] convert literal APN name to protocol encoded version before use In-Reply-To: <56499802.8010703@sysmocom.de> References: <1447426657-17954-1-git-send-email-aschultz@tpip.net> <56499802.8010703@sysmocom.de> Message-ID: <20151116085923.GJ4687@nataraja> Hi Jacob, On Mon, Nov 16, 2015 at 09:46:58AM +0100, Jacob Erlbeck wrote: > Nevertheless most of the basic GPRS stuff (e.g. gsm_04_08_gprs.c which > is on a similar level) is still in openbsc, so I would like to have more > of a concept (gsm, gb, or a new gprs lib? Name prefix?) before starting > refactoring. I would argue to put more things into libosmogsm. We already have plenty of libraries and I think there's not much point to have even more fragmentation. I mean, we're not talking about hundreds of megabyte of boost-enabled C++ code, but some amount of helper functions here. libosmogb should stay related specific to the Gb (NS/BSSGP) interface, I think that's a pretty clean/clear split. In terms of prefixing: libosmogsm uses gsm* where * is for the reduced spec number, and some gprs_* symbols. I think it's hard to come up with a detailed rule, but I'd say as long as it fits within that scheme it is fine. Starting now to prefix eveything with osmo_ seems a bit ridiculous, with all the existing other-prefixed symbols. but let's kepe the nubmer of prefixes limited ;) -- - Harald Welte http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From nhofmeyr at sysmocom.de Mon Nov 16 14:54:04 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 16 Nov 2015 15:54:04 +0100 Subject: gtphub on master Message-ID: <20151116145404.GB7055@dub5> Hi OpenBSC, I have just merged the gtphub branch to master. The request to do that has been standing for a while, to let Jenkins run the tests etc., but there were still quite volatile parts of the code until now. The last few days, I have successfully tested gtphub in a mock network, using a web capable phone, a sysmoBTS running an SGSN on-board, and a gtphub and OpenGGSN on my laptop. It works: I can browse the net! @Andreas: since our last discussion, I have incorporated all of your comments. It *does* make sense after all. A peer may request gtphub from any port, and by sequence number tracking, the response will go back to that port and IP. Requests with unknown sequence number will be routed according to the header's TEI, which means that gtphub will send Requests always to the default port (a proxy with a specific port may be configured, though). Another thanks for your input! GGSN resolution by DNS (GRX C ares) is taking a shortcut: hoping that the peer will try again, after a DNS request has first been fired, gtphub will simply not respond. Once a GGSN has been resolved and sits in the cache, Requests are served immediately. In this way, I avoided a mechanism to queue incoming Requests (until DNS is done, so that other messages are not blocked in the meantime), which would have been the proper way to do this, but would add quite a bit of complexity that is really only needed for the very first resolution of a given GGSN... According to spec, an SGSN will resend Requests a number of times, so this should actually be sufficient, I guess. Some small bits are still outright missing, as you may notice from the various TODO comments. But all the main parts are implemented and tested. Probably a number of bugs still need to be found. Some infrastructural things are also missing. Coming up is the debian build, and soon to follow: rate control. Thanks for any reviews! (I intend to employ proper peer review for gtphub from this point on...) ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Nov 16 14:58:55 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 16 Nov 2015 15:58:55 +0100 Subject: [PATCH] gtphub collapsed patch (aka bomb) In-Reply-To: <819890475.865025.1446803018892.JavaMail.zimbra@tpip.net> References: <1446602182-32618-1-git-send-email-nhofmeyr@sysmocom.de> <5639CDED.3060406@tpip.net> <20151104152433.GA1486@dub5> <563A2861.8020003@tpip.net> <20151104224707.GB1486@dub5> <819890475.865025.1446803018892.JavaMail.zimbra@tpip.net> Message-ID: <20151116145855.GC7055@dub5> On Fri, Nov 06, 2015 at 10:43:38AM +0100, Andreas Schultz wrote: > Thinks get interesting when you look at the Echo requests. For our GGSN > implementation, I decided to only use the IP's from the GSN information > elements. The way I understand it, Echo is actually defined to be limited to the path, so it is the simplest of them all: reply directly to the IP and port of the sender. Echos don't pass through gtphub, they "rebound". ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From aschultz at tpip.net Mon Nov 16 15:06:42 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:42 +0100 Subject: [PATCH 01/16] gtp: remove unused local variable In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-2-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- gtp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gtp.c b/gtp.c index 7c72eb0..11bda38 100644 --- a/gtp.c +++ b/gtp.c @@ -957,7 +957,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) struct gtp_instance *gti = netdev_priv(dev); struct pdp_ctx *pctx; u16 flow = 0; - u32 gtp_version, link, sgsn_addr, ms_addr, hash_ms, hash_tid; + u32 gtp_version, sgsn_addr, ms_addr, hash_ms, hash_tid; u64 tid; bool found = false; @@ -986,7 +986,6 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) flow = nla_get_u16(info->attrs[GTPA_FLOW]); } - link = nla_get_u32(info->attrs[GTPA_LINK]); sgsn_addr = nla_get_u32(info->attrs[GTPA_SGSN_ADDRESS]); ms_addr = nla_get_u32(info->attrs[GTPA_MS_ADDRESS]); -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:45 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:45 +0100 Subject: [PATCH 04/16] gtp: select netns based on NL attribute In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-5-git-send-email-aschultz@tpip.net> This permits a split namespace setup where the GTP transport sockets are in one namespace the gtp tunnel interface is in another namespace. The target namespece is selected by the new GTPA_NET_NS_FD NL attributes. It fall back to the netns of the GTP-U sockets if the NL attr is not present. Signed-off-by: Andreas Schultz --- gtp.c | 41 +++++++++++++++++++++++++++++++++++++---- gtp_nl.h | 1 + 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/gtp.c b/gtp.c index 7c61e61..11f8fad 100644 --- a/gtp.c +++ b/gtp.c @@ -330,6 +330,8 @@ static int gtp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (!gti) goto user; + netdev_dbg(gti->dev, "encap_recv %p\n", sk); + switch (udp_sk(sk)->encap_type) { case UDP_ENCAP_GTP0: netdev_dbg(gti->dev, "received GTP0 packet\n"); @@ -738,7 +740,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - struct gtp_net *gn = net_generic(src_net, gtp_net_id); + struct gtp_net *gn; struct net_device *real_dev; struct gtp_instance *gti; int hashsize, err, fd0, fd1; @@ -778,6 +780,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, if (err < 0) goto err1; + gn = net_generic(dev_net(dev), gtp_net_id); list_add_rcu(>i->list, &gn->gtp_instance_list); netdev_dbg(dev, "registered new interface\n"); @@ -845,6 +848,19 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = { .fill_info = gtp_fill_info, }; +static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[]) +{ + struct net *net; + /* Examine the link attributes and figure out which + * network namespace we are talking about. + */ + if (tb[GTPA_NET_NS_FD]) + net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD])); + else + net = get_net(src_net); + return net; +} + static int gtp_hashtable_new(struct gtp_instance *gti, int hsize) { int i; @@ -893,6 +909,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, struct socket *sock0, *sock1u; struct sock *sk; + netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1); + sock0 = sockfd_lookup(fd_gtp0, &err); if (sock0 == NULL) { netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0); @@ -918,6 +936,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, goto err2; } + netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u); + gti->sock0 = sock0; gti->sock1u = sock1u; @@ -1059,7 +1079,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct net_device *dev; if (!info->attrs[GTPA_VERSION] || @@ -1069,6 +1089,10 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) !info->attrs[GTPA_TID]) return -EINVAL; + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (net == NULL) + return -EINVAL; + /* Check if there's an existing gtpX device to configure */ dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) @@ -1079,7 +1103,7 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct gtp_instance *gti; struct net_device *dev; struct pdp_ctx *pctx; @@ -1107,6 +1131,10 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) if (gtp_version == GTP_V1 && tid > UINT_MAX) return -EINVAL; + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (net == NULL) + return -EINVAL; + /* Check if there's an existing gtpX device to configure */ dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) @@ -1175,7 +1203,7 @@ nla_put_failure: static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct net_device *dev; struct gtp_instance *gti; struct pdp_ctx *pctx = NULL; @@ -1196,6 +1224,10 @@ static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (net == NULL) + return -EINVAL; + /* Check if there's an existing gtpX device to configure */ dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) @@ -1304,6 +1336,7 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { [GTPA_SGSN_ADDRESS] = { .type = NLA_NESTED, }, [GTPA_MS_ADDRESS] = { .type = NLA_NESTED, }, [GTPA_FLOW] = { .type = NLA_U16, }, + [GTPA_NET_NS_FD] = { .type = NLA_U32, }, }; static const struct genl_ops gtp_genl_ops[] = { diff --git a/gtp_nl.h b/gtp_nl.h index 7bdd2f5..c20666d 100644 --- a/gtp_nl.h +++ b/gtp_nl.h @@ -40,6 +40,7 @@ enum gtp_attrs { GTPA_SGSN_ADDRESS, GTPA_MS_ADDRESS, GTPA_FLOW, + GTPA_NET_NS_FD, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:44 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:44 +0100 Subject: [PATCH 03/16] gtp: convert the global gtp_instance_list to a per netns list In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-4-git-send-email-aschultz@tpip.net> This add basic network namespace support by changing to global gtp_instance_list into a pre namespace list. Before this change all pdp context would be visible from all network namespaces, now only the namespace that they belong too, can see them. Also selectively destroy all gtp devices when a namespace is destroyed. Signed-off-by: Andreas Schultz --- gtp.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/gtp.c b/gtp.c index 7e615f3..7c61e61 100644 --- a/gtp.c +++ b/gtp.c @@ -20,13 +20,15 @@ #include #include +#include #include #include #include #include #include #include - +#include +# #include "gtp.h" #include "gtp_nl.h" @@ -72,7 +74,11 @@ struct gtp_instance { struct hlist_head *addr_hash; }; -static LIST_HEAD(gtp_instance_list); /* XXX netns */ +static int gtp_net_id __read_mostly; + +struct gtp_net { + struct list_head gtp_instance_list; +}; static inline u32 gtp0_hashfn(u64 tid) { @@ -732,6 +738,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { + struct gtp_net *gn = net_generic(src_net, gtp_net_id); struct net_device *real_dev; struct gtp_instance *gti; int hashsize, err, fd0, fd1; @@ -771,7 +778,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, if (err < 0) goto err1; - list_add_rcu(>i->list, >p_instance_list); + list_add_rcu(>i->list, &gn->gtp_instance_list); netdev_dbg(dev, "registered new interface\n"); @@ -941,11 +948,12 @@ static void gtp_encap_disable(struct gtp_instance *gti) sockfd_put(gti->sock0); } -static struct net_device *gtp_find_dev(int ifindex) +static struct net_device *gtp_find_dev(struct net *net, int ifindex) { + struct gtp_net *gn = net_generic(net, gtp_net_id); struct gtp_instance *gti; - list_for_each_entry_rcu(gti, >p_instance_list, list) { + list_for_each_entry_rcu(gti, &gn->gtp_instance_list, list) { if (ifindex == gti->dev->ifindex) return gti->dev; } @@ -1051,6 +1059,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) { + struct net *net = sock_net(skb->sk); struct net_device *dev; if (!info->attrs[GTPA_VERSION] || @@ -1061,7 +1070,7 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) return -EINVAL; /* Check if there's an existing gtpX device to configure */ - dev = gtp_find_dev(nla_get_u32(info->attrs[GTPA_LINK])); + dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) return -ENODEV; @@ -1070,6 +1079,7 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) { + struct net *net = sock_net(skb->sk); struct gtp_instance *gti; struct net_device *dev; struct pdp_ctx *pctx; @@ -1098,7 +1108,7 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) return -EINVAL; /* Check if there's an existing gtpX device to configure */ - dev = gtp_find_dev(nla_get_u32(info->attrs[GTPA_LINK])); + dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) return -ENODEV; @@ -1165,6 +1175,7 @@ nla_put_failure: static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) { + struct net *net = sock_net(skb->sk); struct net_device *dev; struct gtp_instance *gti; struct pdp_ctx *pctx = NULL; @@ -1186,7 +1197,7 @@ static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) } /* Check if there's an existing gtpX device to configure */ - dev = gtp_find_dev(nla_get_u32(info->attrs[GTPA_LINK])); + dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) return -ENODEV; @@ -1249,11 +1260,13 @@ gtp_genl_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb) unsigned long tid = cb->args[1]; struct gtp_instance *last_gti = (struct gtp_instance *)cb->args[2], *gti; struct pdp_ctx *pctx; + struct net *net = sock_net(skb->sk); + struct gtp_net *gn = net_generic(net, gtp_net_id); if (cb->args[4]) return 0; - list_for_each_entry_rcu(gti, >p_instance_list, list) { + list_for_each_entry_rcu(gti, &gn->gtp_instance_list, list) { if (last_gti && last_gti != gti) continue; else @@ -1315,6 +1328,37 @@ static const struct genl_ops gtp_genl_ops[] = { }, }; +static int __net_init gtp_net_init(struct net *net) +{ + struct gtp_net *gn = net_generic(net, gtp_net_id); + + INIT_LIST_HEAD(&gn->gtp_instance_list); + + return 0; +} + +static void __net_exit gtp_net_exit(struct net *net) +{ + struct gtp_net *gn = net_generic(net, gtp_net_id); + struct gtp_instance *gti; + LIST_HEAD(list); + + rtnl_lock(); + list_for_each_entry_rcu(gti, &gn->gtp_instance_list, list) { + gtp_dellink(gti->dev, &list); + } + + unregister_netdevice_many(&list); + rtnl_unlock(); +} + +static struct pernet_operations gtp_net_ops = { + .init = gtp_net_init, + .exit = gtp_net_exit, + .id = >p_net_id, + .size = sizeof(struct gtp_net), +}; + static int __init gtp_init(void) { int err; @@ -1329,10 +1373,17 @@ static int __init gtp_init(void) if (err < 0) goto unreg_rtnl_link; + err = register_pernet_subsys(>p_net_ops); + if (err < 0) + goto unreg_genl_family; + pr_info("GTP module loaded (pdp ctx size %Zd bytes)\n", sizeof(struct pdp_ctx)); return 0; +unreg_genl_family: + genl_unregister_family(>p_genl_family); + unreg_rtnl_link: rtnl_link_unregister(>p_link_ops); @@ -1344,6 +1395,7 @@ late_initcall(gtp_init); static void __exit gtp_fini(void) { + unregister_pernet_subsys(>p_net_ops); genl_unregister_family(>p_genl_family); rtnl_link_unregister(>p_link_ops); -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:50 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:50 +0100 Subject: [PATCH 09/16] gtp: replace udp encap setup with setup_udp_tunnel_sock In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-10-git-send-email-aschultz@tpip.net> setup_udp_tunnel_sock() is doing exactly the same as we did before. So instead of replicating all that, simply use it instead. Signed-off-by: Andreas Schultz --- gtp.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/gtp.c b/gtp.c index 40a5d1c..794b459 100644 --- a/gtp.c +++ b/gtp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -931,7 +932,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, { int err; struct socket *sock0, *sock1u; - struct sock *sk; + struct udp_tunnel_sock_cfg tuncfg = {NULL}; netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1); @@ -965,18 +966,15 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, gti->sock0 = sock0; gti->sock1u = sock1u; - sk = gti->sock0->sk; - udp_sk(sk)->encap_type = UDP_ENCAP_GTP0; - udp_sk(sk)->encap_rcv = gtp_udp_encap_recv; - udp_sk(sk)->encap_destroy = gtp_udp_encap_destroy; - sk->sk_user_data = gti; - udp_encap_enable(); - - sk = gti->sock1u->sk; - udp_sk(sk)->encap_type = UDP_ENCAP_GTP1U; - udp_sk(sk)->encap_rcv = gtp_udp_encap_recv; - udp_sk(sk)->encap_destroy = gtp_udp_encap_destroy; - sk->sk_user_data = gti; + tuncfg.sk_user_data = gti; + tuncfg.encap_rcv = gtp_udp_encap_recv; + tuncfg.encap_destroy = gtp_udp_encap_destroy; + + tuncfg.encap_type = UDP_ENCAP_GTP0; + setup_udp_tunnel_sock(sock_net(gti->sock0->sk), gti->sock0, &tuncfg); + + tuncfg.encap_type = UDP_ENCAP_GTP1U; + setup_udp_tunnel_sock(sock_net(gti->sock1u->sk), gti->sock1u, &tuncfg); err = 0; -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:53 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:53 +0100 Subject: [PATCH 12/16] gtp-rtnl: sync GTPA_FLOW nl attribute name from kernel to userspace In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-13-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- libgtnl/include/linux/gtp_nl.h | 2 +- libgtnl/src/gtp-genl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libgtnl/include/linux/gtp_nl.h b/libgtnl/include/linux/gtp_nl.h index a8fdf3a..a1e8ce1 100644 --- a/libgtnl/include/linux/gtp_nl.h +++ b/libgtnl/include/linux/gtp_nl.h @@ -39,7 +39,7 @@ enum gtp_attrs { GTPA_TID, /* 64 bits for GTPv1 */ GTPA_SGSN_ADDRESS, GTPA_MS_ADDRESS, - GTPA_FLOWID, /* only for GTPv0 */ + GTPA_FLOW, /* only for GTPv0 */ GTPA_NET_NS_FD, __GTPA_MAX, }; diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c index 9e68a30..2717821 100644 --- a/libgtnl/src/gtp-genl.c +++ b/libgtnl/src/gtp-genl.c @@ -50,7 +50,7 @@ static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); mnl_attr_put_u64(nlh, GTPA_TID, t->tid); - mnl_attr_put_u16(nlh, GTPA_FLOWID, t->flowid); + mnl_attr_put_u16(nlh, GTPA_FLOW, t->flowid); } int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t) -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:54 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:54 +0100 Subject: [PATCH 13/16] gtp-rtnl: real_ifname is not long needed, remove it In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-14-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- libgtnl/include/libgtpnl/gtpnl.h | 3 +-- libgtnl/src/gtp-rtnl.c | 4 +--- libgtnl/tools/gtp-link-add.c | 5 ++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libgtnl/include/libgtpnl/gtpnl.h b/libgtnl/include/libgtpnl/gtpnl.h index 3d3fd73..49ba03d 100644 --- a/libgtnl/include/libgtpnl/gtpnl.h +++ b/libgtnl/include/libgtpnl/gtpnl.h @@ -16,8 +16,7 @@ int genl_lookup_family(struct mnl_socket *nl, const char *family); struct in_addr; -int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, - int fd0, int fd1); +int gtp_dev_create(int dest_ns, const char *gtp_ifname, int fd0, int fd1); int gtp_dev_config(const char *iface, struct in_addr *net, uint32_t prefix); int gtp_dev_destroy(const char *gtp_ifname); diff --git a/libgtnl/src/gtp-rtnl.c b/libgtnl/src/gtp-rtnl.c index db54653..0999aa3 100644 --- a/libgtnl/src/gtp-rtnl.c +++ b/libgtnl/src/gtp-rtnl.c @@ -108,8 +108,7 @@ static int gtp_dev_talk(struct nlmsghdr *nlh, uint32_t seq) return ret; } -int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, - int fd0, int fd1) +int gtp_dev_create(int dest_ns, const char *gtp_ifname, int fd0, int fd1) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; @@ -126,7 +125,6 @@ int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, if (dest_ns > 0) mnl_attr_put_u32(nlh, IFLA_NET_NS_FD, dest_ns); - mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(real_ifname)); mnl_attr_put_str(nlh, IFLA_IFNAME, gtp_ifname); nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO); mnl_attr_put_str(nlh, IFLA_INFO_KIND, "gtp"); diff --git a/libgtnl/tools/gtp-link-add.c b/libgtnl/tools/gtp-link-add.c index 3d893eb..4ef025e 100644 --- a/libgtnl/tools/gtp-link-add.c +++ b/libgtnl/tools/gtp-link-add.c @@ -43,8 +43,8 @@ int main(int argc, char *argv[]) unsigned int seq, portid, change = 0, flags = 0; struct nlattr *nest, *nest2; - if (argc != 2) { - printf("Usage: %s [ifname]\n", argv[0]); + if (argc != 1) { + printf("Usage: %s\n", argv[0]); exit(EXIT_FAILURE); } @@ -62,7 +62,6 @@ int main(int argc, char *argv[]) int fd1 = socket(AF_INET, SOCK_DGRAM, 0); int fd2 = socket(AF_INET, SOCK_DGRAM, 0); - mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(argv[1])); mnl_attr_put_str(nlh, IFLA_IFNAME, "gtp0"); nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO); mnl_attr_put_str(nlh, IFLA_INFO_KIND, "gtp"); -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:57 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:57 +0100 Subject: [PATCH 16/16] gtp: add support for replacing PDP contexts In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-17-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- gtp.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/gtp.c b/gtp.c index 4b233f7..2b8738d 100644 --- a/gtp.c +++ b/gtp.c @@ -1080,24 +1080,44 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) } if (found) { + struct pdp_ctx *repl_pctx; + if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) return -EEXIST; - if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) - return -EOPNOTSUPP; - ipv4_pdp_fill(pctx, info); + repl_pctx = kmemdup(pctx, sizeof(struct pdp_ctx), GFP_KERNEL); + if (repl_pctx == NULL) + return -ENOMEM; + + ipv4_pdp_fill(repl_pctx, info); + + /* only the SGSN can be changed */ + if (pctx->af != repl_pctx->af || + pctx->gtp_version != repl_pctx->gtp_version || + memcpy(&pctx->u, &repl_pctx->u, sizeof(pctx->u) != 0)) { + kfree(repl_pctx); + return -EINVAL; + } + + hlist_replace_rcu(&pctx->hlist_addr, &repl_pctx->hlist_addr); + hlist_replace_rcu(&pctx->hlist_tid, &repl_pctx->hlist_tid); - if (pctx->gtp_version == GTP_V0) + kfree_rcu(pctx, rcu_head); + + if (repl_pctx->gtp_version == GTP_V0) netdev_dbg(dev, "GTPv0-U: update tunnel id = %llx (pdp %p)\n", - pctx->u.v0.tid, pctx); - else if (pctx->gtp_version == GTP_V1) + repl_pctx->u.v0.tid, repl_pctx); + else if (repl_pctx->gtp_version == GTP_V1) netdev_dbg(dev, "GTPv1-U: update tunnel id = %x/%x (pdp %p)\n", - pctx->u.v1.i_tid, pctx->u.v1.o_tid, pctx); + repl_pctx->u.v1.i_tid, repl_pctx->u.v1.o_tid, repl_pctx); return 0; } + if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) + return -ENXIO; + pctx = kmalloc(sizeof(struct pdp_ctx), GFP_KERNEL); if (pctx == NULL) return -ENOMEM; -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:51 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:51 +0100 Subject: [PATCH 10/16] gtp: switch to iptunnel framework and no longer depend on real_dev In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-11-git-send-email-aschultz@tpip.net> Send tunnel data on GTP-U socket insead of raw interface and use existing iptunnel helpers for that. Signed-off-by: Andreas Schultz --- gtp.c | 223 ++++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 116 insertions(+), 107 deletions(-) diff --git a/gtp.c b/gtp.c index 794b459..2ac6431 100644 --- a/gtp.c +++ b/gtp.c @@ -68,7 +68,6 @@ struct gtp_instance { struct socket *sock1u; struct net_device *dev; - struct net_device *real_dev; unsigned int hash_size; struct hlist_head *tid_hash; @@ -404,7 +403,6 @@ static int gtp_dev_init(struct net_device *dev) { struct gtp_instance *gti = netdev_priv(dev); - dev->flags = IFF_NOARP; gti->dev = dev; dev->tstats = alloc_percpu(struct pcpu_sw_netstats); @@ -424,26 +422,34 @@ static void gtp_dev_uninit(struct net_device *dev) #define IP_UDP_LEN (sizeof(struct iphdr) + sizeof(struct udphdr)) -static struct rtable * -ip4_route_output_gtp(struct net *net, struct flowi4 *fl4, - __be32 daddr, __be32 saddr, __u8 tos, int oif) +static inline void init_gtp_flow(struct flowi4 *fl4, + const struct sock *sk, + __be32 daddr) { memset(fl4, 0, sizeof(*fl4)); - fl4->flowi4_oif = oif; + fl4->flowi4_oif = sk->sk_bound_dev_if; fl4->daddr = daddr; - fl4->saddr = saddr; - fl4->flowi4_tos = tos; - fl4->flowi4_proto = IPPROTO_UDP; + fl4->saddr = inet_sk(sk)->inet_saddr; + fl4->flowi4_tos = RT_CONN_FLAGS(sk); + fl4->flowi4_proto = sk->sk_protocol; +} + +static struct rtable * +ip4_route_output_gtp(struct net *net, struct flowi4 *fl4, + const struct sock *sk, + __be32 daddr) +{ + init_gtp_flow(fl4, sk, daddr); return ip_route_output_key(net, fl4); } static inline void -gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx, int payload_len) +gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) { struct gtp0_header *gtp0; + int payload_len = skb->len; /* ensure there is sufficient headroom */ - skb_cow(skb, sizeof(*gtp0) + IP_UDP_LEN); gtp0 = (struct gtp0_header *) skb_push(skb, sizeof(*gtp0)); gtp0->flags = 0x1e; /* V0, GTP-non-prime */ @@ -457,12 +463,12 @@ gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx, int payload_len) } static inline void -gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx, int payload_len) +gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) { struct gtp1_header *gtp1; + int payload_len = skb->len; /* ensure there is sufficient headroom */ - skb_cow(skb, sizeof(*gtp1) + IP_UDP_LEN); gtp1 = (struct gtp1_header *) skb_push(skb, sizeof(*gtp1)); /* Bits 8 7 6 5 4 3 2 1 @@ -502,6 +508,7 @@ gtp_iptunnel_xmit_stats(int err, struct net_device_stats *err_stats, } struct gtp_pktinfo { + struct sock *sk; union { struct iphdr *iph; struct ipv6hdr *ip6h; @@ -515,10 +522,12 @@ struct gtp_pktinfo { }; static inline void -gtp_set_pktinfo_ipv4(struct gtp_pktinfo *pktinfo, struct iphdr *iph, +gtp_set_pktinfo_ipv4(struct gtp_pktinfo *pktinfo, struct sock *sk, + struct iphdr *iph, struct pdp_ctx *pctx, struct rtable *rt, struct flowi4 *fl4, struct net_device *dev) { + pktinfo->sk = sk; pktinfo->iph = iph; pktinfo->pctx = pctx; pktinfo->rt = rt; @@ -530,7 +539,7 @@ static int gtp_ip4_prepare_xmit(struct sk_buff *skb, struct net_device *dev, struct gtp_pktinfo *pktinfo) { struct gtp_instance *gti = netdev_priv(dev); - struct inet_sock *inet = inet_sk(gti->sock0->sk); + struct sock *sk; struct iphdr *iph; struct pdp_ctx *pctx; struct rtable *rt; @@ -549,14 +558,23 @@ static int gtp_ip4_prepare_xmit(struct sk_buff *skb, struct net_device *dev, netdev_dbg(dev, "found PDP context %p\n", pctx); /* Obtain route for the new encapsulated GTP packet */ - rt = ip4_route_output_gtp(dev_net(dev), &fl4, - pctx->sgsn_addr.ip4.s_addr, - inet->inet_saddr, 0, - gti->real_dev->ifindex); + switch (pctx->gtp_version) { + case GTP_V0: + sk = gti->sock0->sk; + break; + case GTP_V1: + sk = gti->sock1u->sk; + break; + default: + return -ENOENT; + } + + rt = ip4_route_output_gtp(sock_net(sk), &fl4, + gti->sock0->sk, + pctx->sgsn_addr.ip4.s_addr); if (IS_ERR(rt)) { - netdev_dbg(dev, "no route to SSGN %pI4 from ifidx=%d\n", - &pctx->sgsn_addr.ip4.s_addr, - gti->real_dev->ifindex); + netdev_dbg(dev, "no route to SSGN %pI4\n", + &pctx->sgsn_addr.ip4.s_addr); dev->stats.tx_carrier_errors++; goto err; } @@ -570,12 +588,11 @@ static int gtp_ip4_prepare_xmit(struct sk_buff *skb, struct net_device *dev, } skb_dst_drop(skb); - skb_dst_set(skb, &rt->dst); /* This is similar to tnl_update_pmtu() */ df = iph->frag_off; if (df) { - mtu = dst_mtu(&rt->dst) - gti->real_dev->hard_header_len - + mtu = dst_mtu(&rt->dst) - dev->hard_header_len - sizeof(struct iphdr) - sizeof(struct udphdr); switch (pctx->gtp_version) { case GTP_V0: @@ -586,10 +603,9 @@ static int gtp_ip4_prepare_xmit(struct sk_buff *skb, struct net_device *dev, break; } } else - mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; + mtu = dst_mtu(&rt->dst); - if (skb_dst(skb)) - skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); + rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu); if (!skb_is_gso(skb) && (iph->frag_off & htons(IP_DF)) && mtu < ntohs(iph->tot_len)) { @@ -600,7 +616,7 @@ static int gtp_ip4_prepare_xmit(struct sk_buff *skb, struct net_device *dev, goto err_rt; } - gtp_set_pktinfo_ipv4(pktinfo, iph, pctx, rt, &fl4, dev); + gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, &fl4, dev); return 0; err_rt: @@ -616,34 +632,23 @@ static int gtp_ip6_prepare_xmit(struct sk_buff *skb, struct net_device *dev, return 0; } -static inline void -gtp_push_ip4hdr(struct sk_buff *skb, struct gtp_pktinfo *pktinfo) +static inline int +gtp_udp_tunnel_xmit(struct sk_buff *skb, __be16 port, + struct gtp_pktinfo *pktinfo) { - struct iphdr *iph; - - /* Push down and install the IP header. Similar to iptunnel_xmit() */ - skb_push(skb, sizeof(struct iphdr)); - skb_reset_network_header(skb); - - iph = ip_hdr(skb); - - iph->version = 4; - iph->ihl = sizeof(struct iphdr) >> 2; - iph->frag_off = htons(IP_DF); - iph->protocol = IPPROTO_UDP; - iph->tos = pktinfo->iph->tos; - iph->daddr = pktinfo->fl4.daddr; - iph->saddr = pktinfo->fl4.saddr; - iph->ttl = ip4_dst_hoplimit(&pktinfo->rt->dst); - __ip_select_ident(dev_net(pktinfo->rt->dst.dev), iph, - (skb_shinfo(skb)->gso_segs ?: 1) - 1); - netdev_dbg(pktinfo->dev, "gtp -> IP src: %pI4 dst: %pI4\n", - &iph->saddr, &iph->daddr); + &pktinfo->iph->saddr, &pktinfo->iph->daddr); + + return udp_tunnel_xmit_skb(pktinfo->rt, pktinfo->sk, skb, + pktinfo->fl4.saddr, + pktinfo->fl4.daddr, + pktinfo->iph->tos, + ip4_dst_hoplimit(&pktinfo->rt->dst), + htons(IP_DF), port, port, true, false); } -static inline void -gtp_push_ip6hdr(struct sk_buff *skb, struct gtp_pktinfo *pktinfo) +static inline int +gtp_ip6tunnel_xmit(struct sk_buff *skb, struct gtp_pktinfo *pktinfo) { /* TODO IPV6 support */ } @@ -654,9 +659,17 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int payload_len; struct gtp_pktinfo pktinfo; unsigned int proto = ntohs(skb->protocol); - int gtph_len, err; + int gtph_len, err = -EINVAL; + __be16 gtph_port; rcu_read_lock(); + + /* ensure there is sufficient headroom */ + if (skb_cow_head(skb, dev->needed_headroom)) + goto tx_error; + + skb_reset_inner_headers(skb); + switch (proto) { case ETH_P_IP: err = gtp_ip4_prepare_xmit(skb, dev, &pktinfo); @@ -669,56 +682,55 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev) if (err < 0) goto tx_error; - /* Annotate length of the encapsulated packet */ - payload_len = skb->len; - /* Push down GTP header */ switch (pktinfo.pctx->gtp_version) { case GTP_V0: - gtp0_push_header(skb, pktinfo.pctx, payload_len); - break; - case GTP_V1: - gtp1_push_header(skb, pktinfo.pctx, payload_len); - break; - } - - /* Push down and install the UDP header. */ - skb_push(skb, sizeof(struct udphdr)); - skb_reset_transport_header(skb); - - uh = udp_hdr(skb); - switch (pktinfo.pctx->gtp_version) { - case GTP_V0: - uh->source = uh->dest = htons(GTP0_PORT); + gtph_port = htons(GTP0_PORT); gtph_len = sizeof(struct gtp0_header); + + gtp0_push_header(skb, pktinfo.pctx); break; case GTP_V1: - uh->source = uh->dest = htons(GTP1U_PORT); + gtph_port = htons(GTP1U_PORT); gtph_len = sizeof(struct gtp1_header); + + gtp1_push_header(skb, pktinfo.pctx); break; + default: + goto tx_error; } - uh->len = htons(sizeof(struct udphdr) + payload_len + gtph_len); - uh->check = 0; - - netdev_dbg(dev, "gtp -> UDP src: %u dst: %u (len %u)\n", - ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); - switch (proto) { case ETH_P_IP: - gtp_push_ip4hdr(skb, &pktinfo); + err = gtp_udp_tunnel_xmit(skb, gtph_port, &pktinfo); break; case ETH_P_IPV6: - gtp_push_ip6hdr(skb, &pktinfo); + /* Annotate length of the encapsulated packet */ + payload_len = skb->len; + + /* Push down and install the UDP header. */ + skb_push(skb, sizeof(struct udphdr)); + skb_reset_transport_header(skb); + + uh = udp_hdr(skb); + + uh->source = uh->dest = gtph_port; + uh->len = htons(sizeof(struct udphdr) + payload_len + gtph_len); + uh->check = 0; + + netdev_dbg(dev, "gtp -> UDP src: %u dst: %u (len %u)\n", + ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); + + nf_reset(skb); + + netdev_dbg(dev, "Good, now packet leaving from GGSN to SGSN\n"); + + err = gtp_ip6tunnel_xmit(skb, &pktinfo); break; } - rcu_read_unlock(); - nf_reset(skb); - - netdev_dbg(dev, "Good, now packet leaving from GGSN to SGSN\n"); + rcu_read_unlock(); - err = ip_local_out(skb); gtp_iptunnel_xmit_stats(err, &dev->stats, dev->tstats); return NETDEV_TX_OK; @@ -737,10 +749,26 @@ static const struct net_device_ops gtp_netdev_ops = { static void gtp_link_setup(struct net_device *dev) { - dev->priv_flags |= IFF_NO_QUEUE; - dev->netdev_ops = >p_netdev_ops; dev->destructor = free_netdev; + + dev->hard_header_len = 0; + dev->addr_len = 0; + + /* Zero header length */ + dev->type = ARPHRD_NONE; + dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->tx_queue_len = 1000; + + dev->priv_flags |= IFF_NO_QUEUE; + dev->features |= NETIF_F_LLTX; + netif_keep_dst(dev); + + dev->needed_headroom = LL_MAX_HEADER + + sizeof(struct iphdr) + + sizeof(struct udphdr) + + sizeof(struct gtp0_header); + } static int gtp_hashtable_new(struct gtp_instance *gti, int hsize); @@ -752,30 +780,13 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct gtp_net *gn; - struct net_device *real_dev; struct gtp_instance *gti; int hashsize, err, fd0, fd1; - if (!tb[IFLA_LINK]) - return -EINVAL; - - real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); - if (!real_dev) - return -ENODEV; - - dev_hold(real_dev); - if (!tb[IFLA_MTU]) - dev->mtu = real_dev->mtu; - else if (dev->mtu > real_dev->mtu) { - netdev_dbg(dev, "GTP mtu greater that transport MTU (%d > %d)\n", - dev->mtu, real_dev->mtu); - err = -EINVAL; - goto out_err; - } + dev->mtu = 1500; gti = netdev_priv(dev); - gti->real_dev = real_dev; fd0 = nla_get_u32(data[IFLA_GTP_FD0]); fd1 = nla_get_u32(data[IFLA_GTP_FD1]); @@ -813,7 +824,6 @@ out_encap: gtp_encap_disable(gti); out_err: - dev_put(real_dev); return err; } @@ -823,7 +833,6 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head) gtp_encap_disable(gti); gtp_hashtable_free(gti); - dev_put(gti->real_dev); list_del_rcu(>i->list); unregister_netdevice_queue(dev, head); } -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:52 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:52 +0100 Subject: [PATCH 11/16] gtp: Split TID handling got GTPv0 and GTPv1 In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-12-git-send-email-aschultz@tpip.net> GTPv1 tunnel use a separate TEI for each direction. Add a union to hold TID for v0 and v1 separately. Signed-off-by: Andreas Schultz --- gtp.c | 211 +++++++++++++++++++++++++++++++++++---------------------------- gtp_nl.h | 2 + 2 files changed, 118 insertions(+), 95 deletions(-) diff --git a/gtp.c b/gtp.c index 2ac6431..a4be31d 100644 --- a/gtp.c +++ b/gtp.c @@ -39,7 +39,17 @@ struct pdp_ctx { struct hlist_node hlist_tid; struct hlist_node hlist_addr; - u64 tid; + union { + uint64_t tid; + struct { + uint64_t tid; + u16 flow; + } v0 __attribute__((__packed__)); + struct { + uint32_t i_tid; + uint32_t o_tid; + } v1 __attribute__((__packed__)); + } u; u8 gtp_version; u16 af; @@ -53,7 +63,6 @@ struct pdp_ctx { struct in_addr ip4; } sgsn_addr; - u16 flow; atomic_t tx_seq; struct rcu_head rcu_head; @@ -113,7 +122,7 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_instance *gti, u64 tid) head = >i->tid_hash[gtp0_hashfn(tid) % gti->hash_size]; hlist_for_each_entry_rcu(pdp, head, hlist_tid) { - if (pdp->gtp_version == GTP_V0 && pdp->tid == tid) + if (pdp->gtp_version == GTP_V0 && pdp->u.v0.tid == tid) return pdp; } @@ -129,7 +138,7 @@ static struct pdp_ctx *gtp1_pdp_find(struct gtp_instance *gti, u32 tid) head = >i->tid_hash[gtp1u_hashfn(tid) % gti->hash_size]; hlist_for_each_entry_rcu(pdp, head, hlist_tid) { - if (pdp->gtp_version == GTP_V1 && pdp->tid == tid) + if (pdp->gtp_version == GTP_V1 && pdp->u.v1.i_tid == tid) return pdp; } @@ -456,10 +465,10 @@ gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) gtp0->type = GTP_TPDU; gtp0->length = htons(payload_len); gtp0->seq = htons((atomic_inc_return(&pctx->tx_seq)-1) % 0xffff); - gtp0->flow = htons(pctx->flow); + gtp0->flow = htons(pctx->u.v0.flow); gtp0->number = 0xFF; gtp0->spare[0] = gtp0->spare[1] = gtp0->spare[2] = 0xFF; - gtp0->tid = cpu_to_be64(pctx->tid); + gtp0->tid = cpu_to_be64(pctx->u.v0.tid); } static inline void @@ -480,7 +489,7 @@ gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) gtp1->flags = 0x38; /* V1, GTP-non-prime */ gtp1->type = GTP_TPDU; gtp1->length = htons(payload_len); - gtp1->tid = htonl((u32)pctx->tid); + gtp1->tid = htonl(pctx->u.v1.o_tid); /* TODO: Suppport for extension header, sequence number and N-PDU. * Update the length field if any of them is available. @@ -1021,43 +1030,45 @@ static struct net_device *gtp_find_dev(struct net *net, int ifindex) return NULL; } -static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) +static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) { - struct gtp_instance *gti = netdev_priv(dev); - struct pdp_ctx *pctx; - u16 flow = 0; - u32 gtp_version, sgsn_addr, ms_addr, hash_ms, hash_tid; - u64 tid; - bool found = false; + pctx->gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]); + pctx->af = AF_INET; + pctx->sgsn_addr.ip4.s_addr = + nla_get_u32(info->attrs[GTPA_SGSN_ADDRESS]); + pctx->ms_addr.ip4.s_addr = + nla_get_u32(info->attrs[GTPA_MS_ADDRESS]); - gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]); - switch (gtp_version) { + switch (pctx->gtp_version) { case GTP_V0: - case GTP_V1: + + /* According to TS 09.60, sections 7.5.1 and 7.5.2, the flow + * label needs to be the same for uplink and downlink packets, + * so let's annotate this. + */ + pctx->u.v0.tid = nla_get_u64(info->attrs[GTPA_TID]); + pctx->u.v0.flow = nla_get_u16(info->attrs[GTPA_FLOW]); break; - default: - return -EINVAL; - } - tid = nla_get_u64(info->attrs[GTPA_TID]); - /* GTPv1 allows 32-bits tunnel IDs */ - if (gtp_version == GTP_V1 && tid > UINT_MAX) - return -EINVAL; + case GTP_V1: + pctx->u.v1.i_tid = nla_get_u32(info->attrs[GTPA_I_TID]); + pctx->u.v1.o_tid = nla_get_u32(info->attrs[GTPA_O_TID]); - /* According to TS 09.60, sections 7.5.1 and 7.5.2, the flow label - * needs to be the same for uplink and downlink packets, so let's - * annotate this. - */ - if (gtp_version == GTP_V0) { - if (!info->attrs[GTPA_FLOW]) - return -EINVAL; + break; - flow = nla_get_u16(info->attrs[GTPA_FLOW]); + default: + break; } +} - sgsn_addr = nla_get_u32(info->attrs[GTPA_SGSN_ADDRESS]); - ms_addr = nla_get_u32(info->attrs[GTPA_MS_ADDRESS]); +static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) +{ + struct gtp_instance *gti = netdev_priv(dev); + struct pdp_ctx *pctx; + u32 ms_addr, hash_ms, hash_tid = 0; + bool found = false; + ms_addr = nla_get_u32(info->attrs[GTPA_MS_ADDRESS]); hash_ms = ipv4_hashfn(ms_addr) % gti->hash_size; hlist_for_each_entry_rcu(pctx, >i->addr_hash[hash_ms], hlist_addr) { @@ -1073,47 +1084,50 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) return -EOPNOTSUPP; - pctx->af = AF_INET; - pctx->gtp_version = gtp_version; - pctx->tid = tid; - pctx->sgsn_addr.ip4.s_addr = sgsn_addr; - pctx->ms_addr.ip4.s_addr = ms_addr; + ipv4_pdp_fill(pctx, info); - netdev_dbg(dev, "update tunnel id = %llx (pdp %p)\n", - tid, pctx); + if (pctx->gtp_version == GTP_V0) + netdev_dbg(dev, "GTPv0-U: update tunnel id = %llx (pdp %p)\n", + pctx->u.v0.tid, pctx); + else if (pctx->gtp_version == GTP_V1) + netdev_dbg(dev, "GTPv1-U: update tunnel id = %x/%x (pdp %p)\n", + pctx->u.v1.i_tid, pctx->u.v1.o_tid, pctx); return 0; + } pctx = kmalloc(sizeof(struct pdp_ctx), GFP_KERNEL); if (pctx == NULL) return -ENOMEM; - pctx->af = AF_INET; - pctx->gtp_version = gtp_version; - pctx->tid = tid; - pctx->sgsn_addr.ip4.s_addr = sgsn_addr; - pctx->ms_addr.ip4.s_addr = ms_addr; - pctx->flow = flow; + ipv4_pdp_fill(pctx, info); atomic_set(&pctx->tx_seq, 0); - switch (gtp_version) { + switch (pctx->gtp_version) { case GTP_V0: /* TS 09.60: "The flow label identifies unambiguously a GTP * flow.". We use the tid for this instead, I cannot find a * situation in which this doesn't unambiguosly identify the * PDP context. */ - hash_tid = gtp0_hashfn(tid) % gti->hash_size; + hash_tid = gtp0_hashfn(pctx->u.v0.tid) % gti->hash_size; break; + case GTP_V1: - hash_tid = gtp1u_hashfn(tid) % gti->hash_size; + hash_tid = gtp1u_hashfn(pctx->u.v1.i_tid) % gti->hash_size; break; } + hlist_add_head_rcu(&pctx->hlist_addr, >i->addr_hash[hash_ms]); hlist_add_head_rcu(&pctx->hlist_tid, >i->tid_hash[hash_tid]); - netdev_dbg(dev, "adding tunnel id = %llx (pdp %p)\n", tid, pctx); + if (pctx->gtp_version == GTP_V0) + netdev_dbg(dev, "GTPv0-U: adding tunnel id = %llx (pdp %p)\n", + pctx->u.v0.tid, pctx); + else if (pctx->gtp_version == GTP_V1) + netdev_dbg(dev, "GTPv1-U: adding tunnel id = %x/%x (pdp %p)\n", + pctx->u.v1.i_tid, pctx->u.v1.o_tid, pctx); return 0; } @@ -1126,9 +1140,25 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[GTPA_VERSION] || !info->attrs[GTPA_LINK] || !info->attrs[GTPA_SGSN_ADDRESS] || - !info->attrs[GTPA_MS_ADDRESS] || - !info->attrs[GTPA_TID]) + !info->attrs[GTPA_MS_ADDRESS]) + return -EINVAL; + + switch (nla_get_u32(info->attrs[GTPA_VERSION])) { + case GTP_V0: + if (!info->attrs[GTPA_TID] || + !info->attrs[GTPA_FLOW]) + return -EINVAL; + break; + + case GTP_V1: + if (!info->attrs[GTPA_I_TID] || + !info->attrs[GTPA_O_TID]) + return -EINVAL; + break; + + default: return -EINVAL; + } net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); if (net == NULL) @@ -1148,28 +1178,9 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) struct gtp_instance *gti; struct net_device *dev; struct pdp_ctx *pctx; - u32 gtp_version; - u64 tid; if (!info->attrs[GTPA_VERSION] || - !info->attrs[GTPA_LINK] || - !info->attrs[GTPA_SGSN_ADDRESS] || - !info->attrs[GTPA_MS_ADDRESS] || - !info->attrs[GTPA_TID]) - return -EINVAL; - - gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]); - switch (gtp_version) { - case GTP_V0: - case GTP_V1: - break; - default: - return -EINVAL; - } - - tid = nla_get_u64(info->attrs[GTPA_TID]); - /* GTPv1 allows 32-bits tunnel IDs */ - if (gtp_version == GTP_V1 && tid > UINT_MAX) + !info->attrs[GTPA_LINK]) return -EINVAL; net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); @@ -1183,20 +1194,32 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) gti = netdev_priv(dev); - switch (gtp_version) { + switch (nla_get_u32(info->attrs[GTPA_VERSION])) { case GTP_V0: + if (!info->attrs[GTPA_TID]) + return -EINVAL; pctx = gtp0_pdp_find(gti, nla_get_u64(info->attrs[GTPA_TID])); break; + case GTP_V1: - pctx = gtp1_pdp_find(gti, nla_get_u64(info->attrs[GTPA_TID])); + if (!info->attrs[GTPA_I_TID]) + return -EINVAL; + pctx = gtp1_pdp_find(gti, nla_get_u64(info->attrs[GTPA_I_TID])); break; + + default: + return -EINVAL; } if (pctx == NULL) return -ENOENT; - netdev_dbg(dev, "deleting tunnel with ID %lld\n", - (unsigned long long) nla_get_u64(info->attrs[GTPA_TID])); + if (pctx->gtp_version == GTP_V0) + netdev_dbg(dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n", + pctx->u.v0.tid, pctx); + else if (pctx->gtp_version == GTP_V1) + netdev_dbg(dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n", + pctx->u.v1.i_tid, pctx->u.v1.o_tid, pctx); hlist_del_rcu(&pctx->hlist_tid); hlist_del_rcu(&pctx->hlist_addr); @@ -1228,9 +1251,12 @@ gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, if (nla_put_u32(skb, GTPA_VERSION, pctx->gtp_version) || nla_put_u32(skb, GTPA_SGSN_ADDRESS, pctx->sgsn_addr.ip4.s_addr) || nla_put_u32(skb, GTPA_MS_ADDRESS, pctx->ms_addr.ip4.s_addr) || - nla_put_u64(skb, GTPA_TID, pctx->tid) || (pctx->gtp_version == GTP_V0 && - nla_put_u16(skb, GTPA_FLOW, pctx->flow))) + nla_put_u64(skb, GTPA_TID, pctx->u.v0.tid) && + nla_put_u16(skb, GTPA_FLOW, pctx->u.v0.flow)) || + (pctx->gtp_version == GTP_V1 && + nla_put_u32(skb, GTPA_I_TID, pctx->u.v1.i_tid) && + nla_put_u32(skb, GTPA_O_TID, pctx->u.v1.o_tid))) goto nla_put_failure; genlmsg_end(skb, genlh); @@ -1277,23 +1303,16 @@ static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) gti = netdev_priv(dev); rcu_read_lock(); - if (info->attrs[GTPA_TID]) { + if (gtp_version == GTP_V0 && + info->attrs[GTPA_TID]) { u64 tid = nla_get_u64(info->attrs[GTPA_TID]); - /* GTPv1 allows 32-bits tunnel IDs */ - if (gtp_version == GTP_V1 && tid > UINT_MAX) { - err = -EINVAL; - goto err_unlock; - } + pctx = gtp0_pdp_find(gti, tid); + } else if (gtp_version == GTP_V1 && + info->attrs[GTPA_I_TID]) { + u32 tid = nla_get_u32(info->attrs[GTPA_I_TID]); - switch (gtp_version) { - case GTP_V0: - pctx = gtp0_pdp_find(gti, tid); - break; - case GTP_V1: - pctx = gtp1_pdp_find(gti, tid); - break; - } + pctx = gtp1_pdp_find(gti, tid); } else if (info->attrs[GTPA_MS_ADDRESS]) { u32 ip = nla_get_u32(info->attrs[GTPA_MS_ADDRESS]); @@ -1347,7 +1366,7 @@ gtp_genl_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb) for (i = k; i < gti->hash_size; i++) { hlist_for_each_entry_rcu(pctx, >i->tid_hash[i], hlist_tid) { - if (tid && tid != pctx->tid) + if (tid && tid != pctx->u.tid) continue; else tid = 0; @@ -1358,7 +1377,7 @@ gtp_genl_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb) cb->nlh->nlmsg_type, pctx); if (ret < 0) { cb->args[0] = i; - cb->args[1] = pctx->tid; + cb->args[1] = pctx->u.tid; cb->args[2] = (unsigned long)gti; goto out; } @@ -1378,6 +1397,8 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { [GTPA_MS_ADDRESS] = { .type = NLA_NESTED, }, [GTPA_FLOW] = { .type = NLA_U16, }, [GTPA_NET_NS_FD] = { .type = NLA_U32, }, + [GTPA_I_TID] = { .type = NLA_U32, }, + [GTPA_O_TID] = { .type = NLA_U32, }, }; static const struct genl_ops gtp_genl_ops[] = { diff --git a/gtp_nl.h b/gtp_nl.h index c20666d..370576b 100644 --- a/gtp_nl.h +++ b/gtp_nl.h @@ -41,6 +41,8 @@ enum gtp_attrs { GTPA_MS_ADDRESS, GTPA_FLOW, GTPA_NET_NS_FD, + GTPA_I_TID, + GTPA_O_TID, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:41 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:41 +0100 Subject: [PATCH 00/16] GTP kernel update (patch bomb) Message-ID: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Hi, Sorry for smsching this all together, but I couldn't find a logical point to split the patches. Also the order can't really be changed as most patches depend on each other. After this series, the GTP kernel module is functional for IPv4 payload in IPv4 GTP tunnels (for GTPv0 and v1). The libgtnl API was changed without increasing the SO version of the lib. I think this is ok since nothing really uses it (yet) nor has the library been offcially released. Andreas Schultz (16): gtp: remove unused local variable gtp: remove genl_register_family_with_ops for Linux < 3.13 gtp: convert the global gtp_instance_list to a per netns list gtp: select netns based on NL attribute gtp-rtnl: and netns support gtp: add error handling to gtp_newlink gtp: fix the order of error cases in gtp_encap_enable gtp: add socket destroy handler gtp: replace udp encap setup with setup_udp_tunnel_sock gtp: switch to iptunnel framework and no longer depend on real_dev gtp: Split TID handling got GTPv0 and GTPv1 gtp-rtnl: sync GTPA_FLOW nl attribute name from kernel to userspace gtp-rtnl: real_ifname is not long needed, remove it gtp-rtnl: Split tid handling for GTPv0 and GTPv1 list Andreas Schultz as author gtp: add support for replacing PDP contexts gtp.c | 657 ++++++++++++++++++++++++--------------- gtp_nl.h | 3 + libgtnl/AUTHORS | 1 + libgtnl/include/libgtpnl/gtp.h | 6 + libgtnl/include/libgtpnl/gtpnl.h | 3 +- libgtnl/include/linux/gtp_nl.h | 5 +- libgtnl/src/gtp-genl.c | 34 +- libgtnl/src/gtp-rtnl.c | 10 +- libgtnl/src/gtp.c | 44 ++- libgtnl/src/internal.h | 13 +- libgtnl/src/libgtpnl.map | 6 + libgtnl/tools/Makefile.am | 4 +- libgtnl/tools/gtp-link-add.c | 5 +- libgtnl/tools/gtp-tunnel.c | 132 +++++--- libgtnl/tools/gtpnl.c | 35 --- 15 files changed, 613 insertions(+), 345 deletions(-) delete mode 100644 libgtnl/tools/gtpnl.c -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:43 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:43 +0100 Subject: [PATCH 02/16] gtp: remove genl_register_family_with_ops for Linux < 3.13 In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-3-git-send-email-aschultz@tpip.net> Remove the support for genl_register_family_with_ops for Linux < 3.13. Also reorder the initialization to be more in line with similar modules. Signed-off-by: Andreas Schultz --- gtp.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/gtp.c b/gtp.c index 11bda38..7e615f3 100644 --- a/gtp.c +++ b/gtp.c @@ -1321,35 +1321,31 @@ static int __init gtp_init(void) get_random_bytes(>p_h_initval, sizeof(gtp_h_initval)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) - err = genl_register_family_with_ops(>p_genl_family, gtp_genl_ops); - if (err < 0) - return err; -#else - err = genl_register_family_with_ops(>p_genl_family, - gtp_genl_ops, - ARRAY_SIZE(gtp_genl_ops)); - if (err < 0) - return err; -#endif err = rtnl_link_register(>p_link_ops); if (err < 0) - goto err1; + goto error_out; + + err = genl_register_family_with_ops(>p_genl_family, gtp_genl_ops); + if (err < 0) + goto unreg_rtnl_link; pr_info("GTP module loaded (pdp ctx size %Zd bytes)\n", sizeof(struct pdp_ctx)); return 0; -err1: + +unreg_rtnl_link: + rtnl_link_unregister(>p_link_ops); + +error_out: pr_err("error loading GTP module loaded\n"); - genl_unregister_family(>p_genl_family); return err; } late_initcall(gtp_init); static void __exit gtp_fini(void) { - rtnl_link_unregister(>p_link_ops); genl_unregister_family(>p_genl_family); + rtnl_link_unregister(>p_link_ops); pr_info("GTP module unloaded\n"); } -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:48 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:48 +0100 Subject: [PATCH 07/16] gtp: fix the order of error cases in gtp_encap_enable In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-8-git-send-email-aschultz@tpip.net> The ordering of the error case exit was wrong and would attempt to release the wrong socket. Signed-off-by: Andreas Schultz --- gtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtp.c b/gtp.c index 4f5729e..61add82 100644 --- a/gtp.c +++ b/gtp.c @@ -967,10 +967,10 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, sk->sk_user_data = gti; return 0; -err1: - sockfd_put(sock0); err2: sockfd_put(sock1u); +err1: + sockfd_put(sock0); return err; } -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:46 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:46 +0100 Subject: [PATCH 05/16] gtp-rtnl: and netns support In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-6-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- libgtnl/include/libgtpnl/gtp.h | 2 ++ libgtnl/include/libgtpnl/gtpnl.h | 2 +- libgtnl/include/linux/gtp_nl.h | 1 + libgtnl/src/gtp-genl.c | 2 ++ libgtnl/src/gtp-rtnl.c | 8 +++++++- libgtnl/src/gtp.c | 12 ++++++++++++ libgtnl/src/internal.h | 1 + libgtnl/src/libgtpnl.map | 2 ++ 8 files changed, 28 insertions(+), 2 deletions(-) diff --git a/libgtnl/include/libgtpnl/gtp.h b/libgtnl/include/libgtpnl/gtp.h index 10b34d5..fa09d2a 100644 --- a/libgtnl/include/libgtpnl/gtp.h +++ b/libgtnl/include/libgtpnl/gtp.h @@ -8,6 +8,7 @@ struct gtp_tunnel; struct gtp_tunnel *gtp_tunnel_alloc(void); void gtp_tunnel_free(struct gtp_tunnel *t); +void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns); void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx); void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr); void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr); @@ -15,6 +16,7 @@ void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version); void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid); void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid); +const int gtp_tunnel_get_ifns(struct gtp_tunnel *t); const uint32_t gtp_tunnel_get_ifidx(struct gtp_tunnel *t); const struct in_addr *gtp_tunnel_get_ms_ip4(struct gtp_tunnel *t); const struct in_addr *gtp_tunnel_get_sgsn_ip4(struct gtp_tunnel *t); diff --git a/libgtnl/include/libgtpnl/gtpnl.h b/libgtnl/include/libgtpnl/gtpnl.h index c4faf6c..3d3fd73 100644 --- a/libgtnl/include/libgtpnl/gtpnl.h +++ b/libgtnl/include/libgtpnl/gtpnl.h @@ -16,7 +16,7 @@ int genl_lookup_family(struct mnl_socket *nl, const char *family); struct in_addr; -int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, +int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, int fd0, int fd1); int gtp_dev_config(const char *iface, struct in_addr *net, uint32_t prefix); int gtp_dev_destroy(const char *gtp_ifname); diff --git a/libgtnl/include/linux/gtp_nl.h b/libgtnl/include/linux/gtp_nl.h index 0a28046..a8fdf3a 100644 --- a/libgtnl/include/linux/gtp_nl.h +++ b/libgtnl/include/linux/gtp_nl.h @@ -40,6 +40,7 @@ enum gtp_attrs { GTPA_SGSN_ADDRESS, GTPA_MS_ADDRESS, GTPA_FLOWID, /* only for GTPv0 */ + GTPA_NET_NS_FD, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c index c1f60ab..9e68a30 100644 --- a/libgtnl/src/gtp-genl.c +++ b/libgtnl/src/gtp-genl.c @@ -44,6 +44,8 @@ static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) { mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version); + if (t->ifns > 0) + mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns); mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx); mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); diff --git a/libgtnl/src/gtp-rtnl.c b/libgtnl/src/gtp-rtnl.c index 22b9430..db54653 100644 --- a/libgtnl/src/gtp-rtnl.c +++ b/libgtnl/src/gtp-rtnl.c @@ -38,6 +38,10 @@ #include "internal.h" +#if !defined(IFLA_LINK_NETNSID) +#define IFLA_LINK_NETNSID (IFLA_PHYS_SWITCH_ID + 1) +#endif + static struct nlmsghdr * gtp_put_nlmsg(char *buf, uint16_t type, uint16_t nl_flags, uint32_t seq) { @@ -104,7 +108,7 @@ static int gtp_dev_talk(struct nlmsghdr *nlh, uint32_t seq) return ret; } -int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, +int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, int fd0, int fd1) { char buf[MNL_SOCKET_BUFFER_SIZE]; @@ -120,6 +124,8 @@ int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, ifm->ifi_change |= IFF_UP; ifm->ifi_flags |= IFF_UP; + if (dest_ns > 0) + mnl_attr_put_u32(nlh, IFLA_NET_NS_FD, dest_ns); mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(real_ifname)); mnl_attr_put_str(nlh, IFLA_IFNAME, gtp_ifname); nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO); diff --git a/libgtnl/src/gtp.c b/libgtnl/src/gtp.c index 4534091..6e3d473 100644 --- a/libgtnl/src/gtp.c +++ b/libgtnl/src/gtp.c @@ -39,6 +39,12 @@ void gtp_tunnel_free(struct gtp_tunnel *t) } EXPORT_SYMBOL(gtp_tunnel_free); +void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns) +{ + t->ifns = ifns; +} +EXPORT_SYMBOL(gtp_tunnel_set_ifns); + void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx) { t->ifidx = ifidx; @@ -75,6 +81,12 @@ void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid) } EXPORT_SYMBOL(gtp_tunnel_set_flowid); +const int gtp_tunnel_get_ifns(struct gtp_tunnel *t) +{ + return t->ifns; +} +EXPORT_SYMBOL(gtp_tunnel_get_ifns); + const uint32_t gtp_tunnel_get_ifidx(struct gtp_tunnel *t) { return t->ifidx; diff --git a/libgtnl/src/internal.h b/libgtnl/src/internal.h index 75b3954..68f0135 100644 --- a/libgtnl/src/internal.h +++ b/libgtnl/src/internal.h @@ -13,6 +13,7 @@ #include struct gtp_tunnel { + int ifns; uint32_t ifidx; struct in_addr ms_addr; struct in_addr sgsn_addr; diff --git a/libgtnl/src/libgtpnl.map b/libgtnl/src/libgtpnl.map index 6e69ef8..2368467 100644 --- a/libgtnl/src/libgtpnl.map +++ b/libgtnl/src/libgtpnl.map @@ -15,12 +15,14 @@ global: gtp_tunnel_alloc; gtp_tunnel_free; + gtp_tunnel_set_ifns; gtp_tunnel_set_ifidx; gtp_tunnel_set_ms_ip4; gtp_tunnel_set_sgsn_ip4; gtp_tunnel_set_version; gtp_tunnel_set_tid; gtp_tunnel_set_flowid; + gtp_tunnel_get_ifns; gtp_tunnel_get_ifidx; gtp_tunnel_get_ms_ip4; gtp_tunnel_get_sgsn_ip4; -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:49 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:49 +0100 Subject: [PATCH 08/16] gtp: add socket destroy handler In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-9-git-send-email-aschultz@tpip.net> Add a socket destroy handler and use it to detach and release all resources from an UDP socket. Do not longer pin the socket with a reference. This together with the release handler allows user space to close the socket from underneath us. The destroy handler will handle the rest. Signed-off-by: Andreas Schultz --- gtp.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/gtp.c b/gtp.c index 61add82..40a5d1c 100644 --- a/gtp.c +++ b/gtp.c @@ -80,6 +80,8 @@ struct gtp_net { struct list_head gtp_instance_list; }; +static void gtp_encap_disable(struct gtp_instance *gti); + static inline u32 gtp0_hashfn(u64 tid) { u32 *tid32 = (u32 *) &tid; @@ -317,6 +319,16 @@ out_rcu: return ret; } +static void gtp_udp_encap_destroy(struct sock *sk) +{ + struct gtp_instance *gti = sk_to_gti(sk); + + if (gti) { + gtp_encap_disable(gti); + sock_put(sk); + } +} + /* UDP encapsulation receive handler. See net/ipv4/udp.c. * Return codes: 0: success, <0: error, >0: passed up to userspace UDP. */ @@ -401,8 +413,6 @@ static int gtp_dev_init(struct net_device *dev) return 0; } -static void gtp_encap_disable(struct gtp_instance *gti); - static void gtp_dev_uninit(struct net_device *dev) { struct gtp_instance *gti = netdev_priv(dev); @@ -958,15 +968,18 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, sk = gti->sock0->sk; udp_sk(sk)->encap_type = UDP_ENCAP_GTP0; udp_sk(sk)->encap_rcv = gtp_udp_encap_recv; + udp_sk(sk)->encap_destroy = gtp_udp_encap_destroy; sk->sk_user_data = gti; udp_encap_enable(); sk = gti->sock1u->sk; udp_sk(sk)->encap_type = UDP_ENCAP_GTP1U; udp_sk(sk)->encap_rcv = gtp_udp_encap_recv; + udp_sk(sk)->encap_destroy = gtp_udp_encap_destroy; sk->sk_user_data = gti; - return 0; + err = 0; + err2: sockfd_put(sock1u); err1: @@ -976,10 +989,17 @@ err1: static void gtp_encap_disable(struct gtp_instance *gti) { - if (gti->sock1u) - sockfd_put(gti->sock1u); - if (gti->sock0) - sockfd_put(gti->sock0); + if (gti->sock0 && gti->sock0->sk) { + udp_sk(gti->sock0->sk)->encap_type = 0; + rcu_assign_sk_user_data(gti->sock0->sk, NULL); + } + if (gti->sock1u && gti->sock1u->sk) { + udp_sk(gti->sock1u->sk)->encap_type = 0; + rcu_assign_sk_user_data(gti->sock1u->sk, NULL); + } + + gti->sock0 = NULL; + gti->sock1u = NULL; } static struct net_device *gtp_find_dev(struct net *net, int ifindex) -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:56 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:56 +0100 Subject: [PATCH 15/16] list Andreas Schultz as author In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-16-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- gtp.c | 1 + libgtnl/AUTHORS | 1 + 2 files changed, 2 insertions(+) diff --git a/gtp.c b/gtp.c index a4be31d..4b233f7 100644 --- a/gtp.c +++ b/gtp.c @@ -3,6 +3,7 @@ /* (C) 2012-2014 by sysmocom - s.f.m.c. GmbH * Author: Harald Welte * Pablo Neira Ayuso + * Andreas Schultz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/libgtnl/AUTHORS b/libgtnl/AUTHORS index 7deed5b..649d40b 100644 --- a/libgtnl/AUTHORS +++ b/libgtnl/AUTHORS @@ -1 +1,2 @@ Pablo Neira Ayuso +Andreas Schultz -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:55 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:55 +0100 Subject: [PATCH 14/16] gtp-rtnl: Split tid handling for GTPv0 and GTPv1 In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-15-git-send-email-aschultz@tpip.net> GTPv1 tunnel use a separate 32bit TIDs for each direction while GTPv0 uses only one 64bit TID. Signed-off-by: Andreas Schultz --- libgtnl/include/libgtpnl/gtp.h | 4 ++ libgtnl/include/linux/gtp_nl.h | 2 + libgtnl/src/gtp-genl.c | 32 ++++++++-- libgtnl/src/gtp.c | 32 ++++++++-- libgtnl/src/internal.h | 12 +++- libgtnl/src/libgtpnl.map | 4 ++ libgtnl/tools/Makefile.am | 4 +- libgtnl/tools/gtp-tunnel.c | 132 ++++++++++++++++++++++++++++------------- libgtnl/tools/gtpnl.c | 35 ----------- 9 files changed, 168 insertions(+), 89 deletions(-) delete mode 100644 libgtnl/tools/gtpnl.c diff --git a/libgtnl/include/libgtpnl/gtp.h b/libgtnl/include/libgtpnl/gtp.h index fa09d2a..52fa4d9 100644 --- a/libgtnl/include/libgtpnl/gtp.h +++ b/libgtnl/include/libgtpnl/gtp.h @@ -14,6 +14,8 @@ void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr); void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr); void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version); void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid); +void gtp_tunnel_set_i_tid(struct gtp_tunnel *t, uint32_t i_tid); +void gtp_tunnel_set_o_tid(struct gtp_tunnel *t, uint32_t o_tid); void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid); const int gtp_tunnel_get_ifns(struct gtp_tunnel *t); @@ -22,6 +24,8 @@ const struct in_addr *gtp_tunnel_get_ms_ip4(struct gtp_tunnel *t); const struct in_addr *gtp_tunnel_get_sgsn_ip4(struct gtp_tunnel *t); int gtp_tunnel_get_version(struct gtp_tunnel *t); uint64_t gtp_tunnel_get_tid(struct gtp_tunnel *t); +uint32_t gtp_tunnel_get_i_tid(struct gtp_tunnel *t); +uint32_t gtp_tunnel_get_o_tid(struct gtp_tunnel *t); uint16_t gtp_tunnel_get_flowid(struct gtp_tunnel *t); #endif diff --git a/libgtnl/include/linux/gtp_nl.h b/libgtnl/include/linux/gtp_nl.h index a1e8ce1..5859b4e 100644 --- a/libgtnl/include/linux/gtp_nl.h +++ b/libgtnl/include/linux/gtp_nl.h @@ -41,6 +41,8 @@ enum gtp_attrs { GTPA_MS_ADDRESS, GTPA_FLOW, /* only for GTPv0 */ GTPA_NET_NS_FD, + GTPA_I_TID, + GTPA_O_TID, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c index 2717821..2b72600 100644 --- a/libgtnl/src/gtp-genl.c +++ b/libgtnl/src/gtp-genl.c @@ -49,8 +49,13 @@ static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx); mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); - mnl_attr_put_u64(nlh, GTPA_TID, t->tid); - mnl_attr_put_u16(nlh, GTPA_FLOW, t->flowid); + if (t->gtp_version == GTP_V0) { + mnl_attr_put_u64(nlh, GTPA_TID, t->u.v0.tid); + mnl_attr_put_u16(nlh, GTPA_FLOW, t->u.v0.flowid); + } else if (t->gtp_version == GTP_V1) { + mnl_attr_put_u32(nlh, GTPA_I_TID, t->u.v1.i_tid); + mnl_attr_put_u32(nlh, GTPA_O_TID, t->u.v1.o_tid); + } } int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t) @@ -95,7 +100,15 @@ EXPORT_SYMBOL(gtp_del_tunnel); struct gtp_pdp { uint32_t version; - uint64_t tid; + union { + struct { + uint64_t tid; + } v0; + struct { + uint32_t i_tid; + uint32_t o_tid; + } v1; + } u; struct in_addr sgsn_addr; struct in_addr ms_addr; }; @@ -115,6 +128,8 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data) return MNL_CB_ERROR; } break; + case GTPA_O_TID: + case GTPA_I_TID: case GTPA_SGSN_ADDRESS: case GTPA_MS_ADDRESS: case GTPA_VERSION: @@ -138,7 +153,11 @@ static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data) mnl_attr_parse(nlh, sizeof(*genl), genl_gtp_validate_cb, tb); if (tb[GTPA_TID]) - pdp.tid = mnl_attr_get_u64(tb[GTPA_TID]); + pdp.u.v0.tid = mnl_attr_get_u64(tb[GTPA_TID]); + if (tb[GTPA_I_TID]) + pdp.u.v1.i_tid = mnl_attr_get_u32(tb[GTPA_I_TID]); + if (tb[GTPA_O_TID]) + pdp.u.v1.o_tid = mnl_attr_get_u32(tb[GTPA_O_TID]); if (tb[GTPA_SGSN_ADDRESS]) { pdp.sgsn_addr.s_addr = mnl_attr_get_u32(tb[GTPA_SGSN_ADDRESS]); @@ -151,7 +170,10 @@ static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data) } printf("version %u ", pdp.version); - printf("tid %"PRIu64" ms_addr %s ", pdp.tid, inet_ntoa(pdp.sgsn_addr)); + if (pdp.version == GTP_V0) + printf("tid %"PRIu64" ms_addr %s ", pdp.u.v0.tid, inet_ntoa(pdp.sgsn_addr)); + else if (pdp.version == GTP_V1) + printf("tid %u/%u ms_addr %s ", pdp.u.v1.i_tid, pdp.u.v1.o_tid, inet_ntoa(pdp.sgsn_addr)); printf("sgsn_addr %s\n", inet_ntoa(pdp.ms_addr)); return MNL_CB_OK; diff --git a/libgtnl/src/gtp.c b/libgtnl/src/gtp.c index 6e3d473..4fedf81 100644 --- a/libgtnl/src/gtp.c +++ b/libgtnl/src/gtp.c @@ -71,16 +71,28 @@ EXPORT_SYMBOL(gtp_tunnel_set_version); void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid) { - t->tid = tid; + t->u.v0.tid = tid; } EXPORT_SYMBOL(gtp_tunnel_set_tid); void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid) { - t->flowid = flowid; + t->u.v0.flowid = flowid; } EXPORT_SYMBOL(gtp_tunnel_set_flowid); +void gtp_tunnel_set_i_tid(struct gtp_tunnel *t, uint32_t i_tid) +{ + t->u.v1.i_tid = i_tid; +} +EXPORT_SYMBOL(gtp_tunnel_set_i_tid); + +void gtp_tunnel_set_o_tid(struct gtp_tunnel *t, uint32_t o_tid) +{ + t->u.v1.o_tid = o_tid; +} +EXPORT_SYMBOL(gtp_tunnel_set_o_tid); + const int gtp_tunnel_get_ifns(struct gtp_tunnel *t) { return t->ifns; @@ -113,12 +125,24 @@ EXPORT_SYMBOL(gtp_tunnel_get_version); uint64_t gtp_tunnel_get_tid(struct gtp_tunnel *t) { - return t->tid; + return t->u.v0.tid; } EXPORT_SYMBOL(gtp_tunnel_get_tid); uint16_t gtp_tunnel_get_flowid(struct gtp_tunnel *t) { - return t->flowid; + return t->u.v0.flowid; } EXPORT_SYMBOL(gtp_tunnel_get_flowid); + +uint32_t gtp_tunnel_get_i_tid(struct gtp_tunnel *t) +{ + return t->u.v1.i_tid; +} +EXPORT_SYMBOL(gtp_tunnel_get_i_tid); + +uint32_t gtp_tunnel_get_o_tid(struct gtp_tunnel *t) +{ + return t->u.v1.o_tid; +} +EXPORT_SYMBOL(gtp_tunnel_get_o_tid); diff --git a/libgtnl/src/internal.h b/libgtnl/src/internal.h index 68f0135..2496454 100644 --- a/libgtnl/src/internal.h +++ b/libgtnl/src/internal.h @@ -17,9 +17,17 @@ struct gtp_tunnel { uint32_t ifidx; struct in_addr ms_addr; struct in_addr sgsn_addr; - uint64_t tid; - uint16_t flowid; int gtp_version; + union { + struct { + uint64_t tid; + uint16_t flowid; + } v0; + struct { + uint32_t i_tid; + uint32_t o_tid; + } v1; + } u; }; #endif diff --git a/libgtnl/src/libgtpnl.map b/libgtnl/src/libgtpnl.map index 2368467..09bdde5 100644 --- a/libgtnl/src/libgtpnl.map +++ b/libgtnl/src/libgtpnl.map @@ -22,6 +22,8 @@ global: gtp_tunnel_set_version; gtp_tunnel_set_tid; gtp_tunnel_set_flowid; + gtp_tunnel_set_i_tid; + gtp_tunnel_set_o_tid; gtp_tunnel_get_ifns; gtp_tunnel_get_ifidx; gtp_tunnel_get_ms_ip4; @@ -29,6 +31,8 @@ global: gtp_tunnel_get_version; gtp_tunnel_get_tid; gtp_tunnel_get_flowid; + gtp_tunnel_get_i_tid; + gtp_tunnel_get_o_tid; local: *; }; diff --git a/libgtnl/tools/Makefile.am b/libgtnl/tools/Makefile.am index 7880f3c..89dca32 100644 --- a/libgtnl/tools/Makefile.am +++ b/libgtnl/tools/Makefile.am @@ -3,8 +3,8 @@ include $(top_srcdir)/Make_global.am check_PROGRAMS = gtp-link-add \ gtp-tunnel -gtp_link_add_SOURCES = gtp-link-add.c gtpnl.c +gtp_link_add_SOURCES = gtp-link-add.c gtp_link_add_LDADD = ../src/libgtpnl.la ${LIBMNL_LIBS} -gtp_tunnel_SOURCES = gtp-tunnel.c gtpnl.c +gtp_tunnel_SOURCES = gtp-tunnel.c gtp_tunnel_LDADD = ../src/libgtpnl.la ${LIBMNL_LIBS} diff --git a/libgtnl/tools/gtp-tunnel.c b/libgtnl/tools/gtp-tunnel.c index 9c52a27..409126e 100644 --- a/libgtnl/tools/gtp-tunnel.c +++ b/libgtnl/tools/gtp-tunnel.c @@ -28,71 +28,91 @@ #include #include #include +#include +#include #include #include #include +#include #include +static void add_usage(const char *name) +{ + printf("%s add \n", + name); + printf("%s add \n", + name); +} + static int add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl) { + struct gtp_tunnel *t; uint32_t gtp_ifidx; struct in_addr ms, sgsn; - struct nlmsghdr *nlh; - char buf[MNL_SOCKET_BUFFER_SIZE]; - uint32_t seq = time(NULL), gtp_version; + uint32_t gtp_version; + int optidx; - if (argc != 7) { - printf("%s add \n", - argv[0]); + if (argc < 7 || argc > 8) { + add_usage(argv[0]); return EXIT_FAILURE; } - gtp_ifidx = if_nametoindex(argv[2]); + + t = gtp_tunnel_alloc(); + optidx = 2; + + gtp_ifidx = if_nametoindex(argv[optidx]); if (gtp_ifidx == 0) { - fprintf(stderr, "wrong GTP interface %s\n", argv[2]); + fprintf(stderr, "wrong GTP interface %s\n", argv[optidx]); return EXIT_FAILURE; } + gtp_tunnel_set_ifidx(t, gtp_ifidx); - if (inet_aton(argv[5], &ms) < 0) { - perror("bad address for ms"); - exit(EXIT_FAILURE); - } - - if (inet_aton(argv[6], &sgsn) < 0) { - perror("bad address for sgsn"); - exit(EXIT_FAILURE); - } + optidx++; - if (strcmp(argv[3], "v0") == 0) + if (strcmp(argv[optidx], "v0") == 0) gtp_version = GTP_V0; - else if (strcmp(argv[3], "v1") == 0) + else if (strcmp(argv[optidx], "v1") == 0) gtp_version = GTP_V1; else { fprintf(stderr, "wrong GTP version %s, use v0 or v1\n", - argv[3]); + argv[optidx]); return EXIT_FAILURE; } + gtp_tunnel_set_version(t, gtp_version); - nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_EXCL | NLM_F_ACK, ++seq, - GTP_CMD_TUNNEL_NEW); - gtp_build_payload(nlh, atoi(argv[4]), gtp_ifidx, sgsn.s_addr, - ms.s_addr, gtp_version); + if (gtp_version == GTP_V0) + gtp_tunnel_set_tid(t, atoi(argv[optidx++])); + else if (gtp_version == GTP_V1) { + gtp_tunnel_set_i_tid(t, atoi(argv[optidx++])); + gtp_tunnel_set_o_tid(t, atoi(argv[optidx++])); + } - if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) - perror("genl_socket_talk"); + if (inet_aton(argv[optidx++], &ms) < 0) { + perror("bad address for ms"); + exit(EXIT_FAILURE); + } + gtp_tunnel_set_ms_ip4(t, &ms); + + if (inet_aton(argv[optidx++], &sgsn) < 0) { + perror("bad address for sgsn"); + exit(EXIT_FAILURE); + } + gtp_tunnel_set_sgsn_ip4(t, &sgsn); + + gtp_add_tunnel(genl_id, nl, t); + gtp_tunnel_free(t); return 0; } static int del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl) { + struct gtp_tunnel *t; uint32_t gtp_ifidx; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t seq = time(NULL); if (argc != 5) { printf("%s add \n", @@ -100,21 +120,44 @@ del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl) return EXIT_FAILURE; } - gtp_ifidx = if_nametoindex(argv[2]); + t = gtp_tunnel_alloc(); - nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_ACK, ++seq, - GTP_CMD_TUNNEL_DELETE); - gtp_build_payload(nlh, atoi(argv[4]), gtp_ifidx, 0, 0, atoi(argv[3])); + gtp_ifidx = if_nametoindex(argv[2]); + if (gtp_ifidx == 0) { + fprintf(stderr, "wrong GTP interface %s\n", argv[2]); + return EXIT_FAILURE; + } + gtp_tunnel_set_ifidx(t, gtp_ifidx); + + if (strcmp(argv[3], "v0") == 0) { + gtp_tunnel_set_version(t, GTP_V0); + gtp_tunnel_set_tid(t, atoi(argv[4])); + } else if (strcmp(argv[3], "v1") == 0) { + gtp_tunnel_set_version(t, GTP_V1); + gtp_tunnel_set_i_tid(t, atoi(argv[4])); + } else { + fprintf(stderr, "wrong GTP version %s, use v0 or v1\n", + argv[3]); + return EXIT_FAILURE; + } - if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) - perror("genl_socket_talk"); + gtp_del_tunnel(genl_id, nl, t); + gtp_tunnel_free(t); return 0; } struct gtp_pdp { uint32_t version; - uint64_t tid; + union { + struct { + uint64_t tid; + } v0; + struct { + uint32_t i_tid; + uint32_t o_tid; + } v1; + } u; struct in_addr sgsn_addr; struct in_addr ms_addr; }; @@ -134,6 +177,8 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data) return MNL_CB_ERROR; } break; + case GTPA_I_TID: + case GTPA_O_TID: case GTPA_SGSN_ADDRESS: case GTPA_MS_ADDRESS: case GTPA_VERSION: @@ -152,12 +197,16 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data) static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[GTPA_MAX + 1] = {}; - struct gtp_pdp pdp; + struct gtp_pdp pdp = {}; struct genlmsghdr *genl; mnl_attr_parse(nlh, sizeof(*genl), genl_gtp_validate_cb, tb); if (tb[GTPA_TID]) - pdp.tid = mnl_attr_get_u64(tb[GTPA_TID]); + pdp.u.v0.tid = mnl_attr_get_u64(tb[GTPA_TID]); + if (tb[GTPA_I_TID]) + pdp.u.v1.i_tid = mnl_attr_get_u32(tb[GTPA_I_TID]); + if (tb[GTPA_O_TID]) + pdp.u.v1.o_tid = mnl_attr_get_u32(tb[GTPA_O_TID]); if (tb[GTPA_SGSN_ADDRESS]) { pdp.sgsn_addr.s_addr = mnl_attr_get_u32(tb[GTPA_SGSN_ADDRESS]); @@ -170,7 +219,10 @@ static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data) } printf("version %u ", pdp.version); - printf("tid %llx ms_addr %s ", pdp.tid, inet_ntoa(pdp.ms_addr)); + if (pdp.version == GTP_V0) + printf("tid %"PRIu64" ms_addr %s ", pdp.u.v0.tid, inet_ntoa(pdp.sgsn_addr)); + else if (pdp.version == GTP_V1) + printf("tid %u/%u ms_addr %s ", pdp.u.v1.i_tid, pdp.u.v1.o_tid, inet_ntoa(pdp.sgsn_addr)); printf("sgsn_addr %s\n", inet_ntoa(pdp.sgsn_addr)); return MNL_CB_OK; @@ -197,8 +249,6 @@ list_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl) int main(int argc, char *argv[]) { struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - unsigned int portid; int32_t genl_id; int ret; diff --git a/libgtnl/tools/gtpnl.c b/libgtnl/tools/gtpnl.c deleted file mode 100644 index 252f0b1..0000000 --- a/libgtnl/tools/gtpnl.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Helper functions */ - -/* (C) 2014 by sysmocom - s.f.m.c. GmbH - * Author: Pablo Neira Ayuso - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include -#include -#include - -void gtp_build_payload(struct nlmsghdr *nlh, uint64_t tid, uint32_t ifidx, - uint32_t sgsn_addr, uint32_t ms_addr, uint32_t version) -{ - mnl_attr_put_u32(nlh, GTPA_VERSION, version); - mnl_attr_put_u32(nlh, GTPA_LINK, ifidx); - mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, sgsn_addr); - mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, ms_addr); - mnl_attr_put_u64(nlh, GTPA_TID, tid); -} -- 2.5.0 From aschultz at tpip.net Mon Nov 16 15:06:47 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 16:06:47 +0100 Subject: [PATCH 06/16] gtp: add error handling to gtp_newlink In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <1447686417-3979-7-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- gtp.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/gtp.c b/gtp.c index 11f8fad..4f5729e 100644 --- a/gtp.c +++ b/gtp.c @@ -756,8 +756,12 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, if (!tb[IFLA_MTU]) dev->mtu = real_dev->mtu; - else if (dev->mtu > real_dev->mtu) - return -EINVAL; + else if (dev->mtu > real_dev->mtu) { + netdev_dbg(dev, "GTP mtu greater that transport MTU (%d > %d)\n", + dev->mtu, real_dev->mtu); + err = -EINVAL; + goto out_err; + } gti = netdev_priv(dev); gti->real_dev = real_dev; @@ -765,7 +769,9 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, fd0 = nla_get_u32(data[IFLA_GTP_FD0]); fd1 = nla_get_u32(data[IFLA_GTP_FD1]); - gtp_encap_enable(dev, gti, fd0, fd1); + err = gtp_encap_enable(dev, gti, fd0, fd1); + if (err < 0) + goto out_err; if (!data[IFLA_GTP_HASHSIZE]) hashsize = 1024; @@ -774,21 +780,29 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, err = gtp_hashtable_new(gti, hashsize); if (err < 0) - return err; + goto out_encap; err = register_netdevice(dev); - if (err < 0) - goto err1; + if (err < 0) { + netdev_dbg(dev, "failed to register new netdev %d\n", err); + goto out_hashtable; + } gn = net_generic(dev_net(dev), gtp_net_id); list_add_rcu(>i->list, &gn->gtp_instance_list); - netdev_dbg(dev, "registered new interface\n"); + netdev_dbg(dev, "registered new GTP interface\n"); return 0; -err1: - netdev_dbg(dev, "failed to register new netdev %d\n", err); + +out_hashtable: gtp_hashtable_free(gti); + +out_encap: + gtp_encap_disable(gti); + +out_err: + dev_put(real_dev); return err; } -- 2.5.0 From laforge at gnumonks.org Mon Nov 16 15:52:39 2015 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 16 Nov 2015 16:52:39 +0100 Subject: [PATCH 00/16] GTP kernel update (patch bomb) In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <20151116155239.GS4687@nataraja> Hi Andreas, On Mon, Nov 16, 2015 at 04:06:41PM +0100, Andreas Schultz wrote: > After this series, the GTP kernel module is functional > for IPv4 payload in IPv4 GTP tunnels (for GTPv0 and v1). Thanks a lot. I did a brief review of the patches and they look fine to me. Pablo has more (recent) experience in Linux kernel networking code these days, so I'd like to wait for his feedback on this. > The libgtnl API was changed without increasing the SO version > of the lib. I think this is ok since nothing really uses it > (yet) nor has the library been offcially released. agreed. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From aschultz at tpip.net Mon Nov 16 17:49:16 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 18:49:16 +0100 (CET) Subject: [PATCH 04/16] gtp: select netns based on NL attribute In-Reply-To: <20151116174134.GD4392@salvia> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-5-git-send-email-aschultz@tpip.net> <20151116174134.GD4392@salvia> Message-ID: <1900940422.24117.1447696156812.JavaMail.zimbra@tpip.net> ----- Original Message ----- > From: "Pablo Neira Ayuso" > To: "Andreas Schultz" > Cc: openbsc at lists.osmocom.org, "Harald Welte" > Sent: Monday, November 16, 2015 6:41:34 PM > Subject: Re: [PATCH 04/16] gtp: select netns based on NL attribute > On Mon, Nov 16, 2015 at 04:06:45PM +0100, Andreas Schultz wrote: [...] > > This has to be IS_ERR(). > Didn't know that, thanks for the explanation. I'll send a new patch soon. > BTW, I'd appreciate if you can add netdev_dbg stuff in a separated > patch. Will do. Andreas From aschultz at tpip.net Mon Nov 16 18:16:58 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 16 Nov 2015 19:16:58 +0100 (CET) Subject: [PATCH 06/16] gtp: add error handling to gtp_newlink In-Reply-To: <20151116174629.GF4392@salvia> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-7-git-send-email-aschultz@tpip.net> <20151116174629.GF4392@salvia> Message-ID: <934587666.24310.1447697818921.JavaMail.zimbra@tpip.net> ----- Original Message ----- > From: "Pablo Neira Ayuso" > To: "Andreas Schultz" > Cc: openbsc at lists.osmocom.org, "Harald Welte" > Sent: Monday, November 16, 2015 6:46:29 PM > Subject: Re: [PATCH 06/16] gtp: add error handling to gtp_newlink > On Mon, Nov 16, 2015 at 04:06:47PM +0100, Andreas Schultz wrote: >> Signed-off-by: Andreas Schultz >> --- >> gtp.c | 32 +++++++++++++++++++++++--------- >> 1 file changed, 23 insertions(+), 9 deletions(-) >> >> diff --git a/gtp.c b/gtp.c >> index 11f8fad..4f5729e 100644 >> --- a/gtp.c >> +++ b/gtp.c >> @@ -756,8 +756,12 @@ static int gtp_newlink(struct net *src_net, struct >> net_device *dev, >> >> if (!tb[IFLA_MTU]) >> dev->mtu = real_dev->mtu; >> - else if (dev->mtu > real_dev->mtu) >> - return -EINVAL; >> + else if (dev->mtu > real_dev->mtu) { >> + netdev_dbg(dev, "GTP mtu greater that transport MTU (%d > %d)\n", >> + dev->mtu, real_dev->mtu); >> + err = -EINVAL; >> + goto out_err; > > This is function is using __dev_get_by_index(), so we're not holding a > reference on the netdevice here. But there is a 'dev_hold(real_dev);' right before that if condition. Doesn't that take a reference to the netdevice? Anyway, the conversion to the iptunnel framework makes this code largely obsolete. So I'm going to drop this change. Andreas > >> + } >> >> gti = netdev_priv(dev); >> gti->real_dev = real_dev; > [...] >> +out_err: >> + dev_put(real_dev); >> return err; > > } From amber_sarosh at hotmail.com Tue Nov 17 06:19:59 2015 From: amber_sarosh at hotmail.com (Amber and Sarosh) Date: Tue, 17 Nov 2015 11:19:59 +0500 Subject: Changing Configuration Parameters Dynamically - OpenBSC In-Reply-To: <20151110195052.GV8473@nataraja> References: , <20151110195052.GV8473@nataraja> Message-ID: Thank you for your reply.Yes, we have tested and found that change in LAC is truly effective when BTS is restarted. But we cannot understand the behavior of user (user1) which is attached to say LAC=1 and when LAC is changed to say LAC=2 , without restarting the whole system(osmo-nitb, osmo-bts and osmo-trx), only silent call stops working for user1 and rest of the functions keep working. We have found that in this case, The user1 already attached to the Old LAC will now be considered unattached for calls onlyThis user1 is however seen to be semi attached with the network as the network still logs its channel requests if a call i made by this userThis user1 can still receive SMS from the system only when it requests any channel from the systemThis user1 does not go to its real network for a long period of time Can someone explain this behavior, that a user attached to an old LAC cannot be sent a silent call but can be sent an sms and its logs and call requests are being processed too under new lac by same network when its LAC is changed without restarting the BTS? P.S. Sorry for the long email. It's done for proper understanding of the scenario. Regards, Amber & Sarosh > Date: Tue, 10 Nov 2015 20:50:52 +0100 > From: laforge at gnumonks.org > To: amber_sarosh at hotmail.com > CC: openbsc at lists.osmocom.org > Subject: Re: Changing Configuration Parameters Dynamically - OpenBSC > > On Wed, Nov 04, 2015 at 11:32:59AM +0500, Amber and Sarosh wrote: > > Hi,Can someone inform us if the VTY configuration commands to change > > parameters e.g. cell id, location area code, MS power etc. that are > > run on OpenBSC VTY telnet interface take effect on next restart of > > the OpenBSC session or during the same session? If former is the case, > > is there any way to dynamically change Cell ID, LAC, MS TX power etc > > i.e. without restarting the OpenBSC session? > > * you don't need to restart openbsc to change any parameter > > * some parameters (almost all under the bts/trx/ts nodes) are > communicated via A-bis OML at BTS connection time. > Those parameters are not becoming effective until the BTS re-connects > and thus goes throug OML initialization. There is a vty command that > you can use to drop the a-bis OML connection for a specific BTS. > > * other parameters (affecting OpenBSC behavior directly) become > effectively immediately. > > -- > - Harald Welte http://laforge.gnumonks.org/ > ============================================================================ > "Privacy in residential applications is a desirable marketing option." > (ETSI EN 300 175-7 Ch. A6) -------------- next part -------------- An HTML attachment was scrubbed... URL: From jerlbeck at sysmocom.de Tue Nov 17 07:42:05 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 08:42:05 +0100 Subject: [PATCH] gsm: Add APN conversion functions Message-ID: <1447746125-23933-1-git-send-email-jerlbeck@sysmocom.de> These functions are currently part of openbsc but also needed by other projects. The function have been renamed as follows: gprs_apn_to_str -> osmo_apn_to_str gprs_str_to_apn -> osmo_apn_from_str Sponsored-by: On-Waves ehf --- include/osmocom/gsm/apn.h | 4 ++ src/gsm/apn.c | 76 +++++++++++++++++++++++++++++ src/gsm/libosmogsm.map | 2 + tests/Makefile.am | 10 ++-- tests/gprs/gprs_test.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++ tests/gprs/gprs_test.ok | 1 + tests/testsuite.at | 6 +++ 7 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 tests/gprs/gprs_test.c create mode 100644 tests/gprs/gprs_test.ok diff --git a/include/osmocom/gsm/apn.h b/include/osmocom/gsm/apn.h index d8d7399..9e3dca3 100644 --- a/include/osmocom/gsm/apn.h +++ b/include/osmocom/gsm/apn.h @@ -11,3 +11,7 @@ char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni); char *osmo_apn_qualify_from_imsi(const char *imsi, const char *ni, int have_3dig_mnc); + +int osmo_apn_from_str(uint8_t *apn_enc, size_t max_apn_enc_len, const char *str); +char * osmo_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t apn_enc_len); + diff --git a/src/gsm/apn.c b/src/gsm/apn.c index 413130a..ef7190d 100644 --- a/src/gsm/apn.c +++ b/src/gsm/apn.c @@ -36,3 +36,79 @@ char *osmo_apn_qualify_from_imsi(const char *imsi, } return osmo_apn_qualify(atoi(cbuf), atoi(nbuf), ni); } + +/** + * Convert an encoded APN into a dot-separated string. + * + * \param out_str the destination buffer (size must be >= max(app_enc_len,1)) + * \param apn_enc the encoded APN + * \param apn_enc_len the length of the encoded APN + * + * \returns out_str on success and NULL otherwise + */ +char * osmo_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t apn_enc_len) +{ + char *str = out_str; + size_t rest_chars = apn_enc_len; + + while (rest_chars > 0 && apn_enc[0]) { + size_t label_size = apn_enc[0]; + if (label_size + 1 > rest_chars) + return NULL; + + memmove(str, apn_enc + 1, label_size); + str += label_size; + rest_chars -= label_size + 1; + apn_enc += label_size + 1; + + if (rest_chars) + *(str++) = '.'; + } + str[0] = '\0'; + + return out_str; +} + +/** + * Convert a dot-separated string into an encoded APN. + * + * \param apn_enc the encoded APN + * \param max_apn_enc_len the size of the apn_enc buffer + * \param str the source string + * + * \returns out_str on success and NULL otherwise + */ +int osmo_apn_from_str(uint8_t *apn_enc, size_t max_apn_enc_len, const char *str) +{ + uint8_t *last_len_field; + int len; + + /* Can we even write the length field to the output? */ + if (max_apn_enc_len == 0) + return -1; + + /* Remember where we need to put the length once we know it */ + last_len_field = apn_enc; + len = 1; + apn_enc += 1; + + while (str[0]) { + if (len >= max_apn_enc_len) + return -1; + + if (str[0] == '.') { + *last_len_field = (apn_enc - last_len_field) - 1; + last_len_field = apn_enc; + } else { + *apn_enc = str[0]; + } + apn_enc += 1; + str += 1; + len += 1; + } + + *last_len_field = (apn_enc - last_len_field) - 1; + + return len; +} + diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 0c0d9f7..2aef050 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -269,6 +269,8 @@ ipa_send; osmo_apn_qualify; osmo_apn_qualify_from_imsi; +osmo_apn_to_str; +osmo_apn_from_str; local: *; }; diff --git a/tests/Makefile.am b/tests/Makefile.am index 223535f..4442355 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,7 +6,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ conv/conv_test auth/milenage_test lapd/lapd_test \ gsm0808/gsm0808_test gsm0408/gsm0408_test \ gb/bssgp_fc_test gb/gprs_bssgp_test gb/gprs_ns_test \ - kasumi/kasumi_test logging/logging_test fr/fr_test \ + gprs/gprs_test kasumi/kasumi_test \ + logging/logging_test fr/fr_test \ loggingrb/loggingrb_test strrb/strrb_test \ vty/vty_test comp128/comp128_test utils/utils_test \ smscb/gsm0341_test stats/stats_test @@ -45,6 +46,9 @@ gsm0808_gsm0808_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/ gsm0408_gsm0408_test_SOURCES = gsm0408/gsm0408_test.c gsm0408_gsm0408_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la +gprs_gprs_test_SOURCES = gprs/gprs_test.c +gprs_gprs_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la + lapd_lapd_test_SOURCES = lapd/lapd_test.c lapd_lapd_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la @@ -116,8 +120,8 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ lapd/lapd_test.ok gsm0408/gsm0408_test.ok \ gsm0808/gsm0808_test.ok gb/bssgp_fc_tests.err \ gb/bssgp_fc_tests.ok gb/bssgp_fc_tests.sh \ - gb/gprs_bssgp_test.ok \ - gb/gprs_ns_test.ok kasumi/kasumi_test.ok \ + gb/gprs_bssgp_test.ok gb/gprs_ns_test.ok \ + gprs/gprs_test.ok kasumi/kasumi_test.ok \ msgfile/msgfile_test.ok msgfile/msgconfig.cfg \ logging/logging_test.ok logging/logging_test.err \ fr/fr_test.ok loggingrb/logging_test.ok \ diff --git a/tests/gprs/gprs_test.c b/tests/gprs/gprs_test.c new file mode 100644 index 0000000..be80e5c --- /dev/null +++ b/tests/gprs/gprs_test.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +static void apn_round_trip(const uint8_t *input, size_t len, const char *wanted_output) +{ + char output[len ? len : 1]; + uint8_t encoded[len + 50]; + char *out_str; + int enc_len; + + /* decode and verify we have what we want */ + out_str = osmo_apn_to_str(output, input, len); + OSMO_ASSERT(out_str); + OSMO_ASSERT(out_str == &output[0]); + OSMO_ASSERT(strlen(out_str) == strlen(wanted_output)); + OSMO_ASSERT(strcmp(out_str, wanted_output) == 0); + + /* encode and verify it */ + if (len != 0) { + enc_len = osmo_apn_from_str(encoded, ARRAY_SIZE(encoded), wanted_output); + OSMO_ASSERT(enc_len == len); + OSMO_ASSERT(memcmp(encoded, input, enc_len) == 0); + } else { + enc_len = osmo_apn_from_str(encoded, 0, wanted_output); + OSMO_ASSERT(enc_len == -1); + } +} + +static void test_gsm_03_03_apn(void) +{ + + { + /* test invalid writes */ + const uint8_t ref[10] = { 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF }; + uint8_t output[10]; + int enc_len; + + memcpy(output, ref, ARRAY_SIZE(output)); + enc_len = osmo_apn_from_str(output, 0, ""); + OSMO_ASSERT(enc_len == -1); + OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0); + + memcpy(output, ref, ARRAY_SIZE(output)); + enc_len = osmo_apn_from_str(output, 0, "foo"); + OSMO_ASSERT(enc_len == -1); + OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0); + + memcpy(output, ref, ARRAY_SIZE(output)); + enc_len = osmo_apn_from_str(output, 1, "foo"); + OSMO_ASSERT(enc_len == -1); + OSMO_ASSERT(memcmp(ref + 1, output + 1, ARRAY_SIZE(ref) - 1) == 0); + + memcpy(output, ref, ARRAY_SIZE(output)); + enc_len = osmo_apn_from_str(output, 2, "foo"); + OSMO_ASSERT(enc_len == -1); + OSMO_ASSERT(memcmp(ref + 2, output + 2, ARRAY_SIZE(ref) - 2) == 0); + + memcpy(output, ref, ARRAY_SIZE(output)); + enc_len = osmo_apn_from_str(output, 3, "foo"); + OSMO_ASSERT(enc_len == -1); + OSMO_ASSERT(memcmp(ref + 3, output + 3, ARRAY_SIZE(ref) - 3) == 0); + } + + { + /* single empty label */ + uint8_t input[] = { 0x0 }; + const char *output = ""; + apn_round_trip(input, ARRAY_SIZE(input), output); + } + + { + /* no label */ + uint8_t input[] = { }; + const char *output = ""; + apn_round_trip(input, ARRAY_SIZE(input), output); + } + + { + /* single label with A */ + uint8_t input[] = { 0x1, 65 }; + const char *output = "A"; + apn_round_trip(input, ARRAY_SIZE(input), output); + OSMO_ASSERT(osmo_apn_to_str(NULL, input, ARRAY_SIZE(input) - 1) == NULL); + } + + { + uint8_t input[] = { 0x3, 65, 66, 67, 0x2, 90, 122 }; + const char *output = "ABC.Zz"; + char tmp[strlen(output) + 1]; + apn_round_trip(input, ARRAY_SIZE(input), output); + OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 1) == NULL); + OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 2) == NULL); + OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 4) == NULL); + OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 5) == NULL); + OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 6) == NULL); + } +} + +const struct log_info_cat default_categories[] = { +}; + +static struct log_info info = { + .cat = default_categories, + .num_cat = ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + osmo_init_logging(&info); + + test_gsm_03_03_apn(); + + printf("Done.\n"); + return EXIT_SUCCESS; +} diff --git a/tests/gprs/gprs_test.ok b/tests/gprs/gprs_test.ok new file mode 100644 index 0000000..619c561 --- /dev/null +++ b/tests/gprs/gprs_test.ok @@ -0,0 +1 @@ +Done. diff --git a/tests/testsuite.at b/tests/testsuite.at index a542798..85c3e8b 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -84,6 +84,12 @@ cat $abs_srcdir/gsm0408/gsm0408_test.ok > expout AT_CHECK([$abs_top_builddir/tests/gsm0408/gsm0408_test], [0], [expout], [ignore]) AT_CLEANUP +AT_SETUP([gprs]) +AT_KEYWORDS([gprs]) +cat $abs_srcdir/gprs/gprs_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/gprs/gprs_test], [0], [expout], [ignore]) +AT_CLEANUP + AT_SETUP([logging]) AT_KEYWORDS([logging]) cat $abs_srcdir/logging/logging_test.ok > expout -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 09:37:45 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 10:37:45 +0100 Subject: [PATCH 2/6] msgb: Let msgb_hexdump be more tolerant In-Reply-To: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447753069-17466-2-git-send-email-jerlbeck@sysmocom.de> This patch makes msgb_hexdump accept out of range lXh pointers and shows info about them instead of aborting the dump entirely. Sponsored-by: On-Waves ehf --- src/msgb.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/msgb.c b/src/msgb.c index a257479..d896b53 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -263,10 +263,25 @@ const char *msgb_hexdump(const struct msgb *msg) if (!lxhs[i]) continue; - if (lxhs[i] < msg->data) - goto out_of_range; + if (lxhs[i] < msg->head) + continue; + if (lxhs[i] > msg->head + msg->data_len) + continue; if (lxhs[i] > msg->tail) - goto out_of_range; + continue; + if (lxhs[i] < msg->data || lxhs[i] > msg->tail) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d=data%+d) ", + i+1, lxhs[i] - msg->data); + buf_offs += nchars; + continue; + } + if (lxhs[i] < start) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d%+d) ", i+1, start - lxhs[i]); + buf_offs += nchars; + continue; + } nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, "%s[L%d]> ", osmo_hexdump(start, lxhs[i] - start), @@ -282,11 +297,28 @@ const char *msgb_hexdump(const struct msgb *msg) if (nchars < 0 || nchars + buf_offs >= sizeof(buf)) return "ERROR"; - return buf; + buf_offs += nchars; + + for (i = 0; i < ARRAY_SIZE(lxhs); i++) { + if (!lxhs[i]) + continue; + + if (lxhs[i] < msg->head || lxhs[i] > msg->head + msg->data_len) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d out of range) ", i+1); + } else if (lxhs[i] <= msg->data + msg->data_len && + lxhs[i] > msg->tail) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d=tail%+d) ", + i+1, lxhs[i] - msg->tail); + } else + continue; + + if (nchars < 0 || nchars + buf_offs >= sizeof(buf)) + return "ERROR"; + buf_offs += nchars; + } -out_of_range: - nchars = snprintf(buf, sizeof(buf) - buf_offs, - "!!! L%d out of range", i+1); return buf; } -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 09:37:46 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 10:37:46 +0100 Subject: [PATCH 3/6] msgb: Add msgb_test_invariant function In-Reply-To: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447753069-17466-3-git-send-email-jerlbeck@sysmocom.de> This adds a function that verifies whether a mgsb is consistent. Sponsored-by: On-Waves ehf --- include/osmocom/core/msgb.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 21e363a..2bf4ac5 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -77,6 +77,7 @@ extern const char *msgb_hexdump(const struct msgb *msg); extern int msgb_resize_area(struct msgb *msg, uint8_t *area, size_t old_size, size_t new_size); extern struct msgb *msgb_copy(const struct msgb *msg, const char *name); +static int msgb_test_invariant(const struct msgb *msg) __attribute__((pure)); #ifdef MSGB_DEBUG #include @@ -412,6 +413,45 @@ static inline struct msgb *msgb_alloc_headroom(int size, int headroom, return msg; } +/*! \brief Check a message buffer for consistency + * \param[in] msg message buffer + * \returns 0 (false) if inconsistent, != 0 (true) otherwise + */ +static inline int msgb_test_invariant(const struct msgb *msg) +{ + const unsigned char *lbound; + if (!msg || !msg->data || !msg->tail || + (msg->data + msg->len != msg->tail) || + (msg->data < msg->head) || + (msg->tail > msg->head + msg->data_len)) + return 0; + + lbound = msg->head; + + if (msg->l1h) { + if (msg->l1h < lbound) + return 0; + lbound = msg->l1h; + } + if (msg->l2h) { + if (msg->l2h < lbound) + return 0; + lbound = msg->l2h; + } + if (msg->l3h) { + if (msg->l3h < lbound) + return 0; + lbound = msg->l3h; + } + if (msg->l4h) { + if (msg->l4h < lbound) + return 0; + lbound = msg->l4h; + } + + return lbound <= msg->head + msg->data_len; +} + /* non inline functions to ease binding */ uint8_t *msgb_data(const struct msgb *msg); -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 09:37:44 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 10:37:44 +0100 Subject: [PATCH 1/6] msgb: Add msgb_resize_area and msgb_copy Message-ID: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> These functions originate from openbsc/src/gprs but are generic msgb helper functions. msgb_copy: This function allocates a new msgb, copies the data buffer of msg, and adjusts the pointers (incl. l1h-l4h) accordingly. msgb_resize_area: This resizes a sub area of the msgb data and adjusts the pointers (incl. l1h-l4h) accordingly. Sponsored-by: On-Waves ehf --- include/osmocom/core/msgb.h | 3 ++ src/msgb.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 644a639..21e363a 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -74,6 +74,9 @@ extern struct msgb *msgb_dequeue(struct llist_head *queue); extern void msgb_reset(struct msgb *m); uint16_t msgb_length(const struct msgb *msg); extern const char *msgb_hexdump(const struct msgb *msg); +extern int msgb_resize_area(struct msgb *msg, uint8_t *area, + size_t old_size, size_t new_size); +extern struct msgb *msgb_copy(const struct msgb *msg, const char *name); #ifdef MSGB_DEBUG #include diff --git a/src/msgb.c b/src/msgb.c index b2fe1d2..a257479 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -153,6 +153,94 @@ void msgb_set_talloc_ctx(void *ctx) tall_msgb_ctx = ctx; } +/*! \brief Copy an msgb. + * + * This function allocates a new msgb, copies the data buffer of msg, + * and adjusts the pointers (incl l1h-l4h) accordingly. The cb part + * is not copied. + * \param[in] msg The old msgb object + * \param[in] name Human-readable name to be associated with msgb + */ +struct msgb *msgb_copy(const struct msgb *msg, const char *name) +{ + struct msgb *new_msg; + + new_msg = msgb_alloc(msg->data_len, name); + if (!new_msg) + return NULL; + + /* copy data */ + memcpy(new_msg->_data, msg->_data, new_msg->data_len); + + /* copy header */ + new_msg->len = msg->len; + new_msg->data += msg->data - msg->_data; + new_msg->head += msg->head - msg->_data; + new_msg->tail += msg->tail - msg->_data; + + if (msg->l1h) + new_msg->l1h = new_msg->_data + (msg->l1h - msg->_data); + if (msg->l2h) + new_msg->l2h = new_msg->_data + (msg->l2h - msg->_data); + if (msg->l3h) + new_msg->l3h = new_msg->_data + (msg->l3h - msg->_data); + if (msg->l4h) + new_msg->l4h = new_msg->_data + (msg->l4h - msg->_data); + + return new_msg; +} + +/*! \brief Resize an area within an msgb + * + * This resizes a sub area of the msgb data and adjusts the pointers (incl + * l1h-l4h) accordingly. The cb part is not updated. If the area is extended, + * the contents of the extension is undefined. The complete sub area must be a + * part of [data,tail]. + * + * \param[inout] msg The msgb object + * \param[in] area A pointer to the sub-area + * \param[in] old_size The old size of the sub-area + * \param[in] new_size The new size of the sub-area + * \returns 0 on success, -1 if there is not enough space to extend the area + */ +int msgb_resize_area(struct msgb *msg, uint8_t *area, + size_t old_size, size_t new_size) +{ + int rc; + uint8_t *rest = area + old_size; + int rest_len = msg->len - old_size - (area - msg->data); + int delta_size = (int)new_size - (int)old_size; + + if (area < msg->data || rest > msg->tail) + MSGB_ABORT(msg, "Sub area is not fully contained in the msg data\n"); + + if (delta_size == 0) + return 0; + + if (delta_size > 0) { + rc = msgb_trim(msg, msg->len + delta_size); + if (rc < 0) + return rc; + } + + memmove(area + new_size, area + old_size, rest_len); + + if (msg->l1h >= rest) + msg->l1h += delta_size; + if (msg->l2h >= rest) + msg->l2h += delta_size; + if (msg->l3h >= rest) + msg->l3h += delta_size; + if (msg->l4h >= rest) + msg->l4h += delta_size; + + if (delta_size < 0) + msgb_trim(msg, msg->len + delta_size); + + return 0; +} + + /*! \brief Return a (static) buffer containing a hexdump of the msg * \param[in] msg message buffer * \returns a pointer to a static char array -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 09:37:49 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 10:37:49 +0100 Subject: [PATCH 6/6] gb: Add bssgp_msgb_copy function In-Reply-To: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447753069-17466-6-git-send-email-jerlbeck@sysmocom.de> This function originates from openbsc/src/gprs but is just specific to BSSGP/Gb on the same level like bssgp_msgb_alloc. This commit puts the former gprs_msgb_copy function beside bssgp_msgb_alloc. Renamed function: gprs_msgb_copy -> bssgp_msgb_copy Sponsored-by: On-Waves ehf --- include/osmocom/gprs/gprs_bssgp.h | 1 + src/gb/gprs_bssgp_util.c | 30 ++++++++++++++++++++++++++++++ src/gb/libosmogb.map | 1 + tests/gb/gprs_bssgp_test.c | 34 ++++++++++++++++++++++++++++++++++ tests/gb/gprs_bssgp_test.ok | 4 ++++ 5 files changed, 70 insertions(+) diff --git a/include/osmocom/gprs/gprs_bssgp.h b/include/osmocom/gprs/gprs_bssgp.h index e24b563..c0b3f65 100644 --- a/include/osmocom/gprs/gprs_bssgp.h +++ b/include/osmocom/gprs/gprs_bssgp.h @@ -12,6 +12,7 @@ /* gprs_bssgp_util.c */ extern struct gprs_ns_inst *bssgp_nsi; struct msgb *bssgp_msgb_alloc(void); +struct msgb *bssgp_msgb_copy(const struct msgb *msg, const char *name); const char *bssgp_cause_str(enum gprs_bssgp_cause cause); /* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, diff --git a/src/gb/gprs_bssgp_util.c b/src/gb/gprs_bssgp_util.c index 3c42e4d..19ae23a 100644 --- a/src/gb/gprs_bssgp_util.c +++ b/src/gb/gprs_bssgp_util.c @@ -79,6 +79,36 @@ struct msgb *bssgp_msgb_alloc(void) return msg; } +struct msgb *bssgp_msgb_copy(const struct msgb *msg, const char *name) +{ + struct libgb_msgb_cb *old_cb, *new_cb; + struct msgb *new_msg; + + new_msg = msgb_copy(msg, name); + if (!new_msg) + return NULL; + + /* copy GB specific data */ + old_cb = LIBGB_MSGB_CB(msg); + new_cb = LIBGB_MSGB_CB(new_msg); + + if (old_cb->bssgph) + new_cb->bssgph = new_msg->_data + (old_cb->bssgph - msg->_data); + if (old_cb->llch) + new_cb->llch = new_msg->_data + (old_cb->llch - msg->_data); + + /* bssgp_cell_id is a pointer into the old msgb, so we need to make + * it a pointer into the new msgb */ + if (old_cb->bssgp_cell_id) + new_cb->bssgp_cell_id = new_msg->_data + + (old_cb->bssgp_cell_id - msg->_data); + new_cb->nsei = old_cb->nsei; + new_cb->bvci = old_cb->bvci; + new_cb->tlli = old_cb->tlli; + + return new_msg; +} + /* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, uint16_t bvci, uint16_t ns_bvci) diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map index 43ebbf8..75406c0 100644 --- a/src/gb/libosmogb.map +++ b/src/gb/libosmogb.map @@ -6,6 +6,7 @@ bssgp_fc_in; bssgp_fc_init; bssgp_fc_ms_init; bssgp_msgb_alloc; +bssgp_msgb_copy; bssgp_msgb_tlli_put; bssgp_parse_cell_id; bssgp_tx_bvc_block; diff --git a/tests/gb/gprs_bssgp_test.c b/tests/gb/gprs_bssgp_test.c index 14ba4d1..bf35546 100644 --- a/tests/gb/gprs_bssgp_test.c +++ b/tests/gb/gprs_bssgp_test.c @@ -254,6 +254,39 @@ static void test_bssgp_flow_control_bvc(void) printf("----- %s END\n", __func__); } +static void test_bssgp_msgb_copy() +{ + struct msgb *msg, *msg2; + uint16_t bvci_be = htons(2); + uint8_t cause = BSSGP_CAUSE_OML_INTERV; + + printf("----- %s START\n", __func__); + msg = bssgp_msgb_alloc(); + + msg->l3h = msgb_data(msg); + msgb_v_put(msg, BSSGP_PDUT_BVC_RESET); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, sizeof(bvci_be), (uint8_t *)&bvci_be); + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, sizeof(cause), &cause); + + msgb_bvci(msg) = 0xbad; + msgb_nsei(msg) = 0xbee; + + printf("Old msgb: %s\n", msgb_hexdump(msg)); + msg2 = bssgp_msgb_copy(msg, "test"); + printf("New msgb: %s\n", msgb_hexdump(msg2)); + + OSMO_ASSERT(msgb_bvci(msg2) == 0xbad); + OSMO_ASSERT(msgb_nsei(msg2) == 0xbee); + OSMO_ASSERT(msgb_l3(msg2) == msgb_data(msg2)); + OSMO_ASSERT(msgb_bssgph(msg2) == msgb_data(msg2)); + OSMO_ASSERT(msgb_bssgp_len(msg2) == msgb_length(msg2)); + + msgb_free(msg); + msgb_free(msg2); + + printf("----- %s END\n", __func__); +} + static struct log_info info = {}; int main(int argc, char **argv) @@ -278,6 +311,7 @@ int main(int argc, char **argv) test_bssgp_status(); test_bssgp_bad_reset(); test_bssgp_flow_control_bvc(); + test_bssgp_msgb_copy(); printf("===== BSSGP test END\n\n"); exit(EXIT_SUCCESS); diff --git a/tests/gb/gprs_bssgp_test.ok b/tests/gb/gprs_bssgp_test.ok index 83d633b..c5b3e7d 100644 --- a/tests/gb/gprs_bssgp_test.ok +++ b/tests/gb/gprs_bssgp_test.ok @@ -13,5 +13,9 @@ BSSGP primitive, SAP 16777221, prim = 11, op = 2, msg = 41 07 81 05 04 82 04 d2 Got message: 26 1e 81 2a 05 82 10 22 03 82 c0 40 01 82 08 11 1c 82 60 20 Got message: 26 1e 81 2a 05 82 10 22 03 82 c0 40 01 82 08 11 1c 82 60 20 3c 81 78 06 82 11 44 ----- test_bssgp_flow_control_bvc END +----- test_bssgp_msgb_copy START +Old msgb: [L3]> 22 04 82 00 02 07 81 08 +New msgb: [L3]> 22 04 82 00 02 07 81 08 +----- test_bssgp_msgb_copy END ===== BSSGP test END -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 09:37:47 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 10:37:47 +0100 Subject: [PATCH 4/6] msgb/test: Add test for msgb message buffers In-Reply-To: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447753069-17466-4-git-send-email-jerlbeck@sysmocom.de> This tests several API functions of the msgb by checking the invariant and by dumping resulting message buffers as hex. Sponsored-by: On-Waves ehf Conflicts: tests/Makefile.am --- tests/Makefile.am | 9 +++- tests/msgb/msgb_test.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/msgb/msgb_test.ok | 21 +++++++++ tests/testsuite.at | 6 +++ 4 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 tests/msgb/msgb_test.c create mode 100644 tests/msgb/msgb_test.ok diff --git a/tests/Makefile.am b/tests/Makefile.am index 4442355..edf25a0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,7 +10,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ logging/logging_test fr/fr_test \ loggingrb/loggingrb_test strrb/strrb_test \ vty/vty_test comp128/comp128_test utils/utils_test \ - smscb/gsm0341_test stats/stats_test + smscb/gsm0341_test stats/stats_test \ + msgb/msgb_test if ENABLE_MSGFILE check_PROGRAMS += msgfile/msgfile_test @@ -52,6 +53,9 @@ gprs_gprs_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gs lapd_lapd_test_SOURCES = lapd/lapd_test.c lapd_lapd_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la +msgb_msgb_test_SOURCES = msgb/msgb_test.c +msgb_msgb_test_LDADD = $(top_builddir)/src/libosmocore.la + msgfile_msgfile_test_SOURCES = msgfile/msgfile_test.c msgfile_msgfile_test_LDADD = $(top_builddir)/src/libosmocore.la @@ -127,7 +131,8 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ fr/fr_test.ok loggingrb/logging_test.ok \ loggingrb/logging_test.err strrb/strrb_test.ok \ vty/vty_test.ok comp128/comp128_test.ok \ - utils/utils_test.ok stats/stats_test.ok + utils/utils_test.ok stats/stats_test.ok \ + msgb/msgb_test.ok DISTCLEANFILES = atconfig diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c new file mode 100644 index 0000000..412e8bb --- /dev/null +++ b/tests/msgb/msgb_test.c @@ -0,0 +1,120 @@ +/* + * (C) 2014 by On-Waves + * 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 + +#define CHECK_RC(rc) \ + if (rc != 0) { \ + printf("Operation failed rc=%d on %s:%d\n", rc, __FILE__, __LINE__); \ + abort(); \ + } + +static void test_msgb_api() +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + unsigned char *cptr = NULL; + int rc; + + printf("Testing the msgb API\n"); + + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l1h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l2h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l3h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l4h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + OSMO_ASSERT(msgb_length(msg) == 16); + cptr = msgb_push(msg, 4); + printf("push(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + OSMO_ASSERT(msgb_length(msg) == 20); + rc = msgb_trim(msg, 16); + printf("trim(16) -> %d\n", rc); + CHECK_RC(rc); + OSMO_ASSERT(msgb_test_invariant(msg)); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_length(msg) == 16); + + cptr = msgb_get(msg, 4); + printf("get(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + OSMO_ASSERT(msgb_length(msg) == 12); + + printf("Test msgb_hexdump\n"); + msg->l1h = msg->head; + printf("Buffer: %s\n", msgb_hexdump(msg)); + msg->l3h = msg->data; + printf("Buffer: %s\n", msgb_hexdump(msg)); + msg->l3h = msg->head - 1; + printf("Buffer: %s\n", msgb_hexdump(msg)); + +#if 0 +extern void msgb_reset(struct msgb *m); +#define msgb_l1(m) ((void *)(MSGB_CHECK2(m)->l1h)) +static inline unsigned int msgb_l1len(const struct msgb *msgb) + static inline int msgb_tailroom(const struct msgb *msgb) + static inline int msgb_headroom(const struct msgb *msgb) + static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len) + static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) + static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) + static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len) + + static inline unsigned char *msgb_pull_to_l3(struct msgb *msg) + static inline int msgb_trim(struct msgb *msg, int len) + static inline int msgb_l3trim(struct msgb *msg, int l3len) + uint8_t *msgb_data(const struct msgb *msg); + return; +#endif +} + +static struct log_info info = {}; + +int main(int argc, char **argv) +{ + osmo_init_logging(&info); + + test_msgb_api(); + + printf("Success.\n"); + + return 0; +} diff --git a/tests/msgb/msgb_test.ok b/tests/msgb/msgb_test.ok new file mode 100644 index 0000000..f8de0cd --- /dev/null +++ b/tests/msgb/msgb_test.ok @@ -0,0 +1,21 @@ +Testing the msgb API +Buffer: +put(4) -> data+0 +Buffer: [L1]> 00 00 00 00 +put(4) -> data+4 +Buffer: [L1]> 00 00 00 00 [L2]> 00 00 00 00 +put(4) -> data+8 +Buffer: [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 +put(4) -> data+12 +Buffer: [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 [L4]> 00 00 00 00 +push(4) -> data+0 +Buffer: 00 00 00 00 [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 [L4]> 00 00 00 00 +trim(16) -> 0 +Buffer: 00 00 00 00 [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 [L4]> +get(4) -> data+12 +Buffer: 00 00 00 00 [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> (L4=tail+4) +Test msgb_hexdump +Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 [L3]> (L4=tail+4) +Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> (L3+8) 00 00 00 00 (L4=tail+4) +Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 (L3 out of range) (L4=tail+4) +Success. diff --git a/tests/testsuite.at b/tests/testsuite.at index 85c3e8b..12199e3 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -27,6 +27,12 @@ cat $abs_srcdir/conv/conv_test.ok > expout AT_CHECK([$abs_top_builddir/tests/conv/conv_test], [0], [expout]) AT_CLEANUP +AT_SETUP([msgb]) +AT_KEYWORDS([msgb]) +cat $abs_srcdir/msgb/msgb_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/msgb/msgb_test], [0], [expout]) +AT_CLEANUP + if ENABLE_MSGFILE AT_SETUP([msgfile]) AT_KEYWORDS([msgfile]) -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 09:37:48 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 10:37:48 +0100 Subject: [PATCH 5/6] msgb/test: Add tests for msgb_resize_area and msgb_copy In-Reply-To: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447753069-17466-5-git-send-email-jerlbeck@sysmocom.de> Sponsored-by: On-Waves ehf --- tests/msgb/msgb_test.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++-- tests/msgb/msgb_test.ok | 2 ++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c index 412e8bb..08d9857 100644 --- a/tests/msgb/msgb_test.c +++ b/tests/msgb/msgb_test.c @@ -87,6 +87,7 @@ static void test_msgb_api() msg->l3h = msg->head - 1; printf("Buffer: %s\n", msgb_hexdump(msg)); + #if 0 extern void msgb_reset(struct msgb *m); #define msgb_l1(m) ((void *)(MSGB_CHECK2(m)->l1h)) @@ -97,15 +98,61 @@ static inline unsigned int msgb_l1len(const struct msgb *msgb) static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len) - + static inline unsigned char *msgb_pull_to_l3(struct msgb *msg) static inline int msgb_trim(struct msgb *msg, int len) static inline int msgb_l3trim(struct msgb *msg, int l3len) uint8_t *msgb_data(const struct msgb *msg); - return; +return; #endif } +static void test_msgb_copy() +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + struct msgb *msg2; + + printf("Testing msgb_copy\n"); + + msg->l1h = msgb_put(msg, 20); + msg->l2h = msgb_put(msg, 20); + msg->l3h = msgb_put(msg, 20); + msg->l4h = msgb_put(msg, 20); + + msg2 = msgb_copy(msg, "copy"); + + OSMO_ASSERT(msgb_length(msg) == msgb_length(msg2)); + OSMO_ASSERT(msgb_l1len(msg) == msgb_l1len(msg2)); + OSMO_ASSERT(msgb_l2len(msg) == msgb_l2len(msg2)); + OSMO_ASSERT(msgb_l3len(msg) == msgb_l3len(msg2)); + OSMO_ASSERT(msg->tail - msg->l4h == msg2->tail - msg2->l4h); +} + +static void test_msgb_resize_area() +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + int rc; + + printf("Testing msgb_resize_area\n"); + + msg->l1h = msgb_put(msg, 20); + msg->l2h = msgb_put(msg, 20); + msg->l3h = msgb_put(msg, 20); + msg->l4h = msgb_put(msg, 20); + + rc = msgb_resize_area(msg, msg->l2h, 20, 20 + 30); + + OSMO_ASSERT(rc >= 0); + OSMO_ASSERT(msgb_length(msg) == 80 + 30); + OSMO_ASSERT(msgb_l1len(msg) == 80 + 30); + OSMO_ASSERT(msgb_l2len(msg) == 60 + 30); + OSMO_ASSERT(msgb_l3len(msg) == 40); + OSMO_ASSERT(msg->tail - msg->l4h == 20); + + rc = msgb_resize_area(msg, msg->l2h, 50, 8000); + OSMO_ASSERT(rc == -1); +} + static struct log_info info = {}; int main(int argc, char **argv) @@ -113,6 +160,8 @@ int main(int argc, char **argv) osmo_init_logging(&info); test_msgb_api(); + test_msgb_copy(); + test_msgb_resize_area(); printf("Success.\n"); diff --git a/tests/msgb/msgb_test.ok b/tests/msgb/msgb_test.ok index f8de0cd..3ace5be 100644 --- a/tests/msgb/msgb_test.ok +++ b/tests/msgb/msgb_test.ok @@ -18,4 +18,6 @@ Test msgb_hexdump Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 [L3]> (L4=tail+4) Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> (L3+8) 00 00 00 00 (L4=tail+4) Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 (L3 out of range) (L4=tail+4) +Testing msgb_copy +Testing msgb_resize_area Success. -- 1.9.1 From aschultz at tpip.net Tue Nov 17 10:09:46 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 11:09:46 +0100 (CET) Subject: [PATCH 05/16] gtp-rtnl: and netns support In-Reply-To: <20151116174355.GE4392@salvia> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-6-git-send-email-aschultz@tpip.net> <20151116174355.GE4392@salvia> Message-ID: <963352600.30683.1447754986159.JavaMail.zimbra@tpip.net> ----- Original Message ----- > From: "Pablo Neira Ayuso" > To: "Andreas Schultz" > Cc: openbsc at lists.osmocom.org, "Harald Welte" > Sent: Monday, November 16, 2015 6:43:55 PM > Subject: Re: [PATCH 05/16] gtp-rtnl: and netns support > On Mon, Nov 16, 2015 at 04:06:46PM +0100, Andreas Schultz wrote: >> diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c >> index c1f60ab..9e68a30 100644 >> --- a/libgtnl/src/gtp-genl.c >> +++ b/libgtnl/src/gtp-genl.c >> @@ -44,6 +44,8 @@ >> static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) >> { >> mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version); >> + if (t->ifns > 0) >> + mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns); > > Any reason not to consider descriptor zero as valid? ifns is a file descriptor and fd's are as far as I know always greater zero. So, I didn't see a reason to permit zero there when simply not setting the attribute would serve the same purpose. > I guess we'll need some flags for gtp_tunnel so we know what we have > set here. > >> mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx); >> mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); >> mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); >> diff --git a/libgtnl/src/gtp-rtnl.c b/libgtnl/src/gtp-rtnl.c >> index 22b9430..db54653 100644 >> --- a/libgtnl/src/gtp-rtnl.c >> +++ b/libgtnl/src/gtp-rtnl.c >> @@ -38,6 +38,10 @@ >> >> #include "internal.h" >> >> +#if !defined(IFLA_LINK_NETNSID) >> +#define IFLA_LINK_NETNSID (IFLA_PHYS_SWITCH_ID + 1) >> +#endif > > Why do you need this? I'm test compiling the library on an older kernel. I'll remove that. From jerlbeck at sysmocom.de Tue Nov 17 10:52:25 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 11:52:25 +0100 Subject: [PATCH 2/3] log: Add conditional logging based on log_check_level In-Reply-To: <1447757546-31341-1-git-send-email-jerlbeck@sysmocom.de> References: <1447757546-31341-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447757546-31341-2-git-send-email-jerlbeck@sysmocom.de> Currently the LOGP/DEBUGP arguments are always evaluated even if no logging will happen at all. This can be expensive, for instance if hexdumps or pretty printed object names are generated. This causes high base load especially on embedded devices and is a major part of CPU usage e.g. of the osmo-pcu. This commit uses the log_check_level function to avoid the evaluation of the parameters if it is known in advance, that no logging entry will be generated. Sponsored-by: On-Waves ehf --- include/osmocom/core/logging.h | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h index 290b33d..e51487b 100644 --- a/include/osmocom/core/logging.h +++ b/include/osmocom/core/logging.h @@ -19,8 +19,18 @@ #define DEBUG #ifdef DEBUG -#define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args) -#define DEBUGPC(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 1, fmt, ## args) +#define DEBUGP(ss, fmt, args...) \ + do { \ + if (log_check_level(ss, LOGL_DEBUG)) \ + logp(ss, __FILE__, __LINE__, 0, fmt, ## args); \ + } while(0) + +#define DEBUGPC(ss, fmt, args...) \ + do { \ + if (log_check_level(ss, LOGL_DEBUG)) \ + logp(ss, __FILE__, __LINE__, 1, fmt, ## args); \ + } while(0) + #else #define DEBUGP(xss, fmt, args...) #define DEBUGPC(ss, fmt, args...) @@ -39,7 +49,10 @@ void logp(int subsys, const char *file, int line, int cont, const char *format, * \param[in] args variable argument list */ #define LOGP(ss, level, fmt, args...) \ - logp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args) + do { \ + if (log_check_level(ss, level)) \ + logp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args); \ + } while(0) /*! \brief Continue a log message through the Osmocom logging framework * \param[in] ss logging subsystem (e.g. \ref DLGLOBAL) @@ -48,7 +61,10 @@ void logp(int subsys, const char *file, int line, int cont, const char *format, * \param[in] args variable argument list */ #define LOGPC(ss, level, fmt, args...) \ - logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args) + do { \ + if (log_check_level(ss, level)) \ + logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args); \ + } while(0) /*! \brief different log levels */ #define LOGL_DEBUG 1 /*!< \brief debugging information */ -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 10:52:24 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 11:52:24 +0100 Subject: [PATCH 1/3] log: Add log_check_level function Message-ID: <1447757546-31341-1-git-send-email-jerlbeck@sysmocom.de> This commit adds this predicate function which can be used to avoid the execution of code if a certain log level is not enabled. The function will only return 0 (false), if it is sure that a logging call for the same facility and level will not produce any output. This safety criterion shall ensure, that no logging output is lost due to the use of this predicate as a guard. On the other hand, even if the predicate returns != 0 (true), no logging output might get generated by a similar logging command. Note that the current implementation is not focussed on performance, which could be improved by using a lookup table instead of iterating through every target. Sponsored-by: On-Waves ehf --- include/osmocom/core/logging.h | 1 + src/logging.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h index 1c159d0..290b33d 100644 --- a/include/osmocom/core/logging.h +++ b/include/osmocom/core/logging.h @@ -198,6 +198,7 @@ void logp2(int subsys, unsigned int level, const char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 6, 7))); int log_init(const struct log_info *inf, void *talloc_ctx); +int log_check_level(int subsys, unsigned int level); /* context management */ void log_reset_context(void); diff --git a/src/logging.c b/src/logging.c index 876964a..c7b1999 100644 --- a/src/logging.c +++ b/src/logging.c @@ -865,4 +865,43 @@ int log_init(const struct log_info *inf, void *ctx) return 0; } +/*! \brief Check whether a log entry will be generated. + * \returns != 0 if a log entry might get generated by at least one target */ +int log_check_level(int subsys, unsigned int level) +{ + struct log_target *tar; + + if (subsys < 0) + subsys = subsys_lib2index(subsys); + + if (subsys > osmo_log_info->num_cat) + subsys = DLGLOBAL; + + /* TODO: The following could/should be cached (update on config) */ + + llist_for_each_entry(tar, &osmo_log_target_list, entry) { + struct log_category *category; + + category = &tar->categories[subsys]; + /* subsystem is not supposed to be logged */ + if (!category->enabled) + continue; + + /* Check the global log level */ + if (tar->loglevel != 0 && level < tar->loglevel) + continue; + + /* Check the category log level */ + if (tar->loglevel == 0 && category->loglevel != 0 && + level < category->loglevel) + continue; + + /* This might get logged (ignoring filters) */ + return 1; + } + + /* We are sure, that this will not be logged. */ + return 0; +} + /*! @} */ -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 10:52:26 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 11:52:26 +0100 Subject: [PATCH 3/3] log/test: Extend test case for log_check_level In-Reply-To: <1447757546-31341-1-git-send-email-jerlbeck@sysmocom.de> References: <1447757546-31341-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447757546-31341-3-git-send-email-jerlbeck@sysmocom.de> This commit adds OSMO_ASSERTs for mandatory conditions related to log_check_level, and fprintfs for optional conditions, since it is always safe for log_check_level to return != 0. Sponsored-by: On-Waves ehf --- tests/logging/logging_test.c | 10 ++++++++++ tests/logging/logging_test.err | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/logging/logging_test.c b/tests/logging/logging_test.c index b263f90..3c8bac4 100644 --- a/tests/logging/logging_test.c +++ b/tests/logging/logging_test.c @@ -78,16 +78,26 @@ int main(int argc, char **argv) log_parse_category_mask(stderr_target, "DRLL:DCC"); log_parse_category_mask(stderr_target, "DRLL"); DEBUGP(DCC, "You should not see this\n"); + if (log_check_level(DMM, LOGL_DEBUG) != 0) + fprintf(stderr, "log_check_level did not catch this case\n"); log_parse_category_mask(stderr_target, "DRLL:DCC"); DEBUGP(DRLL, "You should see this\n"); + OSMO_ASSERT(log_check_level(DRLL, LOGL_DEBUG) != 0); DEBUGP(DCC, "You should see this\n"); + OSMO_ASSERT(log_check_level(DCC, LOGL_DEBUG) != 0); DEBUGP(DMM, "You should not see this\n"); + if (log_check_level(DMM, LOGL_DEBUG) != 0) + fprintf(stderr, "log_check_level did not catch this case\n"); + OSMO_ASSERT(filter_called == 0); log_set_all_filter(stderr_target, 0); DEBUGP(DRLL, "You should not see this and filter is called\n"); OSMO_ASSERT(filter_called == 1); + if (log_check_level(DRLL, LOGL_DEBUG) != 0) + fprintf(stderr, + "log_check_level did not catch this case (filter)\n"); return 0; } diff --git a/tests/logging/logging_test.err b/tests/logging/logging_test.err index b59d2e8..c3b67cc 100644 --- a/tests/logging/logging_test.err +++ b/tests/logging/logging_test.err @@ -1,3 +1,3 @@ You should see this You should see this - \ No newline at end of file +log_check_level did not catch this case (filter) -- 1.9.1 From aschultz at tpip.net Tue Nov 17 11:06:17 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:06:17 +0100 Subject: [PATCH 0/3] netns support for gtp-kernel Message-ID: <1447758380-22202-1-git-send-email-aschultz@tpip.net> This is the part from the larger patch that deals with network namespace support only. The debug instrumentation is there to better diagnose cross namespace device setup. The netlink attribute IFLA_NET_NS_FD can be used to specifiy the namespace for the newly create gtp netdevice. In the libgtnl API the netspace filedescriptor is optional. Andreas -- Andreas Schultz (3): gtp: add some debug instrumentation gtp: select netns based on NL attribute gtp-rtnl: and netns support gtp.c | 41 ++++++++++++++++++++++++++++++++++++---- gtp_nl.h | 1 + libgtnl/include/libgtpnl/gtp.h | 2 ++ libgtnl/include/libgtpnl/gtpnl.h | 2 +- libgtnl/include/linux/gtp_nl.h | 1 + libgtnl/src/gtp-genl.c | 2 ++ libgtnl/src/gtp-rtnl.c | 4 +++- libgtnl/src/gtp.c | 12 ++++++++++++ libgtnl/src/internal.h | 1 + libgtnl/src/libgtpnl.map | 2 ++ 10 files changed, 62 insertions(+), 6 deletions(-) -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:06:20 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:06:20 +0100 Subject: [PATCH 3/3] gtp-rtnl: and netns support In-Reply-To: <1447758380-22202-1-git-send-email-aschultz@tpip.net> References: <1447758380-22202-1-git-send-email-aschultz@tpip.net> Message-ID: <1447758380-22202-4-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- libgtnl/include/libgtpnl/gtp.h | 2 ++ libgtnl/include/libgtpnl/gtpnl.h | 2 +- libgtnl/include/linux/gtp_nl.h | 1 + libgtnl/src/gtp-genl.c | 2 ++ libgtnl/src/gtp-rtnl.c | 4 +++- libgtnl/src/gtp.c | 12 ++++++++++++ libgtnl/src/internal.h | 1 + libgtnl/src/libgtpnl.map | 2 ++ 8 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libgtnl/include/libgtpnl/gtp.h b/libgtnl/include/libgtpnl/gtp.h index 10b34d5..fa09d2a 100644 --- a/libgtnl/include/libgtpnl/gtp.h +++ b/libgtnl/include/libgtpnl/gtp.h @@ -8,6 +8,7 @@ struct gtp_tunnel; struct gtp_tunnel *gtp_tunnel_alloc(void); void gtp_tunnel_free(struct gtp_tunnel *t); +void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns); void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx); void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr); void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr); @@ -15,6 +16,7 @@ void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version); void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid); void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid); +const int gtp_tunnel_get_ifns(struct gtp_tunnel *t); const uint32_t gtp_tunnel_get_ifidx(struct gtp_tunnel *t); const struct in_addr *gtp_tunnel_get_ms_ip4(struct gtp_tunnel *t); const struct in_addr *gtp_tunnel_get_sgsn_ip4(struct gtp_tunnel *t); diff --git a/libgtnl/include/libgtpnl/gtpnl.h b/libgtnl/include/libgtpnl/gtpnl.h index c4faf6c..3d3fd73 100644 --- a/libgtnl/include/libgtpnl/gtpnl.h +++ b/libgtnl/include/libgtpnl/gtpnl.h @@ -16,7 +16,7 @@ int genl_lookup_family(struct mnl_socket *nl, const char *family); struct in_addr; -int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, +int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, int fd0, int fd1); int gtp_dev_config(const char *iface, struct in_addr *net, uint32_t prefix); int gtp_dev_destroy(const char *gtp_ifname); diff --git a/libgtnl/include/linux/gtp_nl.h b/libgtnl/include/linux/gtp_nl.h index 0a28046..a8fdf3a 100644 --- a/libgtnl/include/linux/gtp_nl.h +++ b/libgtnl/include/linux/gtp_nl.h @@ -40,6 +40,7 @@ enum gtp_attrs { GTPA_SGSN_ADDRESS, GTPA_MS_ADDRESS, GTPA_FLOWID, /* only for GTPv0 */ + GTPA_NET_NS_FD, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c index c1f60ab..9e68a30 100644 --- a/libgtnl/src/gtp-genl.c +++ b/libgtnl/src/gtp-genl.c @@ -44,6 +44,8 @@ static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) { mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version); + if (t->ifns > 0) + mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns); mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx); mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); diff --git a/libgtnl/src/gtp-rtnl.c b/libgtnl/src/gtp-rtnl.c index 22b9430..2cd6da9 100644 --- a/libgtnl/src/gtp-rtnl.c +++ b/libgtnl/src/gtp-rtnl.c @@ -104,7 +104,7 @@ static int gtp_dev_talk(struct nlmsghdr *nlh, uint32_t seq) return ret; } -int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, +int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, int fd0, int fd1) { char buf[MNL_SOCKET_BUFFER_SIZE]; @@ -120,6 +120,8 @@ int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, ifm->ifi_change |= IFF_UP; ifm->ifi_flags |= IFF_UP; + if (dest_ns > 0) + mnl_attr_put_u32(nlh, IFLA_NET_NS_FD, dest_ns); mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(real_ifname)); mnl_attr_put_str(nlh, IFLA_IFNAME, gtp_ifname); nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO); diff --git a/libgtnl/src/gtp.c b/libgtnl/src/gtp.c index 4534091..6e3d473 100644 --- a/libgtnl/src/gtp.c +++ b/libgtnl/src/gtp.c @@ -39,6 +39,12 @@ void gtp_tunnel_free(struct gtp_tunnel *t) } EXPORT_SYMBOL(gtp_tunnel_free); +void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns) +{ + t->ifns = ifns; +} +EXPORT_SYMBOL(gtp_tunnel_set_ifns); + void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx) { t->ifidx = ifidx; @@ -75,6 +81,12 @@ void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid) } EXPORT_SYMBOL(gtp_tunnel_set_flowid); +const int gtp_tunnel_get_ifns(struct gtp_tunnel *t) +{ + return t->ifns; +} +EXPORT_SYMBOL(gtp_tunnel_get_ifns); + const uint32_t gtp_tunnel_get_ifidx(struct gtp_tunnel *t) { return t->ifidx; diff --git a/libgtnl/src/internal.h b/libgtnl/src/internal.h index 75b3954..68f0135 100644 --- a/libgtnl/src/internal.h +++ b/libgtnl/src/internal.h @@ -13,6 +13,7 @@ #include struct gtp_tunnel { + int ifns; uint32_t ifidx; struct in_addr ms_addr; struct in_addr sgsn_addr; diff --git a/libgtnl/src/libgtpnl.map b/libgtnl/src/libgtpnl.map index 6e69ef8..2368467 100644 --- a/libgtnl/src/libgtpnl.map +++ b/libgtnl/src/libgtpnl.map @@ -15,12 +15,14 @@ global: gtp_tunnel_alloc; gtp_tunnel_free; + gtp_tunnel_set_ifns; gtp_tunnel_set_ifidx; gtp_tunnel_set_ms_ip4; gtp_tunnel_set_sgsn_ip4; gtp_tunnel_set_version; gtp_tunnel_set_tid; gtp_tunnel_set_flowid; + gtp_tunnel_get_ifns; gtp_tunnel_get_ifidx; gtp_tunnel_get_ms_ip4; gtp_tunnel_get_sgsn_ip4; -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:06:18 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:06:18 +0100 Subject: [PATCH 1/3] gtp: add some debug instrumentation In-Reply-To: <1447758380-22202-1-git-send-email-aschultz@tpip.net> References: <1447758380-22202-1-git-send-email-aschultz@tpip.net> Message-ID: <1447758380-22202-2-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- gtp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gtp.c b/gtp.c index 8782fea..cbe2da1 100644 --- a/gtp.c +++ b/gtp.c @@ -330,6 +330,8 @@ static int gtp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (!gti) goto user; + netdev_dbg(gti->dev, "encap_recv %p\n", sk); + switch (udp_sk(sk)->encap_type) { case UDP_ENCAP_GTP0: netdev_dbg(gti->dev, "received GTP0 packet\n"); @@ -893,6 +895,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, struct socket *sock0, *sock1u; struct sock *sk; + netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1); + sock0 = sockfd_lookup(fd_gtp0, &err); if (sock0 == NULL) { netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0); @@ -918,6 +922,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, goto err2; } + netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u); + gti->sock0 = sock0; gti->sock1u = sock1u; -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:06:19 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:06:19 +0100 Subject: [PATCH 2/3] gtp: select netns based on NL attribute In-Reply-To: <1447758380-22202-1-git-send-email-aschultz@tpip.net> References: <1447758380-22202-1-git-send-email-aschultz@tpip.net> Message-ID: <1447758380-22202-3-git-send-email-aschultz@tpip.net> This permits a split namespace setup where the GTP transport sockets are in one namespace the gtp tunnel interface is in another namespace. The target namespece is selected by the new GTPA_NET_NS_FD NL attributes. It fall back to the netns of the GTP-U sockets if the NL attr is not present. Signed-off-by: Andreas Schultz --- gtp.c | 35 +++++++++++++++++++++++++++++++---- gtp_nl.h | 1 + 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/gtp.c b/gtp.c index cbe2da1..0a45f53 100644 --- a/gtp.c +++ b/gtp.c @@ -740,7 +740,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - struct gtp_net *gn = net_generic(src_net, gtp_net_id); + struct gtp_net *gn; struct net_device *real_dev; struct gtp_instance *gti; int hashsize, err, fd0, fd1; @@ -780,6 +780,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, if (err < 0) goto err1; + gn = net_generic(dev_net(dev), gtp_net_id); list_add_rcu(>i->list, &gn->gtp_instance_list); netdev_dbg(dev, "registered new interface\n"); @@ -847,6 +848,19 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = { .fill_info = gtp_fill_info, }; +static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[]) +{ + struct net *net; + /* Examine the link attributes and figure out which + * network namespace we are talking about. + */ + if (tb[GTPA_NET_NS_FD]) + net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD])); + else + net = get_net(src_net); + return net; +} + static int gtp_hashtable_new(struct gtp_instance *gti, int hsize) { int i; @@ -1065,7 +1079,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct net_device *dev; if (!info->attrs[GTPA_VERSION] || @@ -1075,6 +1089,10 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) !info->attrs[GTPA_TID]) return -EINVAL; + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (IS_ERR(net)) + return -EINVAL; + /* Check if there's an existing gtpX device to configure */ dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) @@ -1085,7 +1103,7 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct gtp_instance *gti; struct net_device *dev; struct pdp_ctx *pctx; @@ -1113,6 +1131,10 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) if (gtp_version == GTP_V1 && tid > UINT_MAX) return -EINVAL; + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (IS_ERR(net)) + return -EINVAL; + /* Check if there's an existing gtpX device to configure */ dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) @@ -1181,7 +1203,7 @@ nla_put_failure: static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct net_device *dev; struct gtp_instance *gti; struct pdp_ctx *pctx = NULL; @@ -1202,6 +1224,10 @@ static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (IS_ERR(net)) + return -EINVAL; + /* Check if there's an existing gtpX device to configure */ dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); if (dev == NULL) @@ -1310,6 +1336,7 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { [GTPA_SGSN_ADDRESS] = { .type = NLA_NESTED, }, [GTPA_MS_ADDRESS] = { .type = NLA_NESTED, }, [GTPA_FLOW] = { .type = NLA_U16, }, + [GTPA_NET_NS_FD] = { .type = NLA_U32, }, }; static const struct genl_ops gtp_genl_ops[] = { diff --git a/gtp_nl.h b/gtp_nl.h index 7bdd2f5..c20666d 100644 --- a/gtp_nl.h +++ b/gtp_nl.h @@ -40,6 +40,7 @@ enum gtp_attrs { GTPA_SGSN_ADDRESS, GTPA_MS_ADDRESS, GTPA_FLOW, + GTPA_NET_NS_FD, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:22:45 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:22:45 +0100 Subject: [PATCH openggsn 4/4] ggsn: add network namespace support In-Reply-To: <1447759365-24099-1-git-send-email-aschultz@tpip.net> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> Message-ID: <1447759365-24099-5-git-send-email-aschultz@tpip.net> The kernel gtp can now be create in an existing sub namespace. Signed-off-by: Andreas Schultz --- ggsn/cmdline.c | 41 ++++++++++++++--- ggsn/cmdline.ggo | 1 + ggsn/cmdline.h | 8 +++- ggsn/ggsn.c | 19 +++++++- ggsn/gtp-kernel.c | 33 ++++++++++--- ggsn/gtp-kernel.h | 6 ++- lib/Makefile.am | 4 +- lib/netns.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/netns.h | 26 +++++++++++ 9 files changed, 255 insertions(+), 18 deletions(-) create mode 100644 lib/netns.c create mode 100644 lib/netns.h diff --git a/ggsn/cmdline.c b/ggsn/cmdline.c index a4c25d8..a7572af 100644 --- a/ggsn/cmdline.c +++ b/ggsn/cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.5 + File autogenerated by gengetopt version 2.22.6 generated with the following command: gengetopt --conf-parser @@ -29,6 +29,8 @@ const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTIONS]..."; +const char *gengetopt_args_info_versiontext = ""; + const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { @@ -37,8 +39,8 @@ const char *gengetopt_args_info_help[] = { " -f, --fg Run in foreground (default=off)", " -d, --debug Run in debug mode (default=off)", " -c, --conf=STRING Read configuration file (default=`/etc/ggsn.conf')", - " --pidfile=STRING Filename of process id file \n (default=`/var/run/ggsn.pid')", - " --statedir=STRING Directory of nonvolatile data \n (default=`/var/lib/ggsn/')", + " --pidfile=STRING Filename of process id file\n (default=`/var/run/ggsn.pid')", + " --statedir=STRING Directory of nonvolatile data\n (default=`/var/lib/ggsn/')", " -l, --listen=STRING Local interface", " -n, --net=STRING Network (default=`192.168.0.0/24')", " --ipup=STRING Script to run after link-up", @@ -53,6 +55,7 @@ const char *gengetopt_args_info_help[] = { " --logfile=STRING Logfile for errors", " --loglevel=STRING Global log ldevel (default=`error')", " -g, --gtpnl=STRING GTP kernel support (default=`eth0')", + " --gtpns=STRING Namespace for GTP interface", 0 }; @@ -123,6 +126,7 @@ void clear_given (struct gengetopt_args_info *args_info) args_info->logfile_given = 0 ; args_info->loglevel_given = 0 ; args_info->gtpnl_given = 0 ; + args_info->gtpns_given = 0 ; } static @@ -165,6 +169,8 @@ void clear_args (struct gengetopt_args_info *args_info) args_info->loglevel_orig = NULL; args_info->gtpnl_arg = gengetopt_strdup ("eth0"); args_info->gtpnl_orig = NULL; + args_info->gtpns_arg = NULL; + args_info->gtpns_orig = NULL; } @@ -193,7 +199,8 @@ void init_args_info(struct gengetopt_args_info *args_info) args_info->qos_help = gengetopt_args_info_help[17] ; args_info->logfile_help = gengetopt_args_info_help[18] ; args_info->loglevel_help = gengetopt_args_info_help[19] ; - args_info->gtpnl_help = gengetopt_args_info_help[19] ; + args_info->gtpnl_help = gengetopt_args_info_help[20] ; + args_info->gtpns_help = gengetopt_args_info_help[21] ; } @@ -203,6 +210,9 @@ cmdline_parser_print_version (void) printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); + + if (strlen(gengetopt_args_info_versiontext) > 0) + printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { @@ -306,6 +316,8 @@ cmdline_parser_release (struct gengetopt_args_info *args_info) free_string_field (&(args_info->loglevel_orig)); free_string_field (&(args_info->gtpnl_arg)); free_string_field (&(args_info->gtpnl_orig)); + free_string_field (&(args_info->gtpns_arg)); + free_string_field (&(args_info->gtpns_orig)); @@ -378,6 +390,8 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) write_into_file(outfile, "loglevel", args_info->loglevel_orig, 0); if (args_info->gtpnl_given) write_into_file(outfile, "gtpnl", args_info->gtpnl_orig, 0); + if (args_info->gtpns_given) + write_into_file(outfile, "gtpns", args_info->gtpns_orig, 0); i = EXIT_SUCCESS; @@ -602,7 +616,7 @@ cmdline_parser_internal ( { int c; /* Character of the parsed option. */ - int error = 0; + int error_occurred = 0; struct gengetopt_args_info local_args_info; int override; @@ -653,6 +667,7 @@ cmdline_parser_internal ( { "logfile", 1, NULL, 0 }, { "loglevel", 1, NULL, 0 }, { "gtpnl", 1, NULL, 'g' }, + { "gtpns", 1, NULL, 0 }, { 0, 0, 0, 0 } }; @@ -920,6 +935,20 @@ cmdline_parser_internal ( goto failure; } + /* Namespace for GTP interface. */ + else if (strcmp (long_options[option_index].name, "gtpns") == 0) + { + + + if (update_arg( (void *)&(args_info->gtpns_arg), + &(args_info->gtpns_orig), &(args_info->gtpns_given), + &(local_args_info.gtpns_given), optarg, 0, 0, ARG_STRING, + check_ambiguity, override, 0, 0, + "gtpns", '-', + additional_error)) + goto failure; + + } break; case '?': /* Invalid option. */ @@ -937,7 +966,7 @@ cmdline_parser_internal ( cmdline_parser_release (&local_args_info); - if ( error ) + if ( error_occurred ) return (EXIT_FAILURE); return 0; diff --git a/ggsn/cmdline.ggo b/ggsn/cmdline.ggo index 47ff102..a7d876c 100644 --- a/ggsn/cmdline.ggo +++ b/ggsn/cmdline.ggo @@ -35,4 +35,5 @@ option "logfile" - "Logfile for errors" string no option "loglevel" - "Global log ldevel" string default="error" no option "gtpnl" g "GTP kernel support" string default="eth0" no +option "gtpns" - "Namespace for GTP interface" string no diff --git a/ggsn/cmdline.h b/ggsn/cmdline.h index 150fb4d..77d60c2 100644 --- a/ggsn/cmdline.h +++ b/ggsn/cmdline.h @@ -1,6 +1,6 @@ /** @file cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.5 + * generated by GNU Gengetopt version 2.22.6 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt by Lorenzo Bettini */ @@ -98,6 +98,9 @@ struct gengetopt_args_info char * gtpnl_arg; /**< @brief GTP kernel support (default='eth0'). */ char * gtpnl_orig; /**< @brief GTP kernel support original value given at command line. */ const char *gtpnl_help; /**< @brief GTP kernel support help description. */ + char * gtpns_arg; /**< @brief Namespace for GTP interface. */ + char * gtpns_orig; /**< @brief Namespace for GTP interface original value given at command line. */ + const char *gtpns_help; /**< @brief Namespace for GTP interface help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ @@ -120,6 +123,7 @@ struct gengetopt_args_info unsigned int logfile_given ; /**< @brief Whether logfile was given. */ unsigned int loglevel_given ; /**< @brief Whether loglevel was given. */ unsigned int gtpnl_given ; /**< @brief Whether gtpnl was given. */ + unsigned int gtpns_given ; /**< @brief Whether gtpns was given. */ } ; @@ -137,6 +141,8 @@ struct cmdline_parser_params extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; +/** @brief the description string of the program */ +extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 9e8e213..f823552 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -48,6 +48,7 @@ #include +#include "../lib/netns.h" #include "../lib/tun.h" #include "../lib/ippool.h" #include "../lib/syserr.h" @@ -59,6 +60,8 @@ int end = 0; int maxfd = 0; /* For select() */ +int gtp_ns = 0; + struct in_addr listen_; struct in_addr netaddr, destaddr, net, mask; /* Network interface */ struct in_addr dns1, dns2; /* PCO DNS address */ @@ -262,6 +265,8 @@ int main(int argc, char **argv) printf("statedir: %s\n", args_info.statedir_arg); if (args_info.gtpnl_arg) printf("gtpnl: %s\n", args_info.gtpnl_arg); + if (args_info.gtpns_arg) + printf("gtpns: %s\n", args_info.gtpns_arg); printf("timelimit: %d\n", args_info.timelimit_arg); } @@ -324,6 +329,8 @@ int main(int argc, char **argv) printf("statedir: %s\n", args_info.statedir_arg); if (args_info.gtpnl_arg) printf("gtpnl: %s\n", args_info.gtpnl_arg); + if (args_info.gtpns_arg) + printf("gtpns: %s\n", args_info.gtpns_arg); printf("timelimit: %d\n", args_info.timelimit_arg); } @@ -506,6 +513,16 @@ int main(int argc, char **argv) log_pid(args_info.pidfile_arg); } + init_netns(); + if (args_info.gtpns_arg) { + DEBUGP(DGGSN, "gtpclient: Initialising Network Namespace\n"); + + if ((gtp_ns = get_nsfd(args_info.gtpns_arg)) <= 0) { + SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to initialize network namespace"); + exit(1); + } + } + DEBUGP(DGGSN, "gtpclient: Initialising GTP tunnel\n"); if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) { @@ -520,7 +537,7 @@ int main(int argc, char **argv) maxfd = gsn->fd1u; /* use GTP kernel module for data packet encapsulation */ - if (gtp_kernel_init(gsn, &net, &mask, &args_info) < 0) + if (gtp_kernel_init(gtp_ns, gsn, &net, &mask, &args_info) < 0) goto err; gtp_set_cb_data_ind(gsn, encaps_tun); diff --git a/ggsn/gtp-kernel.c b/ggsn/gtp-kernel.c index 487ae35..3dabdb4 100644 --- a/ggsn/gtp-kernel.c +++ b/ggsn/gtp-kernel.c @@ -23,6 +23,7 @@ #include +#include "../lib/netns.h" #include "../lib/tun.h" #include "../lib/syserr.h" #include "../gtp/pdp.h" @@ -82,6 +83,8 @@ static int mask2prefix(struct in_addr *mask) } static struct { + int ns; + int ifidx; int genl_id; struct mnl_socket *nl; bool enabled; @@ -90,21 +93,27 @@ static struct { /* Always forces the kernel to allocate gtp0. If it exists it hits EEXIST */ #define GTP_DEVNAME "gtp0" -int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, +int gtp_kernel_init(int ns, + struct gsn_t *gsn, struct in_addr *net, struct in_addr *mask, struct gengetopt_args_info *args_info) { + unsigned int ret = 0; + sigset_t oldmask; + if (!args_info->gtpnl_given) return 0; - if (gtp_dev_create(GTP_DEVNAME, args_info->gtpnl_orig, + if (gtp_dev_create(ns, GTP_DEVNAME, args_info->gtpnl_orig, gsn->fd0, gsn->fd1u) < 0) { SYS_ERR(DGGSN, LOGL_ERROR, 0, "cannot create GTP tunnel device: %s\n", strerror(errno)); return -1; } + gtp_nl.enabled = true; + gtp_nl.ns = ns; gtp_nl.nl = genl_socket_open(); if (gtp_nl.nl == NULL) { @@ -127,6 +136,12 @@ int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, DEBUGP(DGGSN, "Setting route to reach %s via %s\n", args_info->net_arg, GTP_DEVNAME); + /* configure gtp dev in it's own namespace */ + if (ns > 0) + switch_ns(ns, &oldmask); + + gtp_nl.ifidx = if_nametoindex(GTP_DEVNAME); + if (gtp_dev_config(GTP_DEVNAME, net, mask2prefix(mask)) < 0) { SYS_ERR(DGGSN, LOGL_ERROR, 0, "Cannot add route to reach network %s\n", @@ -151,12 +166,16 @@ int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, if (err < 0) { SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to launch script `%s'", ipup); - return -1; + ret = -1; } } + + if (ns > 0) + restore_ns(&oldmask); + SYS_ERR(DGGSN, LOGL_NOTICE, 0, "GTP kernel configured\n"); - return 0; + return ret; } void gtp_kernel_stop(void) @@ -185,7 +204,8 @@ int gtp_kernel_tunnel_add(struct pdp_t *pdp) memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr)); memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr)); - gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME)); + gtp_tunnel_set_ifns(t, gtp_nl.ns); + gtp_tunnel_set_ifidx(t, gtp_nl.ifidx); gtp_tunnel_set_version(t, pdp->version); gtp_tunnel_set_ms_ip4(t, &ms); gtp_tunnel_set_sgsn_ip4(t, &sgsn); @@ -216,7 +236,8 @@ int gtp_kernel_tunnel_del(struct pdp_t *pdp) if (t == NULL) return -1; - gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME)); + gtp_tunnel_set_ifns(t, gtp_nl.ns); + gtp_tunnel_set_ifidx(t, gtp_nl.ifidx); gtp_tunnel_set_version(t, pdp->version); if (pdp->version == 0) { gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi)); diff --git a/ggsn/gtp-kernel.h b/ggsn/gtp-kernel.h index 628002f..ce636a9 100644 --- a/ggsn/gtp-kernel.h +++ b/ggsn/gtp-kernel.h @@ -7,7 +7,8 @@ extern int debug; extern char *ipup; #ifdef GTP_KERNEL -int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, +int gtp_kernel_init(int ns, + struct gsn_t *gsn, struct in_addr *net, struct in_addr *mask, struct gengetopt_args_info *args_info); void gtp_kernel_stop(void); @@ -18,7 +19,8 @@ int gtp_kernel_tunnel_del(struct pdp_t *pdp); int gtp_kernel_enabled(void); #else -static inline int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, +static inline int gtp_kernel_init(int ns, + struct gsn_t *gsn, struct in_addr *net, struct in_addr *mask, struct gengetopt_args_info *args_info) { diff --git a/lib/Makefile.am b/lib/Makefile.am index 756d566..54c8953 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,7 +1,7 @@ noinst_LIBRARIES = libmisc.a -noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h +noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h netns.h AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) -libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c +libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c netns.c diff --git a/lib/netns.c b/lib/netns.c new file mode 100644 index 0000000..29f2536 --- /dev/null +++ b/lib/netns.c @@ -0,0 +1,135 @@ +/* + * NETNS functions. + * Copyright (C) 2014, 2015 Travelping GmbH + * + * The contents of this file may be used under the terms of the GNU + * General Public License Version 2, provided that the above copyright + * notice and this permission notice is included in all copies or + * substantial portions of the software. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netns.h" + +#define NETNS_PATH "/var/run/netns" + +int default_nsfd; + +int switch_ns(int nsfd, sigset_t *oldmask) +{ + sigset_t intmask; + + sigfillset(&intmask); + sigprocmask(SIG_BLOCK, &intmask, oldmask); + + return setns(nsfd, CLONE_NEWNET); +} + +void restore_ns(sigset_t *oldmask) +{ + setns(default_nsfd, CLONE_NEWNET); + + sigprocmask(SIG_SETMASK, oldmask, NULL); +} + +int open_ns(int nsfd, const char *pathname, int flags) +{ + sigset_t intmask, oldmask; + int fd; + int errsv; + + sigfillset(&intmask); + sigprocmask(SIG_BLOCK, &intmask, &oldmask); + + setns(nsfd, CLONE_NEWNET); + fd = open(pathname, flags); + errsv = errno; + setns(default_nsfd, CLONE_NEWNET); + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + + errno = errsv; + return fd; +} + +int socket_ns(int nsfd, int domain, int type, int protocol) +{ + sigset_t intmask, oldmask; + int sk; + int errsv; + + sigfillset(&intmask); + sigprocmask(SIG_BLOCK, &intmask, &oldmask); + + setns(nsfd, CLONE_NEWNET); + sk = socket(domain, type, protocol); + errsv = errno; + setns(default_nsfd, CLONE_NEWNET); + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + + errno = errsv; + return sk; +} + +void init_netns() +{ + if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0) { + perror("init_netns"); + exit(EXIT_FAILURE); + } +} + +int get_nsfd(const char *name) +{ + int r; + sigset_t intmask, oldmask; + char path[MAXPATHLEN] = NETNS_PATH; + + r = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); + if (r < 0 && errno != EEXIST) + return r; + + snprintf(path, sizeof(path), "%s/%s", NETNS_PATH, name); + r = open(path, O_RDONLY|O_CREAT|O_EXCL, 0); + if (r < 0) { + if (errno == EEXIST) + return open(path, O_RDONLY); + + return r; + } + close(r); + + sigfillset(&intmask); + sigprocmask(SIG_BLOCK, &intmask, &oldmask); + + unshare(CLONE_NEWNET); + mount("/proc/self/ns/net", path, "none", MS_BIND, NULL); + + setns(default_nsfd, CLONE_NEWNET); + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + + return open(path, O_RDONLY); +} diff --git a/lib/netns.h b/lib/netns.h new file mode 100644 index 0000000..1b646c9 --- /dev/null +++ b/lib/netns.h @@ -0,0 +1,26 @@ +/* + * NETNS functions. + * Copyright (C) 2014, 2015 Travelping GmbH + * + * The contents of this file may be used under the terms of the GNU + * General Public License Version 2, provided that the above copyright + * notice and this permission notice is included in all copies or + * substantial portions of the software. + * + */ + +#ifndef __NETNS_H +#define __NETNS_H + +extern int default_nsfd; + +void init_netns(void); + +int switch_ns(int nsfd, sigset_t *oldmask); +void restore_ns(sigset_t *oldmask); + +int open_ns(int nsfd, const char *pathname, int flags); +int socket_ns(int nsfd, int domain, int type, int protocol); +int get_nsfd(const char *name); + +#endif -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:22:42 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:22:42 +0100 Subject: [PATCH openggsn 1/4] ggsn: add support for GTP kernel data encapsulation In-Reply-To: <1447759365-24099-1-git-send-email-aschultz@tpip.net> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> Message-ID: <1447759365-24099-2-git-send-email-aschultz@tpip.net> From: Pablo Neira Ayuso This patch adds the -g, --gtpnl=device option that allows you to enable the GTP kernel tunneling mode in openggsn. You have to specify the real downlink device that will be used to tunnel traffic, eg. -g=eth0 This means that the gtp0 device will be created and it will use eth0 as the real device to encapsulate packet coming from the Internet that are addressed to the MS (so the tunnel devuce encapsulates these IP packets in GTP packets when traveling to the SGSN). Alternatively, you can also add this to the ggsn.conf configuration file: gtpnl eth0 The device has to be the real device that can route packets to the SGSN, if you select the wrong device, the kernel routing code may not find a way to reach the SSGN, you've been warned. Therefore, if this option is set, the operational becomes the following: 1) A gtp0 device is created via rtnetlink and configure the socket encapsulation infrastructure in the kernel. 2) Whenever a PDP context is created, this adds the necessary tunnel configuration via genetlink GTP interface. 3) Whenever a PDP context is destroyed, this deletes the tunnel via genetlink GTP interface. 4) Destroy the gtp0 device if ggsn is stopped, including all of the existing tunnels. You require the osmo-ggsn.git tree, which contains the kernel module gtp.ko and the libgtpnl library that you have to compile and install. Make sure you have loaded the gtp.ko kernel module before launching the ggsn daemon using the kernel driver mode, otherwise you will get a nice "operation not supported" error message ;-). This patch also adds supports for "ipup" configuration option to invoke an external script after the gtp0 device has been brought up. Typical command to add the route to reach the MS behind the GGSN is required, eg. ip route add 10.0.0.0/8 dev gtp0. The (horrible) ggsn parser has been manually extended to support the new configuration option. That code doesn't look nice, but it just mimics what we already have there for consistency, please don't blame me for that. If you want to run in debugging mode, I suggest you to use: sudo ggsn -c ggsn.conf -f -d Note that you do have to run openggsn as root to bring up the gtp0 device. You have to see this message that announce that the GTP kernel mode is enabled. openggsn[1106]: ggsn.c: 656: Using the GTP kernel mode (genl ID is 25) This patch also automagically sets up route to reach MS from Internet just like tun mode does. This is fundamental to get this working, better don't leave to the admin, he may forget to add this route. In this patch, I tried to encapsulate this new feature as much as possible as Harald initially suggested. To compile this feature, you have to pass --enable-gtp-kernel, ie. ./configire --enable-gtp-kernel Otherwise, the code to interact with the gtp kernel part is not compiled. Signed-off-by: Andreas Schultz --- configure.ac | 15 ++++ ggsn/Makefile.am | 11 ++- ggsn/cmdline.c | 39 ++++++--- ggsn/cmdline.ggo | 3 + ggsn/cmdline.h | 8 +- ggsn/ggsn.c | 35 +++++++- ggsn/gtp-kernel.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ggsn/gtp-kernel.h | 51 ++++++++++++ 8 files changed, 384 insertions(+), 18 deletions(-) create mode 100644 ggsn/gtp-kernel.c create mode 100644 ggsn/gtp-kernel.h diff --git a/configure.ac b/configure.ac index e31a79e..1fad6b1 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,17 @@ AC_SUBST(EXEC_LDADD) # FIXME: Replace `main' with a function in `-links': #AC_CHECK_LIB([inks], [main]) +dnl GTP kernel dependencies +AC_ARG_ENABLE([gtp-kernel], + AS_HELP_STRING([--enable-gtp-kernel], [Build GTP tunneling kernel]), + [enable_gtp_kernel="$enableval"], [enable_gtp_kernel="no"]) + +if test "x$enable_gtp_kernel" = "xyes"; then + PKG_CHECK_MODULES([LIBGTPNL], [libgtpnl >= 1.0.0]) +fi + +AM_CONDITIONAL([ENABLE_GTP_KERNEL], [test "$enable_gtp_kernel" = "yes"]) + # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT @@ -119,3 +130,7 @@ AC_CONFIG_FILES([Makefile libgtp.pc openggsn.spec]) AC_OUTPUT + +echo " +openggsn Configuration: + GTP kernel support: ${enable_gtp_kernel}" diff --git a/ggsn/Makefile.am b/ggsn/Makefile.am index 91df8f0..c8868c1 100644 --- a/ggsn/Makefile.am +++ b/ggsn/Makefile.am @@ -4,7 +4,16 @@ AM_LDFLAGS = @EXEC_LDFLAGS@ AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) +if ENABLE_GTP_KERNEL +AM_CFLAGS += -DGTP_KERNEL +ggsn_LDADD = @EXEC_LDADD@ -lgtp -lgtpnl -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) +else ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) +endif + ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a -ggsn_SOURCES = ggsn.c cmdline.c cmdline.h +ggsn_SOURCES = ggsn.c cmdline.c cmdline.h gtp-kernel.h +if ENABLE_GTP_KERNEL +ggsn_SOURCES += gtp-kernel.c +endif diff --git a/ggsn/cmdline.c b/ggsn/cmdline.c index 37ed992..a4c25d8 100644 --- a/ggsn/cmdline.c +++ b/ggsn/cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.6 + File autogenerated by gengetopt version 2.22.5 generated with the following command: gengetopt --conf-parser @@ -29,8 +29,6 @@ const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTIONS]..."; -const char *gengetopt_args_info_versiontext = ""; - const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { @@ -39,8 +37,8 @@ const char *gengetopt_args_info_help[] = { " -f, --fg Run in foreground (default=off)", " -d, --debug Run in debug mode (default=off)", " -c, --conf=STRING Read configuration file (default=`/etc/ggsn.conf')", - " --pidfile=STRING Filename of process id file\n (default=`/var/run/ggsn.pid')", - " --statedir=STRING Directory of nonvolatile data\n (default=`/var/lib/ggsn/')", + " --pidfile=STRING Filename of process id file \n (default=`/var/run/ggsn.pid')", + " --statedir=STRING Directory of nonvolatile data \n (default=`/var/lib/ggsn/')", " -l, --listen=STRING Local interface", " -n, --net=STRING Network (default=`192.168.0.0/24')", " --ipup=STRING Script to run after link-up", @@ -54,6 +52,7 @@ const char *gengetopt_args_info_help[] = { " -q, --qos=INT Requested quality of service (default=`0x0b921f')", " --logfile=STRING Logfile for errors", " --loglevel=STRING Global log ldevel (default=`error')", + " -g, --gtpnl=STRING GTP kernel support (default=`eth0')", 0 }; @@ -123,6 +122,7 @@ void clear_given (struct gengetopt_args_info *args_info) args_info->qos_given = 0 ; args_info->logfile_given = 0 ; args_info->loglevel_given = 0 ; + args_info->gtpnl_given = 0 ; } static @@ -163,6 +163,8 @@ void clear_args (struct gengetopt_args_info *args_info) args_info->logfile_orig = NULL; args_info->loglevel_arg = gengetopt_strdup ("error"); args_info->loglevel_orig = NULL; + args_info->gtpnl_arg = gengetopt_strdup ("eth0"); + args_info->gtpnl_orig = NULL; } @@ -191,6 +193,7 @@ void init_args_info(struct gengetopt_args_info *args_info) args_info->qos_help = gengetopt_args_info_help[17] ; args_info->logfile_help = gengetopt_args_info_help[18] ; args_info->loglevel_help = gengetopt_args_info_help[19] ; + args_info->gtpnl_help = gengetopt_args_info_help[19] ; } @@ -200,9 +203,6 @@ cmdline_parser_print_version (void) printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); - - if (strlen(gengetopt_args_info_versiontext) > 0) - printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { @@ -304,6 +304,8 @@ cmdline_parser_release (struct gengetopt_args_info *args_info) free_string_field (&(args_info->logfile_orig)); free_string_field (&(args_info->loglevel_arg)); free_string_field (&(args_info->loglevel_orig)); + free_string_field (&(args_info->gtpnl_arg)); + free_string_field (&(args_info->gtpnl_orig)); @@ -374,6 +376,8 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) write_into_file(outfile, "logfile", args_info->logfile_orig, 0); if (args_info->loglevel_given) write_into_file(outfile, "loglevel", args_info->loglevel_orig, 0); + if (args_info->gtpnl_given) + write_into_file(outfile, "gtpnl", args_info->gtpnl_orig, 0); i = EXIT_SUCCESS; @@ -598,7 +602,7 @@ cmdline_parser_internal ( { int c; /* Character of the parsed option. */ - int error_occurred = 0; + int error = 0; struct gengetopt_args_info local_args_info; int override; @@ -648,10 +652,11 @@ cmdline_parser_internal ( { "qos", 1, NULL, 'q' }, { "logfile", 1, NULL, 0 }, { "loglevel", 1, NULL, 0 }, + { "gtpnl", 1, NULL, 'g' }, { 0, 0, 0, 0 } }; - c = getopt_long (argc, argv, "hVfdc:l:n:a:q:", long_options, &option_index); + c = getopt_long (argc, argv, "hVfdc:l:n:a:q:g:", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ @@ -747,6 +752,18 @@ cmdline_parser_internal ( goto failure; break; + case 'g': /* GTP kernel support. */ + + + if (update_arg( (void *)&(args_info->gtpnl_arg), + &(args_info->gtpnl_orig), &(args_info->gtpnl_given), + &(local_args_info.gtpnl_given), optarg, 0, "eth0", ARG_STRING, + check_ambiguity, override, 0, 0, + "gtpnl", 'g', + additional_error)) + goto failure; + + break; case 0: /* Long option with no short option */ /* Filename of process id file. */ @@ -920,7 +937,7 @@ cmdline_parser_internal ( cmdline_parser_release (&local_args_info); - if ( error_occurred ) + if ( error ) return (EXIT_FAILURE); return 0; diff --git a/ggsn/cmdline.ggo b/ggsn/cmdline.ggo index 9c4c976..47ff102 100644 --- a/ggsn/cmdline.ggo +++ b/ggsn/cmdline.ggo @@ -33,3 +33,6 @@ option "apn" a "Access point name" string default="internet option "qos" q "Requested quality of service" int default="0x0b921f" no option "logfile" - "Logfile for errors" string no option "loglevel" - "Global log ldevel" string default="error" no + +option "gtpnl" g "GTP kernel support" string default="eth0" no + diff --git a/ggsn/cmdline.h b/ggsn/cmdline.h index a87fa4a..150fb4d 100644 --- a/ggsn/cmdline.h +++ b/ggsn/cmdline.h @@ -1,6 +1,6 @@ /** @file cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.6 + * generated by GNU Gengetopt version 2.22.5 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt by Lorenzo Bettini */ @@ -95,6 +95,9 @@ struct gengetopt_args_info char * loglevel_arg; /**< @brief Global log ldevel (default='error'). */ char * loglevel_orig; /**< @brief Global log ldevel original value given at command line. */ const char *loglevel_help; /**< @brief Global log ldevel help description. */ + char * gtpnl_arg; /**< @brief GTP kernel support (default='eth0'). */ + char * gtpnl_orig; /**< @brief GTP kernel support original value given at command line. */ + const char *gtpnl_help; /**< @brief GTP kernel support help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ @@ -116,6 +119,7 @@ struct gengetopt_args_info unsigned int qos_given ; /**< @brief Whether qos was given. */ unsigned int logfile_given ; /**< @brief Whether logfile was given. */ unsigned int loglevel_given ; /**< @brief Whether loglevel was given. */ + unsigned int gtpnl_given ; /**< @brief Whether gtpnl was given. */ } ; @@ -133,8 +137,6 @@ struct cmdline_parser_params extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; -/** @brief the description string of the program */ -extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 53c8c01..821c942 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -54,6 +54,7 @@ #include "../gtp/pdp.h" #include "../gtp/gtp.h" #include "cmdline.h" +#include "gtp-kernel.h" int end = 0; int maxfd = 0; /* For select() */ @@ -134,6 +135,13 @@ int delete_context(struct pdp_t *pdp) ippool_freeip(ippool, (struct ippoolm_t *)pdp->peer); else SYS_ERR(DGGSN, LOGL_ERROR, 0, "Peer not defined!"); + + if (gtp_kernel_tunnel_del(pdp)) { + SYS_ERR(DGGSN, LOGL_ERROR, 0, + "Cannot delete tunnel from kernel: %s\n", + strerror(errno)); + } + return 0; } @@ -167,6 +175,11 @@ int create_context_ind(struct pdp_t *pdp) pdp->ipif = tun; /* TODO */ member->peer = pdp; + if (gtp_kernel_tunnel_add(pdp) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Cannot add tunnel to kernel: %s\n", strerror(errno)); + } + gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ); return 0; /* Success */ } @@ -247,6 +260,8 @@ int main(int argc, char **argv) printf("pidfile: %s\n", args_info.pidfile_arg); if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg); + if (args_info.gtpnl_arg) + printf("gtpnl: %s\n", args_info.gtpnl_arg); printf("timelimit: %d\n", args_info.timelimit_arg); } @@ -307,6 +322,8 @@ int main(int argc, char **argv) printf("pidfile: %s\n", args_info.pidfile_arg); if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg); + if (args_info.gtpnl_arg) + printf("gtpnl: %s\n", args_info.gtpnl_arg); printf("timelimit: %d\n", args_info.timelimit_arg); } @@ -502,10 +519,18 @@ int main(int argc, char **argv) if (gsn->fd1u > maxfd) maxfd = gsn->fd1u; + /* use GTP kernel module for data packet encapsulation */ + if (gtp_kernel_init(gsn, &net, &mask, &args_info) < 0) + goto err; + gtp_set_cb_data_ind(gsn, encaps_tun); gtp_set_cb_delete_context(gsn, delete_context); gtp_set_cb_create_context_ind(gsn, create_context_ind); + /* skip the configuration of the tun0 if we're using the gtp0 device */ + if (gtp_kernel_enabled()) + goto skip_tun; + /* Create a tunnel interface */ DEBUGP(DGGSN, "Creating tun interface\n"); if (tun_new((struct tun_t **)&tun)) { @@ -526,6 +551,8 @@ int main(int argc, char **argv) if (ipup) tun_runscript(tun, ipup); +skip_tun: + /******************************************************************/ /* Main select loop */ /******************************************************************/ @@ -556,7 +583,7 @@ int main(int argc, char **argv) break; } - if (tun->fd != -1 && FD_ISSET(tun->fd, &fds) && + if (tun && tun->fd != -1 && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) { SYS_ERR(DGGSN, LOGL_ERROR, 0, "TUN read failed (fd)=(%d)", tun->fd); @@ -572,11 +599,13 @@ int main(int argc, char **argv) gtp_decaps1u(gsn); } - +err: + gtp_kernel_stop(); cmdline_parser_free(&args_info); ippool_free(ippool); gtp_free(gsn); - tun_free(tun); + if (tun) + tun_free(tun); return 1; diff --git a/ggsn/gtp-kernel.c b/ggsn/gtp-kernel.c new file mode 100644 index 0000000..16e51ac --- /dev/null +++ b/ggsn/gtp-kernel.c @@ -0,0 +1,240 @@ +#ifdef __linux__ +#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */ +#endif + +#include "../config.h" + +#ifdef HAVE_STDINT_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "../lib/tun.h" +#include "../lib/syserr.h" +#include "../gtp/pdp.h" +#include "../gtp/gtp.h" +#include "cmdline.h" + +#include +#include +#include + +#include "gtp-kernel.h" + +static void pdp_debug(struct pdp_t *pdp) +{ + int i; + uint64_t teid; + + if (!debug) + return; + + printf("version %u\n", pdp->version); + if (pdp->version == 0) { + teid = pdp_gettid(pdp->imsi, pdp->nsapi); + printf("flowid %u\n", pdp->flru); + } else { + teid = pdp->teid_gn; /* GTPIE_TEI_DI */ + } + + printf("teid %llx\n", teid); + printf("address (%u)\n", pdp->eua.l); + + /* Byte 0: 0xf1 == IETF */ + /* Byte 1: 0x21 == IPv4 */ + /* Byte 2-6: IPv4 address */ + + for (i = 0; i < 6; i++) + printf("%x ", pdp->eua.v[i] & 0xff); /* GTPIE_EUA */ + + printf("\n"); + printf("sgsn-addr (%u)\n", pdp->gsnrc.l); + + for (i = 0; i < 4; i++) + printf("%x ", pdp->gsnrc.v[i] & 0xff); /* GTPIE_GSN_ADDR */ + + printf("\n"); +} + +static int mask2prefix(struct in_addr *mask) +{ + uint32_t tmp = ntohl(mask->s_addr); + int k; + + for (k=0; tmp > 0; k++) + tmp = (tmp << 1); + + return k; +} + +static struct { + int genl_id; + struct mnl_socket *nl; + bool enabled; +} gtp_nl; + +/* Always forces the kernel to allocate gtp0. If it exists it hits EEXIST */ +#define GTP_DEVNAME "gtp0" + +int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, + struct in_addr *mask, + struct gengetopt_args_info *args_info) +{ + if (!args_info->gtpnl_given) + return 0; + + if (gtp_dev_create(GTP_DEVNAME, args_info->gtpnl_orig, + gsn->fd0, gsn->fd1u) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "cannot create GTP tunnel device: %s\n", + strerror(errno)); + return -1; + } + gtp_nl.enabled = true; + + gtp_nl.nl = genl_socket_open(); + if (gtp_nl.nl == NULL) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "cannot create genetlink socket\n"); + return -1; + } + gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp"); + if (gtp_nl.genl_id < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "cannot lookup GTP genetlink ID\n"); + return -1; + } + if (debug) { + sys_err(LOG_NOTICE, __FILE__, __LINE__, 0, + "Using the GTP kernel mode (genl ID is %d)\n", + gtp_nl.genl_id); + } + + if (debug) { + printf("Setting route to reach %s via %s\n", + args_info->net_arg, GTP_DEVNAME); + } + + if (gtp_dev_config(GTP_DEVNAME, net, mask2prefix(mask)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Cannot add route to reach network %s\n", + args_info->net_arg); + } + + /* launch script if it is set to bring up the route to reach + * the MS, eg. ip ro add 10.0.0.0/8 dev gtp0. Better add this + * using native rtnetlink interface given that we know the + * MS network mask, later. + */ + if (ipup) { + char cmd[1024]; + int err; + + /* eg. /home/ggsn/ipup gtp0 10.0.0.0/8 */ + snprintf(cmd, sizeof(cmd), "%s %s %s", + ipup, GTP_DEVNAME, args_info->net_arg); + cmd[sizeof(cmd)-1] = '\0'; + + err = system(cmd); + if (err < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to launch script `%s'", ipup); + return -1; + } + } + sys_err(LOG_NOTICE, __FILE__, __LINE__, 0, "GTP kernel configured\n"); + + return 0; +} + +void gtp_kernel_stop(void) +{ + if (!gtp_nl.enabled) + return; + + gtp_dev_destroy(GTP_DEVNAME); +} + +int gtp_kernel_tunnel_add(struct pdp_t *pdp) +{ + struct in_addr ms, sgsn; + struct gtp_tunnel *t; + int ret; + + if (!gtp_nl.enabled) + return 0; + + pdp_debug(pdp); + + t = gtp_tunnel_alloc(); + if (t == NULL) + return -1; + + memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr)); + memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr)); + + gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME)); + gtp_tunnel_set_version(t, pdp->version); + gtp_tunnel_set_ms_ip4(t, &ms); + gtp_tunnel_set_sgsn_ip4(t, &sgsn); + if (pdp->version == 0) { + gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi)); + gtp_tunnel_set_flowid(t, pdp->flru); + } else { + gtp_tunnel_set_tid(t, pdp->teid_gn); /* GTPIE_TEI_DI */ + } + + ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t); + gtp_tunnel_free(t); + + return ret; +} + +int gtp_kernel_tunnel_del(struct pdp_t *pdp) +{ + struct gtp_tunnel *t; + int ret; + + if (!gtp_nl.enabled) + return 0; + + pdp_debug(pdp); + + t = gtp_tunnel_alloc(); + if (t == NULL) + return -1; + + gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME)); + gtp_tunnel_set_version(t, pdp->version); + if (pdp->version == 0) { + gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi)); + gtp_tunnel_set_flowid(t, pdp->flru); + } else { + gtp_tunnel_set_tid(t, pdp->teid_gn); /* GTPIE_TEI_DI */ + } + + ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t); + gtp_tunnel_free(t); + + return ret; +} + +int gtp_kernel_enabled(void) +{ + return gtp_nl.enabled; +} diff --git a/ggsn/gtp-kernel.h b/ggsn/gtp-kernel.h new file mode 100644 index 0000000..7bf533d --- /dev/null +++ b/ggsn/gtp-kernel.h @@ -0,0 +1,51 @@ +#ifndef _GTP_KERNEL_H_ +#define _GTP_KERNEL_H_ + +struct gengetopt_args_info; + +extern int debug; +extern char *ipup; + +#ifdef GTP_KERNEL +int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, + struct in_addr *mask, + struct gengetopt_args_info *args_info); +void gtp_kernel_stop(void); + +int gtp_kernel_tunnel_add(struct pdp_t *pdp); +int gtp_kernel_tunnel_del(struct pdp_t *pdp); + +int gtp_kernel_enabled(void); + +#else +static inline int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, + struct in_addr *mask, + struct gengetopt_args_info *args_info) +{ + if (args_info->gtpnl_given) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "ggsn compiled without GTP kernel support!\n"); + return -1; + } + return 0; +} + +static inline void gtp_kernel_stop(void) {} + +static inline int gtp_kernel_tunnel_add(struct pdp_t *pdp) +{ + return 0; +} + +static inline int gtp_kernel_tunnel_del(struct pdp_t *pdp) +{ + return 0; +} + +static inline int gtp_kernel_enabled(void) +{ + return 0; +} + +#endif +#endif /* _GTP_KERNEL_H_ */ -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:22:44 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:22:44 +0100 Subject: [PATCH openggsn 3/4] ggsn: fix autotool pkg-config invokation In-Reply-To: <1447759365-24099-1-git-send-email-aschultz@tpip.net> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> Message-ID: <1447759365-24099-4-git-send-email-aschultz@tpip.net> see https://autotools.io/pkgconfig/pkg_check_modules.html, Optional Modules for explanation Signed-off-by: Andreas Schultz --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 1fad6b1..3f5148a 100644 --- a/configure.ac +++ b/configure.ac @@ -50,9 +50,9 @@ AC_ARG_ENABLE([gtp-kernel], AS_HELP_STRING([--enable-gtp-kernel], [Build GTP tunneling kernel]), [enable_gtp_kernel="$enableval"], [enable_gtp_kernel="no"]) -if test "x$enable_gtp_kernel" = "xyes"; then +AS_IF([test "x$enable_gtp_kernel" = "xyes"], [ PKG_CHECK_MODULES([LIBGTPNL], [libgtpnl >= 1.0.0]) -fi +]) AM_CONDITIONAL([ENABLE_GTP_KERNEL], [test "$enable_gtp_kernel" = "yes"]) -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:22:41 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:22:41 +0100 Subject: [PATCH openggsn 0/4] add and update gtp-kernel support to openggsn Message-ID: <1447759365-24099-1-git-send-email-aschultz@tpip.net> This series imports Pablo Neira Ayuso original gtp-kernel support patch unmodified to master and applies some fixes ontop of it. The last patch in the series then add network namespace support to it. This state is in sync with gtp-kernel patch I posted a few minutes ago. Andreas -- Andreas Schultz (3): ggsn: update gpt-kernel logging to libosmocore ggsn: fix autotool pkg-config invokation ggsn: add network namespace support Pablo Neira Ayuso (1): ggsn: add support for GTP kernel data encapsulation configure.ac | 15 ++++ ggsn/Makefile.am | 11 ++- ggsn/cmdline.c | 48 +++++++++- ggsn/cmdline.ggo | 4 + ggsn/cmdline.h | 8 ++ ggsn/ggsn.c | 52 ++++++++++- ggsn/gtp-kernel.c | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ggsn/gtp-kernel.h | 53 +++++++++++ lib/Makefile.am | 4 +- lib/netns.c | 135 ++++++++++++++++++++++++++++ lib/netns.h | 26 ++++++ 11 files changed, 607 insertions(+), 7 deletions(-) create mode 100644 ggsn/gtp-kernel.c create mode 100644 ggsn/gtp-kernel.h create mode 100644 lib/netns.c create mode 100644 lib/netns.h -- 2.5.0 From aschultz at tpip.net Tue Nov 17 11:22:43 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 12:22:43 +0100 Subject: [PATCH openggsn 2/4] ggsn: update gpt-kernel logging to libosmocore In-Reply-To: <1447759365-24099-1-git-send-email-aschultz@tpip.net> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> Message-ID: <1447759365-24099-3-git-send-email-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- ggsn/ggsn.c | 2 +- ggsn/gtp-kernel.c | 21 +++++++++------------ ggsn/gtp-kernel.h | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 821c942..9e8e213 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -176,7 +176,7 @@ int create_context_ind(struct pdp_t *pdp) member->peer = pdp; if (gtp_kernel_tunnel_add(pdp) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_ERROR, 0, "Cannot add tunnel to kernel: %s\n", strerror(errno)); } diff --git a/ggsn/gtp-kernel.c b/ggsn/gtp-kernel.c index 16e51ac..487ae35 100644 --- a/ggsn/gtp-kernel.c +++ b/ggsn/gtp-kernel.c @@ -8,7 +8,6 @@ #include #endif -#include #include #include #include @@ -100,7 +99,7 @@ int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, if (gtp_dev_create(GTP_DEVNAME, args_info->gtpnl_orig, gsn->fd0, gsn->fd1u) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_ERROR, 0, "cannot create GTP tunnel device: %s\n", strerror(errno)); return -1; @@ -109,29 +108,27 @@ int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, gtp_nl.nl = genl_socket_open(); if (gtp_nl.nl == NULL) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_ERROR, 0, "cannot create genetlink socket\n"); return -1; } gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp"); if (gtp_nl.genl_id < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_ERROR, 0, "cannot lookup GTP genetlink ID\n"); return -1; } if (debug) { - sys_err(LOG_NOTICE, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_NOTICE, 0, "Using the GTP kernel mode (genl ID is %d)\n", gtp_nl.genl_id); } - if (debug) { - printf("Setting route to reach %s via %s\n", - args_info->net_arg, GTP_DEVNAME); - } + DEBUGP(DGGSN, "Setting route to reach %s via %s\n", + args_info->net_arg, GTP_DEVNAME); if (gtp_dev_config(GTP_DEVNAME, net, mask2prefix(mask)) < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_ERROR, 0, "Cannot add route to reach network %s\n", args_info->net_arg); } @@ -152,12 +149,12 @@ int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, err = system(cmd); if (err < 0) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to launch script `%s'", ipup); return -1; } } - sys_err(LOG_NOTICE, __FILE__, __LINE__, 0, "GTP kernel configured\n"); + SYS_ERR(DGGSN, LOGL_NOTICE, 0, "GTP kernel configured\n"); return 0; } diff --git a/ggsn/gtp-kernel.h b/ggsn/gtp-kernel.h index 7bf533d..628002f 100644 --- a/ggsn/gtp-kernel.h +++ b/ggsn/gtp-kernel.h @@ -23,7 +23,7 @@ static inline int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net, struct gengetopt_args_info *args_info) { if (args_info->gtpnl_given) { - sys_err(LOG_ERR, __FILE__, __LINE__, 0, + SYS_ERR(DGGSN, LOGL_ERROR, 0, "ggsn compiled without GTP kernel support!\n"); return -1; } -- 2.5.0 From nhofmeyr at sysmocom.de Tue Nov 17 11:51:55 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 12:51:55 +0100 Subject: [PATCH 2/3] gtphub: fix fatal log msg for SGSN proxy. In-Reply-To: <1447761116-7633-1-git-send-email-nhofmeyr@sysmocom.de> References: <1447761116-7633-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1447761116-7633-2-git-send-email-nhofmeyr@sysmocom.de> While reworking the logging, a stray comma found its way into the code. Fixes coverity 1339765. Sponsored-by: On-Waves ehi --- openbsc/src/gprs/gtphub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index 049e9f5..406d60d 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -1878,7 +1878,7 @@ int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg) &hub->to_sgsns[plane_idx], &cfg->sgsn_proxy[plane_idx]) != 0) { - LOG(LOGL_FATAL, "Cannot configure SGSN proxy", + LOG(LOGL_FATAL, "Cannot configure SGSN proxy" " %s port %d.\n", cfg->sgsn_proxy[plane_idx].addr_str, (int)cfg->sgsn_proxy[plane_idx].port); -- 2.1.4 From nhofmeyr at sysmocom.de Tue Nov 17 11:51:54 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 12:51:54 +0100 Subject: [PATCH 1/3] gtphub: fix gtphub_read() semantics. Message-ID: <1447761116-7633-1-git-send-email-nhofmeyr@sysmocom.de> gtphub always wants to know the sender, hence make the from_addr pointer mandatory. Fixes two coverity complaints (1339766, 1339764). Sponsored-by: On-Waves ehi --- openbsc/src/gprs/gtphub.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index e00d6cd..049e9f5 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -784,16 +784,16 @@ static int gtphub_bind_start(struct gtphub_bind *b, return 0; } -/* Recv datagram from from->fd, optionally write sender's address to *from_addr. +/* Recv datagram from from->fd, write sender's address to *from_addr. * Return the number of bytes read, zero on error. */ static int gtphub_read(const struct osmo_fd *from, struct osmo_sockaddr *from_addr, uint8_t *buf, size_t buf_len) { - /* recvfrom requires the available length set in *from_addr_len. */ - if (from_addr) - from_addr->l = sizeof(from_addr->a); + OSMO_ASSERT(from_addr); + /* recvfrom requires the available length set in *from_addr_len. */ + from_addr->l = sizeof(from_addr->a); errno = 0; ssize_t received = recvfrom(from->fd, buf, buf_len, 0, (struct sockaddr*)&from_addr->a, @@ -807,12 +807,10 @@ static int gtphub_read(const struct osmo_fd *from, return 0; } - if (from_addr) { - LOG(LOGL_DEBUG, "from %s\n", osmo_sockaddr_to_str(from_addr)); - } + LOG(LOGL_DEBUG, "Received %d bytes from %s\n%s\n", + (int)received, osmo_sockaddr_to_str(from_addr), + osmo_hexdump(buf, received)); - LOG(LOGL_DEBUG, "Received %d %s\n", - (int)received, osmo_hexdump(buf, received)); return received; } -- 2.1.4 From nhofmeyr at sysmocom.de Tue Nov 17 11:51:56 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 12:51:56 +0100 Subject: [PATCH 3/3] gtphub: fix three oversights (thanks to coverity). In-Reply-To: <1447761116-7633-1-git-send-email-nhofmeyr@sysmocom.de> References: <1447761116-7633-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1447761116-7633-3-git-send-email-nhofmeyr@sysmocom.de> - an unnecessary if-not-NULL check (1339764); - a missing nul termination safety net (1339768); - a typo resulting in the wrong proxy being logged (1339767). Sponsored-by: On-Waves ehi --- openbsc/src/gprs/gtphub.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index 406d60d..22da9a3 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -1223,10 +1223,7 @@ static int gtphub_write(const struct osmo_fd *to, errno = 0; ssize_t sent = sendto(to->fd, buf, buf_len, 0, (struct sockaddr*)&to_addr->a, to_addr->l); - - if (to_addr) { - LOG(LOGL_DEBUG, "to %s\n", osmo_sockaddr_to_str(to_addr)); - } + LOG(LOGL_DEBUG, "to %s\n", osmo_sockaddr_to_str(to_addr)); if (sent == -1) { LOG(LOGL_ERROR, "error: %s\n", strerror(errno)); @@ -1712,6 +1709,7 @@ void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str, gtphub_port_ref_count_inc(pp); strncpy(ggsn->apn_oi_str, apn_oi_str, sizeof(ggsn->apn_oi_str)); + ggsn->apn_oi_str[sizeof(ggsn->apn_oi_str) - 1] = '\0'; ggsn->expiry_entry.del_cb = resolved_gssn_del_cb; expiry_add(&hub->expire_tei_maps, &ggsn->expiry_entry, now); @@ -1902,7 +1900,7 @@ int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg) } for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) { - if (hub->sgsn_proxy[plane_idx]) + if (hub->ggsn_proxy[plane_idx]) LOG(LOGL_NOTICE, "Using GGSN %s proxy %s\n", gtphub_plane_idx_names[plane_idx], gtphub_port_str(hub->ggsn_proxy[plane_idx])); -- 2.1.4 From jerlbeck at sysmocom.de Tue Nov 17 12:18:25 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 13:18:25 +0100 Subject: [PATCH 5/5] stats: Add TODO comment to rate_ctr In-Reply-To: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> References: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447762705-14297-5-git-send-email-jerlbeck@sysmocom.de> Currently the counters are scanned twice, once for interval computation and once for reporting. This adds a reminder to move the interval computation code to a special stats reporter which just updates the fields. Sponsored-by: On-Waves ehf --- src/rate_ctr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rate_ctr.c b/src/rate_ctr.c index 50b3fe7..436deef 100644 --- a/src/rate_ctr.c +++ b/src/rate_ctr.c @@ -92,6 +92,9 @@ int64_t rate_ctr_difference(struct rate_ctr *ctr) return result; } +/* TODO: support update intervals > 1s */ +/* TODO: implement this as a special stats reporter */ + static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv) { /* calculate rate over last interval */ -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 12:18:21 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 13:18:21 +0100 Subject: [PATCH 1/5] stats: Move statsd related code into a separate file Message-ID: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> This commit moves the stats specific code parts into stats_statsd.c while keeping the generic parts in stats.c. The code in stats.c no longer contains references to statsd symbols. Note that the VTY code still needs to know about every stats reporter backend. Sponsored-by: On-Waves ehf --- include/osmocom/core/stats.h | 16 +++-- src/Makefile.am | 2 +- src/stats.c | 148 +++------------------------------------- src/stats_statsd.c | 158 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 144 deletions(-) create mode 100644 src/stats_statsd.c diff --git a/include/osmocom/core/stats.h b/include/osmocom/core/stats.h index 39eae08..96f687e 100644 --- a/include/osmocom/core/stats.h +++ b/include/osmocom/core/stats.h @@ -38,8 +38,8 @@ enum osmo_stats_class { }; enum osmo_stats_reporter_type { - OSMO_STATS_REPORTER_STATSD, OSMO_STATS_REPORTER_LOG, + OSMO_STATS_REPORTER_STATSD, }; struct osmo_stats_reporter { @@ -96,9 +96,6 @@ struct osmo_stats_reporter *osmo_stats_reporter_alloc(enum osmo_stats_reporter_t const char *name); void osmo_stats_reporter_free(struct osmo_stats_reporter *srep); -struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name); -struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name); - struct osmo_stats_reporter *osmo_stats_reporter_find(enum osmo_stats_reporter_type type, const char *name); @@ -111,3 +108,14 @@ int osmo_stats_reporter_set_max_class(struct osmo_stats_reporter *srep, int osmo_stats_reporter_set_name_prefix(struct osmo_stats_reporter *srep, const char *prefix); int osmo_stats_reporter_enable(struct osmo_stats_reporter *srep); int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep); + +/* reporter creation */ +struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name); +struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name); + +/* helper functions for reporter implementations */ +int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data, + int data_len); +int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep); +int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep); +int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep); diff --git a/src/Makefile.am b/src/Makefile.am index 7aa6a78..00b97d0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \ gsmtap_util.c crc16.c panic.c backtrace.c \ conv.c application.c rbtree.c strrb.c \ loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c \ - macaddr.c stat_item.c stats.c + macaddr.c stat_item.c stats.c stats_statsd.c BUILT_SOURCES = crc8gen.c crc16gen.c crc32gen.c crc64gen.c diff --git a/src/stats.c b/src/stats.c index 16e2971..5547910 100644 --- a/src/stats.c +++ b/src/stats.c @@ -42,7 +42,7 @@ #include #define STATS_DEFAULT_INTERVAL 5 /* secs */ -#define STATS_DEFAULT_STATSD_BUFLEN 256 +#define STATS_DEFAULT_BUFLEN 256 static LLIST_HEAD(osmo_stats_reporter_list); static void *osmo_stats_ctx = NULL; @@ -56,16 +56,6 @@ struct osmo_stats_config *osmo_stats_config = &s_stats_config; static struct osmo_timer_list osmo_stats_timer; -static int osmo_stats_reporter_statsd_open(struct osmo_stats_reporter *srep); -static int osmo_stats_reporter_statsd_close(struct osmo_stats_reporter *srep); -static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep, - const struct rate_ctr_group *ctrg, - const struct rate_ctr_desc *desc, - int64_t value, int64_t delta); -static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep, - const struct osmo_stat_item_group *statg, - const struct osmo_stat_item_desc *desc, int value); - static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep, const struct rate_ctr_group *ctrg, const struct rate_ctr_desc *desc, @@ -74,10 +64,6 @@ static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep, const struct osmo_stat_item_group *statg, const struct osmo_stat_item_desc *desc, int value); -static int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data, - int data_len); -static int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep); - static int update_srep_config(struct osmo_stats_reporter *srep) { int rc = 0; @@ -300,7 +286,7 @@ int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep) return update_srep_config(srep); } -static int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data, +int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data, int data_len) { int rc; @@ -314,7 +300,7 @@ static int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char return rc; } -static int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep) +int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep) { int rc; @@ -394,31 +380,16 @@ static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep, desc->name, value, desc->unit); } -/*** statsd reporter ***/ - -struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name) -{ - struct osmo_stats_reporter *srep; - srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_STATSD, name); - - srep->have_net_config = 1; - - srep->open = osmo_stats_reporter_statsd_open; - srep->close = osmo_stats_reporter_statsd_close; - srep->send_counter = osmo_stats_reporter_statsd_send_counter; - srep->send_item = osmo_stats_reporter_statsd_send_item; - - return srep; -} +/*** i/o helper functions ***/ -static int osmo_stats_reporter_statsd_open(struct osmo_stats_reporter *srep) +int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep) { int sock; int rc; - int buffer_size = STATS_DEFAULT_STATSD_BUFLEN; + int buffer_size = STATS_DEFAULT_BUFLEN; - if (srep->fd != -1) - osmo_stats_reporter_statsd_close(srep); + if (srep->fd != -1 && srep->close) + srep->close(srep); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) @@ -448,7 +419,7 @@ failed: return rc; } -static int osmo_stats_reporter_statsd_close(struct osmo_stats_reporter *srep) +int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep) { int rc; if (srep->fd == -1) @@ -463,107 +434,6 @@ static int osmo_stats_reporter_statsd_close(struct osmo_stats_reporter *srep) return rc == -1 ? -errno : 0; } -static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep, - const char *name1, unsigned int index1, const char *name2, int value, - const char *unit) -{ - char *buf; - int buf_size; - int nchars, rc = 0; - char *fmt = NULL; - char *prefix = srep->name_prefix; - int old_len = msgb_length(srep->buffer); - - if (prefix) { - if (name1) { - if (index1 != 0) - fmt = "%1$s.%2$s.%6$u.%3$s:%4$d|%5$s"; - else - fmt = "%1$s.%2$s.%3$s:%4$d|%5$s"; - } else { - fmt = "%1$s.%2$0.0s%3$s:%4$d|%5$s"; - } - } else { - prefix = ""; - if (name1) { - if (index1 != 0) - fmt = "%1$s%2$s.%6$u.%3$s:%4$d|%5$s"; - else - fmt = "%1$s%2$s.%3$s:%4$d|%5$s"; - } else { - fmt = "%1$s%2$0.0s%3$s:%4$d|%5$s"; - } - } - - if (srep->agg_enabled) { - if (msgb_length(srep->buffer) > 0 && - msgb_tailroom(srep->buffer) > 0) - { - msgb_put_u8(srep->buffer, '\n'); - } - } - - buf = (char *)msgb_put(srep->buffer, 0); - buf_size = msgb_tailroom(srep->buffer); - - nchars = snprintf(buf, buf_size, fmt, - prefix, name1, name2, - value, unit, index1); - - if (nchars >= buf_size) { - /* Truncated */ - /* Restore original buffer (without trailing LF) */ - msgb_trim(srep->buffer, old_len); - /* Send it */ - rc = osmo_stats_reporter_send_buffer(srep); - - /* Try again */ - buf = (char *)msgb_put(srep->buffer, 0); - buf_size = msgb_tailroom(srep->buffer); - - nchars = snprintf(buf, buf_size, fmt, - prefix, name1, name2, - value, unit, index1); - - if (nchars >= buf_size) - return -EMSGSIZE; - } - - if (nchars > 0) - msgb_trim(srep->buffer, msgb_length(srep->buffer) + nchars); - - if (!srep->agg_enabled) - rc = osmo_stats_reporter_send_buffer(srep); - - return rc; -} - -static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep, - const struct rate_ctr_group *ctrg, - const struct rate_ctr_desc *desc, - int64_t value, int64_t delta) -{ - if (ctrg) - return osmo_stats_reporter_statsd_send(srep, - ctrg->desc->group_name_prefix, - ctrg->idx, - desc->name, delta, "c"); - else - return osmo_stats_reporter_statsd_send(srep, - NULL, 0, - desc->name, delta, "c"); -} - -static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep, - const struct osmo_stat_item_group *statg, - const struct osmo_stat_item_desc *desc, int value) -{ - return osmo_stats_reporter_statsd_send(srep, - statg->desc->group_name_prefix, - statg->idx, - desc->name, value, desc->unit); -} - /*** generic rate counter support ***/ static int osmo_stats_reporter_send_counter(struct osmo_stats_reporter *srep, diff --git a/src/stats_statsd.c b/src/stats_statsd.c new file mode 100644 index 0000000..c76f8f6 --- /dev/null +++ b/src/stats_statsd.c @@ -0,0 +1,158 @@ +/* + * (C) 2015 by Sysmocom s.f.m.c. GmbH + * + * Author: Jacob Erlbeck + * + * 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 osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep, + const struct rate_ctr_group *ctrg, + const struct rate_ctr_desc *desc, + int64_t value, int64_t delta); +static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep, + const struct osmo_stat_item_group *statg, + const struct osmo_stat_item_desc *desc, int value); + +struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name) +{ + struct osmo_stats_reporter *srep; + srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_STATSD, name); + + srep->have_net_config = 1; + + srep->open = osmo_stats_reporter_udp_open; + srep->close = osmo_stats_reporter_udp_close; + srep->send_counter = osmo_stats_reporter_statsd_send_counter; + srep->send_item = osmo_stats_reporter_statsd_send_item; + + return srep; +} + +static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep, + const char *name1, unsigned int index1, const char *name2, int value, + const char *unit) +{ + char *buf; + int buf_size; + int nchars, rc = 0; + char *fmt = NULL; + char *prefix = srep->name_prefix; + int old_len = msgb_length(srep->buffer); + + if (prefix) { + if (name1) { + if (index1 != 0) + fmt = "%1$s.%2$s.%6$u.%3$s:%4$d|%5$s"; + else + fmt = "%1$s.%2$s.%3$s:%4$d|%5$s"; + } else { + fmt = "%1$s.%2$0.0s%3$s:%4$d|%5$s"; + } + } else { + prefix = ""; + if (name1) { + if (index1 != 0) + fmt = "%1$s%2$s.%6$u.%3$s:%4$d|%5$s"; + else + fmt = "%1$s%2$s.%3$s:%4$d|%5$s"; + } else { + fmt = "%1$s%2$0.0s%3$s:%4$d|%5$s"; + } + } + + if (srep->agg_enabled) { + if (msgb_length(srep->buffer) > 0 && + msgb_tailroom(srep->buffer) > 0) + { + msgb_put_u8(srep->buffer, '\n'); + } + } + + buf = (char *)msgb_put(srep->buffer, 0); + buf_size = msgb_tailroom(srep->buffer); + + nchars = snprintf(buf, buf_size, fmt, + prefix, name1, name2, + value, unit, index1); + + if (nchars >= buf_size) { + /* Truncated */ + /* Restore original buffer (without trailing LF) */ + msgb_trim(srep->buffer, old_len); + /* Send it */ + rc = osmo_stats_reporter_send_buffer(srep); + + /* Try again */ + buf = (char *)msgb_put(srep->buffer, 0); + buf_size = msgb_tailroom(srep->buffer); + + nchars = snprintf(buf, buf_size, fmt, + prefix, name1, name2, + value, unit, index1); + + if (nchars >= buf_size) + return -EMSGSIZE; + } + + if (nchars > 0) + msgb_trim(srep->buffer, msgb_length(srep->buffer) + nchars); + + if (!srep->agg_enabled) + rc = osmo_stats_reporter_send_buffer(srep); + + return rc; +} + +static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep, + const struct rate_ctr_group *ctrg, + const struct rate_ctr_desc *desc, + int64_t value, int64_t delta) +{ + if (ctrg) + return osmo_stats_reporter_statsd_send(srep, + ctrg->desc->group_name_prefix, + ctrg->idx, + desc->name, delta, "c"); + else + return osmo_stats_reporter_statsd_send(srep, + NULL, 0, + desc->name, delta, "c"); +} + +static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep, + const struct osmo_stat_item_group *statg, + const struct osmo_stat_item_desc *desc, int value) +{ + return osmo_stats_reporter_statsd_send(srep, + statg->desc->group_name_prefix, + statg->idx, + desc->name, value, desc->unit); +} -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 12:18:22 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 13:18:22 +0100 Subject: [PATCH 2/5] stats: Reorder functions in stats.c In-Reply-To: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> References: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447762705-14297-2-git-send-email-jerlbeck@sysmocom.de> Due to prior refactoring, the functions do not have an sensible order in the file. This commit tries to improve that a little bit. Sponsored-by: On-Waves ehf --- src/stats.c | 120 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/src/stats.c b/src/stats.c index 5547910..73b2703 100644 --- a/src/stats.c +++ b/src/stats.c @@ -286,6 +286,60 @@ int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep) return update_srep_config(srep); } +/*** i/o helper functions ***/ + +int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep) +{ + int sock; + int rc; + int buffer_size = STATS_DEFAULT_BUFLEN; + + if (srep->fd != -1 && srep->close) + srep->close(srep); + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + return -errno; + + if (srep->bind_addr_len > 0) { + rc = bind(sock, &srep->bind_addr, srep->bind_addr_len); + if (rc == -1) + goto failed; + } + + srep->fd = sock; + + if (srep->mtu > 0) { + buffer_size = srep->mtu - 20 /* IP */ - 8 /* UDP */; + srep->agg_enabled = 1; + } + + srep->buffer = msgb_alloc(buffer_size, "stats buffer"); + + return 0; + +failed: + rc = -errno; + close(sock); + + return rc; +} + +int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep) +{ + int rc; + if (srep->fd == -1) + return -EBADF; + + osmo_stats_reporter_send_buffer(srep); + + rc = close(srep->fd); + srep->fd = -1; + msgb_free(srep->buffer); + srep->buffer = NULL; + return rc == -1 ? -errno : 0; +} + int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data, int data_len) { @@ -315,16 +369,6 @@ int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep) return rc; } -static int osmo_stats_reporter_check_config(struct osmo_stats_reporter *srep, - unsigned int index, int class_id) -{ - if (class_id == OSMO_STATS_CLASS_UNKNOWN) - class_id = index != 0 ? - OSMO_STATS_CLASS_SUBSCRIBER : OSMO_STATS_CLASS_GLOBAL; - - return class_id <= srep->max_class; -} - /*** log reporter ***/ struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name) @@ -380,58 +424,16 @@ static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep, desc->name, value, desc->unit); } -/*** i/o helper functions ***/ - -int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep) -{ - int sock; - int rc; - int buffer_size = STATS_DEFAULT_BUFLEN; - - if (srep->fd != -1 && srep->close) - srep->close(srep); - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock == -1) - return -errno; +/*** helper for reporting ***/ - if (srep->bind_addr_len > 0) { - rc = bind(sock, &srep->bind_addr, srep->bind_addr_len); - if (rc == -1) - goto failed; - } - - srep->fd = sock; - - if (srep->mtu > 0) { - buffer_size = srep->mtu - 20 /* IP */ - 8 /* UDP */; - srep->agg_enabled = 1; - } - - srep->buffer = msgb_alloc(buffer_size, "stats buffer"); - - return 0; - -failed: - rc = -errno; - close(sock); - - return rc; -} - -int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep) +static int osmo_stats_reporter_check_config(struct osmo_stats_reporter *srep, + unsigned int index, int class_id) { - int rc; - if (srep->fd == -1) - return -EBADF; - - osmo_stats_reporter_send_buffer(srep); + if (class_id == OSMO_STATS_CLASS_UNKNOWN) + class_id = index != 0 ? + OSMO_STATS_CLASS_SUBSCRIBER : OSMO_STATS_CLASS_GLOBAL; - rc = close(srep->fd); - srep->fd = -1; - msgb_free(srep->buffer); - srep->buffer = NULL; - return rc == -1 ? -errno : 0; + return class_id <= srep->max_class; } /*** generic rate counter support ***/ -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 12:18:23 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 13:18:23 +0100 Subject: [PATCH 3/5] stats/test: Add test for reporting In-Reply-To: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> References: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447762705-14297-3-git-send-email-jerlbeck@sysmocom.de> This tests uses a dedicated test reported to check several aspects of the value reporting. - addition/removal of stats reporter - addition/removal of counters/items - setting of max_class - initial value flush - updating single counters/items - reporter retrieval - enable/disable Sponsored-by: On-Waves ehf --- tests/stats/stats_test.c | 278 +++++++++++++++++++++++++++++++++++++++++++--- tests/stats/stats_test.ok | 108 ++++++++++++++++++ 2 files changed, 369 insertions(+), 17 deletions(-) diff --git a/tests/stats/stats_test.c b/tests/stats/stats_test.c index f8c7dc0..f6efd3e 100644 --- a/tests/stats/stats_test.c +++ b/tests/stats/stats_test.c @@ -23,28 +23,49 @@ #include #include #include +#include +#include #include +enum test_ctr { + TEST_A_CTR, + TEST_B_CTR, +}; + +static const struct rate_ctr_desc ctr_description[] = { + [TEST_A_CTR] = { "ctr.a", "The A counter value"}, + [TEST_B_CTR] = { "ctr.b", "The B counter value"}, +}; + +static const struct rate_ctr_group_desc ctrg_desc = { + .group_name_prefix = "ctr-test.one", + .group_description = "Counter test number 1", + .num_ctr = ARRAY_SIZE(ctr_description), + .ctr_desc = ctr_description, + .class_id = OSMO_STATS_CLASS_SUBSCRIBER, +}; + +enum test_items { + TEST_A_ITEM, + TEST_B_ITEM, +}; + +static const struct osmo_stat_item_desc item_description[] = { + [TEST_A_ITEM] = { "item.a", "The A value", "ma", 4, -1 }, + [TEST_B_ITEM] = { "item.b", "The B value", "kb", 7, -1 }, +}; + +static const struct osmo_stat_item_group_desc statg_desc = { + .group_name_prefix = "test.one", + .group_description = "Test number 1", + .num_items = ARRAY_SIZE(item_description), + .item_desc = item_description, + .class_id = OSMO_STATS_CLASS_PEER, +}; + static void stat_test(void) { - enum test_items { - TEST_A_ITEM, - TEST_B_ITEM, - }; - - static const struct osmo_stat_item_desc item_description[] = { - { "item.a", "The A value", "ma", 4, -1 }, - { "item.b", "The B value", "kb", 7, -1 }, - }; - - static const struct osmo_stat_item_group_desc statg_desc = { - .group_name_prefix = "test.one", - .group_description = "Test number 1", - .num_items = ARRAY_SIZE(item_description), - .item_desc = item_description, - }; - struct osmo_stat_item_group *statg = osmo_stat_item_group_alloc(NULL, &statg_desc, 0); @@ -201,6 +222,228 @@ static void stat_test(void) OSMO_ASSERT(sgrp2 == NULL); } +/*** stats reporter tests ***/ + +/* define a special stats reporter for testing */ + +static int send_count; + +enum { + OSMO_STATS_REPORTER_TEST = OSMO_STATS_REPORTER_LOG + 1, +}; + +static int stats_reporter_test_send_counter(struct osmo_stats_reporter *srep, + const struct rate_ctr_group *ctrg, + const struct rate_ctr_desc *desc, + int64_t value, int64_t delta) +{ + const char *group_name = ctrg ? ctrg->desc->group_name_prefix : ""; + + printf(" %s: counter p=%s g=%s i=%u n=%s v=%lld d=%lld\n", + srep->name, + srep->name_prefix ? srep->name_prefix : "", + group_name, ctrg ? ctrg->idx : 0, + desc->name, (long long)value, (long long)delta); + + send_count += 1; + return 0; +} + +static int stats_reporter_test_send_item(struct osmo_stats_reporter *srep, + const struct osmo_stat_item_group *statg, + const struct osmo_stat_item_desc *desc, int value) +{ + printf(" %s: item p=%s g=%s i=%u n=%s v=%d u=%s\n", + srep->name, + srep->name_prefix ? srep->name_prefix : "", + statg->desc->group_name_prefix, statg->idx, + desc->name, value, desc->unit ? desc->unit : ""); + + send_count += 1; + return 0; +} + +static int stats_reporter_test_open(struct osmo_stats_reporter *srep) +{ + printf(" %s: open\n", srep->name); + return 0; +} + +static int stats_reporter_test_close(struct osmo_stats_reporter *srep) +{ + printf(" %s: close\n", srep->name); + return 0; +} + +static struct osmo_stats_reporter *stats_reporter_create_test(const char *name) +{ + struct osmo_stats_reporter *srep; + srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_TEST, name); + + srep->have_net_config = 0; + + srep->open = stats_reporter_test_open; + srep->close = stats_reporter_test_close; + srep->send_counter = stats_reporter_test_send_counter; + srep->send_item = stats_reporter_test_send_item; + + return srep; +} + + +static void test_reporting() +{ + struct osmo_stats_reporter *srep1, *srep2, *srep; + struct osmo_stat_item_group *statg1, *statg2; + struct rate_ctr_group *ctrg1, *ctrg2; + + int rc; + + printf("Start test: %s\n", __func__); + + /* Allocate counters and items */ + statg1 = osmo_stat_item_group_alloc(NULL, &statg_desc, 1); + OSMO_ASSERT(statg1 != NULL); + statg2 = osmo_stat_item_group_alloc(NULL, &statg_desc, 2); + OSMO_ASSERT(statg2 != NULL); + ctrg1 = rate_ctr_group_alloc(NULL, &ctrg_desc, 1); + OSMO_ASSERT(ctrg1 != NULL); + ctrg2 = rate_ctr_group_alloc(NULL, &ctrg_desc, 2); + OSMO_ASSERT(ctrg2 != NULL); + + srep1 = stats_reporter_create_test("test1"); + OSMO_ASSERT(srep1 != NULL); + + srep2 = stats_reporter_create_test("test2"); + OSMO_ASSERT(srep2 != NULL); + + srep = osmo_stats_reporter_find(OSMO_STATS_REPORTER_TEST, "test1"); + OSMO_ASSERT(srep == srep1); + srep = osmo_stats_reporter_find(OSMO_STATS_REPORTER_TEST, "test2"); + OSMO_ASSERT(srep == srep2); + + rc = osmo_stats_reporter_enable(srep1); + OSMO_ASSERT(rc >= 0); + OSMO_ASSERT(srep1->force_single_flush); + rc = osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_SUBSCRIBER); + OSMO_ASSERT(rc >= 0); + + rc = osmo_stats_reporter_enable(srep2); + OSMO_ASSERT(rc >= 0); + OSMO_ASSERT(srep2->force_single_flush); + rc = osmo_stats_reporter_set_max_class(srep2, OSMO_STATS_CLASS_SUBSCRIBER); + OSMO_ASSERT(rc >= 0); + + printf("report (initial):\n"); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 16); + + printf("report (srep1 global):\n"); + /* force single flush */ + osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_GLOBAL); + srep1->force_single_flush = 1; + srep2->force_single_flush = 1; + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 8); + + printf("report (srep1 peer):\n"); + /* force single flush */ + osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_PEER); + srep1->force_single_flush = 1; + srep2->force_single_flush = 1; + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 12); + + printf("report (srep1 subscriber):\n"); + /* force single flush */ + osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_SUBSCRIBER); + srep1->force_single_flush = 1; + srep2->force_single_flush = 1; + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 16); + + printf("report (srep2 disabled):\n"); + /* force single flush */ + srep1->force_single_flush = 1; + srep2->force_single_flush = 1; + rc = osmo_stats_reporter_disable(srep2); + OSMO_ASSERT(rc >= 0); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 8); + + printf("report (srep2 enabled, no flush forced):\n"); + rc = osmo_stats_reporter_enable(srep2); + OSMO_ASSERT(rc >= 0); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 8); + + printf("report (should be empty):\n"); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 0); + + printf("report (group 1, counter 1 update):\n"); + rate_ctr_inc(&ctrg1->ctr[TEST_A_CTR]); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 2); + + printf("report (group 1, item 1 update):\n"); + osmo_stat_item_set(statg1->items[TEST_A_ITEM], 10); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 2); + + printf("report (remove statg1, ctrg1):\n"); + /* force single flush */ + srep1->force_single_flush = 1; + srep2->force_single_flush = 1; + osmo_stat_item_group_free(statg1); + rate_ctr_group_free(ctrg1); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 8); + + printf("report (remove srep1):\n"); + /* force single flush */ + srep1->force_single_flush = 1; + srep2->force_single_flush = 1; + osmo_stats_reporter_free(srep1); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 4); + + printf("report (remove statg2):\n"); + /* force single flush */ + srep2->force_single_flush = 1; + osmo_stat_item_group_free(statg2); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 2); + + printf("report (remove srep2):\n"); + /* force single flush */ + srep2->force_single_flush = 1; + osmo_stats_reporter_free(srep2); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 0); + + printf("report (remove ctrg2, should be empty):\n"); + rate_ctr_group_free(ctrg2); + send_count = 0; + osmo_stats_report(); + OSMO_ASSERT(send_count == 0); + + printf("End test: %s\n", __func__); +} + int main(int argc, char **argv) { static const struct log_info log_info = {}; @@ -209,5 +452,6 @@ int main(int argc, char **argv) osmo_stat_item_init(NULL); stat_test(); + test_reporting(); return 0; } diff --git a/tests/stats/stats_test.ok b/tests/stats/stats_test.ok index e69de29..a0c001b 100644 --- a/tests/stats/stats_test.ok +++ b/tests/stats/stats_test.ok @@ -0,0 +1,108 @@ +Start test: test_reporting + test1: open + test2: open +report (initial): + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test1: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test1: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test1: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test1: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test2: item p= g=test.one i=2 n=item.a v=-1 u=ma + test1: item p= g=test.one i=2 n=item.a v=-1 u=ma + test2: item p= g=test.one i=2 n=item.b v=-1 u=kb + test1: item p= g=test.one i=2 n=item.b v=-1 u=kb + test2: item p= g=test.one i=1 n=item.a v=-1 u=ma + test1: item p= g=test.one i=1 n=item.a v=-1 u=ma + test2: item p= g=test.one i=1 n=item.b v=-1 u=kb + test1: item p= g=test.one i=1 n=item.b v=-1 u=kb +report (srep1 global): + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test2: item p= g=test.one i=2 n=item.a v=-1 u=ma + test2: item p= g=test.one i=2 n=item.b v=-1 u=kb + test2: item p= g=test.one i=1 n=item.a v=-1 u=ma + test2: item p= g=test.one i=1 n=item.b v=-1 u=kb +report (srep1 peer): + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test2: item p= g=test.one i=2 n=item.a v=-1 u=ma + test1: item p= g=test.one i=2 n=item.a v=-1 u=ma + test2: item p= g=test.one i=2 n=item.b v=-1 u=kb + test1: item p= g=test.one i=2 n=item.b v=-1 u=kb + test2: item p= g=test.one i=1 n=item.a v=-1 u=ma + test1: item p= g=test.one i=1 n=item.a v=-1 u=ma + test2: item p= g=test.one i=1 n=item.b v=-1 u=kb + test1: item p= g=test.one i=1 n=item.b v=-1 u=kb +report (srep1 subscriber): + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test1: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test1: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test1: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test1: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test2: item p= g=test.one i=2 n=item.a v=-1 u=ma + test1: item p= g=test.one i=2 n=item.a v=-1 u=ma + test2: item p= g=test.one i=2 n=item.b v=-1 u=kb + test1: item p= g=test.one i=2 n=item.b v=-1 u=kb + test2: item p= g=test.one i=1 n=item.a v=-1 u=ma + test1: item p= g=test.one i=1 n=item.a v=-1 u=ma + test2: item p= g=test.one i=1 n=item.b v=-1 u=kb + test1: item p= g=test.one i=1 n=item.b v=-1 u=kb +report (srep2 disabled): + test2: close + test1: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test1: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test1: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test1: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test1: item p= g=test.one i=2 n=item.a v=-1 u=ma + test1: item p= g=test.one i=2 n=item.b v=-1 u=kb + test1: item p= g=test.one i=1 n=item.a v=-1 u=ma + test1: item p= g=test.one i=1 n=item.b v=-1 u=kb +report (srep2 enabled, no flush forced): + test2: open + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=1 n=ctr.b v=0 d=0 + test2: item p= g=test.one i=2 n=item.a v=-1 u=ma + test2: item p= g=test.one i=2 n=item.b v=-1 u=kb + test2: item p= g=test.one i=1 n=item.a v=-1 u=ma + test2: item p= g=test.one i=1 n=item.b v=-1 u=kb +report (should be empty): +report (group 1, counter 1 update): + test2: counter p= g=ctr-test.one i=1 n=ctr.a v=1 d=1 + test1: counter p= g=ctr-test.one i=1 n=ctr.a v=1 d=1 +report (group 1, item 1 update): + test2: item p= g=test.one i=1 n=item.a v=10 u=ma + test1: item p= g=test.one i=1 n=item.a v=10 u=ma +report (remove statg1, ctrg1): + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test1: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test1: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test2: item p= g=test.one i=2 n=item.a v=-1 u=ma + test1: item p= g=test.one i=2 n=item.a v=-1 u=ma + test2: item p= g=test.one i=2 n=item.b v=-1 u=kb + test1: item p= g=test.one i=2 n=item.b v=-1 u=kb +report (remove srep1): + test1: close + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 + test2: item p= g=test.one i=2 n=item.a v=-1 u=ma + test2: item p= g=test.one i=2 n=item.b v=-1 u=kb +report (remove statg2): + test2: counter p= g=ctr-test.one i=2 n=ctr.a v=0 d=0 + test2: counter p= g=ctr-test.one i=2 n=ctr.b v=0 d=0 +report (remove srep2): + test2: close +report (remove ctrg2, should be empty): +End test: test_reporting -- 1.9.1 From jerlbeck at sysmocom.de Tue Nov 17 12:18:24 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 17 Nov 2015 13:18:24 +0100 Subject: [PATCH 4/5] stats/test: Add memory leak check In-Reply-To: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> References: <1447762705-14297-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1447762705-14297-4-git-send-email-jerlbeck@sysmocom.de> Adds a rudimentary leak check for the counters and stat items. Sponsored-by: On-Waves ehf --- tests/stats/stats_test.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/stats/stats_test.c b/tests/stats/stats_test.c index f6efd3e..75ddf18 100644 --- a/tests/stats/stats_test.c +++ b/tests/stats/stats_test.c @@ -296,19 +296,20 @@ static void test_reporting() struct osmo_stats_reporter *srep1, *srep2, *srep; struct osmo_stat_item_group *statg1, *statg2; struct rate_ctr_group *ctrg1, *ctrg2; + void *stats_ctx = talloc_named_const(NULL, 1, "stats test context"); int rc; printf("Start test: %s\n", __func__); /* Allocate counters and items */ - statg1 = osmo_stat_item_group_alloc(NULL, &statg_desc, 1); + statg1 = osmo_stat_item_group_alloc(stats_ctx, &statg_desc, 1); OSMO_ASSERT(statg1 != NULL); - statg2 = osmo_stat_item_group_alloc(NULL, &statg_desc, 2); + statg2 = osmo_stat_item_group_alloc(stats_ctx, &statg_desc, 2); OSMO_ASSERT(statg2 != NULL); - ctrg1 = rate_ctr_group_alloc(NULL, &ctrg_desc, 1); + ctrg1 = rate_ctr_group_alloc(stats_ctx, &ctrg_desc, 1); OSMO_ASSERT(ctrg1 != NULL); - ctrg2 = rate_ctr_group_alloc(NULL, &ctrg_desc, 2); + ctrg2 = rate_ctr_group_alloc(stats_ctx, &ctrg_desc, 2); OSMO_ASSERT(ctrg2 != NULL); srep1 = stats_reporter_create_test("test1"); @@ -441,6 +442,10 @@ static void test_reporting() osmo_stats_report(); OSMO_ASSERT(send_count == 0); + /* Leak check */ + OSMO_ASSERT(talloc_total_blocks(stats_ctx) == 1); + talloc_free(stats_ctx); + printf("End test: %s\n", __func__); } -- 1.9.1 From aschultz at tpip.net Tue Nov 17 12:44:46 2015 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 17 Nov 2015 13:44:46 +0100 (CET) Subject: [PATCH openggsn 1/4] ggsn: add support for GTP kernel data encapsulation In-Reply-To: <20151117123751.GD20129@salvia> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> <1447759365-24099-2-git-send-email-aschultz@tpip.net> <20151117123751.GD20129@salvia> Message-ID: <206863558.32819.1447764286412.JavaMail.zimbra@tpip.net> ----- Original Message ----- > From: "Pablo Neira Ayuso" > To: "Andreas Schultz" > Cc: openbsc at lists.osmocom.org, "Harald Welte" , "Pablo Neira Ayuso" > Sent: Tuesday, November 17, 2015 1:37:51 PM > Subject: Re: [PATCH openggsn 1/4] ggsn: add support for GTP kernel data encapsulation > On Tue, Nov 17, 2015 at 12:22:42PM +0100, Andreas Schultz wrote: >> From: Pablo Neira Ayuso >> >> This patch adds the -g, --gtpnl=device option that allows you to >> enable the GTP kernel tunneling mode in openggsn. You have to specify >> the real downlink device that will be used to tunnel traffic, eg. >> >> -g=eth0 > > This is basically my original patch rebased upon master or are there > any changes on it? No changes, I wanted to keep you original for reference, then apply the two fixes on top of that and add the netns stuff after that. You patch doesn't build anymore, due to the logging changes. If you want every changeset to build-able, you need to merge it with the log and automake patches. Andreas From nhofmeyr at sysmocom.de Tue Nov 17 13:38:45 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 14:38:45 +0100 Subject: [PATCH 1/3] gtphub: lose obsolete comment. Message-ID: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> The del_cb is now also used for ares (GGSN resolution) timeouts, and expiry is anyway separated from nr_map, so this comment is void. Sponsored-by: On-Waves ehi --- openbsc/include/openbsc/gtphub.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/openbsc/include/openbsc/gtphub.h b/openbsc/include/openbsc/gtphub.h index 49d685c..68cf90e 100644 --- a/openbsc/include/openbsc/gtphub.h +++ b/openbsc/include/openbsc/gtphub.h @@ -248,8 +248,6 @@ int expiry_tick(struct expiry *exq, time_t now); * Mapping allocation and a del_cb are provided by the caller. If del_cb is * NULL, no deallocation will be done (allowing statically allocated entries). */ -/* TODO at some point I thought the allocation & del_cb complexity was - * needed/helpful, but by now it seems like overkill. Maybe lose that again. */ typedef int nr_t; -- 2.1.4 From nhofmeyr at sysmocom.de Tue Nov 17 13:38:46 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 14:38:46 +0100 Subject: [PATCH 2/3] gtphub: fix number map range for TEIs. In-Reply-To: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1447767527-27316-2-git-send-email-nhofmeyr@sysmocom.de> Use unsigned int for nr_map, just large enough to fit the TEI space. Adjust log output formats and casts accordingly. Fixes: TEIs are uint32_t, but the nr_map so far used int. This would cause TEIs from 0x80000000 on to be handled and printed as a negative value. Sponsored-by: On-Waves ehi --- openbsc/include/openbsc/gtphub.h | 2 +- openbsc/src/gprs/gtphub.c | 15 ++++++++------- openbsc/tests/gtphub/gtphub_test.c | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/openbsc/include/openbsc/gtphub.h b/openbsc/include/openbsc/gtphub.h index 68cf90e..c43a328 100644 --- a/openbsc/include/openbsc/gtphub.h +++ b/openbsc/include/openbsc/gtphub.h @@ -249,7 +249,7 @@ int expiry_tick(struct expiry *exq, time_t now); * NULL, no deallocation will be done (allowing statically allocated entries). */ -typedef int nr_t; +typedef unsigned int nr_t; /* Generator for unused numbers. So far this counts upwards from zero, but the * implementation may change in the future. Treat this like an opaque struct. diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index 22da9a3..7c7f693 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -914,10 +914,10 @@ static void gtphub_mapping_del_cb(struct expiring_item *expi) /* Just for log */ struct gtphub_peer_port *from = nrm->origin; OSMO_ASSERT(from); - LOG(LOGL_DEBUG, "expired: %d: nr mapping from %s: %d->%d\n", + LOG(LOGL_DEBUG, "expired: %d: nr mapping from %s: %u->%u\n", (int)nrm->expiry_entry.expiry, gtphub_port_str(from), - (int)nrm->orig, (int)nrm->repl); + (unsigned int)nrm->orig, (unsigned int)nrm->repl); gtphub_port_ref_count_dec(from); @@ -960,10 +960,10 @@ static uint32_t gtphub_tei_mapping_have(struct gtphub *hub, { struct nr_mapping *nrm = gtphub_mapping_have(&hub->tei_map[plane_idx], from, orig_tei, now); - LOG(LOGL_DEBUG, "New %s TEI: (from %s, TEI %d) <-- TEI %d\n", + LOG(LOGL_DEBUG, "New %s TEI: (from %s, TEI %u) <-- TEI %u\n", gtphub_plane_idx_names[plane_idx], gtphub_port_str(from), - (int)orig_tei, (int)nrm->repl); + (unsigned int)orig_tei, (unsigned int)nrm->repl); return (uint32_t)nrm->repl; } @@ -1115,8 +1115,9 @@ static int gtphub_unmap_header_tei(struct gtphub_peer_port **to_port_p, uint32_t unmapped_tei = nrm->orig; set_tei(p, unmapped_tei); - LOG(LOGL_DEBUG, "Unmapped TEI coming from %s: %d -> %d (to %s)\n", - gtphub_port_str(from_port), tei, unmapped_tei, + LOG(LOGL_DEBUG, "Unmapped TEI coming from %s: %u -> %u (to %s)\n", + gtphub_port_str(from_port), + (unsigned int)tei, (unsigned int)unmapped_tei, gtphub_port_str2(to_port)); *to_port_p = to_port; @@ -1309,7 +1310,7 @@ static int gtphub_unmap(struct gtphub *hub, gtphub_peer_str(from_peer), (int)p->seq, gtphub_port_str(from_seq), - (int)p->header_tei, + (unsigned int)p->header_tei, gtphub_port_str2(from_tei) ); } diff --git a/openbsc/tests/gtphub/gtphub_test.c b/openbsc/tests/gtphub/gtphub_test.c index 8434f61..4e22ac7 100644 --- a/openbsc/tests/gtphub/gtphub_test.c +++ b/openbsc/tests/gtphub/gtphub_test.c @@ -233,9 +233,9 @@ static int nr_map_is(struct nr_map *map, const char *str) size_t len = sizeof(buf); struct nr_mapping *m; llist_for_each_entry(m, &map->mappings, entry) { - size_t wrote = snprintf(pos, len, "(%d->%d@%d), ", - (int)m->orig, - (int)m->repl, + size_t wrote = snprintf(pos, len, "(%u->%u@%d), ", + m->orig, + m->repl, (int)m->expiry_entry.expiry); OSMO_ASSERT(wrote < len); pos += wrote; -- 2.1.4 From nhofmeyr at sysmocom.de Tue Nov 17 13:38:47 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 14:38:47 +0100 Subject: [PATCH 3/3] gtphub: nr_map: add min,max and wrap. In-Reply-To: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1447767527-27316-3-git-send-email-nhofmeyr@sysmocom.de> Implement min/max bounds for nr_pool, adjust nr_pool_init() and current tests, and create unit tests for nr_map wrapping. Sequence numbers range from 0 to 65535, while TEIs range from 1 to 0xffffffff. Both cause problems when the nr_pool surpasses the range: seq exit their valid range, causing unmappings to fail, and a TEI would be mapped as zero (invalid). Add a comment about TEI wrapping, and lose the comment about random TEIs (not really important). Sponsored-by: On-Waves ehi --- openbsc/include/openbsc/gtphub.h | 11 +++++++-- openbsc/src/gprs/gtphub.c | 21 +++++++++------- openbsc/tests/gtphub/gtphub_test.c | 49 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/openbsc/include/openbsc/gtphub.h b/openbsc/include/openbsc/gtphub.h index c43a328..77e43e4 100644 --- a/openbsc/include/openbsc/gtphub.h +++ b/openbsc/include/openbsc/gtphub.h @@ -256,7 +256,8 @@ typedef unsigned int nr_t; * If this becomes random, the tests need to be fixed. */ struct nr_pool { nr_t last_nr; - /* TODO add min, max, for safe wrapping */ + nr_t nr_min; + nr_t nr_max; }; struct nr_mapping { @@ -275,7 +276,7 @@ struct nr_map { }; -void nr_pool_init(struct nr_pool *pool); +void nr_pool_init(struct nr_pool *pool, nr_t nr_min, nr_t nr_max); /* Return the next unused number from the nr_pool. */ nr_t nr_pool_next(struct nr_pool *pool); @@ -398,6 +399,12 @@ struct gtphub { /* pointers to an entry of to_ggsns[x].peers */ struct gtphub_peer_port *ggsn_proxy[GTPH_PLANE_N]; + /* The TEI numbers will simply wrap and be reused, which will work out + * in practice. Problems would arise if one given peer maintained the + * same TEI for a time long enough for the TEI nr map to wrap an entire + * uint32_t; if a new TEI were mapped every second, this would take + * more than 100 years (in which a single given TEI must not time out) + * to cause a problem. */ struct nr_map tei_map[GTPH_PLANE_N]; struct nr_pool tei_pool[GTPH_PLANE_N]; diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index 7c7f693..155024b 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -577,18 +577,21 @@ void expiring_item_del(struct expiring_item *item) /* nr_map, nr_pool */ -void nr_pool_init(struct nr_pool *pool) +void nr_pool_init(struct nr_pool *pool, nr_t nr_min, nr_t nr_max) { - *pool = (struct nr_pool){}; + *pool = (struct nr_pool){ + .nr_min = nr_min, + .nr_max = nr_max, + .last_nr = nr_max + }; } nr_t nr_pool_next(struct nr_pool *pool) { - pool->last_nr ++; - - OSMO_ASSERT(pool->last_nr > 0); - /* TODO: gracefully handle running out of TEIs. */ - /* TODO: random TEIs. */ + if (pool->last_nr >= pool->nr_max) + pool->last_nr = pool->nr_min; + else + pool->last_nr ++; return pool->last_nr; } @@ -1806,7 +1809,7 @@ void gtphub_init(struct gtphub *hub) int plane_idx; for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) { - nr_pool_init(&hub->tei_pool[plane_idx]); + nr_pool_init(&hub->tei_pool[plane_idx], 1, 0xffffffff); nr_map_init(&hub->tei_map[plane_idx], &hub->tei_pool[plane_idx], &hub->expire_tei_maps); @@ -1974,7 +1977,7 @@ static struct gtphub_peer *gtphub_peer_new(struct gtphub *hub, INIT_LLIST_HEAD(&peer->addresses); - nr_pool_init(&peer->seq_pool); + nr_pool_init(&peer->seq_pool, 0, 0xffff); nr_map_init(&peer->seq_map, &peer->seq_pool, &hub->expire_seq_maps); /* TODO use something random to pick the initial sequence nr. diff --git a/openbsc/tests/gtphub/gtphub_test.c b/openbsc/tests/gtphub/gtphub_test.c index 4e22ac7..b1ebb40 100644 --- a/openbsc/tests/gtphub/gtphub_test.c +++ b/openbsc/tests/gtphub/gtphub_test.c @@ -157,7 +157,7 @@ static void test_nr_map_basic(void) struct nr_map _map; struct nr_map *map = &_map; - nr_pool_init(pool); + nr_pool_init(pool, 1, 1000); nr_map_init(map, pool, NULL); OSMO_ASSERT(llist_empty(&map->mappings)); @@ -253,6 +253,50 @@ static int nr_map_is(struct nr_map *map, const char *str) return 1; } +static int test_nr_map_wrap_with(nr_t nr_min, nr_t nr_max, nr_t repl_last, + nr_t orig_start, int orig_n, + const char *expect) +{ + struct nr_pool _pool; + struct nr_pool *pool = &_pool; + struct nr_map _map; + struct nr_map *map = &_map; + + nr_pool_init(pool, nr_min, nr_max); + nr_map_init(map, pool, NULL); + + pool->last_nr = repl_last; + + void *origin = (void*)0x1234; + + int i; + for (i = 0; i < orig_n; i++) + LVL2_ASSERT(nr_map_have(map, origin, orig_start + i, 0)); + + LVL2_ASSERT(nr_map_is(map, expect)); + + nr_map_clear(map); + return 1; +} + +static void test_nr_map_wrap(void) +{ + OSMO_ASSERT(test_nr_map_wrap_with( + 0, UINT_MAX, UINT_MAX - 2, + 1, 5, + "(1->4294967294 at 0), " + "(2->4294967295 at 0), " + "(3->0 at 0), " + "(4->1 at 0), " + "(5->2 at 0), " + )); + OSMO_ASSERT(test_nr_map_wrap_with( + 5, 10, 8, + 1, 5, + "(1->9 at 0), (2->10 at 0), (3->5 at 0), (4->6 at 0), (5->7 at 0), " + )); +} + static void test_expiry(void) { struct expiry expiry; @@ -261,7 +305,7 @@ static void test_expiry(void) int i; expiry_init(&expiry, 30); - nr_pool_init(&pool); + nr_pool_init(&pool, 1, 1000); nr_map_init(&map, &pool, &expiry); OSMO_ASSERT(nr_map_is(&map, "")); @@ -947,6 +991,7 @@ int main(int argc, char **argv) osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub"); test_nr_map_basic(); + test_nr_map_wrap(); test_expiry(); test_echo(); test_create_pdp_ctx(); -- 2.1.4 From nhofmeyr at sysmocom.de Tue Nov 17 14:03:21 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 15:03:21 +0100 Subject: [PATCH 02/16] gtp: remove genl_register_family_with_ops for Linux < 3.13 In-Reply-To: <1447686417-3979-3-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-3-git-send-email-aschultz@tpip.net> Message-ID: <20151117140321.GB1126@dub5> On Mon, Nov 16, 2015 at 04:06:43PM +0100, Andreas Schultz wrote: > pr_err("error loading GTP module loaded\n"); Not related to the patch, but I notice the weird message... ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Tue Nov 17 14:03:32 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 17 Nov 2015 15:03:32 +0100 Subject: [PATCH 03/16] gtp: convert the global gtp_instance_list to a per netns list In-Reply-To: <1447686417-3979-4-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-4-git-send-email-aschultz@tpip.net> Message-ID: <20151117140332.GC1126@dub5> On Mon, Nov 16, 2015 at 04:06:44PM +0100, Andreas Schultz wrote: > This add basic network namespace support by changing to global > gtp_instance_list into a pre namespace list. Just a hair splitting style remark ... from my ASF days I've adopted the nice, short and simple way of writing comments and log messages, which is to basically use imperatives without naming subjects, all the time: "Add foo. Return bar. Implement baz." (not "This adds foo" or "This function returns bar", etc.) It always makes things shorter and easier to edit, because it loses all the verb suffixes ("add", not "adds"). I'm writing this mainly because following this style helped me a lot, not trying to impose it on others -- carry on, no problems here ;) That said, above log message has English errors: > This add basic network namespace support "adds" > by changing to global gtp_instance_list into a pre namespace list. A "to" too many? Is "pre namespace list" something I don't know or could it be described more clearly? > all pdp context "contexts" > now only the namespace that they belong too, can see them. "...belong to can see them" (lose an o and the comma) I'm sorry to review the log message and omit the code, but I'm juust out of time for now. More will follow. ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From laforge at gnumonks.org Tue Nov 17 14:53:33 2015 From: laforge at gnumonks.org (Harald Welte) Date: Tue, 17 Nov 2015 15:53:33 +0100 Subject: [PATCH openggsn 1/4] ggsn: add support for GTP kernel data encapsulation In-Reply-To: <20151117131237.GA21153@salvia> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> <1447759365-24099-2-git-send-email-aschultz@tpip.net> <20151117123751.GD20129@salvia> <206863558.32819.1447764286412.JavaMail.zimbra@tpip.net> <20151117131237.GA21153@salvia> Message-ID: <20151117145333.GY4687@nataraja> Hi Pablo and Andreas, On Tue, Nov 17, 2015 at 02:12:37PM +0100, Pablo Neira Ayuso wrote: > @Harald, any objection if I push this patchset? not at all! -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From pablo at soleta.eu Mon Nov 16 17:38:10 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:38:10 +0100 Subject: [PATCH 01/16] gtp: remove unused local variable In-Reply-To: <1447686417-3979-2-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-2-git-send-email-aschultz@tpip.net> Message-ID: <20151116173810.GA4392@salvia> Applied. From pablo at soleta.eu Mon Nov 16 17:39:00 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:39:00 +0100 Subject: [PATCH 02/16] gtp: remove genl_register_family_with_ops for Linux < 3.13 In-Reply-To: <1447686417-3979-3-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-3-git-send-email-aschultz@tpip.net> Message-ID: <20151116173900.GB4392@salvia> On Mon, Nov 16, 2015 at 04:06:43PM +0100, Andreas Schultz wrote: > Remove the support for genl_register_family_with_ops for > Linux < 3.13. Also reorder the initialization to be more > in line with similar modules. Also applied with minor nitpick, see below. > -err1: > + > +unreg_rtnl_link: > + rtnl_link_unregister(>p_link_ops); > + No need for extra space here, I have mangled the patch here, no problem. > +error_out: > pr_err("error loading GTP module loaded\n"); > - genl_unregister_family(>p_genl_family); > return err; > } > late_initcall(gtp_init); > > static void __exit gtp_fini(void) > { > - rtnl_link_unregister(>p_link_ops); > genl_unregister_family(>p_genl_family); > + rtnl_link_unregister(>p_link_ops); > > pr_info("GTP module unloaded\n"); > } > -- > 2.5.0 > From pablo at soleta.eu Mon Nov 16 17:39:53 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:39:53 +0100 Subject: [PATCH 03/16] gtp: convert the global gtp_instance_list to a per netns list In-Reply-To: <1447686417-3979-4-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-4-git-send-email-aschultz@tpip.net> Message-ID: <20151116173953.GC4392@salvia> On Mon, Nov 16, 2015 at 04:06:44PM +0100, Andreas Schultz wrote: > This add basic network namespace support by changing to global > gtp_instance_list into a pre namespace list. > Before this change all pdp context would be visible from all > network namespaces, now only the namespace that they belong too, > can see them. > > Also selectively destroy all gtp devices when a namespace is > destroyed. > > Signed-off-by: Andreas Schultz > --- > gtp.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- > 1 file changed, 61 insertions(+), 9 deletions(-) > > diff --git a/gtp.c b/gtp.c > index 7e615f3..7c61e61 100644 > --- a/gtp.c > +++ b/gtp.c > @@ -20,13 +20,15 @@ > #include > #include > > +#include > #include > #include > #include > #include > #include > #include > - > +#include > +# This line above has slipped through, no problem I have fixed this here. Applied. From pablo at soleta.eu Mon Nov 16 17:41:34 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:41:34 +0100 Subject: [PATCH 04/16] gtp: select netns based on NL attribute In-Reply-To: <1447686417-3979-5-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-5-git-send-email-aschultz@tpip.net> Message-ID: <20151116174134.GD4392@salvia> On Mon, Nov 16, 2015 at 04:06:45PM +0100, Andreas Schultz wrote: > This permits a split namespace setup where the GTP transport > sockets are in one namespace the gtp tunnel interface is in > another namespace. > > The target namespece is selected by the new GTPA_NET_NS_FD NL > attributes. It fall back to the netns of the GTP-U sockets if > the NL attr is not present. > > Signed-off-by: Andreas Schultz > --- > gtp.c | 41 +++++++++++++++++++++++++++++++++++++---- > gtp_nl.h | 1 + > 2 files changed, 38 insertions(+), 4 deletions(-) > > diff --git a/gtp.c b/gtp.c > index 7c61e61..11f8fad 100644 > --- a/gtp.c > +++ b/gtp.c > @@ -330,6 +330,8 @@ static int gtp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) > if (!gti) > goto user; > > + netdev_dbg(gti->dev, "encap_recv %p\n", sk); > + > switch (udp_sk(sk)->encap_type) { > case UDP_ENCAP_GTP0: > netdev_dbg(gti->dev, "received GTP0 packet\n"); > @@ -738,7 +740,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, > static int gtp_newlink(struct net *src_net, struct net_device *dev, > struct nlattr *tb[], struct nlattr *data[]) > { > - struct gtp_net *gn = net_generic(src_net, gtp_net_id); > + struct gtp_net *gn; > struct net_device *real_dev; > struct gtp_instance *gti; > int hashsize, err, fd0, fd1; > @@ -778,6 +780,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, > if (err < 0) > goto err1; > > + gn = net_generic(dev_net(dev), gtp_net_id); > list_add_rcu(>i->list, &gn->gtp_instance_list); > > netdev_dbg(dev, "registered new interface\n"); > @@ -845,6 +848,19 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = { > .fill_info = gtp_fill_info, > }; > > +static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[]) > +{ > + struct net *net; > + /* Examine the link attributes and figure out which > + * network namespace we are talking about. > + */ > + if (tb[GTPA_NET_NS_FD]) > + net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD])); I can see this returns ERR_PTR() so... > + else > + net = get_net(src_net); > + return net; > +} > + > static int gtp_hashtable_new(struct gtp_instance *gti, int hsize) > { > int i; > @@ -893,6 +909,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, > struct socket *sock0, *sock1u; > struct sock *sk; > > + netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1); > + > sock0 = sockfd_lookup(fd_gtp0, &err); > if (sock0 == NULL) { > netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0); > @@ -918,6 +936,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, > goto err2; > } > > + netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u); > + > gti->sock0 = sock0; > gti->sock1u = sock1u; > > @@ -1059,7 +1079,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) > > static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) > { > - struct net *net = sock_net(skb->sk); > + struct net *net; > struct net_device *dev; > > if (!info->attrs[GTPA_VERSION] || > @@ -1069,6 +1089,10 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) > !info->attrs[GTPA_TID]) > return -EINVAL; > > + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); > + if (net == NULL) This has to be IS_ERR(). > + return -EINVAL; > + > /* Check if there's an existing gtpX device to configure */ > dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); > if (dev == NULL) > @@ -1079,7 +1103,7 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) > > static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) > { > - struct net *net = sock_net(skb->sk); > + struct net *net; > struct gtp_instance *gti; > struct net_device *dev; > struct pdp_ctx *pctx; > @@ -1107,6 +1131,10 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) > if (gtp_version == GTP_V1 && tid > UINT_MAX) > return -EINVAL; > > + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); > + if (net == NULL) This one too. > + return -EINVAL; > + > /* Check if there's an existing gtpX device to configure */ > dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); > if (dev == NULL) > @@ -1175,7 +1203,7 @@ nla_put_failure: > > static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) > { > - struct net *net = sock_net(skb->sk); > + struct net *net; > struct net_device *dev; > struct gtp_instance *gti; > struct pdp_ctx *pctx = NULL; > @@ -1196,6 +1224,10 @@ static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) > return -EINVAL; > } > > + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); > + if (net == NULL) And here. BTW, I'd appreciate if you can add netdev_dbg stuff in a separated patch. From pablo at soleta.eu Mon Nov 16 17:43:55 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:43:55 +0100 Subject: [PATCH 05/16] gtp-rtnl: and netns support In-Reply-To: <1447686417-3979-6-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-6-git-send-email-aschultz@tpip.net> Message-ID: <20151116174355.GE4392@salvia> On Mon, Nov 16, 2015 at 04:06:46PM +0100, Andreas Schultz wrote: > diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c > index c1f60ab..9e68a30 100644 > --- a/libgtnl/src/gtp-genl.c > +++ b/libgtnl/src/gtp-genl.c > @@ -44,6 +44,8 @@ > static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) > { > mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version); > + if (t->ifns > 0) > + mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns); Any reason not to consider descriptor zero as valid? I guess we'll need some flags for gtp_tunnel so we know what we have set here. > mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx); > mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); > mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); > diff --git a/libgtnl/src/gtp-rtnl.c b/libgtnl/src/gtp-rtnl.c > index 22b9430..db54653 100644 > --- a/libgtnl/src/gtp-rtnl.c > +++ b/libgtnl/src/gtp-rtnl.c > @@ -38,6 +38,10 @@ > > #include "internal.h" > > +#if !defined(IFLA_LINK_NETNSID) > +#define IFLA_LINK_NETNSID (IFLA_PHYS_SWITCH_ID + 1) > +#endif Why do you need this? From pablo at soleta.eu Mon Nov 16 17:46:29 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:46:29 +0100 Subject: [PATCH 06/16] gtp: add error handling to gtp_newlink In-Reply-To: <1447686417-3979-7-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-7-git-send-email-aschultz@tpip.net> Message-ID: <20151116174629.GF4392@salvia> On Mon, Nov 16, 2015 at 04:06:47PM +0100, Andreas Schultz wrote: > Signed-off-by: Andreas Schultz > --- > gtp.c | 32 +++++++++++++++++++++++--------- > 1 file changed, 23 insertions(+), 9 deletions(-) > > diff --git a/gtp.c b/gtp.c > index 11f8fad..4f5729e 100644 > --- a/gtp.c > +++ b/gtp.c > @@ -756,8 +756,12 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, > > if (!tb[IFLA_MTU]) > dev->mtu = real_dev->mtu; > - else if (dev->mtu > real_dev->mtu) > - return -EINVAL; > + else if (dev->mtu > real_dev->mtu) { > + netdev_dbg(dev, "GTP mtu greater that transport MTU (%d > %d)\n", > + dev->mtu, real_dev->mtu); > + err = -EINVAL; > + goto out_err; This is function is using __dev_get_by_index(), so we're not holding a reference on the netdevice here. > + } > > gti = netdev_priv(dev); > gti->real_dev = real_dev; [...] > +out_err: > + dev_put(real_dev); > return err; > } From pablo at soleta.eu Mon Nov 16 17:48:23 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:48:23 +0100 Subject: [PATCH 07/16] gtp: fix the order of error cases in gtp_encap_enable In-Reply-To: <1447686417-3979-8-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-8-git-send-email-aschultz@tpip.net> Message-ID: <20151116174823.GA4672@salvia> On Mon, Nov 16, 2015 at 04:06:48PM +0100, Andreas Schultz wrote: > The ordering of the error case exit was wrong and would > attempt to release the wrong socket. also applied. From pablo at soleta.eu Mon Nov 16 17:53:45 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:53:45 +0100 Subject: [PATCH 11/16] gtp: Split TID handling got GTPv0 and GTPv1 In-Reply-To: <1447686417-3979-12-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-12-git-send-email-aschultz@tpip.net> Message-ID: <20151116175345.GG4392@salvia> On Mon, Nov 16, 2015 at 04:06:52PM +0100, Andreas Schultz wrote: > GTPv1 tunnel use a separate TEI for each direction. Add a union > to hold TID for v0 and v1 separately. > > Signed-off-by: Andreas Schultz > --- > gtp.c | 211 +++++++++++++++++++++++++++++++++++---------------------------- > gtp_nl.h | 2 + > 2 files changed, 118 insertions(+), 95 deletions(-) > > diff --git a/gtp.c b/gtp.c > index 2ac6431..a4be31d 100644 > --- a/gtp.c > +++ b/gtp.c > @@ -39,7 +39,17 @@ struct pdp_ctx { > struct hlist_node hlist_tid; > struct hlist_node hlist_addr; > > - u64 tid; > + union { > + uint64_t tid; > + struct { > + uint64_t tid; > + u16 flow; > + } v0 __attribute__((__packed__)); We're not sending this through network, so this packed attribute makes no sense to me. From pablo at soleta.eu Mon Nov 16 17:55:59 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:55:59 +0100 Subject: [PATCH 00/16] GTP kernel update (patch bomb) In-Reply-To: <1447686417-3979-1-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> Message-ID: <20151116175559.GH4392@salvia> On Mon, Nov 16, 2015 at 04:06:41PM +0100, Andreas Schultz wrote: > Hi, > > Sorry for smsching this all together, but I couldn't find a > logical point to split the patches. Also the order can't > really be changed as most patches depend on each other. I have reviewed and applied as much as I could, please follow up with another incremental update. > After this series, the GTP kernel module is functional > for IPv4 payload in IPv4 GTP tunnels (for GTPv0 and v1). > > The libgtnl API was changed without increasing the SO version > of the lib. I think this is ok since nothing really uses it > (yet) nor has the library been offcially released. Then, why update it? Thanks. From pablo at soleta.eu Mon Nov 16 17:59:54 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 18:59:54 +0100 Subject: [PATCH 03/16] gtp: convert the global gtp_instance_list to a per netns list In-Reply-To: <1447686417-3979-4-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-4-git-send-email-aschultz@tpip.net> Message-ID: <20151116175954.GA5562@salvia> On Mon, Nov 16, 2015 at 04:06:44PM +0100, Andreas Schultz wrote: > +static void __net_exit gtp_net_exit(struct net *net) > +{ > + struct gtp_net *gn = net_generic(net, gtp_net_id); > + struct gtp_instance *gti; > + LIST_HEAD(list); > + > + rtnl_lock(); > + list_for_each_entry_rcu(gti, &gn->gtp_instance_list, list) { BTW, I have also removed the _rcu here. The instance list is protected by rtnl_lock, so no need for safe read-side interation here. > + gtp_dellink(gti->dev, &list); > + } > + > + unregister_netdevice_many(&list); > + rtnl_unlock(); > +} From pablo at soleta.eu Mon Nov 16 21:57:50 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Mon, 16 Nov 2015 22:57:50 +0100 Subject: [PATCH 06/16] gtp: add error handling to gtp_newlink In-Reply-To: <934587666.24310.1447697818921.JavaMail.zimbra@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-7-git-send-email-aschultz@tpip.net> <20151116174629.GF4392@salvia> <934587666.24310.1447697818921.JavaMail.zimbra@tpip.net> Message-ID: <20151116215750.GA6725@salvia> On Mon, Nov 16, 2015 at 07:16:58PM +0100, Andreas Schultz wrote: > >> diff --git a/gtp.c b/gtp.c > >> index 11f8fad..4f5729e 100644 > >> --- a/gtp.c > >> +++ b/gtp.c > >> @@ -756,8 +756,12 @@ static int gtp_newlink(struct net *src_net, struct > >> net_device *dev, > >> > >> if (!tb[IFLA_MTU]) > >> dev->mtu = real_dev->mtu; > >> - else if (dev->mtu > real_dev->mtu) > >> - return -EINVAL; > >> + else if (dev->mtu > real_dev->mtu) { > >> + netdev_dbg(dev, "GTP mtu greater that transport MTU (%d > %d)\n", > >> + dev->mtu, real_dev->mtu); > >> + err = -EINVAL; > >> + goto out_err; > > > > This is function is using __dev_get_by_index(), so we're not holding a > > reference on the netdevice here. > > But there is a 'dev_hold(real_dev);' right before that if condition. Doesn't that > take a reference to the netdevice? Ah I see. Right, there is a leak there. > Anyway, the conversion to the iptunnel framework makes this code largely > obsolete. So I'm going to drop this change. OK. From pablo at soleta.eu Tue Nov 17 12:31:48 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Tue, 17 Nov 2015 13:31:48 +0100 Subject: [PATCH 05/16] gtp-rtnl: and netns support In-Reply-To: <963352600.30683.1447754986159.JavaMail.zimbra@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-6-git-send-email-aschultz@tpip.net> <20151116174355.GE4392@salvia> <963352600.30683.1447754986159.JavaMail.zimbra@tpip.net> Message-ID: <20151117123148.GA20129@salvia> On Tue, Nov 17, 2015 at 11:09:46AM +0100, Andreas Schultz wrote: > ----- Original Message ----- > > From: "Pablo Neira Ayuso" > > To: "Andreas Schultz" > > Cc: openbsc at lists.osmocom.org, "Harald Welte" > > Sent: Monday, November 16, 2015 6:43:55 PM > > Subject: Re: [PATCH 05/16] gtp-rtnl: and netns support > > > On Mon, Nov 16, 2015 at 04:06:46PM +0100, Andreas Schultz wrote: > >> diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c > >> index c1f60ab..9e68a30 100644 > >> --- a/libgtnl/src/gtp-genl.c > >> +++ b/libgtnl/src/gtp-genl.c > >> @@ -44,6 +44,8 @@ > >> static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) > >> { > >> mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version); > >> + if (t->ifns > 0) > >> + mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns); > > > > Any reason not to consider descriptor zero as valid? > > ifns is a file descriptor and fd's are as far as I know always greater zero. > So, I didn't see a reason to permit zero there when simply not setting the > attribute would serve the same purpose. You close(0) and then allocate a descriptor via open(...) and see what it happens. #include #include #include int main(void) { int fd; close(0); fd = open("/etc/passwd", O_RDONLY); printf("fd = %d\n", fd); } From pablo at soleta.eu Tue Nov 17 12:33:17 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Tue, 17 Nov 2015 13:33:17 +0100 Subject: [PATCH 2/3] gtp: select netns based on NL attribute In-Reply-To: <1447758380-22202-3-git-send-email-aschultz@tpip.net> References: <1447758380-22202-1-git-send-email-aschultz@tpip.net> <1447758380-22202-3-git-send-email-aschultz@tpip.net> Message-ID: <20151117123317.GB20129@salvia> On Tue, Nov 17, 2015 at 12:06:19PM +0100, Andreas Schultz wrote: > This permits a split namespace setup where the GTP transport > sockets are in one namespace the gtp tunnel interface is in > another namespace. > > The target namespece is selected by the new GTPA_NET_NS_FD NL > attributes. It fall back to the netns of the GTP-U sockets if > the NL attr is not present. > > Signed-off-by: Andreas Schultz > --- > gtp.c | 35 +++++++++++++++++++++++++++++++---- > gtp_nl.h | 1 + > 2 files changed, 32 insertions(+), 4 deletions(-) > > diff --git a/gtp.c b/gtp.c > index cbe2da1..0a45f53 100644 > --- a/gtp.c > +++ b/gtp.c > @@ -740,7 +740,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, > static int gtp_newlink(struct net *src_net, struct net_device *dev, > struct nlattr *tb[], struct nlattr *data[]) > { > - struct gtp_net *gn = net_generic(src_net, gtp_net_id); > + struct gtp_net *gn; > struct net_device *real_dev; > struct gtp_instance *gti; > int hashsize, err, fd0, fd1; > @@ -780,6 +780,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, > if (err < 0) > goto err1; > > + gn = net_generic(dev_net(dev), gtp_net_id); > list_add_rcu(>i->list, &gn->gtp_instance_list); > > netdev_dbg(dev, "registered new interface\n"); > @@ -847,6 +848,19 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = { > .fill_info = gtp_fill_info, > }; > > +static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[]) > +{ > + struct net *net; > + /* Examine the link attributes and figure out which > + * network namespace we are talking about. > + */ > + if (tb[GTPA_NET_NS_FD]) > + net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD])); > + else > + net = get_net(src_net); > + return net; > +} > + > static int gtp_hashtable_new(struct gtp_instance *gti, int hsize) > { > int i; > @@ -1065,7 +1079,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) > > static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) > { > - struct net *net = sock_net(skb->sk); > + struct net *net; > struct net_device *dev; > > if (!info->attrs[GTPA_VERSION] || > @@ -1075,6 +1089,10 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) > !info->attrs[GTPA_TID]) > return -EINVAL; > > + net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); > + if (IS_ERR(net)) > + return -EINVAL; You probably want to propagate the real error reason: return PTR_ERR(net); From pablo at soleta.eu Tue Nov 17 12:35:26 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Tue, 17 Nov 2015 13:35:26 +0100 Subject: [PATCH 1/3] gtp: add some debug instrumentation In-Reply-To: <1447758380-22202-2-git-send-email-aschultz@tpip.net> References: <1447758380-22202-1-git-send-email-aschultz@tpip.net> <1447758380-22202-2-git-send-email-aschultz@tpip.net> Message-ID: <20151117123526.GC20129@salvia> Applied. From pablo at soleta.eu Tue Nov 17 12:37:51 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Tue, 17 Nov 2015 13:37:51 +0100 Subject: [PATCH openggsn 1/4] ggsn: add support for GTP kernel data encapsulation In-Reply-To: <1447759365-24099-2-git-send-email-aschultz@tpip.net> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> <1447759365-24099-2-git-send-email-aschultz@tpip.net> Message-ID: <20151117123751.GD20129@salvia> On Tue, Nov 17, 2015 at 12:22:42PM +0100, Andreas Schultz wrote: > From: Pablo Neira Ayuso > > This patch adds the -g, --gtpnl=device option that allows you to > enable the GTP kernel tunneling mode in openggsn. You have to specify > the real downlink device that will be used to tunnel traffic, eg. > > -g=eth0 This is basically my original patch rebased upon master or are there any changes on it? From pablo at soleta.eu Tue Nov 17 12:45:16 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Tue, 17 Nov 2015 13:45:16 +0100 Subject: [PATCH openggsn 4/4] ggsn: add network namespace support In-Reply-To: <1447759365-24099-5-git-send-email-aschultz@tpip.net> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> <1447759365-24099-5-git-send-email-aschultz@tpip.net> Message-ID: <20151117124516.GE20129@salvia> On Tue, Nov 17, 2015 at 12:22:45PM +0100, Andreas Schultz wrote: > The kernel gtp can now be create in an existing sub namespace. Could you please document this a bit more? BTW, if I'm asking for things it is not because I want to start some philosophical debate on documentation and submission standards... The reason behind is way more simple than all that: the less time I have to dedicate to follow your track, the less time I have to dedicate on this sort of hobby project. Thanks. From pablo at soleta.eu Tue Nov 17 13:12:37 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Tue, 17 Nov 2015 14:12:37 +0100 Subject: [PATCH openggsn 1/4] ggsn: add support for GTP kernel data encapsulation In-Reply-To: <206863558.32819.1447764286412.JavaMail.zimbra@tpip.net> References: <1447759365-24099-1-git-send-email-aschultz@tpip.net> <1447759365-24099-2-git-send-email-aschultz@tpip.net> <20151117123751.GD20129@salvia> <206863558.32819.1447764286412.JavaMail.zimbra@tpip.net> Message-ID: <20151117131237.GA21153@salvia> On Tue, Nov 17, 2015 at 01:44:46PM +0100, Andreas Schultz wrote: > ----- Original Message ----- > > From: "Pablo Neira Ayuso" > > To: "Andreas Schultz" > > Cc: openbsc at lists.osmocom.org, "Harald Welte" , "Pablo Neira Ayuso" > > Sent: Tuesday, November 17, 2015 1:37:51 PM > > Subject: Re: [PATCH openggsn 1/4] ggsn: add support for GTP kernel data encapsulation > > > On Tue, Nov 17, 2015 at 12:22:42PM +0100, Andreas Schultz wrote: > >> From: Pablo Neira Ayuso > >> > >> This patch adds the -g, --gtpnl=device option that allows you to > >> enable the GTP kernel tunneling mode in openggsn. You have to specify > >> the real downlink device that will be used to tunnel traffic, eg. > >> > >> -g=eth0 > > > > This is basically my original patch rebased upon master or are there > > any changes on it? > > No changes, I wanted to keep you original for reference, then apply > the two fixes on top of that and add the netns stuff after that. > > You patch doesn't build anymore, due to the logging changes. If you want > every changeset to build-able, you need to merge it with the log and > automake patches. Makes sense, thanks. @Harald, any objection if I push this patchset? Thanks. From nhofmeyr at sysmocom.de Wed Nov 18 14:29:43 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 18 Nov 2015 15:29:43 +0100 Subject: [PATCH 0/1] A patch for openbsc In-Reply-To: <1446901252-5264-1-git-send-email-alexander.huemer@xx.vu> References: <20151107123941.GA26613@yade.xx.vu> <1446901252-5264-1-git-send-email-alexander.huemer@xx.vu> Message-ID: <20151118142910.GB2021@dub5> On Sat, Nov 07, 2015 at 02:00:51PM +0100, Alexander Huemer wrote: > so I guess the right format specifier to use here is "%td", since the > expression is (something like) a ptrdiff_t. Thanks, it's actually the first time I come across ptrdiff_t. From the explanations I've found, this is The Correct (TM) type to use, indeed. In my /usr/lib/gcc/x86_64-linux-gnu it's defined as long int. I ask myself though -- for linkage size smaller than 2 GB, apparently the default everywhere, pointer differences will stay within the 32 bit address range, and using an int should suffice? To link surpassing 2 GB, one needs to explicitly pass -mcmodel=medium to gcc, and I doubt any osmo project will surpass 2 GB linkage any time soon ;) Instead of reading man snprintf all the time, I actually tend to use %d and cast the argument to (int) :P This will only work if the thing to print is entirely within the int range, of course. uint16_t x = 5; printf("%d", (int)x); An advantage here is that the type of x can be tweaked later without having to edit the formats everywhere (error prone). I can't really find them now, but I dimly remember seeing some osmo code here and there where printf() formats could use some more attention... Like, is it accurate to pass an enum type to %d without casting? And so on. Most of those instances still print the correct value because, I assume, actual storage of the values is often blown up to the CPU's native size... (handwavy) ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Nov 18 14:57:44 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 18 Nov 2015 15:57:44 +0100 Subject: [PATCH 06/16] gtp: add error handling to gtp_newlink In-Reply-To: <1447686417-3979-7-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-7-git-send-email-aschultz@tpip.net> Message-ID: <20151118144652.GC2021@dub5> On Mon, Nov 16, 2015 at 04:06:47PM +0100, Andreas Schultz wrote: > Signed-off-by: Andreas Schultz > --- > gtp.c | 32 +++++++++++++++++++++++--------- > 1 file changed, 23 insertions(+), 9 deletions(-) > > diff --git a/gtp.c b/gtp.c > index 11f8fad..4f5729e 100644 > --- a/gtp.c > +++ b/gtp.c > @@ -756,8 +756,12 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, > > if (!tb[IFLA_MTU]) > dev->mtu = real_dev->mtu; > - else if (dev->mtu > real_dev->mtu) > - return -EINVAL; > + else if (dev->mtu > real_dev->mtu) { > + netdev_dbg(dev, "GTP mtu greater that transport MTU (%d > %d)\n", "than" with n ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Nov 18 15:05:11 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 18 Nov 2015 16:05:11 +0100 Subject: git repos for patch Message-ID: <20151118150456.GD2021@dub5> Hi list, I'm sometimes confused about which repository a patch set is intended for. Is there an easy way to include the repository name in a mailed patch set, besides naming it manually in a cover-letter? ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Nov 18 15:13:10 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 18 Nov 2015 16:13:10 +0100 Subject: [PATCH] gtphub: fix build: remove obsolete EXTRA_DIST. Message-ID: <1447859590-12199-1-git-send-email-nhofmeyr@sysmocom.de> --- openbsc/tests/gtphub/Makefile.am | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openbsc/tests/gtphub/Makefile.am b/openbsc/tests/gtphub/Makefile.am index d818811..59480ed 100644 --- a/openbsc/tests/gtphub/Makefile.am +++ b/openbsc/tests/gtphub/Makefile.am @@ -2,10 +2,7 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) EXTRA_DIST = \ - gtphub_test.ok \ - gtphub_nc_test.sh \ - gtphub_nc_test.ok \ - hex2bin.py + gtphub_test.ok noinst_PROGRAMS = gtphub_test -- 2.1.4 From nhofmeyr at sysmocom.de Wed Nov 18 16:36:51 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 18 Nov 2015 17:36:51 +0100 Subject: [PATCH] gtphub: fix build: remove obsolete EXTRA_DIST. In-Reply-To: <1447859590-12199-1-git-send-email-nhofmeyr@sysmocom.de> References: <1447859590-12199-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20151118163651.GA22666@dub5> I'll actually just merge this myself. ~Neels On Wed, Nov 18, 2015 at 04:13:10PM +0100, Neels Hofmeyr wrote: > --- > openbsc/tests/gtphub/Makefile.am | 5 +---- > 1 file changed, 1 insertion(+), 4 deletions(-) > > diff --git a/openbsc/tests/gtphub/Makefile.am b/openbsc/tests/gtphub/Makefile.am > index d818811..59480ed 100644 > --- a/openbsc/tests/gtphub/Makefile.am > +++ b/openbsc/tests/gtphub/Makefile.am > @@ -2,10 +2,7 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include > AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) > > EXTRA_DIST = \ > - gtphub_test.ok \ > - gtphub_nc_test.sh \ > - gtphub_nc_test.ok \ > - hex2bin.py > + gtphub_test.ok > > noinst_PROGRAMS = gtphub_test > > -- > 2.1.4 > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Nov 18 16:40:34 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 18 Nov 2015 17:40:34 +0100 Subject: [PATCH 1/3] gtphub: fix gtphub_read() semantics. In-Reply-To: <1447761116-7633-1-git-send-email-nhofmeyr@sysmocom.de> References: <1447761116-7633-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20151118164034.GB22666@dub5> Since they (should) fix coverity complaints, I'm also merging these three to master myself. ~Neels On Tue, Nov 17, 2015 at 12:51:54PM +0100, Neels Hofmeyr wrote: > gtphub always wants to know the sender, hence make the from_addr pointer > mandatory. > > Fixes two coverity complaints (1339766, 1339764). > > Sponsored-by: On-Waves ehi > --- > openbsc/src/gprs/gtphub.c | 16 +++++++--------- > 1 file changed, 7 insertions(+), 9 deletions(-) > > diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c > index e00d6cd..049e9f5 100644 > --- a/openbsc/src/gprs/gtphub.c > +++ b/openbsc/src/gprs/gtphub.c > @@ -784,16 +784,16 @@ static int gtphub_bind_start(struct gtphub_bind *b, > return 0; > } > > -/* Recv datagram from from->fd, optionally write sender's address to *from_addr. > +/* Recv datagram from from->fd, write sender's address to *from_addr. > * Return the number of bytes read, zero on error. */ > static int gtphub_read(const struct osmo_fd *from, > struct osmo_sockaddr *from_addr, > uint8_t *buf, size_t buf_len) > { > - /* recvfrom requires the available length set in *from_addr_len. */ > - if (from_addr) > - from_addr->l = sizeof(from_addr->a); > + OSMO_ASSERT(from_addr); > > + /* recvfrom requires the available length set in *from_addr_len. */ > + from_addr->l = sizeof(from_addr->a); > errno = 0; > ssize_t received = recvfrom(from->fd, buf, buf_len, 0, > (struct sockaddr*)&from_addr->a, > @@ -807,12 +807,10 @@ static int gtphub_read(const struct osmo_fd *from, > return 0; > } > > - if (from_addr) { > - LOG(LOGL_DEBUG, "from %s\n", osmo_sockaddr_to_str(from_addr)); > - } > + LOG(LOGL_DEBUG, "Received %d bytes from %s\n%s\n", > + (int)received, osmo_sockaddr_to_str(from_addr), > + osmo_hexdump(buf, received)); > > - LOG(LOGL_DEBUG, "Received %d %s\n", > - (int)received, osmo_hexdump(buf, received)); > return received; > } > > -- > 2.1.4 > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Wed Nov 18 16:44:03 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 18 Nov 2015 16:44:03 +0000 Subject: [PATCH] gtphub: fix build: remove obsolete EXTRA_DIST. In-Reply-To: <20151118163651.GA22666@dub5> References: <1447859590-12199-1-git-send-email-nhofmeyr@sysmocom.de> <20151118163651.GA22666@dub5> Message-ID: > On 18 Nov 2015, at 16:36, Neels Hofmeyr wrote: > > I'll actually just merge this myself. yes, go ahead and push this one :) From suraev at alumni.ntnu.no Wed Nov 18 20:43:10 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Wed, 18 Nov 2015 21:43:10 +0100 Subject: channel availability In-Reply-To: <20151114202001.GU4687@nataraja> References: <56472931.9070807@alumni.ntnu.no> <20151114202001.GU4687@nataraja> Message-ID: <564CE2DE.3050809@alumni.ntnu.no> 14.11.2015 21:20, Harald Welte ?????: > On Sat, Nov 14, 2015 at 01:29:37PM +0100, Suraev wrote: >> MY question is - how to troubleshoot this? Where can I look as to >> which channels are available, which are occupied and by whom? > > 'show lchan' shows you the state of currently allocated logical > channels. That's what have puzzled me most - "show lchan" returns nothing but "imm. ass. reject" is still the constant reply. > 'by whom' doesn't really work unless we have received an > identity of the subscirber already. You don't know at the time of RACH > request. > Anyway, it turned out that the problem was between the chair and the keyboard: I've used wrong branch of Osmo-BTS which was incompatible with my hw. Now everything seems to be fine component wise - all logs seems adequate, calls going through. The only issue - no internet on the device, even name resolution fails. Seems like packets are not forwarded properly. What would the best place to poke into user's traffic - see what packets come from which phone and what happens to them and to return traffic? cheers, Max. From laforge at gnumonks.org Thu Nov 19 08:26:42 2015 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 19 Nov 2015 09:26:42 +0100 Subject: channel availability In-Reply-To: <564CE2DE.3050809@alumni.ntnu.no> References: <56472931.9070807@alumni.ntnu.no> <20151114202001.GU4687@nataraja> <564CE2DE.3050809@alumni.ntnu.no> Message-ID: <20151119082642.GU4687@nataraja> On Wed, Nov 18, 2015 at 09:43:10PM +0100, Suraev wrote: > Anyway, it turned out that the problem was between the chair and the > keyboard: I've used wrong branch of Osmo-BTS which was incompatible > with my hw. which branch is the incompatible branch, and which branch are you using now? We have merged osmo-trx support into master in order to get rid of of the need of the nightmare of too many branches. It would be a pity if all that effort was for nothing. > The only issue - no internet on the device, even name resolution fails. Seems like > packets are not forwarded properly. What would the best place to poke into user's > traffic - see what packets come from which phone and what happens to them and to > return traffic? does the GPRS control plane work, i.e. do you se GPRS ATTACH / ACCEPT, ROUTING AREA UPDATE ATTACH/ ACCEPT, PDP CONTEXT ACTIVATE / ACCEPT? You can follow this in the VTY logging of OsmoSGSN (logging level for mobility management and session management). Alternatively, the Gb interface on port 23000/udp can be followed n wireshark. You need to 'decode as... Gb (or was it called GPRS-Gb?) -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From suraev at alumni.ntnu.no Thu Nov 19 11:41:42 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Thu, 19 Nov 2015 12:41:42 +0100 Subject: channel availability In-Reply-To: <20151119082642.GU4687@nataraja> References: <56472931.9070807@alumni.ntnu.no> <20151114202001.GU4687@nataraja> <564CE2DE.3050809@alumni.ntnu.no> <20151119082642.GU4687@nataraja> Message-ID: <564DB576.50706@alumni.ntnu.no> 19.11.2015 09:26, Harald Welte ?????: > which branch is the incompatible branch, and which branch are you using > now? We have merged osmo-trx support into master in order to get rid of > of the need of the nightmare of too many branches. It would be a pity > if all that effort was for nothing. > Hmm, I thought that process was still ongoing. I'm using branch 201509-fairwaves-rebase of Osmo-BTS with usrp b210. The rest of the components are at master branch. > does the GPRS control plane work, i.e. do you se GPRS ATTACH / ACCEPT, > ROUTING AREA UPDATE ATTACH/ ACCEPT, PDP CONTEXT ACTIVATE / ACCEPT? > > You can follow this in the VTY logging of OsmoSGSN (logging level for > mobility management and session management). You mean: telnet localhost 4245 en logging enable logging set-log-mask DMM:DCC ? > Alternatively, the Gb interface on port 23000/udp can be followed n > wireshark. You need to 'decode as... Gb (or was it called GPRS-Gb?) > I can decode it as GPRS (wireshark 1.12.7). In this case I've got: gprs attach request, with id request followed by attach accept and attach complete. The tun0 is created, masquerading is on by iptables, forwarding is enabled with sysctl. After the gprs attach I see lots of FLOW-CONTROL_BVC and NS-ALIVE messages with corresponding -ACK. The strange thing is - I see no packets over tun0 at all. Same goes for udp port 23000 except what was mentioned above. Shouldn't I be able to at least see dns queries from mobile? The logs from OsmoPCU also looks cryptic but the message about timeout seems suspicious: <0001> sysmo_sock.cpp:283 PCU-SYSMO socket has been connected <0001> pcu_l1_if.cpp:343 BTS available <0008> gprs_ns.c:233 NSVCI=65534 Creating NS-VC <0008> gprs_ns.c:233 NSVCI=101 Creating NS-VC <0008> gprs_ns.c:1561 NSEI=101 RESET procedure based on API request <0008> gprs_ns.c:392 NSEI=101 Tx NS RESET (NSVCI=101, cause=O&M intervention) <0001> pcu_l1_if.cpp:80 Sending activate request: trx=0 ts=6 <0001> pcu_l1_if.cpp:469 PDCH: trx=0 ts=6 <0001> pcu_l1_if.cpp:80 Sending activate request: trx=0 ts=7 <0001> pcu_l1_if.cpp:469 PDCH: trx=0 ts=7 <0008> gprs_ns.c:935 NSVCI=101 Rx NS RESET ACK (NSEI=101, NSVCI=101) <0008> gprs_ns.c:501 NSEI=101 Tx NS UNBLOCK (NSVCI=101) <0008> gprs_ns.c:1345 NSEI=101 Rx NS UNBLOCK ACK <000a> gprs_bssgp_pcu.cpp:489 NS-VC 101 is unblocked. <0009> gprs_bssgp_pcu.cpp:749 Sending reset on BVCI 0 <0009> gprs_bssgp_bss.c:290 BSSGP (BVCI=0) Tx BVC-RESET CAUSE=8 <0009> gprs_bssgp_pcu.cpp:757 Sending reset on BVCI 2 <0009> gprs_bssgp_bss.c:290 BSSGP (BVCI=2) Tx BVC-RESET CAUSE=8 <0009> gprs_bssgp_pcu.cpp:765 Sending unblock on BVCI 2 <0009> gprs_bssgp_bss.c:270 BSSGP (BVCI=2) Tx BVC-BLOCK <0001> pcu_l1_if.cpp:295 RACH request received: sapi=1 qta=0, ra=120, fn=1742448 <0009> tbf_ul.cpp:407 LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0x865ad706 DIR=UL STATE=FLOW) len=52 <0009> gprs_bssgp_pcu.cpp:179 LLC [SGSN -> PCU] = TLLI: 0x865ad706 IMSI: 000 len: 9 <0007> gprs_rlcmac_meas.cpp:104 UL RSSI of TLLI=0x865ad706: -62 dBm <0001> pcu_l1_if.cpp:295 RACH request received: sapi=1 qta=0, ra=123, fn=1742930 <0007> gprs_rlcmac_meas.cpp:159 DL packet loss of IMSI=000 / TLLI=0x865ad706: 0% <0009> tbf_ul.cpp:407 LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0x865ad706 DIR=UL STATE=FLOW) len=17 <0009> gprs_bssgp_pcu.cpp:179 LLC [SGSN -> PCU] = TLLI: 0x865ad706 IMSI: 000 len: 9 <0007> gprs_rlcmac_meas.cpp:104 UL RSSI of TLLI=0x865ad706: -66 dBm <0002> tbf.cpp:434 TBF(TFI=0 TLLI=0x865ad706 DIR=DL STATE=ASSIGN) poll timeout for FN=1743252 (curr FN 1743313) <0002> tbf.cpp:485 - Timeout for polling PACKET CONTROL ACK for PACKET DOWNLINK ASSIGNMENT. <0002> tbf.cpp:777 - Assignment was on PACCH <0002> tbf.cpp:785 - No downlink ACK received yet <0002> bts.cpp:812 Recovered downlink assignment for TBF(TFI=0 TLLI=0x865ad706 DIR=DL STATE=FLOW) <0007> gprs_rlcmac_meas.cpp:184 DL Bandwitdh of IMSI=000 / TLLI=0x865ad706: 0 KBits/s <0007> gprs_rlcmac_meas.cpp:159 DL packet loss of IMSI=000 / TLLI=0x865ad706: 0% <0009> tbf_ul.cpp:407 LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0x865ad706 DIR=UL STATE=FLOW) len=17 <0009> gprs_bssgp_pcu.cpp:179 LLC [SGSN -> PCU] = TLLI: 0x865ad706 IMSI: 901708776992222 len: 26 <0002> tbf.cpp:434 TBF(TFI=0 TLLI=0x865ad706 DIR=UL STATE=FINISHED) poll timeout for FN=1743534 (curr FN 1743599) <0002> tbf.cpp:485 - Timeout for polling PACKET CONTROL ACK for PACKET DOWNLINK ASSIGNMENT. <0002> tbf.cpp:777 - Assignment was on PACCH <0002> tbf.cpp:785 - No downlink ACK received yet <0002> bts.cpp:812 Recovered downlink assignment for TBF(TFI=0 TLLI=0x865ad706 DIR=DL STATE=FLOW) <0007> gprs_rlcmac_meas.cpp:184 DL Bandwitdh of IMSI=000 / TLLI=0x865ad706: 0 KBits/s <0007> gprs_rlcmac_meas.cpp:159 DL packet loss of IMSI=000 / TLLI=0x865ad706: 0% <0009> tbf_ul.cpp:407 LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0x865ad706 DIR=UL STATE=FLOW) len=17 <0009> gprs_bssgp_pcu.cpp:179 LLC [SGSN -> PCU] = TLLI: 0x865ad706 IMSI: 901708776992222 len: 26 <0002> tbf.cpp:434 TBF(TFI=0 TLLI=0x865ad706 DIR=UL STATE=FINISHED) poll timeout for FN=1743534 (curr FN 1743599) <0002> tbf.cpp:485 - Timeout for polling PACKET CONTROL ACK for PACKET DOWNLINK ASSIGNMENT. <0002> tbf.cpp:777 - Assignment was on PACCH <0002> tbf.cpp:779 - Uplink data was received <0002> tbf.cpp:434 TBF(TFI=0 TLLI=0x865ad706 DIR=UL STATE=FINISHED) poll timeout for FN=1743638 (curr FN 1743703) <0007> gprs_rlcmac_meas.cpp:184 DL Bandwitdh of IMSI=901708776992222 / TLLI=0x865ad706: 0 KBits/s <0007> gprs_rlcmac_meas.cpp:104 UL RSSI of TLLI=0x865ad706: -67 dBm <0007> gprs_rlcmac_meas.cpp:159 DL packet loss of IMSI=901708776992222 / TLLI=0x865ad706: 0% <0001> pcu_l1_if.cpp:295 RACH request received: sapi=1 qta=0, ra=121, fn=1744126 <0009> tbf_ul.cpp:407 LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0xc7c9a645 DIR=UL STATE=FLOW) len=8 <0007> gprs_rlcmac_meas.cpp:104 UL RSSI of TLLI=0xc7c9a645: -69 dBm <0002> bts.cpp:767 PACKET CONTROL ACK with unknown FN=1745900 TLLI=0xc7c9a645 (TRX 0 TS 6) <0002> bts.cpp:767 PACKET CONTROL ACK with unknown FN=1746095 TLLI=0xc7c9a645 (TRX 0 TS 6) Any ideas what am I missing in here? cheers, Max. From nhofmeyr at sysmocom.de Thu Nov 19 12:41:05 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 19 Nov 2015 13:41:05 +0100 Subject: [PATCH 13/16] gtp-rtnl: real_ifname is not long needed, remove it In-Reply-To: <1447686417-3979-14-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-14-git-send-email-aschultz@tpip.net> Message-ID: <20151119124105.GB7092@dub5> log message: "no longer needed" ? ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Nov 19 14:00:02 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 19 Nov 2015 15:00:02 +0100 Subject: [PATCH 14/16] gtp-rtnl: Split tid handling for GTPv0 and GTPv1 In-Reply-To: <1447686417-3979-15-git-send-email-aschultz@tpip.net> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-15-git-send-email-aschultz@tpip.net> Message-ID: <20151119140002.GC7092@dub5> On Mon, Nov 16, 2015 at 04:06:55PM +0100, Andreas Schultz wrote: > GTPv1 tunnel use a separate 32bit TIDs for each direction while GTPv0 uses > only one 64bit TID. English nitpicking: "GTPv1 tunnels use separate..." ...and the names differ. In v0, it's called "Tunnel IDentifier"; in v1 they're two "Tunnel Endpoint Identifier"s ("TID" vs. "TEI"). This naming is used consistently in the specs. > --- a/libgtnl/include/libgtpnl/gtp.h > +++ b/libgtnl/include/libgtpnl/gtp.h > @@ -14,6 +14,8 @@ void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr); > void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr); > void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version); > void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid); > +void gtp_tunnel_set_i_tid(struct gtp_tunnel *t, uint32_t i_tid); > +void gtp_tunnel_set_o_tid(struct gtp_tunnel *t, uint32_t o_tid); [...] > +uint32_t gtp_tunnel_get_i_tid(struct gtp_tunnel *t); > +uint32_t gtp_tunnel_get_o_tid(struct gtp_tunnel *t); [...] > + GTPA_I_TID, > + GTPA_O_TID, [...] > + union { [...] > + struct { > + uint32_t i_tid; > + uint32_t o_tid; > + } v1; > + } u; [...] > + else if (pdp.version == GTP_V1) > + printf("tid %u/%u ms_addr %s ", pdp.u.v1.i_tid, pdp.u.v1.o_tid, inet_ntoa(pdp.sgsn_addr)); So I'd call all of these "tei" and "TEI" (leaving v0 ones called "tid"). > +static void add_usage(const char *name) "add" to stdout? :) Ah I see, print the usage for the "add" command.... > +{ > + printf("%s add \n", > + name); > + printf("%s add \n", > + name); > +} "v0" and "v1" are the exact literal arguments to pass, in which case I would omit the braces, like printf("%s add v1 \n", > + uint32_t gtp_version; In the GTP headers, there are just three bits available for indicating the GTP version. Any particular reason to pick a uint32_t? > + t = gtp_tunnel_alloc(); [...] > + gtp_tunnel_free(t); It seems that you calloc and free a struct gtp_tunnel within the same function (I think twice). You could use a local struct instead? struct gtp_tunnel = {0}; And a possible mem leak because of that: > static int > add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl) > { > + struct gtp_tunnel *t; [...] > + t = gtp_tunnel_alloc(); > + optidx = 2; > + > + gtp_ifidx = if_nametoindex(argv[optidx]); > if (gtp_ifidx == 0) { > - fprintf(stderr, "wrong GTP interface %s\n", argv[2]); > + fprintf(stderr, "wrong GTP interface %s\n", argv[optidx]); > return EXIT_FAILURE; t is still allocated upon EXIT_FAILURE. > } > + gtp_tunnel_set_ifidx(t, gtp_ifidx); > > - if (inet_aton(argv[5], &ms) < 0) { > - perror("bad address for ms"); > - exit(EXIT_FAILURE); > - } > - > - if (inet_aton(argv[6], &sgsn) < 0) { > - perror("bad address for sgsn"); > - exit(EXIT_FAILURE); > - } > + optidx++; > > - if (strcmp(argv[3], "v0") == 0) > + if (strcmp(argv[optidx], "v0") == 0) > gtp_version = GTP_V0; > - else if (strcmp(argv[3], "v1") == 0) > + else if (strcmp(argv[optidx], "v1") == 0) > gtp_version = GTP_V1; > else { > fprintf(stderr, "wrong GTP version %s, use v0 or v1\n", > - argv[3]); > + argv[optidx]); > return EXIT_FAILURE; t is still allocated upon EXIT_FAILURE. > } > + gtp_tunnel_set_version(t, gtp_version); > > - nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_EXCL | NLM_F_ACK, ++seq, > - GTP_CMD_TUNNEL_NEW); > - gtp_build_payload(nlh, atoi(argv[4]), gtp_ifidx, sgsn.s_addr, > - ms.s_addr, gtp_version); > + if (gtp_version == GTP_V0) > + gtp_tunnel_set_tid(t, atoi(argv[optidx++])); > + else if (gtp_version == GTP_V1) { > + gtp_tunnel_set_i_tid(t, atoi(argv[optidx++])); > + gtp_tunnel_set_o_tid(t, atoi(argv[optidx++])); > + } > > - if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) > - perror("genl_socket_talk"); > + if (inet_aton(argv[optidx++], &ms) < 0) { > + perror("bad address for ms"); > + exit(EXIT_FAILURE); Some failures return EXIT_FAILURE, some exit() directly? Is that intended? > + } > + gtp_tunnel_set_ms_ip4(t, &ms); > + > + if (inet_aton(argv[optidx++], &sgsn) < 0) { > + perror("bad address for sgsn"); > + exit(EXIT_FAILURE); > + } > + gtp_tunnel_set_sgsn_ip4(t, &sgsn); > + > + gtp_add_tunnel(genl_id, nl, t); > > + gtp_tunnel_free(t); Just to make sure ... t's data is copied by gtp_add_tunnel(), right? All in all, seems to be a case for a local struct. Same thing in del_tunnel(): > return 0; > } > > static int > del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl) > { > + struct gtp_tunnel *t; [...] > + t = gtp_tunnel_alloc(); > > - nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_ACK, ++seq, > - GTP_CMD_TUNNEL_DELETE); > - gtp_build_payload(nlh, atoi(argv[4]), gtp_ifidx, 0, 0, atoi(argv[3])); > + gtp_ifidx = if_nametoindex(argv[2]); > + if (gtp_ifidx == 0) { > + fprintf(stderr, "wrong GTP interface %s\n", argv[2]); > + return EXIT_FAILURE; possible missing free > + } > + gtp_tunnel_set_ifidx(t, gtp_ifidx); > + > + if (strcmp(argv[3], "v0") == 0) { > + gtp_tunnel_set_version(t, GTP_V0); > + gtp_tunnel_set_tid(t, atoi(argv[4])); > + } else if (strcmp(argv[3], "v1") == 0) { > + gtp_tunnel_set_version(t, GTP_V1); > + gtp_tunnel_set_i_tid(t, atoi(argv[4])); > + } else { > + fprintf(stderr, "wrong GTP version %s, use v0 or v1\n", > + argv[3]); > + return EXIT_FAILURE; possible missing free > + } > > - if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) > - perror("genl_socket_talk"); > + gtp_del_tunnel(genl_id, nl, t); > > + gtp_tunnel_free(t); ...same as above. > struct gtp_pdp { > uint32_t version; > - uint64_t tid; > + union { > + struct { > + uint64_t tid; > + } v0; > + struct { > + uint32_t i_tid; > + uint32_t o_tid; > + } v1; > + } u; The same union again? Actually, it seems the entire struct gtp_pdp definition is duplicated. Wouldn't it be better to define it once and reuse? > @@ -152,12 +197,16 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data) > static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data) > { > struct nlattr *tb[GTPA_MAX + 1] = {}; > - struct gtp_pdp pdp; > + struct gtp_pdp pdp = {}; Heh, exactly :) Actually, we've recently had a discussion in the sysmocom office about this way of zero initialization. There's the "traditional" method of naming one element as zero, after which the remaining elements will also be initialized to nul. If the first member is a primitive, {0} suffices. If not, one has to explicitly name a member, which can be cumbersome. Then I came across the possibility to just omit all members and obviously preferred that: {}. However, that doesn't seem to be part of C99, so now I'm back to naming a member again. Any further insights on the subject would be appreciated... ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Nov 19 14:34:31 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 19 Nov 2015 15:34:31 +0100 Subject: [PATCH 1/6] msgb: Add msgb_resize_area and msgb_copy In-Reply-To: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20151119143431.GD7092@dub5> +/*! \brief Copy an msgb. I'd write just "a" here, not "an". I seem to be the English nitpicker among us ;) + * + * This function allocates a new msgb, copies the data buffer of msg, + * and adjusts the pointers (incl l1h-l4h) accordingly. The cb part + * is not copied. + * \param[in] msg The old msgb object + * \param[in] name Human-readable name to be associated with msgb + */ +struct msgb *msgb_copy(const struct msgb *msg, const char *name) +{ [...] +} + +/*! \brief Resize an area within an msgb + * + * This resizes a sub area of the msgb data and adjusts the pointers (incl + * l1h-l4h) accordingly. The cb part is not updated. If the area is extended, + * the contents of the extension is undefined. The complete sub area must be a + * part of [data,tail]. + * + * \param[inout] msg The msgb object + * \param[in] area A pointer to the sub-area + * \param[in] old_size The old size of the sub-area + * \param[in] new_size The new size of the sub-area + * \returns 0 on success, -1 if there is not enough space to extend the area + */ +int msgb_resize_area(struct msgb *msg, uint8_t *area, + size_t old_size, size_t new_size) +{ + int rc; + uint8_t *rest = area + old_size; + int rest_len = msg->len - old_size - (area - msg->data); + int delta_size = (int)new_size - (int)old_size; + + if (area < msg->data || rest > msg->tail) + MSGB_ABORT(msg, "Sub area is not fully contained in the msg data\n"); Just to be super paranoid: old_size is unsigned, sure, but uint8_t *rest could wrap when old_size is (accidentally/crafted) passed as very very large. I could pass area > msg->tail with rest < msg->tail. Also, if new_size were past INT_MAX, (int)new_size would end up negative. Same for old_size. My head is spinning a bit from trying to figure out the result of the subtraction in those cases... ;) What do you think? Not relevant for any normal use, sure, but should we rule out those cases entirely? ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From pablo at soleta.eu Thu Nov 19 16:38:16 2015 From: pablo at soleta.eu (Pablo Neira Ayuso) Date: Thu, 19 Nov 2015 17:38:16 +0100 Subject: [PATCH 13/16] gtp-rtnl: real_ifname is not long needed, remove it In-Reply-To: <20151119124105.GB7092@dub5> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-14-git-send-email-aschultz@tpip.net> <20151119124105.GB7092@dub5> Message-ID: <20151119163816.GA1359@salvia> On Thu, Nov 19, 2015 at 01:41:05PM +0100, Neels Hofmeyr wrote: > log message: "no longer needed" ? Please, no more English description corrections. This is good enough to understand the intention. Thank you. From palm.wang at hotmail.com Fri Nov 20 08:49:00 2015 From: palm.wang at hotmail.com (wangpalm) Date: Fri, 20 Nov 2015 16:49:00 +0800 Subject: EGPRS(EDGE) data rate is not stable? In-Reply-To: <20151105091353.GC9183@nataraja> References: , <20151105091353.GC9183@nataraja> Message-ID: Thanks very much for your advice. I've done the pcap IP-catching, printed out flow-control information of openbsc, excluded the RF problem, and checked the layer3 singals with TEMS tools. Nothing abnormal was found.(Or maybe there was something, but I have not noticed). It just seems suddenly nothing is flowing in and out nanobts for a while. After all of that, I replaced the nanobts (software version: 168d502, aquired with ipaccess-find) with another nanobts (software version: 168a302). The data rate problem never appeared. However, I ran into another problem occasionally, which has not occurred before. After printing following logs, nanoBTS auto-restarts/reconnects with OpenBSC, and thus causes network interruption. ----- Logs ----Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24410:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 1 Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24411:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 2 Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24412:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 3 Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24413:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 4 ---------- At this point, I'm wondering if openbsc has some compatible problems with nanoBTS sw?Has any body run into this, and what's your sw version of nanoBTS? > Date: Thu, 5 Nov 2015 10:13:53 +0100 > From: laforge at gnumonks.org > You are running a complex setup (a GSM/EGPRS network), and there can be > many reasons. > > * Have you excluded RF interference? In order to do that, you could > connect your EGPRS capable MS over coaxial cable, duplexer and > attenuators directly without any antenna to the BTS. This way you > exclude any RF side interference. you also exclude the possibility > that any other phones not part of your test setup are meanwhile > attempting to register or use services of the network > > Next point is to obtain protocol traces (pcap) with synchronized > time-stamps on > * the MS side (the IP you get out of your MS) > * the Gb side betwene BTS and SGSN > * the IP side of the GGSN > > Recording those pcap files and looking at what happens where in the > timeline can be very useful. > > * Have you studied the protocol traces on the Gb level? Looking at them > it should be easy to determine if flow control was an issue at the > time you experience low througput. > > * Have you studied the IP level protocol traces on MS side or on the > GGSN side? What does a TCP sequence number / RTT analysis give you > for those traces? When are packets lost? > > * you could use OsmocomBB + bust_ind + gprsdecode to obtain > air-interface protocol traces to further analyze that interface. > > * finally, the nanoBTS telnet debug interface might be of help to > provide you some insight into what is happening in the (closed source) > PCU at the time you experience problems. > > -- > - Harald Welte http://laforge.gnumonks.org/ > ============================================================================ > "Privacy in residential applications is a desirable marketing option." > (ETSI EN 300 175-7 Ch. A6) -------------- next part -------------- An HTML attachment was scrubbed... URL: From laforge at gnumonks.org Fri Nov 20 10:12:48 2015 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 20 Nov 2015 11:12:48 +0100 Subject: channel availability In-Reply-To: <564DB576.50706@alumni.ntnu.no> References: <56472931.9070807@alumni.ntnu.no> <20151114202001.GU4687@nataraja> <564CE2DE.3050809@alumni.ntnu.no> <20151119082642.GU4687@nataraja> <564DB576.50706@alumni.ntnu.no> Message-ID: <20151120101248.GQ4687@nataraja> Hi Max, On Thu, Nov 19, 2015 at 12:41:42PM +0100, Suraev wrote: > Hmm, I thought that process was still ongoing. from my point of view, l1sap and osmo-trx have been merged. Any additional osmo-trx specific fixes that might be missing must be submitted by those people who are maintaining that port (and actually using it). Unfortunately I have not yet seen any such patches submitted to the mailing list. > logging enable > logging set-log-mask DMM:DCC no: logging enable logging filter all 1 logging level mm debug logging level sm debug > gprs attach request, with id request followed by attach accept and > attach complete. If you're not getting a pdp context activate, then you phone is not activating a pdp context. Without pdp context, no user data. > After the gprs attach I see lots of FLOW-CONTROL_BVC and NS-ALIVE messages > with corresponding -ACK. That's just signalling between PCU and SGSN, unrelate to the MS. > The strange thing is - I see no packets over tun0 at all. Same goes for udp port > 23000 except what was mentioned above. Shouldn't I be able to at least see dns > queries from mobile? The MS is not activating a pdp context. Befoer that you will not see any data. Check your apn configuration. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From sipos.csaba at kvk.uni-obuda.hu Fri Nov 20 14:55:53 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Fri, 20 Nov 2015 15:55:53 +0100 (CET) Subject: EGPRS(EDGE) data rate is not stable? In-Reply-To: References: <20151105091353.GC9183@nataraja> Message-ID: <1430630485.9693940.1448031353986.JavaMail.zimbra@kvk.uni-obuda.hu> Hi, > After printing following logs, nanoBTS auto-restarts/reconnects with OpenBSC, and thus causes network interruption. This is probably cause the management software is also trying to use the same OML interface which OpenBSC already using to comunicate with the BTS. If I recall correctly nanoBTS can be set to have two OML interfaces up, one can be used with the BSC, and the other one can be used with the management software. Of corse if you performing tests which are affecting the radio or signalling parts of the BTS, you will abviously loose the connection temporarily with the BTS. Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "wangpalm" C?mzett: "Harald Welte" M?solatot kap: openbsc at lists.osmocom.org Elk?ld?tt ?zenetek: P?ntek, 2015. November 20. 9:49:00 T?rgy: RE: EGPRS(EDGE) data rate is not stable? Thanks very much for your advice. I've done the pcap IP-catching, printed out flow-control information of openbsc, excluded the RF problem, and checked the layer3 singals with TEMS tools. Nothing abnormal was found.(Or maybe there was something, but I have not noticed). It just seems suddenly nothing is flowing in and out nanobts for a while. After all of that, I replaced the nanobts (software version: 168d502, aquired with ipaccess-find) with another nanobts (software version: 168a302). The data rate problem never appeared. However, I ran into another problem occasionally, which has not occurred before. After printing following logs, nanoBTS auto-restarts/reconnects with OpenBSC, and thus causes network interruption. ----- Logs ----Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24410:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 1 Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24411:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 2 Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24412:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 3 Failure Event Report Type=processing failure Severity=warning level failure Probable cause= 03 00 01 Additional Text=24413:WARN:BH_TRX_ROUTER_TR:igki_nucleus.c#256:Memory pool=2 full, execution delayed. Count 4 ---------- At this point, I'm wondering if openbsc has some compatible problems with nanoBTS sw?Has any body run into this, and what's your sw version of nanoBTS? > Date: Thu, 5 Nov 2015 10:13:53 +0100 > From: laforge at gnumonks.org > You are running a complex setup (a GSM/EGPRS network), and there can be > many reasons. > > * Have you excluded RF interference? In order to do that, you could > connect your EGPRS capable MS over coaxial cable, duplexer and > attenuators directly without any antenna to the BTS. This way you > exclude any RF side interference. you also exclude the possibility > that any other phones not part of your test setup are meanwhile > attempting to register or use services of the network > > Next point is to obtain protocol traces (pcap) with synchronized > time-stamps on > * the MS side (the IP you get out of your MS) > * the Gb side betwene BTS and SGSN > * the IP side of the GGSN > > Recording those pcap files and looking at what happens where in the > timeline can be very useful. > > * Have you studied the protocol traces on the Gb level? Looking at them > it should be easy to determine if flow control was an issue at the > time you experience low througput. > > * Have you studied the IP level protocol traces on MS side or on the > GGSN side? What does a TCP sequence number / RTT analysis give you > for those traces? When are packets lost? > > * you could use OsmocomBB + bust_ind + gprsdecode to obtain > air-interface protocol traces to further analyze that interface. > > * finally, the nanoBTS telnet debug interface might be of help to > provide you some insight into what is happening in the (closed source) > PCU at the time you experience problems. > > -- > - Harald Welte http://laforge.gnumonks.org/ > ============================================================================ > "Privacy in residential applications is a desirable marketing option." > (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Sat Nov 21 14:02:22 2015 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 21 Nov 2015 15:02:22 +0100 Subject: RFC: removing talloc for good? Message-ID: <20151121140222.GA12296@nataraja> Hi all, I've been looking into upgrading our copy of talloc.[ch] in libosmocore, but unlike 7 years ago, it is not that easy anymore. The build system integration is quite heavy, and it might be a good point to simply drop talloc from libosmocore. Also contrary to 7 years ago, distributions tend to ship libtalloc these days. So there's not really any reason to continue shiping it. Right now I'm making it optional, and have sorted out how to make this source compatible. But this generates runtime incompabilities, due to the ABI incompabibilities between our ancient talloc and current talloc :( While the API of our talloc and current talloc seems compatible, the ABI is not. For example, they changed talloc_free() into an inline function resulting in calls to _talloc_free(), while our code links directly against talloc_free(). So We'd have to move from libosmocore-6.0.0 to 7.0.0 as part of the transition and cannot really keep both options without causing additional compatibility issues to our users. So the question is: Why bother? does anyone have objections to removing the built-in talloc? -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Sat Nov 21 15:50:24 2015 From: holger at freyther.de (Holger Freyther) Date: Sat, 21 Nov 2015 15:50:24 +0000 Subject: RFC: removing talloc for good? In-Reply-To: <20151121140222.GA12296@nataraja> References: <20151121140222.GA12296@nataraja> Message-ID: <54DB229F-429F-44DA-B839-2FEC280C33D8@freyther.de> > On 21 Nov 2015, at 14:02, Harald Welte wrote: > > > So the question is: Why bother? does anyone have objections to removing > the built-in talloc? no, have you seen Jan Engelhardt's changes? They are still in our patchwork and serve as reminder that we need to do something about it. I think we should remove at the same time. holger From laforge at gnumonks.org Sat Nov 21 19:18:38 2015 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 21 Nov 2015 20:18:38 +0100 Subject: RFC: removing talloc for good? In-Reply-To: <54DB229F-429F-44DA-B839-2FEC280C33D8@freyther.de> References: <20151121140222.GA12296@nataraja> <54DB229F-429F-44DA-B839-2FEC280C33D8@freyther.de> Message-ID: <20151121191838.GK23520@nataraja> Hi Holger, On Sat, Nov 21, 2015 at 03:50:24PM +0000, Holger Freyther wrote: > no, have you seen Jan Engelhardt's changes? I didn't remember them, no :/ But in any case, your mail was not a response to my question. What do you think about it? > I think we should remove at the same time. I think we should keep it as a convenience wrapper just containing a single line of "#include ". _maybe_ with a #warning together. This makes sense for people wanting to build e.g. older branches with new libosmocore. That wrapper-header doesn't hurt and helps people avoid broken builds. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Sat Nov 21 19:32:41 2015 From: holger at freyther.de (Holger Freyther) Date: Sat, 21 Nov 2015 19:32:41 +0000 Subject: RFC: removing talloc for good? In-Reply-To: <20151121191838.GK23520@nataraja> References: <20151121140222.GA12296@nataraja> <54DB229F-429F-44DA-B839-2FEC280C33D8@freyther.de> <20151121191838.GK23520@nataraja> Message-ID: <2DEC8A13-85DE-4367-AA5A-80227C06916E@freyther.de> > On 21 Nov 2015, at 19:18, Harald Welte wrote: > > But in any case, your mail was not a response to my question. What do > you think about it? Was there another question than if we object? I do not object and I think using the system talloc is the right thing to do. I was surprised that the Fedora package didn't raise this issue. >> I think we should remove at the same time. > > I think we should keep it as a convenience wrapper just containing a > single line of "#include ". _maybe_ with a #warning together. > > This makes sense for people wanting to build e.g. older branches with > new libosmocore. That wrapper-header doesn't hurt and helps people > avoid broken builds. hmm. okay. But new code should use talloc.h directly then? holger From suraev at alumni.ntnu.no Sun Nov 22 16:20:18 2015 From: suraev at alumni.ntnu.no (Suraev) Date: Sun, 22 Nov 2015 17:20:18 +0100 Subject: channel availability In-Reply-To: <20151120101248.GQ4687@nataraja> References: <56472931.9070807@alumni.ntnu.no> <20151114202001.GU4687@nataraja> <564CE2DE.3050809@alumni.ntnu.no> <20151119082642.GU4687@nataraja> <564DB576.50706@alumni.ntnu.no> <20151120101248.GQ4687@nataraja> Message-ID: <5651EB42.1060907@alumni.ntnu.no> 20.11.2015 11:12, Harald Welte ?????: > logging level sm debug I don't see this one but logging level lgtp debug and logging level gprs debug did the trick, thanks! > If you're not getting a pdp context activate, then you phone is not > activating a pdp context. Without pdp context, no user data. Doh! As far as I recall sgsn/ggsn ignores apn (btw, there's nothing while searching for "apn" in wiki) but I forgot that phone still got to have something set as apn ("internet" works fine) in order to start actually using gprs. > > The MS is not activating a pdp context. Befoer that you will not see > any data. Check your apn configuration. I should have guessed - the lack of gprs indicator on the phone means it did not actually attempt to use it. Now, it works, although just one way for some reason. I can see activated pdp context in sgsn vty: OsmoSGSN# show pdp-context all PDP Context IMSI: 901708776992222, SAPI: 3, NSAPI: 5 APN: internet PDP Address: IPv4 192.168.0.2 SGSN PDP Context Statistics: User Data Messages ( In): 16 (0/s 0/m 16/h 0/d) User Data Messages (Out): 0 (0/s 0/m 0/h 0/d) User Data Bytes ( In): 1032 (0/s 0/m 1032/h 0/d) User Data Bytes (Out): 0 (0/s 0/m 0/h 0/d) Also I see the dns requests in tcpdump over tun0 interface. The problem is the above 0 Out - nothing has been sent to the mobile. The masquerading on the host seems to work fine at first glance: ping -S 192.168.0.3 8.8.8.8 gets expected response (here 192.168.0.3 is the address from the space assigned to phones). However, none of the phone's requests receive reply. On the other hand if I try to ping phone directly from the host than I got reply just fine, counters got updated in sgsn, messages are visible in wireshark etc. So it seems like the osmocom side of things is doing fine and the remaining issue is somewhere on the host. I would blame iptables but I've checked that no blocking rules installed and all policies defaults to accept for both regular and nat tables. Anyway, will keep digging, thanks for help! cheers, Max. From nhofmeyr at sysmocom.de Mon Nov 23 09:43:43 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 23 Nov 2015 10:43:43 +0100 Subject: [PATCH 5/6] msgb/test: Add tests for msgb_resize_area and msgb_copy In-Reply-To: <1447753069-17466-5-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1447753069-17466-5-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20151123094343.GA1360@dub5> On Tue, Nov 17, 2015 at 10:37:48AM +0100, Jacob Erlbeck wrote: > diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c > index 412e8bb..08d9857 100644 > --- a/tests/msgb/msgb_test.c > +++ b/tests/msgb/msgb_test.c > @@ -87,6 +87,7 @@ static void test_msgb_api() > msg->l3h = msg->head - 1; > printf("Buffer: %s\n", msgb_hexdump(msg)); > > + > #if 0 > extern void msgb_reset(struct msgb *m); > #define msgb_l1(m) ((void *)(MSGB_CHECK2(m)->l1h)) > @@ -97,15 +98,61 @@ static inline unsigned int msgb_l1len(const struct msgb *msgb) > static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) > static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) > static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len) > - > + > static inline unsigned char *msgb_pull_to_l3(struct msgb *msg) > static inline int msgb_trim(struct msgb *msg, int len) > static inline int msgb_l3trim(struct msgb *msg, int l3len) > uint8_t *msgb_data(const struct msgb *msg); > - return; > +return; > #endif > } ^ seems like those whitespace changes came in by accident... ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Nov 23 10:31:59 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 23 Nov 2015 11:31:59 +0100 Subject: channel availability In-Reply-To: <5651EB42.1060907@alumni.ntnu.no> References: <56472931.9070807@alumni.ntnu.no> <20151114202001.GU4687@nataraja> <564CE2DE.3050809@alumni.ntnu.no> <20151119082642.GU4687@nataraja> <564DB576.50706@alumni.ntnu.no> <20151120101248.GQ4687@nataraja> <5651EB42.1060907@alumni.ntnu.no> Message-ID: <20151123103158.GB1360@dub5> On Sun, Nov 22, 2015 at 05:20:18PM +0100, Suraev wrote: > Doh! As far as I recall sgsn/ggsn ignores apn (btw, there's nothing while searching > for "apn" in wiki) but I forgot that phone still got to have something set as apn > ("internet" works fine) in order to start actually using gprs. The APN may be used to find the proper GGSN to establish a PDP context with (APN and parts of the IMSI are used to compose a "*.gprs" name, which is then resolved using DNS to find the GGSN's IP address). If your SGSN is configured to send things to a specific GGSN, the APN does in fact not have an impact. So it depends on your SGSN's configuration. > I can see activated pdp context in sgsn vty: > > OsmoSGSN# show pdp-context all > PDP Context IMSI: 901708776992222, SAPI: 3, NSAPI: 5 > APN: internet > PDP Address: IPv4 192.168.0.2 > SGSN PDP Context Statistics: > User Data Messages ( In): 16 (0/s 0/m 16/h 0/d) > User Data Messages (Out): 0 (0/s 0/m 0/h 0/d) > User Data Bytes ( In): 1032 (0/s 0/m 1032/h 0/d) > User Data Bytes (Out): 0 (0/s 0/m 0/h 0/d) > > Also I see the dns requests in tcpdump over tun0 interface. > > The problem is the above 0 Out - nothing has been sent to the mobile. I was at first unsure because an SGSN receives and sends both to/from mobile as well as to/from GGSN. But looking at the code, it seems that your interpretation is correct. > The masquerading on the host seems to work fine at first glance: > ping -S 192.168.0.3 8.8.8.8 > gets expected response (here 192.168.0.3 is the address from the space assigned to > phones). Could you explain the -S? In my host system's man page, -S is documented as: -S sndbuf Set socket sndbuf. If not specified, it is selected to buffer not more than one packet. and busybox's ping doesn't document any -S option ... ? So to me it seems your ping command sets a send buffer of 192 packets (ignoring ".168.0.3") and pings google's nameserver. I'm still new on the subject, just hoping to be helpful... I've recently done GTP and PDP context related stuff, so a few shots in the dark: In wireshark, you could examine which GSN addresses the SGSN is telling the GGSN to use ("GPRS Tunneling Protocol" / "GSN address"). There's two, the first is for the Ctrl plane, the second for User. The GGSN will reply to the PDP context creation and then switch to those GSN addresses for subsequent messages. If those are wrong/not reachable from the GGSN side, that may cause lost replies? Have you enabled forwarding on the host running the GGSN? I'm using these commands to be able to locally test with a "fake" GGSN on my laptop: sudo -s echo 1 > /proc/sys/net/ipv4/ip_forward iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Nov 23 10:35:32 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 23 Nov 2015 11:35:32 +0100 Subject: [PATCH 13/16] gtp-rtnl: real_ifname is not long needed, remove it In-Reply-To: <20151119163816.GA1359@salvia> References: <1447686417-3979-1-git-send-email-aschultz@tpip.net> <1447686417-3979-14-git-send-email-aschultz@tpip.net> <20151119124105.GB7092@dub5> <20151119163816.GA1359@salvia> Message-ID: <20151123103532.GC1360@dub5> On Thu, Nov 19, 2015 at 05:38:16PM +0100, Pablo Neira Ayuso wrote: > On Thu, Nov 19, 2015 at 01:41:05PM +0100, Neels Hofmeyr wrote: > > log message: "no longer needed" ? > > Please, no more English description corrections. This is good enough > to understand the intention. Thank you. Acknowledged. Please do correct my own comments/log typos, if you find any. Thanks! ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Nov 23 14:02:08 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 23 Nov 2015 15:02:08 +0100 Subject: HAVE_LIBCARES Message-ID: <20151123140208.GB16329@dub5> About below commit: Sorry / Thanks! I forgot to move gtphub into the HAVE_LIBCARES conditional when I added ares... The gtphub tests wrap the ares functions away, so they build without libc-ares. But does it make sense to enable the gtphub test when the binary isn't built? ~Neels > commit 97b6bfa996ed1745d27c5598186c4583f7e90861 > Author: Harald Welte > Date: Sat Nov 21 13:16:08 2015 +0100 > > Fix compilation with no libc-ares present on the system > > This build failure was introduced with the OAP and gtphub changes. > > diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am > index 5212c67..5e115eb 100644 > --- a/openbsc/src/gprs/Makefile.am > +++ b/openbsc/src/gprs/Makefile.am > @@ -11,9 +11,8 @@ noinst_HEADERS = gprs_sndcp.h > bin_PROGRAMS = osmo-gbproxy > > if HAVE_LIBGTP > -bin_PROGRAMS += osmo-gtphub > if HAVE_LIBCARES > -bin_PROGRAMS += osmo-sgsn > +bin_PROGRAMS += osmo-sgsn osmo-gtphub > endif > endif > > diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am > index 995660a..04b8e34 100644 > --- a/openbsc/tests/Makefile.am > +++ b/openbsc/tests/Makefile.am > @@ -13,7 +13,10 @@ SUBDIRS += smpp > endif > > if HAVE_LIBGTP > -SUBDIRS += sgsn oap gtphub > +SUBDIRS += gtphub > +if HAVE_LIBCARES > +SUBDIRS += sgsn oap > +endif > endif > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From laforge at gnumonks.org Mon Nov 23 21:13:25 2015 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 23 Nov 2015 22:13:25 +0100 Subject: HAVE_LIBCARES In-Reply-To: <20151123140208.GB16329@dub5> References: <20151123140208.GB16329@dub5> Message-ID: <20151123211325.GB12626@nataraja> Hi Neels, On Mon, Nov 23, 2015 at 03:02:08PM +0100, Neels Hofmeyr wrote: > About below commit: Sorry / Thanks! I forgot to move gtphub into the > HAVE_LIBCARES conditional when I added ares... No problem. It's easy to miss such conditional build topics without automatic testing (hint!). It might make sense to have a few chroot() environments with and without those libraries installed and test the builds. Also, it would be good to have some documentation on the build requirements / conditionals in the README file. > But does it make sense to enable the gtphub test when the binary isn't built? No, we can skip that. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From alexander.chemeris at gmail.com Tue Nov 24 01:01:59 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Tue, 24 Nov 2015 04:01:59 +0300 Subject: [PATCH 1/3] mncc: Implement helper functions to convert MNCC cause to a string. In-Reply-To: References: Message-ID: bump It doesn't seem there are any comments on this set of patches. Is it ok to merge them? On Sun, Sep 13, 2015 at 3:46 AM, Alexander Chemeris < alexander.chemeris at gmail.com> wrote: > This is the first patch of the series. The first two patches are > improvements of the log output and are independent of the 3rd patch in > terms of code - proposed logging improvements just make it easier to > debug issues with MNCC cause codes. > > The code is also a part of the achemeris/mncc_cause_fixes_master branch. > > -- > Regards, > Alexander Chemeris. > CEO, Fairwaves, Inc. > https://fairwaves.co > > > -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.chemeris at gmail.com Tue Nov 24 01:02:13 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Tue, 24 Nov 2015 04:02:13 +0300 Subject: [PATCH 2/3] mncc: Log CC cause when sending a primitive to MNCC. In-Reply-To: References: Message-ID: bump On Sun, Sep 13, 2015 at 3:47 AM, Alexander Chemeris < alexander.chemeris at gmail.com> wrote: > The code is also a part of the achemeris/mncc_cause_fixes_master branch. > > -- > Regards, > Alexander Chemeris. > CEO, Fairwaves, Inc. > https://fairwaves.co > > > -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.chemeris at gmail.com Tue Nov 24 01:02:22 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Tue, 24 Nov 2015 04:02:22 +0300 Subject: [PATCH 3/3] mncc: Send "Dest OOO" cause in case of a link radio failure. In-Reply-To: References: Message-ID: bump On Sun, Sep 13, 2015 at 6:24 PM, Alexander Chemeris < alexander.chemeris at gmail.com> wrote: > Btw, I'm not sure 27 DESTINATION_OUT_OF_ORDER is the best cause in > this case. Two other options I see suitable are 102 > RECOVERY_ON_TIMER_EXPIRE and 604 MEDIA_TIMEOUT. Does anyone know is > there an official mapping between Q.850 codes and various GSM cause > codes? > > Another useful change here would be to propagate information about > which timer expired. That would help to gather information about > issues with the network. > > On Sat, Sep 12, 2015 at 8:48 PM, Alexander Chemeris > wrote: > > Previously we were sending a generic "Resource unavailable" cause code > making > > it impossible to distinguish real error cases from a regular radio link > failure. > > This was the reason for many "unknown" call errors we've seen at > Rhizomatica > > installations. Now they are properly classified as non-erroneous call > failures. > > > > The code is also a part of the achemeris/mncc_cause_fixes_master branch. > > > > -- > > Regards, > > Alexander Chemeris. > > CEO, Fairwaves, Inc. > > https://fairwaves.co > > > > > > > > -- > Regards, > Alexander Chemeris. > CEO, Fairwaves, Inc. > https://fairwaves.co > > > -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.chemeris at gmail.com Tue Nov 24 01:09:20 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Tue, 24 Nov 2015 04:09:20 +0300 Subject: Meas_web and meas_json In-Reply-To: <687363025.6773365.1446628686520.JavaMail.zimbra@kvk.uni-obuda.hu> References: <1510240027.5443523.1445891932058.JavaMail.zimbra@kvk.uni-obuda.hu> <1010582984.5443937.1445892326559.JavaMail.zimbra@kvk.uni-obuda.hu> <213728024.5449223.1445896264483.JavaMail.zimbra@kvk.uni-obuda.hu> <687363025.6773365.1446628686520.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: Hi Csaba, On Wed, Nov 4, 2015 at 12:18 PM, Sipos Csaba wrote: > I am playing with the meas_web utility, and I finally have the missing informations for the README to make the installation process more complete, will sending a new copy for you soon. Looking forward to it! > 1. I noticed that the "Type" and "Channel" parameters are not shown on the web interface, but if I run "show lchan" in the BSC console, I got the correct results for both parameters. I checked the temporary files which stores the meas_feed data, and it seems these data parts are not even there, and this is the reason the web interface is not displaying them. This information has been added in the v1 version of the meas_feed stream. It should be available in the master after this commit: 08c508f84a8d088f8454d0f21f83ecc22e30d72d msc: Add channel information to the meas_feed, bump version to v1. > 2. Is there a way to set a time after the inactive old subscribers are deleted from the web interface? On my end the subscribers are just keep coming (a lot of rejected LOC updates) and when they reach the "maximum item number" count the web interface just crashes. Would be lovely to have a timeout value next to the "max item number" to set the amount of time of which the inactive subscribers would disappear from the web interface. And the web interface should not crash even if there is more transactions than the maximum item number :-) Crash is clearly a bug here. I've been testing with Chrome on Ubuntu x64 and have never seen it crashing. Which browser / OS do you use? Do you think you could spot the reason for the crash? -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From jerlbeck at sysmocom.de Tue Nov 24 08:40:48 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 24 Nov 2015 09:40:48 +0100 Subject: [PATCH 1/6] msgb: Add msgb_resize_area and msgb_copy In-Reply-To: <20151119143431.GD7092@dub5> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <20151119143431.GD7092@dub5> Message-ID: <56542290.8070303@sysmocom.de> On 19.11.2015 15:34, Neels Hofmeyr wrote: > +/*! \brief Copy an msgb. > > I'd write just "a" here, not "an". I seem to be the English nitpicker > among us ;) I do not agree in this case. "msgb" is read em-es-... thus starting with a vowel sound. See http://www.macmillandictionary.com/dictionary/british/an_1 ("an X-ray"). > +int msgb_resize_area(struct msgb *msg, uint8_t *area, > + size_t old_size, size_t new_size) > +{ > + int rc; > + uint8_t *rest = area + old_size; > + int rest_len = msg->len - old_size - (area - msg->data); > + int delta_size = (int)new_size - (int)old_size; > + > + if (area < msg->data || rest > msg->tail) > + MSGB_ABORT(msg, "Sub area is not fully contained in the msg data\n"); > > Just to be super paranoid: old_size is unsigned, sure, but uint8_t *rest > could wrap when old_size is (accidentally/crafted) passed as very very > large. I could pass area > msg->tail with rest < msg->tail. > > Also, if new_size were past INT_MAX, (int)new_size would end up negative. > Same for old_size. My head is spinning a bit from trying to figure out the > result of the subtraction in those cases... ;) > > What do you think? Not relevant for any normal use, sure, but should we > rule out those cases entirely? You are right. So a quick fix is to check for rest < area in addition. Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From nhofmeyr at sysmocom.de Tue Nov 24 12:40:18 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 24 Nov 2015 13:40:18 +0100 Subject: [PATCH] gtphub: add to debian build Message-ID: <1448368818-21121-1-git-send-email-nhofmeyr@sysmocom.de> By the example of osmo-sgsn, package osmo-gtphub for debian. Sponsored-by: On-Waves ehi --- debian/control | 14 +++ debian/osmocom-gtphub.default | 2 + debian/osmocom-gtphub.examples | 1 + debian/osmocom-gtphub.init | 150 +++++++++++++++++++++++ debian/osmocom-gtphub.install | 1 + debian/rules | 1 + openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg | 23 ++++ 7 files changed, 192 insertions(+) create mode 100644 debian/osmocom-gtphub.default create mode 100644 debian/osmocom-gtphub.examples create mode 100755 debian/osmocom-gtphub.init create mode 100644 debian/osmocom-gtphub.install create mode 100644 openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg diff --git a/debian/control b/debian/control index 2447d29..53b6908 100644 --- a/debian/control +++ b/debian/control @@ -50,6 +50,12 @@ Depends: ${shlibs:Depends}, ${misc:Depends} Description: Osmocom Base Station Controller Network Address Translation Network address translation for BSC. +Package: osmocom-gtphub +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Osmocom GTP hub + Proxy for comms between SGSN and GGSN. + Package: osmocom-bsc-dbg Architecture: any Section: debug @@ -105,3 +111,11 @@ Priority: extra Depends: osmocom-bsc-nat (= ${binary:Version}), ${misc:Depends} Description: Debug symbols for the OpenBSC Network Address Translation Make debugging possible + +Package: osmocom-gtphub-dbg +Architecture: any +Section: debug +Priority: extra +Depends: osmocom-gtphub (= ${binary:Version}), ${misc:Depends} +Description: Debug symbols for Osmocom GTP hub + Make debugging possible diff --git a/debian/osmocom-gtphub.default b/debian/osmocom-gtphub.default new file mode 100644 index 0000000..6af82da --- /dev/null +++ b/debian/osmocom-gtphub.default @@ -0,0 +1,2 @@ +CONFIG_FILE="/etc/osmocom/osmo-gtphub.cfg" + diff --git a/debian/osmocom-gtphub.examples b/debian/osmocom-gtphub.examples new file mode 100644 index 0000000..48c2dc0 --- /dev/null +++ b/debian/osmocom-gtphub.examples @@ -0,0 +1 @@ +openbsc/doc/examples/osmo-gtphub diff --git a/debian/osmocom-gtphub.init b/debian/osmocom-gtphub.init new file mode 100755 index 0000000..4dc67b3 --- /dev/null +++ b/debian/osmocom-gtphub.init @@ -0,0 +1,150 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: osmo-gtphub +# Required-Start: $network $local_fs +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Osmocom GTP hub +# Description: Osmocom GTP hub +### END INIT INFO + +# Author: Neels Hofmeyr + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +NAME=osmo-gtphub # Introduce the short server's name here +DESC="Osmocom GTP hub" # Introduce a short description here +DAEMON=/usr/bin/osmo-gtphub # Introduce the server's location here +SCRIPTNAME=/etc/init.d/osmocom-gtphub + +# Exit if the package is not installed +[ -x $DAEMON ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/osmocom-gtphub ] && . /etc/default/osmocom-gtphub + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +DAEMON_ARGS="$DAEMON_ARGS -D -c $CONFIG_FILE" + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --exec $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/debian/osmocom-gtphub.install b/debian/osmocom-gtphub.install new file mode 100644 index 0000000..908c1a5 --- /dev/null +++ b/debian/osmocom-gtphub.install @@ -0,0 +1 @@ +/usr/bin/osmo-gtphub diff --git a/debian/rules b/debian/rules index 8047b79..62518d9 100755 --- a/debian/rules +++ b/debian/rules @@ -34,6 +34,7 @@ override_dh_strip: dh_strip -posmocom-sgsn --dbg-package=osmocom-sgsn-dbg dh_strip -posmocom-gbproxy --dbg-package=osmocom-gbproxy-dbg dh_strip -posmocom-bsc-nat --dbg-package=osmocom-bsc-nat-dbg + dh_strip -posmocom-gtphub --dbg-package=osmocom-gtphub-dbg override_dh_auto_configure: echo $(VERSION) > openbsc/.tarball-version diff --git a/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg b/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg new file mode 100644 index 0000000..c9bb4cf --- /dev/null +++ b/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg @@ -0,0 +1,23 @@ +! +! Osmocom gtphub configuration +! + +line vty + no login + +gtphub + ! Local addresses to listen on and send from, each on standard ports + ! 2123 and 2152. Setting these addresses is mandatory. + bind-to-sgsns 127.0.0.1 + bind-to-ggsns 127.0.0.2 + + ! Local nonstandard ports or separate IPs: + !bind-to-sgsns ctrl 127.0.0.1 2342 user 127.0.0.1 4223 + + ! Proxy: unconditionally direct all traffic to... + !ggsn-proxy 127.0.0.3 + !sgsn-proxy 127.0.0.4 + + ! Proxy with nonstandard ports or separate IPs: + !ggsn-proxy ctrl 127.0.0.3 2123 user 127.0.0.5 2152 + -- 2.1.4 From sergey.kostanbaev at gmail.com Wed Nov 25 10:37:01 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 13:37:01 +0300 Subject: [PATCH 1/4] core: RELEASE COMPLETE can be without any payload Message-ID: <1448447824-10290-1-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev This series of patches supposed to add support of USSD-menu style message handling with language support. --- src/gsm/gsm0480.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c index 952604b..9bd54fa 100644 --- a/src/gsm/gsm0480.c +++ b/src/gsm/gsm0480.c @@ -248,12 +248,6 @@ int gsm0480_decode_ss_request(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request *req) { int rc = 0; - - if (len < sizeof(*hdr) + 2) { - LOGP(0, LOGL_DEBUG, "SS Request is too short.\n"); - return 0; - } - if ((hdr->proto_discr & 0x0f) == GSM48_PDISC_NC_SS) { req->transaction_id = hdr->proto_discr & 0x70; rc = parse_ss(hdr, len, req); -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 10:37:02 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 13:37:02 +0300 Subject: [PATCH 2/4] core: Fix handling GSM0480_MTYPE_FACILITY, it has only LV and facility_ie In-Reply-To: <1448447824-10290-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448447824-10290-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448447824-10290-2-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev According to gsm0480 FACILITY message contains LV header not TLV as in REGISTER or RETURN_RESULT --- src/gsm/gsm0480.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c index 9bd54fa..5d1377f 100644 --- a/src/gsm/gsm0480.c +++ b/src/gsm/gsm0480.c @@ -196,6 +196,8 @@ static int parse_ss(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request *req); static int parse_ss_info_elements(const uint8_t *ussd_ie, uint16_t len, struct ss_request *req); +static int parse_ss_facility(const uint8_t *ss_facility, uint16_t len, + struct ss_request *req); static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, struct ss_request *req); static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, @@ -271,9 +273,11 @@ static int parse_ss(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request req->ussd_text[0] = 0xFF; break; case GSM0480_MTYPE_REGISTER: - case GSM0480_MTYPE_FACILITY: rc &= parse_ss_info_elements(&hdr->data[0], len - sizeof(*hdr), req); break; + case GSM0480_MTYPE_FACILITY: + rc &= parse_ss_facility(&hdr->data[0], len - sizeof(*hdr), req); + break; default: LOGP(0, LOGL_DEBUG, "Unknown GSM 04.80 message-type field 0x%02x\n", hdr->msg_type); @@ -284,6 +288,18 @@ static int parse_ss(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request return rc; } +static int parse_ss_facility(const uint8_t *ss_facility, uint16_t len, + struct ss_request *req) +{ + uint8_t facility_length; + + facility_length = ss_facility[0]; + if (len - 1 < facility_length) + return 0; + + return parse_facility_ie(ss_facility + 1, facility_length, req); +} + static int parse_ss_info_elements(const uint8_t *ss_ie, uint16_t len, struct ss_request *req) { -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 10:37:03 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 13:37:03 +0300 Subject: [PATCH 3/4] core: Modify ss_request struct to store all information about USSD session In-Reply-To: <1448447824-10290-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448447824-10290-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448447824-10290-3-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev Do not decode strings inside ss_request, leave it for upper level to support other languages. Parse Return Result accordingly. Add default language decoding in gsm0480_decode_ussd_request() to not break current logic in OpenBSC. Increase message storage to 160 bytes (or 182 symbols in gsm 7-bit encoding) instead of 31 bytes. Store component type, invoke id and message type for USSD menu support on upper level. --- include/osmocom/gsm/gsm0480.h | 26 ++++++--- src/gsm/gsm0480.c | 127 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 130 insertions(+), 23 deletions(-) diff --git a/include/osmocom/gsm/gsm0480.h b/include/osmocom/gsm/gsm0480.h index deac322..094805f 100644 --- a/include/osmocom/gsm/gsm0480.h +++ b/include/osmocom/gsm/gsm0480.h @@ -5,7 +5,8 @@ #include #include -#define MAX_LEN_USSD_STRING 31 +#define MAX_LEN_USSD_STRING 182 +#define MAX_ASN1_LEN_USSD_STRING 160 /* deprecated */ struct ussd_request { @@ -19,13 +20,24 @@ int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len, struct ussd_request *request) OSMO_DEPRECATED("Use gsm0480_decode_ss_request() instead"); struct ss_request { - uint8_t opcode; - uint8_t ss_code; - uint8_t ussd_text[MAX_LEN_USSD_STRING + 1]; - uint8_t transaction_id; - uint8_t invoke_id; -}; + uint8_t transaction_id; /**< L3 transaction ID */ + uint8_t message_type; /**< Message type 2.2 */ + + uint8_t component_type; /**< Component type 3.6.2 */ + uint8_t invoke_id; /**< Invoke id 3.6.3 */ + union { + uint8_t opcode; /**< Operational code 3.6.4 */ + uint8_t error_code; /**< Error code 3.6.6 */ + uint8_t problem_code; /**< Problem code 3.6.7 */ + }; + + uint8_t ussd_text_len; + uint8_t ussd_text_language; + uint8_t ussd_text[MAX_ASN1_LEN_USSD_STRING + 1]; + + uint8_t ss_code; /**< parameters of a Interrogate/Activate/DeactivateSS Request */ +}; int gsm0480_decode_ss_request(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request *request); diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c index 5d1377f..41eea5f 100644 --- a/src/gsm/gsm0480.c +++ b/src/gsm/gsm0480.c @@ -202,6 +202,8 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, struct ss_request *req); static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, struct ss_request *req); +static int parse_ss_return_result(const uint8_t *rr_data, uint16_t length, + struct ss_request *req); static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length, struct ss_request *req); static int parse_ss_for_bs_req(const uint8_t *ss_req_data, @@ -231,10 +233,15 @@ int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len, /* convert from ss_request to legacy ussd_request */ req->transaction_id = ss.transaction_id; req->invoke_id = ss.invoke_id; - if (ss.ussd_text[0] == 0xFF) + if (ss.ussd_text_language != 0x0f || + ss.opcode != GSM0480_OP_CODE_PROCESS_USS_REQ) + req->text[0] = '\0'; else { - memcpy(req->text, ss.ussd_text, sizeof(req->text)); + gsm_7bit_decode_n_ussd(req->text, + sizeof(req->text), + ss.ussd_text, ss.ussd_text_len); + req->text[sizeof(req->text)-1] = '\0'; } } @@ -266,6 +273,7 @@ static int parse_ss(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request int rc = 1; uint8_t msg_type = hdr->msg_type & 0xBF; /* message-type - section 3.4 */ + req->message_type = msg_type; switch (msg_type) { case GSM0480_MTYPE_RELEASE_COMPLETE: LOGP(0, LOGL_DEBUG, "SS Release Complete\n"); @@ -350,6 +358,8 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, return 0; } + req->component_type = component_type; + switch (component_type) { case GSM0480_CTYPE_INVOKE: rc &= parse_ss_invoke(facility_ie+2, @@ -357,10 +367,17 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, req); break; case GSM0480_CTYPE_RETURN_RESULT: + rc &= parse_ss_return_result(facility_ie+2, + component_length, + req); break; case GSM0480_CTYPE_RETURN_ERROR: + /* TODO Error codes */ + LOGP(0, LOGL_DEBUG, "Ignored GSM0480_CTYPE_RETURN_ERROR"); break; case GSM0480_CTYPE_REJECT: + /* TODO rejects */ + LOGP(0, LOGL_DEBUG, "Ignored GSM0480_CTYPE_REJECT"); break; default: LOGP(0, LOGL_DEBUG, "Unknown GSM 04.80 Facility " @@ -374,6 +391,57 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, return rc; } +/* Parse an Return Result component - see table 3.4 */ +static int parse_ss_return_result(const uint8_t *rr_data, uint16_t length, + struct ss_request *req) +{ + int rc = 1; + uint8_t offset; + + if (length < 3) + return 0; + + /* mandatory part */ + if (rr_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) { + LOGP(0, LOGL_DEBUG, "Unexpected GSM 04.80 Component-ID tag " + "0x%02x (expecting Invoke ID tag)\n", rr_data[0]); + } + + offset = rr_data[1] + 2; + req->invoke_id = rr_data[2]; + + if (offset < length) { + if (rr_data[offset] != GSM_0480_SEQUENCE_TAG) + return 0; + if (offset + 2 > length) + return 0; + offset += 2; + + uint8_t operation_code = rr_data[offset+2]; + req->opcode = operation_code; + switch (operation_code) { + case GSM0480_OP_CODE_USS_NOTIFY: + case GSM0480_OP_CODE_USS_REQUEST: + case GSM0480_OP_CODE_PROCESS_USS_REQ: + rc = parse_process_uss_req(rr_data + offset + 3, + length - offset - 3, + req); + break; + case GSM0480_OP_CODE_PROCESS_USS_DATA: + rc = parse_process_uss_data(rr_data + offset + 3, + length - offset - 3, + req); + break; + default: + LOGP(0, LOGL_DEBUG, "GSM 04.80 operation code 0x%02x " + "is not yet handled\n", operation_code); + rc = 0; + break; + } + } + return rc; +} + /* Parse an Invoke component - see table 3.3 */ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, struct ss_request *req) @@ -408,6 +476,8 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, uint8_t operation_code = invoke_data[offset+2]; req->opcode = operation_code; switch (operation_code) { + case GSM0480_OP_CODE_USS_NOTIFY: + case GSM0480_OP_CODE_USS_REQUEST: case GSM0480_OP_CODE_PROCESS_USS_REQ: rc = parse_process_uss_req(invoke_data + offset + 3, length - offset - 3, @@ -436,32 +506,57 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, return rc; } +static const uint8_t *parse_asn1_small_len(const uint8_t *codedlen, uint16_t available, + uint8_t *out_len) +{ + uint8_t lenb = codedlen[0]; + if (lenb < 0x80 && available > 0) { + *out_len = lenb; + return &codedlen[1]; + } else if (lenb == 0x81 && available > 1) { + *out_len = codedlen[1]; + return &codedlen[2]; + } + + return NULL; +} + /* Parse the parameters of a Process UnstructuredSS Request */ static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length, struct ss_request *req) { int rc = 0; - int num_chars; - uint8_t dcs; - - + uint8_t dcs, seq_block_len, num_chars; + const uint8_t *next_ptr; /* we need at least that much */ if (length < 8) return 0; if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) { - if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) { - dcs = uss_req_data[4]; - if ((dcs == 0x0F) && - (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { - num_chars = (uss_req_data[6] * 8) / 7; + next_ptr = parse_asn1_small_len(&uss_req_data[1], length - 1, &seq_block_len); + if (next_ptr == NULL || seq_block_len < 6) + return 0; + + if (next_ptr[0] == ASN1_OCTET_STRING_TAG) { + if (next_ptr[1] != 1) + return 0; + + dcs = next_ptr[2]; + + if (next_ptr[3] == ASN1_OCTET_STRING_TAG) { + next_ptr = parse_asn1_small_len(&next_ptr[4], + seq_block_len - 4, &num_chars); + if (next_ptr == NULL) + return 0; + /* Prevent a mobile-originated buffer-overrun! */ - if (num_chars > MAX_LEN_USSD_STRING) - num_chars = MAX_LEN_USSD_STRING; - gsm_7bit_decode_n_ussd((char *)req->ussd_text, - sizeof(req->ussd_text), - &(uss_req_data[7]), num_chars); + if (num_chars > MAX_ASN1_LEN_USSD_STRING) + num_chars = MAX_ASN1_LEN_USSD_STRING; + + req->ussd_text_language = dcs; + req->ussd_text_len = num_chars; + memcpy(req->ussd_text, next_ptr, num_chars); rc = 1; } } -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 10:37:04 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 13:37:04 +0300 Subject: [PATCH 4/4] core: Parse GSM0480_OP_CODE_PROCESS_USS_DATA message In-Reply-To: <1448447824-10290-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448447824-10290-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448447824-10290-4-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev Add parsing of PROCESS_USS_DATA seen on old phones, it uses 8-bit encoding so the language is hardcoded to it. --- src/gsm/gsm0480.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c index 41eea5f..8c86f49 100644 --- a/src/gsm/gsm0480.c +++ b/src/gsm/gsm0480.c @@ -206,6 +206,8 @@ static int parse_ss_return_result(const uint8_t *rr_data, uint16_t length, struct ss_request *req); static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length, struct ss_request *req); +static int parse_process_uss_data(const uint8_t *uss_req_data, uint16_t length, + struct ss_request *req); static int parse_ss_for_bs_req(const uint8_t *ss_req_data, uint16_t length, struct ss_request *req); @@ -483,6 +485,11 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, length - offset - 3, req); break; + case GSM0480_OP_CODE_PROCESS_USS_DATA: + rc = parse_process_uss_data(invoke_data + offset + 3, + length - offset - 3, + req); + break; case GSM0480_OP_CODE_ACTIVATE_SS: case GSM0480_OP_CODE_DEACTIVATE_SS: case GSM0480_OP_CODE_INTERROGATE_SS: @@ -506,6 +513,30 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, return rc; } +static int parse_process_uss_data(const uint8_t *uss_req_data, uint16_t length, + struct ss_request *req) +{ + uint8_t num_chars; + + /* we need at least that much */ + if (length < 3) + return 0; + + if (uss_req_data[0] != ASN1_IA5_STRING_TAG) + return 0; + + num_chars = uss_req_data[1]; + if (num_chars > length - 2) + return 0; + if (num_chars > MAX_ASN1_LEN_USSD_STRING) + num_chars = MAX_ASN1_LEN_USSD_STRING; + + req->ussd_text_language = 1; + req->ussd_text_len = num_chars; + memcpy(req->ussd_text, uss_req_data + 2, num_chars); + return 1; +} + static const uint8_t *parse_asn1_small_len(const uint8_t *codedlen, uint16_t available, uint8_t *out_len) { -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:52 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:52 +0300 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service Message-ID: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev This series of patches add support for external USSD processing via simplified MAP-like protocol over SUP socket. As an example of a such external application simple USSD to SIP proxy is provided (it targets TS 124 390) --- openbsc/include/openbsc/debug.h | 1 + openbsc/src/libcommon/debug.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 19d8fc2..10b0f46 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -33,6 +33,7 @@ enum { DCTRL, DSMPP, DFILTER, + DSS, Debug_LastEntry, }; diff --git a/openbsc/src/libcommon/debug.c b/openbsc/src/libcommon/debug.c index 7fb3ecb..6536944 100644 --- a/openbsc/src/libcommon/debug.c +++ b/openbsc/src/libcommon/debug.c @@ -165,6 +165,12 @@ static const struct log_info_cat default_categories[] = { .description = "BSC/NAT IMSI based filtering", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DSS] = { + .name = "DSS", + .description = "Layer3 Supplementary Service (SS)", + .color = "\033[0;33m", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; enum log_filter { -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:54 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:54 +0300 Subject: [PATCH 3/8] libmsc: Update USSD to use new ss_request structure In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448449439-10546-3-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev Use new ss_request structure to support long messages and handle FACILITY message type to support USSD menus. --- openbsc/include/openbsc/gsm_04_80.h | 11 ++-- openbsc/src/libmsc/gsm_04_80.c | 119 +++++++++++++++++++++++++++--------- openbsc/src/libmsc/ussd.c | 44 ++++++++----- 3 files changed, 128 insertions(+), 46 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 0a60652..08f974f 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -7,12 +7,15 @@ struct gsm_subscriber_connection; +int gsm0480_send_ussd(struct gsm_subscriber_connection *conn, + struct ss_request *req); + int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, - const struct msgb *in_msg, const char* response_text, - const struct ussd_request *req); + const char *resp_string, + const struct ss_request *req); + int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, - const struct msgb *msg, - const struct ussd_request *request); + const struct ss_request *request); int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text); int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn); diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c index b30f9ee..4585202 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -39,6 +39,22 @@ #include #include +/* This function can handle ASN1 length up to 255 which is enough for USSD */ +static inline unsigned char *msgb_wrap_with_ASN1_TL(struct msgb *msgb, uint8_t tag) +{ + uint16_t origlen = msgb->len; + uint8_t *data = msgb_push(msgb, (origlen > 0x7f) ? 3 : 2); + data[0] = tag; + if (origlen > 0x7f) { + data[1] = 0x81; + data[2] = origlen; + } else { + data[1] = origlen; + } + return data; +} + + static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag) { uint8_t *data = msgb_push(msgb, 2); @@ -59,59 +75,106 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag, return data; } +static inline unsigned char *msgb_wrap_with_L(struct msgb *msgb) +{ + uint8_t *data = msgb_push(msgb, 1); + + data[0] = msgb->len - 1; + return data; +} /* Send response to a mobile-originated ProcessUnstructuredSS-Request */ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, - const struct msgb *in_msg, const char *response_text, - const struct ussd_request *req) + const char *resp_string, + const struct ss_request* req) +{ + struct ss_request rss; + int response_len; + + memset(&rss, 0, sizeof(rss)); + + gsm_7bit_encode_n_ussd(rss.ussd_text, MAX_LEN_USSD_STRING, resp_string, &response_len); + rss.ussd_text_len = response_len; + rss.ussd_text_language = 0x0f; + + rss.transaction_id = req->transaction_id; + rss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE; + rss.component_type = GSM0480_CTYPE_RETURN_RESULT; + rss.invoke_id = req->invoke_id; + rss.opcode = GSM0480_OP_CODE_PROCESS_USS_REQ; + + return gsm0480_send_ussd(conn, &rss); +} + +/* Compose universial SS packet except Reject opcodes */ +int gsm0480_send_ussd(struct gsm_subscriber_connection *conn, + struct ss_request* req) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; uint8_t *ptr8; - int response_len; /* First put the payload text into the message */ ptr8 = msgb_put(msg, 0); - gsm_7bit_encode_n_ussd(ptr8, msgb_tailroom(msg), response_text, &response_len); - msgb_put(msg, response_len); + + memcpy(ptr8, req->ussd_text, req->ussd_text_len); + msgb_put(msg, req->ussd_text_len); /* Then wrap it as an Octet String */ - msgb_wrap_with_TL(msg, ASN1_OCTET_STRING_TAG); + msgb_wrap_with_ASN1_TL(msg, ASN1_OCTET_STRING_TAG); /* Pre-pend the DCS octet string */ - msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, 0x0F); + msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_language); /* Then wrap these as a Sequence */ - msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); - - /* Pre-pend the operation code */ - msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, - GSM0480_OP_CODE_PROCESS_USS_REQ); - - /* Wrap the operation code and IA5 string as a sequence */ - msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); - - /* Pre-pend the invoke ID */ - msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); - - /* Wrap this up as a Return Result component */ - msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT); - - /* Wrap the component in a Facility message */ - msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG); + + if (req->component_type == GSM0480_CTYPE_RETURN_RESULT) { + /* Pre-pend the operation code */ + msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode); + + /* Wrap the operation code and IA5 string as a sequence */ + msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG); + + /* Pre-pend the invoke ID */ + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); + } else if (req->component_type == GSM0480_CTYPE_INVOKE) { + /* Pre-pend the operation code */ + msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode); + + /* Pre-pend the invoke ID */ + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); + } else { + abort(); + } + + /* Wrap this up as an Invoke or a Return Result component */ + msgb_wrap_with_ASN1_TL(msg, req->component_type); + + if (req->message_type == GSM0480_MTYPE_REGISTER || + req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) { + /* Wrap the component in a Facility message, it's not ASN1 */ + msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + } else if (req->message_type == GSM0480_MTYPE_FACILITY) { + /* For GSM0480_MTYPE_FACILITY it's LV not TLV */ + msgb_wrap_with_L(msg); + } else { + abort(); + } /* And finally pre-pend the L3 header */ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id | (1<<7); /* TI direction = 1 */ - gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + gh->msg_type = req->message_type; + + DEBUGP(DSS, "Sending USSD to mobile: %s\n", msgb_hexdump(msg)); return gsm0808_submit_dtap(conn, msg, 0, 0); } int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, - const struct msgb *in_msg, - const struct ussd_request *req) + const struct ss_request *req) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -124,7 +187,7 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); /* Wrap this up as a Reject component */ - msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT); + msgb_wrap_with_ASN1_TL(msg, GSM0480_CTYPE_REJECT); /* Wrap the component in a Facility message */ msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c index 7f01eae..f0426c4 100644 --- a/openbsc/src/libmsc/ussd.c +++ b/openbsc/src/libmsc/ussd.c @@ -33,41 +33,57 @@ #include #include #include +#include +#include +#include /* Declarations of USSD strings to be recognised */ const char USSD_TEXT_OWN_NUMBER[] = "*#100#"; /* Forward declarations of network-specific handler functions */ -static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req); +static int send_own_number(struct gsm_subscriber_connection *conn, const struct ss_request *req); /* Entrypoint - handler function common to all mobile-originated USSDs */ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) { int rc; - struct ussd_request req; + struct ss_request req; + char request_string[MAX_LEN_USSD_STRING + 1]; struct gsm48_hdr *gh; memset(&req, 0, sizeof(req)); gh = msgb_l3(msg); - rc = gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req); + rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req); if (!rc) { - DEBUGP(DMM, "Unhandled SS\n"); - rc = gsm0480_send_ussd_reject(conn, msg, &req); + DEBUGP(DSS, "Unhandled SS\n"); + rc = gsm0480_send_ussd_reject(conn, &req); msc_release_connection(conn); return rc; } - /* Release-Complete */ - if (req.text[0] == '\0') + if (req.message_type == GSM0480_MTYPE_RELEASE_COMPLETE) return 0; - if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.text)) { - DEBUGP(DMM, "USSD: Own number requested\n"); - rc = send_own_number(conn, msg, &req); + if (req.message_type != GSM0480_MTYPE_REGISTER || + req.component_type != GSM0480_CTYPE_INVOKE || + req.opcode != GSM0480_OP_CODE_PROCESS_USS_REQ || + req.ussd_text_language != 0x0f) + { + DEBUGP(DSS, "Unexpected SS\n"); + rc = gsm0480_send_ussd_reject(conn, &req); + msc_release_connection(conn); + return rc; + } + + gsm_7bit_decode_n_ussd(request_string, MAX_LEN_USSD_STRING, req.ussd_text, req.ussd_text_len); + + if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)request_string)) { + DEBUGP(DSS, "USSD: Own number requested\n"); + rc = send_own_number(conn, &req); } else { - DEBUGP(DMM, "Unhandled USSD %s\n", req.text); - rc = gsm0480_send_ussd_reject(conn, msg, &req); + DEBUGP(DSS, "Unhandled USSD %s\n", request_string); + rc = gsm0480_send_ussd_reject(conn, &req); } /* check if we can release it */ @@ -76,12 +92,12 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) } /* A network-specific handler function */ -static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req) +static int send_own_number(struct gsm_subscriber_connection *conn, const struct ss_request *req) { char *own_number = conn->subscr->extension; char response_string[GSM_EXTENSION_LENGTH + 20]; /* Need trailing CR as EOT character */ snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number); - return gsm0480_send_ussd_response(conn, msg, response_string, req); + return gsm0480_send_ussd_response(conn, response_string, req); } -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:53 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:53 +0300 Subject: [PATCH 2/8] libmsc: Add USSD MAP constant in gsup_message_type In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448449439-10546-2-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev This message type is used for all USSD MAP-like messages over SUP --- openbsc/include/openbsc/gprs_gsup_messages.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/include/openbsc/gprs_gsup_messages.h b/openbsc/include/openbsc/gprs_gsup_messages.h index 8cbc809..fb9c66e 100644 --- a/openbsc/include/openbsc/gprs_gsup_messages.h +++ b/openbsc/include/openbsc/gprs_gsup_messages.h @@ -53,6 +53,8 @@ enum gprs_gsup_iei { }; enum gprs_gsup_message_type { + GPRS_GSUP_MSGT_USSD_MAP = 0b01111111, + GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST = 0b00000100, GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR = 0b00000101, GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT = 0b00000110, -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:55 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:55 +0300 Subject: [PATCH 4/8] libmsc: Add external USSD MAP interface In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448449439-10546-4-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev Add simple MAP-like protocol over SUP socket. It forwards USS messages with originated extension and sequence number. Add transaction interface for USSD since now we have async interface for it and USSD session can last for a while in menu scenario. --- openbsc/include/openbsc/gsm_ussd_map.h | 14 +++ openbsc/include/openbsc/gsm_ussd_map_proto.h | 24 ++++ openbsc/include/openbsc/transaction.h | 5 + openbsc/include/openbsc/ussd.h | 9 ++ openbsc/src/libmsc/Makefile.am | 3 +- openbsc/src/libmsc/gsm_ussd_map.c | 92 ++++++++++++++ openbsc/src/libmsc/gsm_ussd_map_proto.c | 158 ++++++++++++++++++++++++ openbsc/src/libmsc/transaction.c | 4 + openbsc/src/libmsc/ussd.c | 176 +++++++++++++++++++++++++++ 9 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 openbsc/include/openbsc/gsm_ussd_map.h create mode 100644 openbsc/include/openbsc/gsm_ussd_map_proto.h create mode 100644 openbsc/src/libmsc/gsm_ussd_map.c create mode 100644 openbsc/src/libmsc/gsm_ussd_map_proto.c diff --git a/openbsc/include/openbsc/gsm_ussd_map.h b/openbsc/include/openbsc/gsm_ussd_map.h new file mode 100644 index 0000000..063f421 --- /dev/null +++ b/openbsc/include/openbsc/gsm_ussd_map.h @@ -0,0 +1,14 @@ +#ifndef _GSM_USSD_MAP_H +#define _GSM_USSD_MAP_H + +#include +#include +#include + +int ussd_map_read_cb(struct gprs_gsup_client *sup_client, + struct msgb *msg); + +int ussd_map_tx_message(struct gsm_network *net, struct ss_request *req, + const char *extension, uint32_t ref); + +#endif /* _GSM_USSD_MAP_H */ diff --git a/openbsc/include/openbsc/gsm_ussd_map_proto.h b/openbsc/include/openbsc/gsm_ussd_map_proto.h new file mode 100644 index 0000000..8190396 --- /dev/null +++ b/openbsc/include/openbsc/gsm_ussd_map_proto.h @@ -0,0 +1,24 @@ +#ifndef _GSM_USSD_MAP_PROTO_H +#define _GSM_USSD_MAP_PROTO_H + +#include + + +enum { + FMAP_MSISDN = 0x80 +}; + +int subscr_uss_message(struct msgb *msg, + struct ss_request *req, + const char* extension, + uint32_t ref); + +int rx_uss_message_parse(const uint8_t* data, + size_t len, + struct ss_request *ss, + uint32_t *ref, + char* extention, + size_t extention_len); + + +#endif /* _GSM_USSD_MAP_PROTO_H */ diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 6ef1612..d82e576 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -56,6 +56,11 @@ struct gsm_trans { struct gsm_sms *sms; } sms; + struct { + uint8_t invoke_id; + uint8_t mo; + uint8_t dirty; + } ss; }; }; diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h index 2665468..d72d35f 100644 --- a/openbsc/include/openbsc/ussd.h +++ b/openbsc/include/openbsc/ussd.h @@ -5,6 +5,15 @@ #include +#define USSD_MO 1 +#define USSD_MT 0 + int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg); + +int on_ussd_response(struct gsm_network *net, uint32_t ref, struct ss_request* req, const char* extention); + + +void _ussd_trans_free(struct gsm_trans *trans); + #endif diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 18bfa0c..616ed89 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -19,7 +19,8 @@ libmsc_a_SOURCES = auth.c \ ussd.c \ vty_interface_layer3.c \ transaction.c \ - osmo_msc.c ctrl_commands.c meas_feed.c + osmo_msc.c ctrl_commands.c meas_feed.c \ + gsm_ussd_map_proto.c gsm_ussd_map.c if BUILD_SMPP noinst_HEADERS += smpp_smsc.h diff --git a/openbsc/src/libmsc/gsm_ussd_map.c b/openbsc/src/libmsc/gsm_ussd_map.c new file mode 100644 index 0000000..21604ca --- /dev/null +++ b/openbsc/src/libmsc/gsm_ussd_map.c @@ -0,0 +1,92 @@ +/* GSM USSD external MAP interface */ + +/* (C) 2015 by Sergey Kostanbaev + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int ussd_map_tx_message(struct gsm_network* net, + struct ss_request *req, + const char* extension, + uint32_t ref) +{ + struct msgb *msg = gprs_gsup_msgb_alloc(); + if (!msg) + return -ENOMEM; + + subscr_uss_message(msg, req, extension, ref); + + return gprs_gsup_client_send(net->ussd_sup_client, msg); +} + + +static int ussd_map_rx_message_int(struct gsm_network *net, const uint8_t* data, size_t len) +{ + char extension[32] = {0}; + uint32_t ref; + struct ss_request ss; + memset(&ss, 0, sizeof(ss)); + + if (rx_uss_message_parse(data, len, &ss, &ref, extension, sizeof(extension))) { + LOGP(DSS, LOGL_ERROR, "Can't parse SUP MAP SS message\n"); + return -1; + } + + LOGP(DSS, LOGL_ERROR, "Got invoke_id=0x%02x opcode=0x%02x facility=0x%02x text=%s\n", + ss.invoke_id, ss.opcode, ss.component_type, ss.ussd_text); + + return on_ussd_response(net, ref, &ss, extension); +} + +static int ussd_map_rx_message(struct gprs_gsup_client *sup_client, struct msgb *msg) +{ + uint8_t *data = msgb_l2(msg); + size_t data_len = msgb_l2len(msg); + struct gsm_network *gsmnet = (struct gsm_network *)sup_client->data; + + if (*data != GPRS_GSUP_MSGT_USSD_MAP) { + return -1; + } + + return ussd_map_rx_message_int(gsmnet, data, data_len); +} + +int ussd_map_read_cb(struct gprs_gsup_client *sup_client, struct msgb *msg) +{ + int rc; + + rc = ussd_map_rx_message(sup_client, msg); + msgb_free(msg); + if (rc < 0) + return -1; + + return rc; +} diff --git a/openbsc/src/libmsc/gsm_ussd_map_proto.c b/openbsc/src/libmsc/gsm_ussd_map_proto.c new file mode 100644 index 0000000..4fc0829 --- /dev/null +++ b/openbsc/src/libmsc/gsm_ussd_map_proto.c @@ -0,0 +1,158 @@ +/* GSM USSD external MAP protocol on pseudo TCAP */ + +/* (C) 2015 by Sergey Kostanbaev + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int subscr_uss_message(struct msgb *msg, + struct ss_request *req, + const char* extension, + uint32_t ref) +{ + size_t bcd_len = 0; + uint8_t *gsup_indicator; + + gsup_indicator = msgb_put(msg, 8); + + /* First byte should always be GPRS_GSUP_MSGT_USSD_MAP */ + gsup_indicator[0] = GPRS_GSUP_MSGT_USSD_MAP; + gsup_indicator[1] = req->message_type; + + gsup_indicator[2] = ref >> 24; + gsup_indicator[3] = ref >> 16; + gsup_indicator[4] = ref >> 7; + gsup_indicator[5] = ref; + + gsup_indicator[6] = req->component_type; + + /* invokeId */ + msgb_tlv_put(msg, GSM0480_COMPIDTAG_INVOKE_ID, 1, &req->invoke_id); + + /* opCode */ + msgb_tlv_put(msg, GSM0480_OPERATION_CODE, 1, &req->opcode); + + if (req->ussd_text_len > 0) { + msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_len + 1, &req->ussd_text_language); + } + + if (extension) { + uint8_t bcd_buf[32]; + bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0, + extension); + msgb_tlv_put(msg, FMAP_MSISDN, bcd_len - 1, &bcd_buf[1]); + } + + /* fill actual length */ + gsup_indicator[7] = 3 + 3 + (req->ussd_text_len + 1 + 2) + (bcd_len + 2);; + + /* wrap with GSM0480_CTYPE_INVOKE */ + // gsm0480_wrap_invoke(msg, req->opcode, invoke_id); + // gsup_indicator = msgb_push(msgb, 1); + // gsup_indicator[0] = GPRS_GSUP_MSGT_MAP; + return 0; +} + + + +int rx_uss_message_parse(const uint8_t* data, + size_t len, + struct ss_request *ss, + uint32_t *pref, + char* extention, + size_t extention_len) +{ + const uint8_t* const_data = data; + uint32_t ref; + + if (len < 8 + 3 + 3) + return -1; + + /* skip GPRS_GSUP_MSGT_MAP */ + ss->message_type = *(++const_data); + + ref = ((uint32_t)(*(++const_data))) << 24; + ref = ((uint32_t)(*(++const_data))) << 16; + ref = ((uint32_t)(*(++const_data))) << 8; + ref = ((uint32_t)(*(++const_data))); + if (pref) + *pref = ref; + + ss->component_type = *(++const_data); + + /* skip full len and move to component id */ + const_data += 2; + + if (*const_data != GSM0480_COMPIDTAG_INVOKE_ID) { + return -1; + } + const_data += 2; + ss->invoke_id = *const_data; + const_data++; + + // + if (*const_data != GSM0480_OPERATION_CODE) { + return -1; + } + const_data += 2; + ss->opcode = *const_data; + const_data++; + + + while (const_data - data < len) { + uint8_t len; + switch (*const_data) { + case ASN1_OCTET_STRING_TAG: + ss->ussd_text_len = len = (*(++const_data) - 1); + ss->ussd_text_language = *(++const_data); + memcpy(ss->ussd_text, + ++const_data, + (len > MAX_LEN_USSD_STRING) ? MAX_LEN_USSD_STRING : len); + const_data += len; + break; + + case FMAP_MSISDN: + len = *(++const_data); + gsm48_decode_bcd_number(extention, + extention_len, + const_data, + 0); + const_data += len + 1; + break; + default: + DEBUGP(DSS, "Unknown code: %d\n", *const_data); + return -1; + } + } + + return 0; +} diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c index a750362..89cb2b5 100644 --- a/openbsc/src/libmsc/transaction.c +++ b/openbsc/src/libmsc/transaction.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,9 @@ void trans_free(struct gsm_trans *trans) case GSM48_PDISC_SMS: _gsm411_sms_trans_free(trans); break; + case GSM48_PDISC_NC_SS: + _ussd_trans_free(trans); + break; } if (trans->paging_request) { diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c index f0426c4..f1e373c 100644 --- a/openbsc/src/libmsc/ussd.c +++ b/openbsc/src/libmsc/ussd.c @@ -33,9 +33,21 @@ #include #include #include +#include #include #include #include +#include +#include + +/* Counter of open sessions */ +static unsigned s_ussd_open_sessions = 0; + +/* Last uniq generated session id */ +static uint32_t s_uniq_ussd_sessiod_id = 0; + +/* Forward declaration of USSD handler for USSD MAP interface */ +static int handle_rcv_ussd_sup(struct gsm_subscriber_connection *conn, struct msgb *msg); /* Declarations of USSD strings to be recognised */ const char USSD_TEXT_OWN_NUMBER[] = "*#100#"; @@ -52,6 +64,9 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) char request_string[MAX_LEN_USSD_STRING + 1]; struct gsm48_hdr *gh; + if (conn->subscr->group->net->ussd_sup_client) + return handle_rcv_ussd_sup(conn, msg); + memset(&req, 0, sizeof(req)); gh = msgb_l3(msg); rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req); @@ -101,3 +116,164 @@ static int send_own_number(struct gsm_subscriber_connection *conn, const struct snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number); return gsm0480_send_ussd_response(conn, response_string, req); } + + +static int ussd_sup_send_reject(struct gsm_network *conn, + uint32_t ref, uint8_t invokeid, uint8_t opcode) +{ + struct ss_request rej; + rej.message_type = GSM0480_MTYPE_RELEASE_COMPLETE; + rej.component_type = GSM0480_CTYPE_REJECT; + rej.invoke_id = invokeid; + rej.opcode = opcode; + rej.ussd_text_len = 0; + + return ussd_map_tx_message(conn, &rej, NULL, ref); +} + +/* Callback from USSD MAP interface */ +int on_ussd_response(struct gsm_network *net, uint32_t ref, struct ss_request *req, const char *extention) +{ + struct gsm_trans *trans = trans_find_by_callref(net, ref); + int rc = 0; + + switch (req->message_type) { + case GSM0480_MTYPE_REGISTER: + DEBUGP(DSS, "Network originated USSD messages isn't supported yet!\n"); + + ussd_sup_send_reject(net, ref, req->invoke_id, req->opcode); + return 0; + + case GSM0480_MTYPE_FACILITY: + case GSM0480_MTYPE_RELEASE_COMPLETE: + if (!trans) { + DEBUGP(DSS, "No session was found for ref: %d!\n", + ref); + + ussd_sup_send_reject(net, ref, req->invoke_id, req->opcode); + return 0; + } + break; + default: + DEBUGP(DSS, "Unknown message type 0x%02x\n", req->message_type); + ussd_sup_send_reject(net, ref, req->invoke_id, req->opcode); + return 0; + } + + req->invoke_id = trans->ss.invoke_id; + req->transaction_id = (trans->transaction_id << 4) ^ 0x80; + + if (req->component_type != GSM0480_CTYPE_REJECT) { + rc = gsm0480_send_ussd(trans->conn, req); + } else { + rc = gsm0480_send_ussd_reject(trans->conn, req); + } + + if (req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) { + struct gsm_subscriber_connection* conn = trans->conn; + + trans_free(trans); + msc_release_connection(conn); + } + + return rc; +} + +/* Handler function common to all mobile-originated USSDs in case if USSD MAP enabled */ +static int handle_rcv_ussd_sup(struct gsm_subscriber_connection *conn, struct msgb *msg) +{ + int rc = 0; + struct gsm48_hdr *gh = msgb_l3(msg); + struct ss_request req; + struct gsm_trans *trans = NULL; + uint8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */ + + if (!conn->subscr) + return -EIO; + + memset(&req, 0, sizeof(req)); + + DEBUGP(DSS, "handle ussd tid=%d: %s\n", transaction_id, msgb_hexdump(msg)); + trans = trans_find_by_id(conn, GSM48_PDISC_NC_SS, transaction_id); + + rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req); + if (!rc) { + DEBUGP(DSS, "Unhandled SS\n"); + if (!trans) { + goto transaction_not_found; + } + + /* don't know how to process */ + goto failed_transaction; + } + + switch (req.message_type) { + case GSM0480_MTYPE_REGISTER: + if (trans) { + /* we already have a transaction, ignore this message */ + goto release_conn; + } + + trans = trans_alloc(conn->bts->network, conn->subscr, + GSM48_PDISC_NC_SS, + transaction_id, s_uniq_ussd_sessiod_id++); + if (!trans) { + DEBUGP(DSS, "Failed to create new ussd transaction\n"); + goto transaction_not_found; + } + + trans->conn = conn; + trans->ss.invoke_id = req.invoke_id; + trans->ss.mo = 1; + trans->ss.dirty = 1; + break; + + case GSM0480_MTYPE_FACILITY: + if (!trans) { + DEBUGP(DSS, "no session found invoke_id=%d tid=%d\n", + req.invoke_id, transaction_id); + goto transaction_not_found; + } + break; + + case GSM0480_MTYPE_RELEASE_COMPLETE: + if (!trans) { + DEBUGP(DSS, "RELEASE_COMPLETE to non-existing transaction!\n"); + goto release_conn; + } + + trans_free(trans); + goto release_conn; + } + + rc = ussd_map_tx_message(conn->subscr->group->net, &req, + conn->subscr->extension, trans->callref); + if (rc) { + /* do not send reject if we failed with the message */ + trans->ss.dirty = 0; + + DEBUGP(DSS, "Unable tp send uss over sup reason: %d\n", rc); + goto failed_transaction; + } + return 0; + +failed_transaction: + trans_free(trans); + +transaction_not_found: + gsm0480_send_ussd_reject(conn, &req); + +release_conn: + msc_release_connection(conn); + return rc; +} + +void _ussd_trans_free(struct gsm_trans *trans) +{ + if (trans->ss.dirty) { + trans->ss.dirty = 0; + + ussd_sup_send_reject(trans->net, trans->callref, trans->ss.invoke_id, 0); + } +} + -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:56 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:56 +0300 Subject: [PATCH 5/8] libmsc: Create a separate SUP socket for USSD MAP In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448449439-10546-5-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/libmsc/vty_interface_layer3.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index c167c49..ffdddfb 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -244,6 +244,7 @@ struct gsm_network { struct llist_head upqueue; struct llist_head trans_list; struct bsc_api *bsc_api; + struct gprs_gsup_client *ussd_sup_client; unsigned int num_bts; struct llist_head bts_list; diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index f49c53a..b7e1eb4 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include @@ -987,6 +989,30 @@ DEFUN(meas_feed_scenario, meas_feed_scenario_cmd, return CMD_SUCCESS; } +DEFUN(sup_ussd_destination, sup_ussd_destination_cmd, + "sup-ussd destination ADDR <0-65535>", + "Enable SUP USSD socket to a given address/port" "destination\n" "address or hostname\n" "port number\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + + if (gsmnet->ussd_sup_client) { + LOGP(DMM, LOGL_FATAL, "Can't create two USSD SUP clients\n"); + vty_out(vty, "%%USSD SUP client already configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + gsmnet->ussd_sup_client = gprs_gsup_client_create( + argv[0], atoi(argv[1]), &ussd_map_read_cb); + if (!gsmnet->ussd_sup_client) { + LOGP(DMM, LOGL_FATAL, "Cannot set up USSD SUP socket\n"); + vty_out(vty, "%%Cannot set up USSD SUP socket%s", VTY_NEWLINE); + return CMD_WARNING; + } + + gsmnet->ussd_sup_client->data = gsmnet; + return CMD_SUCCESS; +} + DEFUN(logging_fltr_imsi, logging_fltr_imsi_cmd, @@ -1124,6 +1150,7 @@ int bsc_vty_init_extra(void) install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd); install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd); install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd); + install_element(NITB_NODE, &sup_ussd_destination_cmd); return 0; } -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:57 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:57 +0300 Subject: [PATCH 6/8] ussd_proxy: Add ussd_proxy utility converting SUP USSD MAP to SIP IMS In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448449439-10546-6-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev This is USSD SUP to SIP IMS (TS 124 390) proxy converter based on sofia-sip library. It's single threaded application that uses sofia-sip event handling style for socket processing and msgb osmocom packet composer/parser. XML is done in very simple way not using external parsing library. Language conversion is done in tricky way since XML in utf-8. First the program tries to convert it to latin1 using iconv and then to gsm 7-bit using osmcom. If it fails it converts to ucs-2 directly. --- openbsc/src/ussd-proxy/Makefile.am | 17 + openbsc/src/ussd-proxy/ussd_proxy.c | 1265 +++++++++++++++++++++++++++++++++++ 2 files changed, 1282 insertions(+) create mode 100644 openbsc/src/ussd-proxy/Makefile.am create mode 100644 openbsc/src/ussd-proxy/ussd_proxy.c diff --git a/openbsc/src/ussd-proxy/Makefile.am b/openbsc/src/ussd-proxy/Makefile.am new file mode 100644 index 0000000..dfb4fc6 --- /dev/null +++ b/openbsc/src/ussd-proxy/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(COVERAGE_CFLAGS) \ + $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) \ + -I/usr/include/sofia-sip-1.12 + +AM_LDFLAGS = $(COVERAGE_LDFLAGS) + +bin_PROGRAMS = ussd-proxy + +ussd_proxy_SOURCES = \ + ussd_proxy.c ../libmsc/gsm_ussd_map_proto.c + +ussd_proxy_LDADD = \ + -lsofia-sip-ua \ + $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS) diff --git a/openbsc/src/ussd-proxy/ussd_proxy.c b/openbsc/src/ussd-proxy/ussd_proxy.c new file mode 100644 index 0000000..04d3826 --- /dev/null +++ b/openbsc/src/ussd-proxy/ussd_proxy.c @@ -0,0 +1,1265 @@ +#ifdef HAVE_CONFIG_H +//#include +#endif + +#include +#include +#include +#include +#include +#include + +typedef struct context_s context_t; +#define NTA_OUTGOING_MAGIC_T context_t +#define SU_ROOT_MAGIC_T context_t +#define NUA_MAGIC_T context_t + +typedef struct operation operation_t; +#define NUA_HMAGIC_T operation_t + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +typedef uint32_t sup_tcap_tid_t; + + +typedef struct isup_connection isup_connection_t; + +struct isup_connection { + context_t *ctx; + + su_socket_t isup_conn_socket; + su_wait_t isup_conn_event; + int isup_register_idx; + + /* osmocom data */ + + struct msgb *pending_msg; +}; + +struct ussd_session { + isup_connection_t *conn; + + sup_tcap_tid_t ref; + + int ms_originated; + struct ss_request rigester_msg; + + char extention[32]; +}; + +struct context_s { + su_home_t home[1]; + su_root_t *root; + + su_socket_t isup_acc_socket; + su_wait_t isup_acc_event; + + nua_t *nua; + + url_t *to_url; + url_t *self_url; + + su_timer_t *timer; + su_duration_t max_ussd_ses_duration; + + /* iconv data */ + iconv_t* utf8_to_ucs2; + iconv_t* ucs2_to_utf8; + + iconv_t* utf8_to_latin1; + iconv_t* latin1_to_utf8; + + /* Array of isup connections */ + struct isup_connection isup[1]; + + /* list of active operations */ + struct llist_head operation_list; + unsigned operation_count; + unsigned operations_max; +}; + + +/* Example of operation handle context information structure */ +struct operation +{ + struct llist_head list; + + nua_handle_t *handle; /* operation handle */ + context_t *ctx; + su_time_t tm_initiated; + + /* protocol specific sessions */ + struct ussd_session ussd; +}; + +static +int ussd_send_data(operation_t *op, int last, const char* lang, unsigned lang_len, + const char* msg, unsigned msg_len); +static +int ussd_send_data_ss(isup_connection_t *conn, struct ss_request* reply, uint32_t ref); + +static +int ussd_send_reject(isup_connection_t *conn, uint32_t ref, uint8_t invoke_id, uint8_t opcode); + +static const char* get_unknown_header(sip_t const *sip, const char *header) +{ + sip_header_t *h = (sip_header_t *)sip->sip_unknown; + for (; h; h = (sip_header_t *)h->sh_succ) { + if (strcasecmp(h->sh_unknown->un_name, header) == 0) { + return h->sh_unknown->un_value; + } + } + return NULL; +} + + +int sup_server_send(isup_connection_t *conn, struct msgb *msg) +{ + ssize_t sz; + + if (!conn) { + msgb_free(msg); + return -ENOTCONN; + } + + ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP); + ipa_msg_push_header(msg, IPAC_PROTO_OSMO); + + LOGP(DLCTRL, LOGL_ERROR, + "Sending wire, will send: %s\n", msgb_hexdump(msg)); + + // FIXME ugly hack!!! + // TODO place message in send queue !!!! + sz = send(conn->isup_conn_socket, msg->data, msg->len, 0); + msgb_free(msg); + + return ((unsigned)sz == msg->len) ? 0 : -1; +} + +static int ussd_parse_xml(const char *xml, + unsigned xml_len, + const char **lang, + unsigned *lang_len, + const char **msg, + unsigned *msg_len) +{ + /* Example of parsing XML + + + en + Test + + */ + + // tag + char* ussd_data_stag = strstr(xml, ""); + if (ussd_data_stag == NULL) + return 0; + + char* ussd_data_etag = strstr(ussd_data_stag, ""); + if (ussd_data_etag == NULL) + return 0; + + // tag + char* ussd_lang_stag = strstr(ussd_data_stag, ""); + if (ussd_lang_stag == NULL) + return 0; + + char* ussd_lang_etag = strstr(ussd_lang_stag, ""); + if (ussd_lang_etag == NULL) + return 0; + + // tag + char* ussd_ussd_stag = strstr(ussd_data_stag, ""); + if (ussd_ussd_stag == NULL) + return 0; + + char* ussd_ussd_etag = strstr(ussd_ussd_stag, ""); + if (ussd_ussd_etag == NULL) + return 0; + + if (ussd_ussd_etag - xml > xml_len || ussd_lang_etag - xml > xml_len) + return 0; + + *lang = ussd_lang_stag + strlen(""); + *lang_len = ussd_lang_etag - *lang; + + *msg = ussd_ussd_stag + strlen(""); + *msg_len = ussd_ussd_etag - *msg; + + return 1; +} + +// Operation APIs +static operation_t* operation_find_by_tid(context_t* ctx, sup_tcap_tid_t ref) +{ + operation_t* op; + llist_for_each_entry(op, &ctx->operation_list, list) { + if (op->ussd.ref == ref) + return op; + } + return NULL; +} + +static operation_t* operation_alloc(context_t* ctx) +{ + operation_t* op; + + if (ctx->operation_count >= ctx->operations_max) { + fprintf(stderr, "!!! maximum number of active session is reached: %d\n", + ctx->operation_count); + return NULL; + } + + /* create operation context information */ + op = su_zalloc(ctx->home, (sizeof *op)); + if (!op) { + return NULL; + } + + op->ctx = ctx; + op->tm_initiated = su_now(); + INIT_LLIST_HEAD(&op->list); + llist_add_tail(&op->list, &ctx->operation_list); + ctx->operation_count++; + + return op; +} + +static void operation_destroy(operation_t* op) +{ + /* release operation handle */ + nua_handle_destroy(op->handle); + op->handle = NULL; + + llist_del(&op->list); + op->ctx->operation_count--; + + fprintf(stderr, "--- operation %*.s from %s destroyed (sessions: %d)\n", + op->ussd.rigester_msg.ussd_text_len, + op->ussd.rigester_msg.ussd_text, + op->ussd.extention, + op->ctx->operation_count); + + /* release operation context information */ + su_free(op->ctx->home, op); +} + +void proxy_r_invite(int status, + char const *phrase, + nua_t *nua, + nua_magic_t *magic, + nua_handle_t *nh, + nua_hmagic_t *hmagic, + sip_t const *sip, + tagi_t tags[]) +{ + fprintf(stderr, "*** Got reply %d for INVITE\n", status); + if (status == 200) { + nua_ack(nh, TAG_END()); + } else { + printf("response to INVITE: %03d %s\n", status, phrase); + + ussd_send_reject(hmagic->ussd.conn, + hmagic->ussd.ref, + hmagic->ussd.rigester_msg.invoke_id, + hmagic->ussd.rigester_msg.opcode); + operation_destroy(hmagic); + } +} + +void proxy_i_bye(int status, + char const *phrase, + nua_t *nua, + nua_magic_t *magic, + nua_handle_t *nh, + nua_hmagic_t *hmagic, + sip_t const *sip, + tagi_t tags[]) +{ + const char* ri; + int rc; + // printf("*** call released:\n%s\n", sip->sip_payload->pl_data); + + ri = get_unknown_header(sip, "Recv-Info"); + if (ri && (strcasecmp(ri, "g.3gpp.ussd") == 0)) { + /* Parse XML */ + const char *language; + const char *msg; + unsigned language_len; + unsigned msg_len; + + if (ussd_parse_xml(sip->sip_payload->pl_data, + sip->sip_payload->pl_len, + &language, &language_len, + &msg, &msg_len)) { + printf("=== USSD (%.*s): %.*s\n", + language_len, language, + msg_len, msg); + + /* Send reply back to SUP */ + // TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + rc = ussd_send_data(hmagic, 1, language, language_len, + msg, msg_len); + if (rc == 0) { + // Normal shutdown + operation_destroy(hmagic); + return; + } + + fprintf(stderr, "*** unable to send to SUP\n"); + } else { + fprintf(stderr, "*** unable to parse XML\n"); + } + } + + fprintf(stderr, "*** response BYE with %d satus is malformed, drop session\n", + status); + ussd_send_reject(hmagic->ussd.conn, + hmagic->ussd.ref, + hmagic->ussd.rigester_msg.invoke_id, + hmagic->ussd.rigester_msg.opcode); + operation_destroy(hmagic); +} + +void proxy_r_bye(int status, + char const *phrase, + nua_t *nua, + nua_magic_t *magic, + nua_handle_t *nh, + nua_hmagic_t *hmagic, + sip_t const *sip, + tagi_t tags[]) +{ + fprintf(stderr, "*** Got reply %d for BUY\n", status); + operation_destroy(hmagic); +} + +void proxy_i_error(int status, + char const *phrase, + nua_t *nua, + nua_magic_t *magic, + nua_handle_t *nh, + nua_hmagic_t *hmagic, + sip_t const *sip, + tagi_t tags[]) +{ +#if 0 + if (!hmagic) { + return; + } + + fprintf(stderr, "*** error in session with %d satus\n", + status); + ussd_send_reject(hmagic->ussd.conn, + hmagic->ussd.rigester_msg.invoke_id, + hmagic->ussd.rigester_msg.opcode); + operation_destroy(hmagic); +#endif +} + +void proxy_info(int status, + char const *phrase, + nua_t *nua, + nua_magic_t *magic, + nua_handle_t *nh, + nua_hmagic_t *hmagic, + sip_t const *sip, + tagi_t tags[], + int response) +{ + const char* ri; + int rc; + + // Normal ACK is recieved + if (response == 1 && status == 200) + return; + + ri = get_unknown_header(sip, "Recv-Info"); + if (ri && (strcasecmp(ri, "g.3gpp.ussd") == 0)) { + /* Parse XML */ + const char *language; + const char *msg; + unsigned language_len; + unsigned msg_len; + + if (ussd_parse_xml(sip->sip_payload->pl_data, + sip->sip_payload->pl_len, + &language, &language_len, + &msg, &msg_len)) { + printf("%s USSD (%.*s): %.*s\n", + (response) ? ">>>" : "<<<", + language_len, language, + msg_len, msg); + + if (hmagic == 0) { + printf("*** unknown session, ignoring"); + + // FIXME this function works only with a dialog! + nua_respond(nh, 481, "INFO with no session", TAG_END()); + return; + } + + /* Send reply back to SUP */ + // TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + rc = ussd_send_data(hmagic, 0, language, language_len, + msg, msg_len); + if (rc == 0) + return; + + fprintf(stderr, "*** unable to send to SUP in INFO\n"); + } else { + fprintf(stderr, "*** unable to parse XML in INFO\n"); + } + } + + fprintf(stderr, "*** %s INFO with %d satus is malformed, drop session\n", + response ? "response" : "request", + status); + ussd_send_reject(hmagic->ussd.conn, + hmagic->ussd.ref, + hmagic->ussd.rigester_msg.invoke_id, + hmagic->ussd.rigester_msg.opcode); + operation_destroy(hmagic); +} + +int ussd_create_xml_latin1(context_t* ctx, + char *content, size_t max_len, + const char* inbuf_latin1, int buf_len) +{ + const char *language = "en"; + char tmpbuf_utf8[2*MAX_LEN_USSD_STRING]; + unsigned tmpbuf_utf8_len; + + char* inbuf = (char*)inbuf_latin1; + size_t inleft = buf_len; + char* outbuf = tmpbuf_utf8; + size_t outleft = sizeof(tmpbuf_utf8); + size_t s; + + s = iconv(ctx->latin1_to_utf8, &inbuf, &inleft, &outbuf, &outleft); + if (s == (size_t)-1) { + LOGP(DLCTRL, LOGL_ERROR, "Unable to encode latin1 into utf8\n"); + return 0; + } + + tmpbuf_utf8_len = outbuf - tmpbuf_utf8; + + int content_len = snprintf(content, max_len, + "\n" + "\n" + "%s\n" + "%.*s\n" + "", + language, + tmpbuf_utf8_len, tmpbuf_utf8); + if (content_len > max_len) { + content[max_len - 1] = 0; + return 0; + } + return 1; +} + +static int decode_to_latin1(char* outbuf, unsigned size, + const uint8_t* msg, unsigned msg_len, uint8_t lang) +{ + if (lang == 0x0f) { + return gsm_7bit_decode_n_ussd(outbuf, size, msg, msg_len); + } else { + LOGP(DLCTRL, LOGL_ERROR, "Unknown language: 0x%02x\n", lang); + return 0; + } +} + +/* URL_RESERVED_CHARS in sofia is not strict enough as in RFC3986 */ +#define RFC3986_RESERVED_CHARS "!*'();:@&=+$,/?#[]" + +int ussd_session_open_mo(operation_t *op, + isup_connection_t *conn, + struct ss_request* ss, + uint32_t ref, + const char* extention) +{ + char content[1024]; + char decoded[MAX_LEN_USSD_STRING + 1]; + char escaped_to[512]; + context_t* ctx = op->ctx; + sip_to_t *to = NULL; + sip_to_t *from = NULL; + url_t to_url, from_url; + char* to_url_str; + char* from_url_str; + + int decoded_len; + + op->ussd.ref = ref; + op->ussd.conn = conn; + op->ussd.ms_originated = 1; + op->ussd.rigester_msg = *ss; + strncpy(op->ussd.extention, extention, sizeof(op->ussd.extention)); + + decoded_len = decode_to_latin1(decoded, MAX_LEN_USSD_STRING, + op->ussd.rigester_msg.ussd_text, + op->ussd.rigester_msg.ussd_text_len, + op->ussd.rigester_msg.ussd_text_language); + if (decoded_len <= 0) { + goto failed_to_parse_xml; + } + decoded[decoded_len] = 0; + + if (!ussd_create_xml_latin1(ctx, content, sizeof(content), + decoded, decoded_len)) { + goto failed_to_parse_xml; + } + + + /* Destination address */ + url_escape(escaped_to, decoded, RFC3986_RESERVED_CHARS); + to_url = *ctx->to_url; + to_url.url_user = escaped_to; + to_url_str = url_as_string(ctx->home, &to_url); + if (to_url_str == NULL) { + goto failed_create_handle; + } + + to = sip_to_create(ctx->home, (url_string_t *)to_url_str); + su_free(ctx->home, to_url_str); + if (!to) { + goto failed_create_handle; + } + + /* Source address */ + from_url = *ctx->self_url; + from_url.url_user = extention; + from_url_str = url_as_string(ctx->home, &from_url); + if (from_url_str == NULL) { + goto failed_create_handle; + } + + from = sip_from_create(ctx->home, (url_string_t *)from_url_str); + su_free(ctx->home, from_url_str); + if (!to) { + goto failed_create_handle; + } + + /* create operation handle */ + op->handle = nua_handle(ctx->nua, + op, + SIPTAG_TO(to), + SIPTAG_FROM(from), + NUTAG_M_USERNAME(extention), + TAG_END()); + + su_free(ctx->home, from); + su_free(ctx->home, to); + from = NULL; + to = NULL; + + if (op->handle == NULL) { + goto failed_create_handle; + } + + nua_invite(op->handle, + SIPTAG_UNKNOWN_STR("Recv-Info: g.3gpp.ussd"), + SIPTAG_CONTENT_TYPE_STR("application/vnd.3gpp.ussd+xml"), + SIPTAG_PAYLOAD_STR(content), + TAG_END()); + return 0; + +failed_create_handle: + if (from != NULL) + su_free(ctx->home, from); + if (to != NULL) + su_free(ctx->home, to); +failed_to_parse_xml: + fprintf(stderr, "*** open_ussd_session failed!\n"); + return -1; +} + +int ussd_session_facility(operation_t *op, + struct ss_request* ss, + const char* extention) +{ + char content[1024]; + char decoded[MAX_LEN_USSD_STRING + 1]; + int decoded_len; + + decoded_len = decode_to_latin1(decoded, MAX_LEN_USSD_STRING, + op->ussd.rigester_msg.ussd_text, + op->ussd.rigester_msg.ussd_text_len, + op->ussd.rigester_msg.ussd_text_language); + if (decoded_len <= 0) { + return -1; + } + decoded[decoded_len] = 0; + + if (!ussd_create_xml_latin1(op->ctx, content, sizeof(content), + decoded, decoded_len)) { + return -1; + } + + nua_info(op->handle, + /* other tags as needed ... */ + SIPTAG_CONTENT_TYPE_STR("application/vnd.3gpp.ussd+xml"), + SIPTAG_UNKNOWN_STR("Recv-Info: g.3gpp.ussd"), + SIPTAG_PAYLOAD_STR(content), + TAG_END()); + + return 0; +} + +void context_callback(nua_event_t event, + int status, + char const *phrase, + nua_t *nua, + nua_magic_t *magic, + nua_handle_t *nh, + nua_hmagic_t *hmagic, + sip_t const *sip, + tagi_t tags[]) +{ + fprintf(stderr, "$$$ got event %d: status: %d (%s) : %p\n", event, status, phrase, hmagic); + + switch (event) { + case nua_i_error: + proxy_i_error(status, phrase, nua, magic, nh, hmagic, sip, tags); + break; + + case nua_i_info: + proxy_info(status, phrase, nua, magic, nh, hmagic, sip, tags, 0); + break; + + case nua_r_info: + proxy_info(status, phrase, nua, magic, nh, hmagic, sip, tags, 1); + break; + + case nua_i_bye: + proxy_i_bye(status, phrase, nua, magic, nh, hmagic, sip, tags); + break; + + case nua_i_invite: + //app_i_invite(status, phrase, nua, magic, nh, hmagic, sip, tags); + break; + + case nua_r_invite: + proxy_r_invite(status, phrase, nua, magic, nh, hmagic, sip, tags); + break; + + case nua_r_bye: + proxy_r_bye(status, phrase, nua, magic, nh, hmagic, sip, tags); + break; + + default: + /* unknown event -> print out error message */ + if (status > 100) { + printf("unknown event %d: %03d %s\n", + event, + status, + phrase); + } else { + printf("unknown event %d\n", event); + } + tl_print(stdout, "", tags); + break; + } +} + +static int rx_sup_uss_message(isup_connection_t *sup_conn, const uint8_t* data, size_t len) +{ + char extention[32] = {0}; + struct ss_request ss; + uint32_t ref; + operation_t* op; + int rc; + context_t *ctx = sup_conn->ctx; + memset(&ss, 0, sizeof(ss)); + + if (rx_uss_message_parse(data, len, &ss, &ref, extention, sizeof(extention))) { + LOGP(DLCTRL, LOGL_ERROR, "Can't parse uss message\n"); + goto err_send_reject; + } + + LOGP(DLCTRL, LOGL_ERROR, "Got ref=%d mtype=0x%02x invoke_id=0x%02x opcode=0x%02x component_type=0x%02x text=%s\n", ref, + ss.message_type, ss.invoke_id, ss.opcode, ss.component_type, ss.ussd_text); + + switch (ss.message_type) { + case GSM0480_MTYPE_REGISTER: + if (ss.component_type != GSM0480_CTYPE_INVOKE) { + LOGP(DLCTRL, LOGL_ERROR, "Non-INVOKE component type in REGISTER: 0x%02x\n", ss.component_type); + goto err_send_reject; + } + if (ss.opcode != GSM0480_OP_CODE_PROCESS_USS_REQ) { + LOGP(DLCTRL, LOGL_ERROR, "Don't know hot to handle this SS opcode: 0x%02x\n", ss.opcode); + goto err_send_reject; + } + /* Create new session */ + op = operation_alloc(ctx); + if (op == NULL) { + LOGP(DLCTRL, LOGL_ERROR, "Unable to allocate new session\n"); + goto err_send_reject; + } + LOGP(DLCTRL, LOGL_ERROR, "New session %.*s from %s, active: %d\n", + ss.ussd_text_len, + ss.ussd_text, + extention, + ctx->operation_count); + + rc = ussd_session_open_mo(op, sup_conn, &ss, ref, extention); + if (rc < 0) { + operation_destroy(op); + goto err_send_reject; + } + break; + + case GSM0480_MTYPE_FACILITY: + //Only MS-originated Menu session is supported, so we ignore INVOKE here + if (ss.component_type != GSM0480_CTYPE_RETURN_RESULT && + ss.component_type != GSM0480_CTYPE_RETURN_ERROR && + ss.component_type != GSM0480_CTYPE_REJECT) { + LOGP(DLCTRL, LOGL_ERROR, "Non-{RESULT/RETURN_ERROR/REJECT} component type in FACILITY: 0x%02x\n", ss.component_type); + goto err_send_reject; + } + // ///////////////////////////////////////////////// + // TODO handle RETURN_ERROR/REJECT + if (ss.component_type != GSM0480_CTYPE_RETURN_RESULT) { + LOGP(DLCTRL, LOGL_ERROR, "Component type in FACILITY: 0x%02x is not implemented yet\n", ss.component_type); + goto err_send_reject; + } + if (ss.opcode != GSM0480_OP_CODE_USS_REQUEST) { + LOGP(DLCTRL, LOGL_ERROR, "Don't know hot to handle this SS opcode: 0x%02x\n", ss.opcode); + goto err_send_reject; + } + op = operation_find_by_tid(ctx, ref); + if (op == NULL) { + LOGP(DLCTRL, LOGL_ERROR, "No active session with tid=%d were found\n", + ss.invoke_id); + goto err_send_reject; + } + + // TODO check result!! MO/MT error handling + rc = ussd_session_facility(op, &ss, extention); + if (rc < 0) { + operation_destroy(op); + goto err_send_reject; + } + break; + + case GSM0480_MTYPE_RELEASE_COMPLETE: + op = operation_find_by_tid(ctx, ref); + if (op == NULL) { + LOGP(DLCTRL, LOGL_ERROR, "No active session with tid=%d were found for RELEASE_COMPLETE\n", + ss.invoke_id); + return 0; + } + + nua_bye(op->handle, TAG_END()); + break; + + default: + LOGP(DLCTRL, LOGL_ERROR, "Unknown message type 0x%02x\n", ss.message_type); + goto err_send_reject; + } + + return 0; + +err_send_reject: + ussd_send_reject(sup_conn, ref, ss.invoke_id, ss.opcode); + return -1; +} + +int ussd_send_reject(isup_connection_t *conn, uint32_t ref, uint8_t invoke_id, uint8_t opcode) +{ + struct ss_request error_ss; + + memset(&error_ss, 0, sizeof(error_ss)); + error_ss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE; + error_ss.component_type = GSM0480_CTYPE_REJECT; + error_ss.invoke_id = invoke_id; + error_ss.opcode = opcode; + + return ussd_send_data_ss(conn, &error_ss, ref); +} + +int ussd_send_data_ss(isup_connection_t *conn, struct ss_request* reply, uint32_t ref) +{ + struct msgb *outmsg = msgb_alloc_headroom(4000, 64, __func__); + subscr_uss_message(outmsg, + reply, + NULL, + ref); + + LOGP(DLCTRL, LOGL_ERROR, + "Sending USS, will send: %s\n", msgb_hexdump(outmsg)); + + return sup_server_send(conn, outmsg); +} + +int ussd_send_data(operation_t *op, int last, const char* lang, unsigned lang_len, + const char* msg, unsigned msg_len) +{ + struct ss_request ss; + memset(&ss, 0, sizeof(ss)); + + // TODO handle language + if (msg == NULL) { + ss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE; + ss.component_type = GSM0480_CTYPE_REJECT; + ss.opcode = op->ussd.rigester_msg.opcode; + } else if (last) { + ss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE; + ss.component_type = GSM0480_CTYPE_RETURN_RESULT; + ss.opcode = op->ussd.rigester_msg.opcode; + } else { + ss.message_type = GSM0480_MTYPE_FACILITY; + ss.component_type = (op->ussd.ms_originated) ? GSM0480_CTYPE_INVOKE + : GSM0480_CTYPE_RETURN_RESULT; + ss.opcode = GSM0480_OP_CODE_USS_REQUEST; + } + + ss.invoke_id = op->ussd.rigester_msg.invoke_id; + + if (msg) { + char tmpbuf[MAX_LEN_USSD_STRING + 1]; + + char* inbuf = (char*)msg; + size_t inleft = msg_len; + char* outbuf = (char*)tmpbuf; + size_t outleft = sizeof(tmpbuf); + size_t s; + + // First of all try latin1 + s = iconv(op->ctx->utf8_to_latin1, + &inbuf, &inleft, + &outbuf, &outleft); + if (s == (size_t)-1) { + outbuf = (char*)ss.ussd_text; + outleft = MAX_LEN_USSD_STRING; + + s = iconv(op->ctx->utf8_to_ucs2, + &inbuf, &inleft, + &outbuf, &outleft); + if (s == (size_t)-1) { + perror("can't convert string from utf8"); + } + // UCS-2 encoding + ss.ussd_text_language = 0x48; + ss.ussd_text_len = (uint8_t*)outbuf - ss.ussd_text; + + } else { + int outlen; + + // Set null-termination + outbuf[0] = 0; + gsm_7bit_encode_n_ussd(ss.ussd_text, + MAX_LEN_USSD_STRING, outbuf, &outlen); + ss.ussd_text_len = outlen; + ss.ussd_text_language = 0x0f; + } + } else { + ss.ussd_text_len = 0; + ss.ussd_text_language = 0x0f; + ss.ussd_text[0] = 0; + } + + return ussd_send_data_ss(op->ussd.conn, &ss, op->ussd.ref); +} + +static void timer_function(su_root_magic_t *magic, + su_timer_t *t, + su_timer_arg_t *arg) +{ + context_t *cli = (context_t*)arg; + su_time_t n = su_now(); + + operation_t *op, *tmp; + llist_for_each_entry_safe(op, tmp, &cli->operation_list, list) { + su_duration_t lasts = su_duration(n, op->tm_initiated); + if (lasts > cli->max_ussd_ses_duration) { + fprintf(stderr, "!!! session %.*s from %s lasted %ld ms, more than thresold %ld ms, destroying\n", + op->ussd.rigester_msg.ussd_text_len, + op->ussd.rigester_msg.ussd_text, + op->ussd.extention, + lasts, + cli->max_ussd_ses_duration); + + + ussd_send_reject(op->ussd.conn, + op->ussd.ref, + op->ussd.rigester_msg.invoke_id, + op->ussd.rigester_msg.opcode); + operation_destroy(op); + } + } +} + +static int isup_handle_connection(context_t *cli, su_wait_t *w, void *p) +{ + int rc; + isup_connection_t *conn = (isup_connection_t*)p; + + int events = su_wait_events(w, conn->isup_conn_socket); + printf("*** connection; event=0x%x\n", events); + + if (events & (SU_WAIT_ERR | SU_WAIT_HUP)) { + printf("*** connection destroyed\n"); + goto err; + } else if (events & SU_WAIT_IN) { + /* Incoming data */ + + struct ipaccess_head *iph; + struct msgb *msg = NULL; + int ret = ipa_msg_recv_buffered(conn->isup_conn_socket, &msg, &conn->pending_msg); + if (ret <= 0) { + if (ret == -EAGAIN) + return 0; + if (ret == 0) + LOGP(DLCTRL, LOGL_INFO, "The control connection was closed\n"); + else + LOGP(DLCTRL, LOGL_ERROR, "Failed to parse ip access message: %d\n", ret); + + goto err; + } + + iph = (struct ipaccess_head *) msg->data; + switch (iph->proto) + { + case IPAC_PROTO_IPACCESS: + if (msg->l2h[0] == IPAC_MSGT_PING) { + printf("*** got PING\n"); + msg->l2h[0] = IPAC_MSGT_PONG; + send(conn->isup_conn_socket, msg->data, ntohs(iph->len) + sizeof(struct ipaccess_head), 0); + msgb_free(msg); + conn->pending_msg = NULL; + return 0; + } + + LOGP(DLCTRL, LOGL_ERROR, "Unknown IPAC_PROTO_IPACCESS msg 0x%x\n", msg->l2h[0]); + goto err; + case IPAC_PROTO_OSMO: + // TODO callback + if (msg->l2h[1] == GPRS_GSUP_MSGT_USSD_MAP) { + LOGP(DLCTRL, LOGL_ERROR, + "Receive USS: %s\n", msgb_hexdump(msg)); + + rc = rx_sup_uss_message(conn, &msg->l2h[1], msgb_l2len(msg) - 1); + if (rc < 0) { + /* TODO raise reject !!!!!!! */ + /* release complete */ + } + + msgb_free(msg); + conn->pending_msg = NULL; + return 0; + } + + /* TODO: handle gprs_gsup_decode() for other types */ + + LOGP(DLCTRL, LOGL_ERROR, "Unknown IPAC_PROTO_OSMO GPRS_GSUP_MSGT_* 0x%x\n", msg->l2h[1]); + msgb_free(msg); + conn->pending_msg = NULL; + goto err; + default: + LOGP(DLCTRL, LOGL_ERROR, "Protocol mismatch. We got 0x%x\n", iph->proto); + goto err; + } + } + + return 0; + +err: + close(conn->isup_conn_socket); + conn->isup_conn_socket = INVALID_SOCKET; + + su_wait_destroy(w); + + msgb_free(conn->pending_msg); + conn->pending_msg = NULL; + //su_root_deregister(cli, cli->isup_register_idx); + return 0; +} + +static int isup_handle_accept(context_t *cli, su_wait_t *w, void *p) +{ + su_sockaddr_t aaddr; + su_socket_t connection; + socklen_t len = sizeof(aaddr); + int rc; + + connection = accept(cli->isup_acc_socket, &aaddr.su_sa, &len); + if (connection == INVALID_SOCKET) { + perror("can't accept isup socket"); + return 0; + } + + printf("*** accepted from %s:%d\n", + inet_ntoa(aaddr.su_sin.sin_addr), + ntohs(aaddr.su_sin.sin_port)); + + /* TODO manage isup connection list, but just now use the single connection */ + isup_connection_t *conn = cli->isup; + if (conn->isup_conn_socket != INVALID_SOCKET) { + fprintf(stderr, "--- Can't accept, there's another connection\n"); + su_close(connection); + return 0; + } + + conn->ctx = cli; + conn->isup_conn_socket = connection; + conn->pending_msg = NULL; + + su_wait_init(&conn->isup_conn_event); + rc = su_wait_create(&conn->isup_conn_event, + conn->isup_conn_socket, + SU_WAIT_IN | /*SU_WAIT_OUT | */ SU_WAIT_HUP | SU_WAIT_ERR); + + conn->isup_register_idx = su_root_register(cli->root, + &conn->isup_conn_event, + isup_handle_connection, + conn, + 0); + return 0; +} + +#define DIPA_USSD_PROXY 0 + +struct log_info_cat ipa_proxy_test_cat[] = { + [DIPA_USSD_PROXY] = { + .name = "DIPA_USSD_PROXY", + .description = "USSD_PROXY", + .color = "\033[1;35m", + .enabled = 1, + .loglevel = LOGL_DEBUG, + }, +}; + +const struct log_info ipa_proxy_test_log_info = { + .filter_fn = NULL, + .cat = ipa_proxy_test_cat, + .num_cat = ARRAY_SIZE(ipa_proxy_test_cat), +}; + + +static void Usage(char* progname) +{ + fprintf(stderr, "Usage:\n" + "%s [options]\n" + "Options\n" + " -p TCP port to listen incoming SUP connection\n" + " (default: 8184)\n" + " -t Destination SIP URL (default: sip:127.0.0.1:5060)\n" + " -u User agent SIP URL (default: sip:127.0.0.1:5090)\n" + " -x Proxy SIP URL (default: )\n" + " -T Force using TCP instead trying UDP\n" + " -D Maximum period of open USSD session (default: 90)\n" + " -o Maximum number of concurrent USSD sessions\n" + " (default: 200)\n" + " -l <0-9> sip sofia loglevel, 0 - none; 9 - max\n" + , progname); +} + +int main(int argc, char *argv[]) +{ + su_home_t *home; + context_t context[1] = {{{SU_HOME_INIT(context)}}}; + su_sockaddr_t listen_addr; + int rc; + int sup_port = 8184; + const char* to_str = "sip:127.0.0.1:5060"; + const char* url_str = "sip:127.0.0.1:5090"; + const char* proxy_str = NULL; + int force_tcp = 0; + int max_ussd_ses_secs = 90; + int max_op_limit = 200; + int sip_loglevel = 1; + int c; + + while ((c = getopt (argc, argv, "x:p:t:u:D:To:l:L7?")) != -1) { + switch (c) + { + case 'x': + proxy_str = optarg; + break; + case 'p': + sup_port = atoi(optarg); + break; + case 't': + to_str = optarg; + break; + case 'u': + url_str = optarg; + break; + case 'T': + force_tcp = 1; + break; + case 'D': + max_ussd_ses_secs = atoi(optarg); + break; + case 'o': + max_op_limit = atoi(optarg); + break; + case 'l': + sip_loglevel = atoi(optarg); + break; + case 'L': + fprintf(stderr, " -L is now obsolete, ignored\n"); + break; + case '7': + fprintf(stderr, " -7 is now obsolete, ignored\n"); + break; + case '?': + default: + Usage(argv[0]); + return 2; + } + } + + osmo_init_logging(&ipa_proxy_test_log_info); + + su_init(); + su_home_init(home = context->home); + + context->root = su_root_create(context); + + su_log_set_level(NULL, sip_loglevel); + + /* Disable threading */ + su_root_threading(context->root, 0); + + if (!context->root) { + fprintf(stderr, "Unable to initialize sip-sofia context\n"); + return 1; + } + + context->utf8_to_latin1=iconv_open("iso8859-1", "utf-8"); + context->latin1_to_utf8=iconv_open("utf-8", "iso8859-1"); + context->utf8_to_ucs2=iconv_open("utf-16be", "utf-8"); + context->ucs2_to_utf8=iconv_open("utf-8", "utf-16be"); + + if (context->utf8_to_ucs2 == NULL || context->ucs2_to_utf8 == NULL || + context->utf8_to_latin1 == NULL || context->latin1_to_utf8 == NULL) { + fprintf(stderr, "Unable to initialize iconv\n"); + return 1; + } + + context->isup_acc_socket = su_socket(AF_INET, SOCK_STREAM, 0); + if (context->isup_acc_socket == INVALID_SOCKET) { + perror("unable to create socket\n"); + return 1; + } + su_setblocking(context->isup_acc_socket, 0); + su_setreuseaddr(context->isup_acc_socket, 1); + + context->isup->isup_conn_socket = INVALID_SOCKET; + + memset(&listen_addr, 0, sizeof(listen_addr)); + listen_addr.su_sin.sin_family = AF_INET; + listen_addr.su_sin.sin_addr.s_addr = INADDR_ANY; + listen_addr.su_sin.sin_port = htons(sup_port); + + rc = bind(context->isup_acc_socket, &listen_addr.su_sa, sizeof(listen_addr.su_sin)); + if (rc < 0) { + perror("cannot bind socket\n"); + return 2; + } + + rc = listen(context->isup_acc_socket, 1); + if (rc < 0) { + perror("cannot bind socket\n"); + return 2; + } + + su_wait_init(&context->isup_acc_event); + su_wait_create(&context->isup_acc_event, context->isup_acc_socket, SU_WAIT_ACCEPT); + su_root_register(context->root, + &context->isup_acc_event, + isup_handle_accept, + NULL, + 0); + + context->to_url = url_make(home, to_str); + context->self_url = url_make(home, url_str); + + if (context->to_url == NULL) { + fprintf(stderr, "Unable to parse destination URL\n"); + return 1; + } + if (context->self_url == NULL) { + fprintf(stderr, "Unable to parse our (source) URL\n"); + return 1; + } + + context->nua = nua_create(context->root, + context_callback, + context, + NUTAG_URL(url_str), + NUTAG_ENABLEINVITE(1), + NUTAG_AUTOALERT(1), + NUTAG_SESSION_TIMER(0), + NUTAG_AUTOANSWER(0), + NUTAG_MEDIA_ENABLE(0), + NUTAG_ALLOW("INVITE, ACK, BYE, CANCEL, INFO"), + TAG_NULL()); + if (context->nua == NULL) { + fprintf(stderr, "Unable to initialize sip-sofia nua\n"); + return 1; + } + + + if (proxy_str) { + nua_set_params(context->nua, + NUTAG_PROXY(proxy_str), + TAG_NULL()); + } + + if (force_tcp) { + nua_set_params(context->nua, + NTATAG_UDP_MTU(10), + TAG_NULL()); + } + + INIT_LLIST_HEAD(&context->operation_list); + context->operation_count = 0; + context->operations_max = max_op_limit; + + su_timer_t* tm = su_timer_create(su_root_task(context->root), 2000); + if (tm == NULL) { + fprintf(stderr, "Unable to initialize sip-sofia timer\n"); + return 1; + } + rc = su_timer_run(tm, timer_function, context); + if (rc < 0) { + fprintf(stderr, "Unable to start sip-sofia timer\n"); + return 1; + } + context->timer = tm; + context->max_ussd_ses_duration = max_ussd_ses_secs * 1000l; + + su_root_run(context->root); + nua_destroy(context->nua); + + return 0; +} + -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:58 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:58 +0300 Subject: [PATCH 7/8] ussd_proxy: Add to openbsc build system In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448449439-10546-7-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev --- openbsc/configure.ac | 12 ++++++++++++ openbsc/src/Makefile.am | 2 +- openbsc/src/ussd-proxy/Makefile.am | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fc30b5e..5489133 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -172,6 +172,17 @@ AC_MSG_CHECKING([whether to enable VTY/CTRL tests]) AC_MSG_RESULT([$enable_ext_tests]) AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes") +# Enable/disable ussd_proxy utility +AC_ARG_ENABLE([ussd_proxy], [AS_HELP_STRING([--enable-ussd-proxy], [Build the USSD MAP SUP to SIP proxy])], + [osmo_ac_build_ussd_proxy="$enableval"],[osmo_ac_build_ussd_proxy="no"]) +if test "$osmo_ac_build_ussd_proxy" = "yes" ; then + PKG_CHECK_MODULES(LIBSOFIA_SIP_UA, sofia-sip-ua >= 1.10) + AC_DEFINE(BUILD_USSD_PROXY, 1, [Define if we want to build ussd_proxy]) +fi +AM_CONDITIONAL(BUILD_USSD_PROXY, test "x$osmo_ac_build_ussd_proxy" = "xyes") +AC_SUBST(osmo_ac_build_smpp) + + dnl Generate the output AM_CONFIG_HEADER(bscconfig.h) @@ -193,6 +204,7 @@ AC_OUTPUT( src/ipaccess/Makefile src/utils/Makefile src/gprs/Makefile + src/ussd-proxy/Makefile tests/Makefile tests/atlocal tests/gsm0408/Makefile diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6f6174e..f12ed54 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,7 +2,7 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) -SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs +SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs ussd-proxy # Conditional modules if BUILD_NAT diff --git a/openbsc/src/ussd-proxy/Makefile.am b/openbsc/src/ussd-proxy/Makefile.am index dfb4fc6..68f3a88 100644 --- a/openbsc/src/ussd-proxy/Makefile.am +++ b/openbsc/src/ussd-proxy/Makefile.am @@ -1,3 +1,4 @@ +if BUILD_USSD_PROXY AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(COVERAGE_CFLAGS) \ $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ @@ -15,3 +16,4 @@ ussd_proxy_LDADD = \ -lsofia-sip-ua \ $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) \ $(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS) +endif \ No newline at end of file -- 1.9.1 From sergey.kostanbaev at gmail.com Wed Nov 25 11:03:59 2015 From: sergey.kostanbaev at gmail.com (Sergey.Kostanbaev) Date: Wed, 25 Nov 2015 14:03:59 +0300 Subject: [PATCH 8/8] libmsc: add gprs files for sup In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <1448449439-10546-8-git-send-email-Sergey.Kostanbaev@moex.com> From: Sergey Kostanbaev USSD SUP based socket depends on gprs SUP files --- openbsc/src/libmsc/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 616ed89..ce3f6a4 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -10,6 +10,9 @@ libmsc_a_SOURCES = auth.c \ db.c \ gsm_04_08.c gsm_04_11.c gsm_04_11_helper.c \ gsm_04_80.c \ + ../gprs/gsm_04_08_gprs.c \ + ../gprs/gprs_utils.c \ + ../gprs/gprs_gsup_messages.c ../gprs/gprs_gsup_client.c \ gsm_subscriber.c \ mncc.c mncc_builtin.c mncc_sock.c \ rrlp.c \ -- 1.9.1 From holger at freyther.de Wed Nov 25 12:22:27 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 13:22:27 +0100 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> Message-ID: <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> > On 25 Nov 2015, at 12:03, Sergey.Kostanbaev wrote: > > From: Sergey Kostanbaev > > This series of patches add support for external USSD processing via > simplified MAP-like protocol over SUP socket. As an example of a such > external application simple USSD to SIP proxy is provided (it targets > TS 124 390) Have you considered using SMPP for USSD? At first this looks more natural than a custom protocol like SUP. holger From holger at freyther.de Wed Nov 25 12:31:29 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 13:31:29 +0100 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> Message-ID: <593F7124-8B57-416B-A920-BD91213C2905@freyther.de> > On 25 Nov 2015, at 13:22, Holger Freyther wrote: > > > > Have you considered using SMPP for USSD? At first this looks more natural > than a custom protocol like SUP. The other part I notice when going through the patches are the following: * Fixes, features without a unit test is very difficult to sell * SUP has a protocol description. If the protocol is changed the description should be updated. * If gprs sup client is used in non GPRS context we either split the protocol up or at least rename and move these files around. If you have questions of any of the above points I am happy to answer them. holger From sergey.kostanbaev at gmail.com Wed Nov 25 13:04:25 2015 From: sergey.kostanbaev at gmail.com (sergey kostanbaev) Date: Wed, 25 Nov 2015 16:04:25 +0300 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: <593F7124-8B57-416B-A920-BD91213C2905@freyther.de> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> <593F7124-8B57-416B-A920-BD91213C2905@freyther.de> Message-ID: On Wed, Nov 25, 2015 at 3:31 PM, Holger Freyther wrote: > > > On 25 Nov 2015, at 13:22, Holger Freyther wrote: > > > > > > > > Have you considered using SMPP for USSD? At first this looks more natural > > than a custom protocol like SUP. > > > The other part I notice when going through the patches are the following: > > * Fixes, features without a unit test is very difficult to sell > I agree that having a unit test is a good sign. But I'm not really familiar with the project rules. I can make unit tests for packet parsing/composing (SS and MAP-like level). But I have no idea how to make a unit test for e.g. USSD transaction based on gsm_trans or more complex things. I'd be glad to hear your thoughts. > * SUP has a protocol description. If the protocol is changed the > description should > be updated. > I think I don't get this. Which protocol description are you talking about? * If gprs sup client is used in non GPRS context we either split the > protocol up or > at least rename and move these files around. > I intentionally left this part as is to get a feedback how it's possible solve. So you suggest to separate abstract socket operations away from GPRS, right? > > If you have questions of any of the above points I am happy to answer them. > > holger -------------- next part -------------- An HTML attachment was scrubbed... URL: From sergey.kostanbaev at gmail.com Wed Nov 25 13:07:18 2015 From: sergey.kostanbaev at gmail.com (sergey kostanbaev) Date: Wed, 25 Nov 2015 16:07:18 +0300 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> Message-ID: Yes, initially I thought about using SMPP for USSD. But it looked really complicated since only few external SMPP libraries have support of USSD and most of that few are in C#/Java/etc. Moreover I didn't have any working software for USSD over SMPP to test interoperability with. So I decided to use GPRS SUP socket as a simple transport to send MAP-like messages. Workflow of this SUP is very simple and basically it forwards SS messages with little modifications. On Wed, Nov 25, 2015 at 3:22 PM, Holger Freyther wrote: > > > On 25 Nov 2015, at 12:03, Sergey.Kostanbaev > wrote: > > > > From: Sergey Kostanbaev > > > > This series of patches add support for external USSD processing via > > simplified MAP-like protocol over SUP socket. As an example of a such > > external application simple USSD to SIP proxy is provided (it targets > > TS 124 390) > > Have you considered using SMPP for USSD? At first this looks more natural > than a custom protocol like SUP. > > holger -------------- next part -------------- An HTML attachment was scrubbed... URL: From holger at freyther.de Wed Nov 25 13:12:33 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 14:12:33 +0100 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> Message-ID: > On 25 Nov 2015, at 14:07, sergey kostanbaev wrote: > > Yes, initially I thought about using SMPP for USSD. But it looked really complicated since only few external SMPP libraries have support of USSD and most of that few are in C#/Java/etc. Moreover I didn't have any working software for USSD over SMPP to test interoperability with. Hmm. We try to follow standard protocol when they exist. E.g. with "GSUP" the decision was that we have a good SS7 MAP stack (with high amount of tests and Q.787 conformance) and doing that in C at the time didn't look like an economic choice. Do you remember how USSD is mapped to SMPP? > So I decided to use GPRS SUP socket as a simple transport to send MAP-like messages. Workflow of this SUP is very simple and basically it forwards SS messages with little modifications. But why GPRS SUP then? E.g. it would be enough for you to use OAP (that just adds a very simple way for authentication)? Which of the existing GSUP messages do you use? holger From sergey.kostanbaev at gmail.com Wed Nov 25 13:37:05 2015 From: sergey.kostanbaev at gmail.com (sergey kostanbaev) Date: Wed, 25 Nov 2015 16:37:05 +0300 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> Message-ID: On Wed, Nov 25, 2015 at 4:12 PM, Holger Freyther wrote: > > > On 25 Nov 2015, at 14:07, sergey kostanbaev > wrote: > > > > Yes, initially I thought about using SMPP for USSD. But it looked really > complicated since only few external SMPP libraries have support of USSD and > most of that few are in C#/Java/etc. Moreover I didn't have any working > software for USSD over SMPP to test interoperability with. > > Hmm. We try to follow standard protocol when they exist. E.g. with "GSUP" > the decision was > that we have a good SS7 MAP stack (with high amount of tests and Q.787 > conformance) and > doing that in C at the time didn't look like an economic choice. > > Do you remember how USSD is mapped to SMPP? > > Yeah I have a description but wasn't able to test it in a real environment. I need to dig in my archives. I'll let you know. > > > > So I decided to use GPRS SUP socket as a simple transport to send > MAP-like messages. Workflow of this SUP is very simple and basically it > forwards SS messages with little modifications. > > But why GPRS SUP then? E.g. it would be enough for you to use OAP (that > just adds a very > simple way for authentication)? Which of the existing GSUP messages do > you use? > > Well may be I wrongly used GPRS SUP as a description. I used none of GPRS SUP messages. I used the ability to send messages over "TCP" (TCP + header) socket. Such code of a socket was in GSUP. I added GPRS_GSUP_MSGT_USSD_MAP constant to not pollute and distinguish that messages. It can b done on a raw socket, but I just reused GSUP socket wrapper. May be this was confusing. > holger -------------- next part -------------- An HTML attachment was scrubbed... URL: From holger at freyther.de Wed Nov 25 14:20:16 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 15:20:16 +0100 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> Message-ID: <9F7EB648-8E99-47EF-BA9E-323C0550D7D8@freyther.de> > On 25 Nov 2015, at 14:37, sergey kostanbaev wrote: > > > > Yeah I have a description but wasn't able to test it in a real environment. I need to dig in my archives. I'll let you know. That would be appreciated and help us making the decision if we want to go with SMPP or a custom protocol. When there were customer requests at sysmocom we had always quoted SMPP work. I know it is unfortunate that you have made the SMPP vs. custom protocol question and spent a lot of work on making it work but for us it is important to know the reasons, e.g. what would client support require for libsmpp34, is there no client support because the protocol is too bad or that not much special needs to be handled. > > So I decided to use GPRS SUP socket as a simple transport to send MAP-like messages. Workflow of this SUP is very simple and basically it forwards SS messages with little modifications. In the long run we should move the re-connect handling into libosmo-abis then. kind regards and thank you for your contribution holger From nhofmeyr at sysmocom.de Wed Nov 25 14:58:34 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 25 Nov 2015 15:58:34 +0100 Subject: [PATCH 1/6] msgb: Add msgb_resize_area and msgb_copy In-Reply-To: <56542290.8070303@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <20151119143431.GD7092@dub5> <56542290.8070303@sysmocom.de> Message-ID: <20151125145834.GA1398@dub5> On Tue, Nov 24, 2015 at 09:40:48AM +0100, Jacob Erlbeck wrote: > On 19.11.2015 15:34, Neels Hofmeyr wrote: > > +/*! \brief Copy an msgb. > > > > I'd write just "a" here, not "an". I seem to be the English nitpicker > > among us ;) > > I do not agree in this case. "msgb" is read em-es-... thus starting with Ah ok, I see your point. I tend to read "message-bee", starting with a consonant, so I'd have written "a". Keep the "an", then :) > > +int msgb_resize_area(struct msgb *msg, uint8_t *area, > > + size_t old_size, size_t new_size) > > +{ > > + int rc; > > + uint8_t *rest = area + old_size; > > + int rest_len = msg->len - old_size - (area - msg->data); > > + int delta_size = (int)new_size - (int)old_size; > > + > > + if (area < msg->data || rest > msg->tail) > > + MSGB_ABORT(msg, "Sub area is not fully contained in the msg data\n"); > > > check for rest < area in addition. Sounds good. Actually, msgb's len fields are typed as uint16_t, so I think old_size and new_size should be uint16_t arguments...? And then, I think these are also necessary: - assert rest_len >= 0, which ensures a valid old_size, i.e. short for old_size <= (msg->len - (area - msg->data)). - assert new_size <= (0xffff - (area - msg->data)) (so that the resulting len is within uint16_t). It's quite time consuming to figure this out in theory, so maybe we can just merge this and have a "break msgb contest", rewarding an Osmocom mug for every msgb API test case that allows arbitrary memory access ;) ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From sipos.csaba at kvk.uni-obuda.hu Wed Nov 25 18:37:49 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Wed, 25 Nov 2015 19:37:49 +0100 (CET) Subject: Meas_web and meas_json In-Reply-To: References: <1510240027.5443523.1445891932058.JavaMail.zimbra@kvk.uni-obuda.hu> <1010582984.5443937.1445892326559.JavaMail.zimbra@kvk.uni-obuda.hu> <213728024.5449223.1445896264483.JavaMail.zimbra@kvk.uni-obuda.hu> <687363025.6773365.1446628686520.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <1503579201.10420115.1448476669036.JavaMail.zimbra@kvk.uni-obuda.hu> Hi Alexander, You just need to wait a little while for the Readme fix :-) Thx for the patch, tomorrow will recompile and see if it fixes it (probably will). The crash happens in Firefox on Ubuntu 64bit. Will try Chrome to test it. For you to know, I just finished putting OpenBSC with two Nokia 2G site family basestations to work as a lab exercise at our University :-) And meas_feed is important for visualizing what happens in various signal conditions, besides spectrum and vector signal analysis ofcorse :-) Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Alexander Chemeris" C?mzett: "Sipos Csaba" M?solatot kap: "OpenBSC Mailing List" Elk?ld?tt ?zenetek: Kedd, 2015. November 24. 2:09:20 T?rgy: Re: Meas_web and meas_json Hi Csaba, On Wed, Nov 4, 2015 at 12:18 PM, Sipos Csaba wrote: > I am playing with the meas_web utility, and I finally have the missing informations for the README to make the installation process more complete, will sending a new copy for you soon. Looking forward to it! > 1. I noticed that the "Type" and "Channel" parameters are not shown on the web interface, but if I run "show lchan" in the BSC console, I got the correct results for both parameters. I checked the temporary files which stores the meas_feed data, and it seems these data parts are not even there, and this is the reason the web interface is not displaying them. This information has been added in the v1 version of the meas_feed stream. It should be available in the master after this commit: 08c508f84a8d088f8454d0f21f83ecc22e30d72d msc: Add channel information to the meas_feed, bump version to v1. > 2. Is there a way to set a time after the inactive old subscribers are deleted from the web interface? On my end the subscribers are just keep coming (a lot of rejected LOC updates) and when they reach the "maximum item number" count the web interface just crashes. Would be lovely to have a timeout value next to the "max item number" to set the amount of time of which the inactive subscribers would disappear from the web interface. And the web interface should not crash even if there is more transactions than the maximum item number :-) Crash is clearly a bug here. I've been testing with Chrome on Ubuntu x64 and have never seen it crashing. Which browser / OS do you use? Do you think you could spot the reason for the crash? -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From holger at freyther.de Wed Nov 25 19:53:45 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 20:53:45 +0100 Subject: [PATCH 2/3] gtphub: fix number map range for TEIs. In-Reply-To: <1447767527-27316-2-git-send-email-nhofmeyr@sysmocom.de> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-2-git-send-email-nhofmeyr@sysmocom.de> Message-ID: > On 17 Nov 2015, at 14:38, Neels Hofmeyr wrote: > > Use unsigned int for nr_map, just large enough to fit the TEI space. > Adjust log output formats and casts accordingly. > > Fixes: TEIs are uint32_t, but the nr_map so far used int. This would cause TEIs > from 0x80000000 on to be handled and printed as a negative value. good! > -typedef int nr_t; > +typedef unsigned int nr_t; use uint32_t here then? and "nr_t" is that clear it refers to a tei? > + (unsigned int)nrm->orig, (unsigned int)nrm->repl); What is the explicit casting about? holger From holger at freyther.de Wed Nov 25 20:05:40 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 21:05:40 +0100 Subject: [PATCH 3/3] gtphub: nr_map: add min,max and wrap. In-Reply-To: <1447767527-27316-3-git-send-email-nhofmeyr@sysmocom.de> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-3-git-send-email-nhofmeyr@sysmocom.de> Message-ID: > On 17 Nov 2015, at 14:38, Neels Hofmeyr wrote: > > > + /* The TEI numbers will simply wrap and be reused, which will work out > + * in practice. Problems would arise if one given peer maintained the > + * same TEI for a time long enough for the TEI nr map to wrap an entire > + * uint32_t; if a new TEI were mapped every second, this would take > + * more than 100 years (in which a single given TEI must not time out) > + * to cause a problem. */ Unless performance matters I am not for probalistic correct, specially not in the beginning of a new piece of software. "Modern" smartphones will open a PDP context very early and they live for a potentially long time (until you reboot your phone or such). So I would prefer to check if a TEI is used (at least the number should be random) before using it. So even if the assignment is not random right now I would still prefer the check if it is assigned or not. E.g. a unit test that exhausts the entire number space should be feasible. holger From holger at freyther.de Wed Nov 25 20:08:26 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 21:08:26 +0100 Subject: [PATCH 1/3] mncc: Implement helper functions to convert MNCC cause to a string. In-Reply-To: References: Message-ID: > On 24 Nov 2015, at 02:01, Alexander Chemeris wrote: Dear Alexander, > bump > > It doesn't seem there are any comments on this set of patches. Is it ok to merge them? the reason is simple and stupid at the same time. I look for pending patches in patchwork and patchwork does not find/see patches that are attachments to mail. If you could, please re-send them inline or try to use git send-email. kind regards holger From alexander.chemeris at gmail.com Wed Nov 25 20:12:37 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Wed, 25 Nov 2015 23:12:37 +0300 Subject: Meas_web and meas_json In-Reply-To: <1503579201.10420115.1448476669036.JavaMail.zimbra@kvk.uni-obuda.hu> References: <1510240027.5443523.1445891932058.JavaMail.zimbra@kvk.uni-obuda.hu> <1010582984.5443937.1445892326559.JavaMail.zimbra@kvk.uni-obuda.hu> <213728024.5449223.1445896264483.JavaMail.zimbra@kvk.uni-obuda.hu> <687363025.6773365.1446628686520.JavaMail.zimbra@kvk.uni-obuda.hu> <1503579201.10420115.1448476669036.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: Hi Csaba, On Wed, Nov 25, 2015 at 9:37 PM, Sipos Csaba wrote: > You just need to wait a little while for the Readme fix :-) I just hope it doesn't get lost :) > Thx for the patch, tomorrow will recompile and see if it fixes it (probably will). > > The crash happens in Firefox on Ubuntu 64bit. Will try Chrome to test it. I tried it under FF on Ubuntu 64bit and it doesn't crash here. Could you provide some backtrace for the crash? > For you to know, I just finished putting OpenBSC with two Nokia 2G site family basestations to work as a lab exercise at our University :-) > > And meas_feed is important for visualizing what happens in various signal conditions, besides spectrum and vector signal analysis ofcorse :-) Good visualization is always helpful for learning. May be your students could write some more visualization tools for OpenBSC? There is a lot to see in there. -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From alexander.chemeris at gmail.com Wed Nov 25 20:14:12 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Wed, 25 Nov 2015 23:14:12 +0300 Subject: [PATCH 1/3] mncc: Implement helper functions to convert MNCC cause to a string. In-Reply-To: References: Message-ID: On Wed, Nov 25, 2015 at 11:08 PM, Holger Freyther wrote: >> On 24 Nov 2015, at 02:01, Alexander Chemeris wrote: >> bump >> >> It doesn't seem there are any comments on this set of patches. Is it ok to merge them? > > the reason is simple and stupid at the same time. I look for pending patches in patchwork and > patchwork does not find/see patches that are attachments to mail. Weird. > If you could, please re-send them inline or try to use git send-email. Let me try -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From holger at freyther.de Wed Nov 25 20:23:37 2015 From: holger at freyther.de (Holger Freyther) Date: Wed, 25 Nov 2015 21:23:37 +0100 Subject: [PATCH] gtphub: add to debian build In-Reply-To: <1448368818-21121-1-git-send-email-nhofmeyr@sysmocom.de> References: <1448368818-21121-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: > On 24 Nov 2015, at 13:40, Neels Hofmeyr wrote: Hi! > By the example of osmo-sgsn, package osmo-gtphub for debian. you walked into an issue/inconcistency I created and we should fix to move forward. > > Sponsored-by: On-Waves ehi > --- > debian/control | 14 +++ > debian/osmocom-gtphub.default | 2 + > debian/osmocom-gtphub.examples | 1 + > debian/osmocom-gtphub.init | 150 +++++++++++++++++++++++ > debian/osmocom-gtphub.install | 1 + The process is called "osmo-gtphub" so the scripts should be called the same and the config file as well. Otherwise it looks good and please push to master. > diff --git a/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg b/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg > new file mode 100644 > index 0000000..c9bb4cf > --- /dev/null > +++ b/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg good! the next change is to modify osmoappdesc.py so gtphub will get some of the "automatic" VTY testing we have. From alexander.chemeris at gmail.com Wed Nov 25 20:31:04 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Wed, 25 Nov 2015 15:31:04 -0500 Subject: [PATCH 1/3] mncc: Implement helper functions to convert MNCC cause to a string. Message-ID: <1448483466-10556-1-git-send-email-Alexander.Chemeris@gmail.com> --- openbsc/include/openbsc/mncc.h | 5 +- openbsc/src/libmsc/mncc.c | 103 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h index 46ba237..92389c2 100644 --- a/openbsc/include/openbsc/mncc.h +++ b/openbsc/include/openbsc/mncc.h @@ -191,8 +191,11 @@ struct gsm_mncc_rtp { uint32_t payload_msg_type; }; -char *get_mncc_name(int value); +const char *get_mncc_name(int value); void mncc_set_cause(struct gsm_mncc *data, int loc, int val); +int mncc_has_cause(struct gsm_mncc *data); +const char *get_mncc_location(int value); +const char *get_mncc_cause(int value); void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg); /* input from CC code into mncc_builtin */ diff --git a/openbsc/src/libmsc/mncc.c b/openbsc/src/libmsc/mncc.c index 2767faa..e8bd9ba 100644 --- a/openbsc/src/libmsc/mncc.c +++ b/openbsc/src/libmsc/mncc.c @@ -34,10 +34,12 @@ #include #include -static struct mncc_names { +struct name_value { char *name; int value; -} mncc_names[] = { +}; + +static struct name_value mncc_names[] = { {"MNCC_SETUP_REQ", 0x0101}, {"MNCC_SETUP_IND", 0x0102}, {"MNCC_SETUP_RSP", 0x0103}, @@ -95,16 +97,103 @@ static struct mncc_names { {NULL, 0} }; -char *get_mncc_name(int value) +static struct name_value mncc_locations[] = { + {"GSM48_CAUSE_LOC_USER", 0x00}, + {"GSM48_CAUSE_LOC_PRN_S_LU", 0x01}, + {"GSM48_CAUSE_LOC_PUN_S_LU", 0x02}, + {"GSM48_CAUSE_LOC_TRANS_NET", 0x03}, + {"GSM48_CAUSE_LOC_PUN_S_RU", 0x04}, + {"GSM48_CAUSE_LOC_PRN_S_RU", 0x05}, + /* not defined */ + {"GSM48_CAUSE_LOC_INN_NET", 0x07}, + {"GSM48_CAUSE_LOC_NET_BEYOND", 0x0a}, + + {NULL, 0} }; + +static struct name_value mncc_causes[] = { + {"GSM48_CC_CAUSE_UNASSIGNED_NR", 1}, + {"GSM48_CC_CAUSE_NO_ROUTE", 3}, + {"GSM48_CC_CAUSE_CHAN_UNACCEPT", 6}, + {"GSM48_CC_CAUSE_OP_DET_BARRING", 8}, + {"GSM48_CC_CAUSE_NORM_CALL_CLEAR", 16}, + {"GSM48_CC_CAUSE_USER_BUSY", 17}, + {"GSM48_CC_CAUSE_USER_NOTRESPOND", 18}, + {"GSM48_CC_CAUSE_USER_ALERTING_NA", 19}, + {"GSM48_CC_CAUSE_CALL_REJECTED", 21}, + {"GSM48_CC_CAUSE_NUMBER_CHANGED", 22}, + {"GSM48_CC_CAUSE_PRE_EMPTION", 25}, + {"GSM48_CC_CAUSE_NONSE_USER_CLR", 26}, + {"GSM48_CC_CAUSE_DEST_OOO", 27}, + {"GSM48_CC_CAUSE_INV_NR_FORMAT", 28}, + {"GSM48_CC_CAUSE_FACILITY_REJ", 29}, + {"GSM48_CC_CAUSE_RESP_STATUS_INQ", 30}, + {"GSM48_CC_CAUSE_NORMAL_UNSPEC", 31}, + {"GSM48_CC_CAUSE_NO_CIRCUIT_CHAN", 34}, + {"GSM48_CC_CAUSE_NETWORK_OOO", 38}, + {"GSM48_CC_CAUSE_TEMP_FAILURE", 41}, + {"GSM48_CC_CAUSE_SWITCH_CONG", 42}, + {"GSM48_CC_CAUSE_ACC_INF_DISCARD", 43}, + {"GSM48_CC_CAUSE_REQ_CHAN_UNAVAIL", 44}, + {"GSM48_CC_CAUSE_RESOURCE_UNAVAIL", 47}, + {"GSM48_CC_CAUSE_QOS_UNAVAIL", 49}, + {"GSM48_CC_CAUSE_REQ_FAC_NOT_SUBSC", 50}, + {"GSM48_CC_CAUSE_INC_BARRED_CUG", 55}, + {"GSM48_CC_CAUSE_BEARER_CAP_UNAUTH", 57}, + {"GSM48_CC_CAUSE_BEARER_CA_UNAVAIL", 58}, + {"GSM48_CC_CAUSE_SERV_OPT_UNAVAIL", 63}, + {"GSM48_CC_CAUSE_BEARERSERV_UNIMPL", 65}, + {"GSM48_CC_CAUSE_ACM_GE_ACM_MAX", 68}, + {"GSM48_CC_CAUSE_REQ_FAC_NOTIMPL", 69}, + {"GSM48_CC_CAUSE_RESTR_BCAP_AVAIL", 70}, + {"GSM48_CC_CAUSE_SERV_OPT_UNIMPL", 79}, + {"GSM48_CC_CAUSE_INVAL_TRANS_ID", 81}, + {"GSM48_CC_CAUSE_USER_NOT_IN_CUG", 87}, + {"GSM48_CC_CAUSE_INCOMPAT_DEST", 88}, + {"GSM48_CC_CAUSE_INVAL_TRANS_NET", 91}, + {"GSM48_CC_CAUSE_SEMANTIC_INCORR", 95}, + {"GSM48_CC_CAUSE_INVAL_MAND_INF", 96}, + {"GSM48_CC_CAUSE_MSGTYPE_NOTEXIST", 97}, + {"GSM48_CC_CAUSE_MSGTYPE_INCOMPAT", 98}, + {"GSM48_CC_CAUSE_IE_NOTEXIST", 99}, + {"GSM48_CC_CAUSE_COND_IE_ERR", 100}, + {"GSM48_CC_CAUSE_MSG_INCOMP_STATE", 101}, + {"GSM48_CC_CAUSE_RECOVERY_TIMER", 102}, + {"GSM48_CC_CAUSE_PROTO_ERR", 111}, + {"GSM48_CC_CAUSE_INTERWORKING", 127}, + + {NULL, 0} }; + +const char *get_name_by_value(struct name_value *pairs, int value, const char *default_val) { int i; - for (i = 0; mncc_names[i].name; i++) { - if (mncc_names[i].value == value) - return mncc_names[i].name; + for (i = 0; pairs[i].name; i++) { + if (pairs[i].value == value) + return pairs[i].name; } - return "MNCC_Unknown"; + return default_val; +} + + +const char *get_mncc_name(int value) +{ + return get_name_by_value(mncc_names, value, "MNCC_Unknown"); +} + +const char *get_mncc_location(int value) +{ + return get_name_by_value(mncc_locations, value, "GSM48_CAUSE_LOC_Unknown"); +} + +const char *get_mncc_cause(int value) +{ + return get_name_by_value(mncc_causes, value, "GSM48_CC_CAUSE_Unknown"); +} + +int mncc_has_cause(struct gsm_mncc *data) +{ + return data->fields & MNCC_F_CAUSE; } void mncc_set_cause(struct gsm_mncc *data, int loc, int val) -- 1.9.1 From alexander.chemeris at gmail.com Wed Nov 25 20:31:05 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Wed, 25 Nov 2015 15:31:05 -0500 Subject: [PATCH 2/3] mncc: Log CC cause when sending a primitive to MNCC. In-Reply-To: <1448483466-10556-1-git-send-email-Alexander.Chemeris@gmail.com> References: <1448483466-10556-1-git-send-email-Alexander.Chemeris@gmail.com> Message-ID: <1448483466-10556-2-git-send-email-Alexander.Chemeris@gmail.com> --- openbsc/src/libmsc/gsm_04_08.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 7db7586..5dd9247 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -1349,20 +1349,26 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans, if (trans) if (trans->conn && trans->conn->lchan) DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) " - "Sending '%s' to MNCC.\n", + "Sending '%s' cause %s/%s to MNCC.\n", trans->conn->lchan->ts->trx->bts->nr, trans->conn->lchan->ts->trx->nr, trans->conn->lchan->ts->nr, trans->transaction_id, (trans->subscr)?(trans->subscr->extension):"-", - get_mncc_name(msg_type)); + get_mncc_name(msg_type), + (mncc_has_cause(mncc))?get_mncc_location(mncc->cause.location):"-", + (mncc_has_cause(mncc))?get_mncc_cause(mncc->cause.value):"-"); else DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " - "Sending '%s' to MNCC.\n", + "Sending '%s' cause %s/%s to MNCC.\n", (trans->subscr)?(trans->subscr->extension):"-", - get_mncc_name(msg_type)); + get_mncc_name(msg_type), + (mncc_has_cause(mncc))?get_mncc_location(mncc->cause.location):"-", + (mncc_has_cause(mncc))?get_mncc_cause(mncc->cause.value):"-"); else DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) " - "Sending '%s' to MNCC.\n", get_mncc_name(msg_type)); + "Sending '%s' cause %s/%s to MNCC.\n", get_mncc_name(msg_type), + (mncc_has_cause(mncc))?get_mncc_location(mncc->cause.location):"-", + (mncc_has_cause(mncc))?get_mncc_cause(mncc->cause.value):"-"); mncc->msg_type = msg_type; -- 1.9.1 From alexander.chemeris at gmail.com Wed Nov 25 20:31:06 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Wed, 25 Nov 2015 15:31:06 -0500 Subject: [PATCH 3/3] mncc: Send "Dest OOO" cause in case of a link radio failure. In-Reply-To: <1448483466-10556-1-git-send-email-Alexander.Chemeris@gmail.com> References: <1448483466-10556-1-git-send-email-Alexander.Chemeris@gmail.com> Message-ID: <1448483466-10556-3-git-send-email-Alexander.Chemeris@gmail.com> Previously we were sending a generic "Resource unavailable" cause code making it impossible to distinguish real error cases from a regular radio link failure. This was the reason for many "unknown" call errors we've seen at Rhizomatica installations. Now they are properly classified as non-erroneous call failures. --- openbsc/include/openbsc/transaction.h | 1 + openbsc/src/libbsc/bsc_api.c | 2 +- openbsc/src/libmsc/gsm_04_08.c | 14 ++++++++++---- openbsc/src/libmsc/transaction.c | 9 +++++++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 6ef1612..303ef6e 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -70,6 +70,7 @@ struct gsm_trans *trans_alloc(struct gsm_network *net, struct gsm_subscriber *subscr, uint8_t protocol, uint8_t trans_id, uint32_t callref); +void trans_free_cause(struct gsm_trans *trans, int gsm0808_cause); void trans_free(struct gsm_trans *trans); int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr, diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c index 504f044..54083f3 100644 --- a/openbsc/src/libbsc/bsc_api.c +++ b/openbsc/src/libbsc/bsc_api.c @@ -830,7 +830,7 @@ static void handle_release(struct gsm_subscriber_connection *conn, /* clear the connection now */ if (bsc->clear_request) - destruct = bsc->clear_request(conn, 0); + destruct = bsc->clear_request(conn, GSM0808_CAUSE_RADIO_INTERFACE_FAILURE); /* now give up all channels */ if (conn->lchan == lchan) diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 5dd9247..94d186d 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -58,6 +58,7 @@ #include #include +#include #include #include #include @@ -410,7 +411,7 @@ void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t caus restart: llist_for_each_entry_safe(trans, temp, &conn->bts->network->trans_list, entry) { if (trans->conn == conn) { - trans_free(trans); + trans_free_cause(trans, cause); goto restart; } } @@ -1399,16 +1400,21 @@ int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans, /* Call Control Specific transaction release. * gets called by trans_free, DO NOT CALL YOURSELF! */ -void _gsm48_cc_trans_free(struct gsm_trans *trans) +void _gsm48_cc_trans_free(struct gsm_trans *trans, int gsm0808_cause) { gsm48_stop_cc_timer(trans); /* send release to L4, if callref still exists */ if (trans->callref) { - /* Ressource unavailable */ + /* Release CC connection */ + int cc_cause = GSM48_CC_CAUSE_RESOURCE_UNAVAIL; + if (gsm0808_cause == GSM0808_CAUSE_RADIO_INTERFACE_FAILURE) + { + cc_cause = GSM48_CC_CAUSE_DEST_OOO; + } mncc_release_ind(trans->net, trans, trans->callref, GSM48_CAUSE_LOC_PRN_S_LU, - GSM48_CC_CAUSE_RESOURCE_UNAVAIL); + cc_cause); } if (trans->cc.state != GSM_CSTATE_NULL) new_cc_state(trans, GSM_CSTATE_NULL); diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c index a750362..95939d3 100644 --- a/openbsc/src/libmsc/transaction.c +++ b/openbsc/src/libmsc/transaction.c @@ -31,7 +31,7 @@ void *tall_trans_ctx; -void _gsm48_cc_trans_free(struct gsm_trans *trans); +void _gsm48_cc_trans_free(struct gsm_trans *trans, int gsm0808_cause); struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn, uint8_t proto, uint8_t trans_id) @@ -89,9 +89,14 @@ struct gsm_trans *trans_alloc(struct gsm_network *net, void trans_free(struct gsm_trans *trans) { + trans_free_cause(trans, -1); +} + +void trans_free_cause(struct gsm_trans *trans, int gsm0808_cause) +{ switch (trans->protocol) { case GSM48_PDISC_CC: - _gsm48_cc_trans_free(trans); + _gsm48_cc_trans_free(trans, gsm0808_cause); break; case GSM48_PDISC_SMS: _gsm411_sms_trans_free(trans); -- 1.9.1 From sipos.csaba at kvk.uni-obuda.hu Wed Nov 25 20:52:44 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Wed, 25 Nov 2015 21:52:44 +0100 (CET) Subject: Meas_web and meas_json In-Reply-To: References: <1510240027.5443523.1445891932058.JavaMail.zimbra@kvk.uni-obuda.hu> <1010582984.5443937.1445892326559.JavaMail.zimbra@kvk.uni-obuda.hu> <213728024.5449223.1445896264483.JavaMail.zimbra@kvk.uni-obuda.hu> <687363025.6773365.1446628686520.JavaMail.zimbra@kvk.uni-obuda.hu> <1503579201.10420115.1448476669036.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <202801686.10432917.1448484764454.JavaMail.zimbra@kvk.uni-obuda.hu> Dear Alexander, > I just hope it doesn't get lost :) Trust me it wont :-) One of the reasons I am creating these and other Wiki pages besides helping others is so I can remeber to the tricks, dependencies or other vital informations I learned and probably will forget :-) > May be your students could write some more visualization tools for OpenBSC? There is a lot to see in there. Just wanted to say the same thing. My personal opinion is that the biggest miss of electrical engineering education (where telecommunication is "wired" to) is that it does not focus enough on actual coding. This is a problem for myself too: I am not a big (or even small) coder, and because of that I can't help myself or others as much as I want to. So I cannot promise I can help a lot, but I am trying :-) Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Alexander Chemeris" C?mzett: "Sipos Csaba" M?solatot kap: "OpenBSC Mailing List" Elk?ld?tt ?zenetek: Szerda, 2015. November 25. 21:12:37 T?rgy: Re: Meas_web and meas_json Hi Csaba, On Wed, Nov 25, 2015 at 9:37 PM, Sipos Csaba wrote: > You just need to wait a little while for the Readme fix :-) I just hope it doesn't get lost :) > Thx for the patch, tomorrow will recompile and see if it fixes it (probably will). > > The crash happens in Firefox on Ubuntu 64bit. Will try Chrome to test it. I tried it under FF on Ubuntu 64bit and it doesn't crash here. Could you provide some backtrace for the crash? > For you to know, I just finished putting OpenBSC with two Nokia 2G site family basestations to work as a lab exercise at our University :-) > > And meas_feed is important for visualizing what happens in various signal conditions, besides spectrum and vector signal analysis ofcorse :-) Good visualization is always helpful for learning. May be your students could write some more visualization tools for OpenBSC? There is a lot to see in there. -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From holger at freyther.de Thu Nov 26 11:03:04 2015 From: holger at freyther.de (Holger Freyther) Date: Thu, 26 Nov 2015 12:03:04 +0100 Subject: Using Gerrit for libosmocore/lib../OpenBSC? Message-ID: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> Hi, I like code-review around mailinglists (mostly everybody can read and learn from comments or code), it shows that people collaborate and that we move forward. What I don't like about the current workflow is that we need to manually close things in patchwork after applying/rejecting/ignoring a patch and that to see if it compiles and works are done after the review and by the person that applies the changes. In other projects I have used Gerrit and besides it being a Java monster found it quite okay to use. One strength is that one can directly push the changes for a branch for review, the other is that Jenkins and Gerrit can collaborate. This means that after a commit is pushed make, make check, make distcheck can be executed. Comments will always be attached to a line and not be lost due me quoting and removing parts of the mail. What I am not sure about: * How do the email notifications look like? E.g. do we just get a "Somebody has commented" mail or do we get diff + comment sent here? In OpenOCD I see there is an email with the diff[1] but no mail with the comments. * Shall we support direct pushes? I think specially in the beginning we should but the branch name for that would change. * A change that impacts libopenbsc+OpenBSC is difficult to represent. It would break "the" build but I don't see any other way. Is there enough consensus to give it a try? holger [1] http://sourceforge.net/p/openocd/mailman/message/34646766/ From alexander.chemeris at gmail.com Thu Nov 26 13:40:35 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Thu, 26 Nov 2015 16:40:35 +0300 Subject: Using Gerrit for libosmocore/lib../OpenBSC? In-Reply-To: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> References: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> Message-ID: Hi Holger, I've never used Gerrit for real, but I assume it's similar to Github's review tools. And if so - there is one more bonus when using it - you can navigate code around the change to get more context if you're not super familiar with that place in the code. Plus highlighting really makes things easier to read than in plan text e-mails. On Thu, Nov 26, 2015 at 2:03 PM, Holger Freyther wrote: > Hi, > > I like code-review around mailinglists (mostly everybody can read and learn from > comments or code), it shows that people collaborate and that we move forward. > > What I don't like about the current workflow is that we need to manually close things > in patchwork after applying/rejecting/ignoring a patch and that to see if it compiles and > works are done after the review and by the person that applies the changes. > > In other projects I have used Gerrit and besides it being a Java monster found it > quite okay to use. One strength is that one can directly push the changes for a branch > for review, the other is that Jenkins and Gerrit can collaborate. This means that after > a commit is pushed make, make check, make distcheck can be executed. Comments > will always be attached to a line and not be lost due me quoting and removing parts > of the mail. > > > What I am not sure about: > > * How do the email notifications look like? E.g. do we just get a "Somebody has > commented" mail or do we get diff + comment sent here? In OpenOCD I see there > is an email with the diff[1] but no mail with the comments. > * Shall we support direct pushes? I think specially in the beginning we should but > the branch name for that would change. > * A change that impacts libopenbsc+OpenBSC is difficult to represent. It would break > "the" build but I don't see any other way. > > Is there enough consensus to give it a try? > > holger > > > > [1] http://sourceforge.net/p/openocd/mailman/message/34646766/ -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From jerlbeck at sysmocom.de Thu Nov 26 15:21:09 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 26 Nov 2015 16:21:09 +0100 Subject: [PATCH 1/6] msgb: Add msgb_resize_area and msgb_copy In-Reply-To: <20151125145834.GA1398@dub5> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <20151119143431.GD7092@dub5> <56542290.8070303@sysmocom.de> <20151125145834.GA1398@dub5> Message-ID: <56572365.20300@sysmocom.de> On 25.11.2015 15:58, Neels Hofmeyr wrote: > > Actually, msgb's len fields are typed as uint16_t, so I think old_size and > new_size should be uint16_t arguments...? I am not fond of using uint16_t in an API for such purposes, the compiler does not catch overflow, it might even be slower than an int when passed as an argument. In my opinion this is just a space optimization for the struct, and should not leak out to the API. Unfortunately the API is already inconsistent by using a mixture of int, unsigned int, and uint16_t types for length parameters. I agree, that size_t should not be added to that list. So the question remains, whether to use "int" or "unsigned int". K&R evangelists would probably go for "int", which has the advantage of to be able to compute differences without changing signedness on the way and to move the wrapping point far away. "unsigned int" had the advantage of not having to check for negative values and that it is more explicit in the API (BTW, msgb_trim uses int and does not check, thanks for the mug ;-) Prefering the "int" variant I have changed the function to int msgb_resize_area(struct msgb *msg, uint8_t *area, int old_size, int new_size) { int rc; uint8_t *rest = area + old_size; int rest_len = msg->len - old_size - (area - msg->data); int delta_size = new_size - old_size; if (old_size < 0 || new_size < 0) MSGB_ABORT(msg, "Negative sizes are not supported\n"); if (area < msg->data || rest > msg->tail) MSGB_ABORT(msg, "Sub area is not fully contained in the msg data\n"); ... } which I believe to be much clearer. > > And then, I think these are also necessary: > > [...] > > - assert new_size <= (0xffff - (area - msg->data)) > (so that the resulting len is within uint16_t). > Note that msgb_trim is responsible for checking the length (which should be fixed for negative values) and thus the upper limit of new_len. I was wondering about whether it makes sense, to handle the "buffer too small" case differently (by returning -1 instead of aborting, like msgb_trim), but could make sense in cases, where one can react to this by allocating a new buffer instead of patching the old one instead. Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From nhofmeyr at sysmocom.de Thu Nov 26 16:29:15 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 26 Nov 2015 17:29:15 +0100 Subject: [PATCH 2/3] gtphub: fix number map range for TEIs. In-Reply-To: References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-2-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20151126162915.GC3629@dub5> On Wed, Nov 25, 2015 at 08:53:45PM +0100, Holger Freyther wrote: > > -typedef int nr_t; > > +typedef unsigned int nr_t; > > use uint32_t here then? and "nr_t" is that clear it refers to a tei? nr_map is used for both sequence numbers and TEIs with different range settings. Sequence numbers range from 0..ffff and TEIs from 1..ffffffff. So nr_t is intended to be more general, but since gtphub is the only scope using it, unsigned int is enough to fit both number spaces (assuming int size will never be less than 32 bits...). So nr_t refers to a TEI as soon as a nr_pool is *used* for a TEI. > > + (unsigned int)nrm->orig, (unsigned int)nrm->repl); > > What is the explicit casting about? To print values 80000000..ffffffff as positive numbers, the printf format is using '%u'. Casting to unsigned int it is my preferred way of making sure the argument matches the printf format... Might not be necessary, but erases all doubt about intention or type sizes. ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Nov 26 16:51:52 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 26 Nov 2015 17:51:52 +0100 Subject: [PATCH 3/3] gtphub: nr_map: add min,max and wrap. In-Reply-To: References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-3-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20151126165152.GD3629@dub5> On Wed, Nov 25, 2015 at 09:05:40PM +0100, Holger Freyther wrote: > > + /* The TEI numbers will simply wrap and be reused, which will work out > > + * in practice. Problems would arise if one given peer maintained the > > + * same TEI for a time long enough for the TEI nr map to wrap an entire > > + * uint32_t; if a new TEI were mapped every second, this would take > > + * more than 100 years (in which a single given TEI must not time out) > > + * to cause a problem. */ > > Unless performance matters I am not for probalistic correct, specially not in the > beginning of a new piece of software. "Modern" smartphones will open a PDP > context very early and they live for a potentially long time (until you reboot your > phone or such). The TEI space will exhaust even slower, then :) The more *new* PDP contexts are created, the faster the pool will wrap. > So I would prefer to check if a TEI is used (at least the number should be random) > before using it. So even if the assignment is not random right now I would still > prefer the check if it is assigned or not. So I should iterate all tunnels to ensure a new TEI is unused. I'm anyway iterating all tunnels to detect a peer reusing a TEI it had sent before, also checking against the mapped TEI is easy to add. > E.g. a unit test that exhausts the entire number space should be feasible. Really? 4.294.967.295 TEI mappings?? Thats 4*sizeof(mapping) gigabytes and might need special memory model options to work, and the testing machine needs that many gigs of ram and will take quite a while: O(n?)... Probably easier to manually assign a given TEI and make the pool return that TEI next. Is your suggestion to shrink the TEI space? And next, what about sequence numbers? The space is much smaller (65.536 values), and expires after 30 seconds. To me, it is much more realistic that we receive 66.000 messages with distinct sequence numbers within the space of 30 seconds, than that a given TEI will remain in use for more than 100 years in a place where a new subscriber shows up every single second. So, verifying that a *sequence number* is unused seems to be way more critical than the TEI check. Which touches the optimization topic. Currently gtphub will have to iterate everything all the time. To optimize, one way would be to list tunnels at the peers they associate with, but if gtphub is used as proxy for a single peer, that has exactly zero effect. So some way of hash map might be more useful. But gtphub wants several different views, i.e. sometimes it wants to find an original TEI, sometimes a mapped TEI, sometimes from SGSN and sometimes from GGSN side, and sometimes it wants to find all tunnels for a given peer. So, to optimize we'd want a couple of separate hash maps hashing one and the same list from different angles. I'd be glad for any ideas, or hints at existing Osmocom API. But, unless told otherwise, I simply won't bother about optimization for now... ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Nov 26 20:37:45 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 26 Nov 2015 21:37:45 +0100 Subject: Using Gerrit for libosmocore/lib../OpenBSC? In-Reply-To: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> References: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> Message-ID: <20151126203745.GB7030@dub5> On Thu, Nov 26, 2015 at 12:03:04PM +0100, Holger Freyther wrote: > [Gerritt] > Is there enough consensus to give it a try? I'm neutral, if you want to try it I wouldn't object. I like simple tools like plain text mails, Gerritt seems to be the opposite. But if it helps to get the context while reading a patch and requires no further effort from us, it may well be worthwhile. My first impression is "crowded UI", but the side-by-side file view could be helpful, yes. When you say Java monster, I also think slow website. It would be nice to not have to wait too much for it to load, which in the Java world translates as "have a fast server with loads of RAM" ... please :) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Thu Nov 26 20:48:34 2015 From: holger at freyther.de (Holger Freyther) Date: Thu, 26 Nov 2015 21:48:34 +0100 Subject: Using Gerrit for libosmocore/lib../OpenBSC? In-Reply-To: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> References: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> Message-ID: > On 26 Nov 2015, at 12:03, Holger Freyther wrote: > > Hi, > > Is there enough consensus to give it a try? The alternatives (and my opinion on them) current setup - It works more scripts - Write a job that checks if pending patches "still" apply or were applied github.com - Still skeptical to rely on proprietary software to build free software gitlab.com - OpenCore so not really compatible with us reviewboard - Not good git integration (last time i checked) phabric - Used by Enlightenment/FreeBSD.. but I never understood the UI.. holger From nhofmeyr at sysmocom.de Thu Nov 26 22:46:16 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 26 Nov 2015 23:46:16 +0100 Subject: [PATCH 3/3] gtphub: nr_map: add min,max and wrap. In-Reply-To: <20151126165152.GD3629@dub5> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-3-git-send-email-nhofmeyr@sysmocom.de> <20151126165152.GD3629@dub5> Message-ID: <20151126224616.GC7030@dub5> On Thu, Nov 26, 2015 at 05:51:52PM +0100, Neels Hofmeyr wrote: > Which touches the optimization topic. Currently gtphub will have to [...] > of separate hash maps hashing one and the same list from different angles. I'm thinking, if we want persistence as well as several optimized querying angles: sqlite might do both at the same time. ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From jerlbeck at sysmocom.de Fri Nov 27 08:38:06 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 09:38:06 +0100 Subject: [PATCH 2/3] gtphub: fix number map range for TEIs. In-Reply-To: <20151126162915.GC3629@dub5> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-2-git-send-email-nhofmeyr@sysmocom.de> <20151126162915.GC3629@dub5> Message-ID: <5658166E.4000308@sysmocom.de> On 26.11.2015 17:29, Neels Hofmeyr wrote: > On Wed, Nov 25, 2015 at 08:53:45PM +0100, Holger Freyther wrote: > >>> + (unsigned int)nrm->orig, (unsigned int)nrm->repl); >> >> What is the explicit casting about? > > To print values 80000000..ffffffff as positive numbers, the printf format > is using '%u'. Casting to unsigned int it is my preferred way of making > sure the argument matches the printf format... > > Might not be necessary, but erases all doubt about intention or type > sizes. As far as I understand the C99 specification, this not necessary. IMO the make the code less readable and the hinder the compiler and tools like coverity to find certain bugs, e.g. if someone raised the type of nmr->orig to 'long long' for some reason, he/she wouldn't get a warning from the tools. Here is the definition of "integer promotions": ?6.3.1.1 (2): "If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions." Here is the definition of "default argument promotions": ?6.5.2.2 (6): "If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. ..." And finally, these have to be applied to the trailing arguments or printf: ?6.5.2.2 (7): "... The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments." Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From jerlbeck at sysmocom.de Fri Nov 27 09:00:08 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 10:00:08 +0100 Subject: [PATCH 3/3] gtphub: nr_map: add min,max and wrap. In-Reply-To: <20151126165152.GD3629@dub5> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-3-git-send-email-nhofmeyr@sysmocom.de> <20151126165152.GD3629@dub5> Message-ID: <56581B98.7000701@sysmocom.de> On 26.11.2015 17:51, Neels Hofmeyr wrote: > On Wed, Nov 25, 2015 at 09:05:40PM +0100, Holger Freyther wrote: >> E.g. a unit test that exhausts the entire number space should be feasible. > > Really? 4.294.967.295 TEI mappings?? Thats 4*sizeof(mapping) gigabytes and > might need special memory model options to work, and the testing > machine needs that many gigs of ram and will take quite a while: O(n?)... I am fond of exhausting tests, too. But AFAI understand, it would be enough to establish one mapping at first and then establishing and releasing them immediately (N = 1) or after e.g. N = 2^16 steps. Thus you had a persistent initial one and a sliding window of N mappings and each new mapping could be checked against at least the first one. If you still ran into memory problems, you would have found a bug that way. > Probably easier to manually assign a given TEI and make the pool return > that TEI next. This won't check the TEI generation, will it? If the allocation was changed in the future (e.g. to be based on random numbers), this kind of test wouldn't find bugs there. Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From jerlbeck at sysmocom.de Fri Nov 27 11:38:08 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 12:38:08 +0100 Subject: [PATCH 5/6] msgb/test: Add tests for msgb_resize_area and msgb_copy In-Reply-To: <20151123094343.GA1360@dub5> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1447753069-17466-5-git-send-email-jerlbeck@sysmocom.de> <20151123094343.GA1360@dub5> Message-ID: <565840A0.1010401@sysmocom.de> On 23.11.2015 10:43, Neels Hofmeyr wrote: > On Tue, Nov 17, 2015 at 10:37:48AM +0100, Jacob Erlbeck wrote: >> diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c >> index 412e8bb..08d9857 100644 >> --- a/tests/msgb/msgb_test.c >> +++ b/tests/msgb/msgb_test.c >> @@ -87,6 +87,7 @@ static void test_msgb_api() >> msg->l3h = msg->head - 1; >> printf("Buffer: %s\n", msgb_hexdump(msg)); >> >> + >> #if 0 >> extern void msgb_reset(struct msgb *m); >> #define msgb_l1(m) ((void *)(MSGB_CHECK2(m)->l1h)) >> @@ -97,15 +98,61 @@ static inline unsigned int msgb_l1len(const struct msgb *msgb) >> static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) >> static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) >> static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len) >> - >> + >> static inline unsigned char *msgb_pull_to_l3(struct msgb *msg) >> static inline int msgb_trim(struct msgb *msg, int len) >> static inline int msgb_l3trim(struct msgb *msg, int l3len) >> uint8_t *msgb_data(const struct msgb *msg); >> - return; >> +return; >> #endif >> } > > ^ seems like those whitespace changes came in by accident... Yes, thanks for noticing. I will remove the complete commentary block. Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From jerlbeck at sysmocom.de Fri Nov 27 12:26:14 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:14 +0100 Subject: [PATCH 2/8] msgb: Let msgb_hexdump be more tolerant In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-3-git-send-email-jerlbeck@sysmocom.de> This patch makes msgb_hexdump accept out of range lXh pointers and shows info about them instead of aborting the dump entirely. Sponsored-by: On-Waves ehf --- src/msgb.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/msgb.c b/src/msgb.c index 3132644..4b108a4 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -266,10 +266,25 @@ const char *msgb_hexdump(const struct msgb *msg) if (!lxhs[i]) continue; - if (lxhs[i] < msg->data) - goto out_of_range; + if (lxhs[i] < msg->head) + continue; + if (lxhs[i] > msg->head + msg->data_len) + continue; if (lxhs[i] > msg->tail) - goto out_of_range; + continue; + if (lxhs[i] < msg->data || lxhs[i] > msg->tail) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d=data%+d) ", + i+1, lxhs[i] - msg->data); + buf_offs += nchars; + continue; + } + if (lxhs[i] < start) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d%+d) ", i+1, start - lxhs[i]); + buf_offs += nchars; + continue; + } nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, "%s[L%d]> ", osmo_hexdump(start, lxhs[i] - start), @@ -285,11 +300,28 @@ const char *msgb_hexdump(const struct msgb *msg) if (nchars < 0 || nchars + buf_offs >= sizeof(buf)) return "ERROR"; - return buf; + buf_offs += nchars; + + for (i = 0; i < ARRAY_SIZE(lxhs); i++) { + if (!lxhs[i]) + continue; + + if (lxhs[i] < msg->head || lxhs[i] > msg->head + msg->data_len) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d out of range) ", i+1); + } else if (lxhs[i] <= msg->data + msg->data_len && + lxhs[i] > msg->tail) { + nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs, + "(L%d=tail%+d) ", + i+1, lxhs[i] - msg->tail); + } else + continue; + + if (nchars < 0 || nchars + buf_offs >= sizeof(buf)) + return "ERROR"; + buf_offs += nchars; + } -out_of_range: - nchars = snprintf(buf, sizeof(buf) - buf_offs, - "!!! L%d out of range", i+1); return buf; } -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:13 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:13 +0100 Subject: [PATCH 1/8] msgb: Add msgb_resize_area and msgb_copy In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-2-git-send-email-jerlbeck@sysmocom.de> These functions originate from openbsc/src/gprs but are generic msgb helper functions. msgb_copy: This function allocates a new msgb, copies the data buffer of msg, and adjusts the pointers (incl. l1h-l4h) accordingly. msgb_resize_area: This resizes a sub area of the msgb data and adjusts the pointers (incl. l1h-l4h) accordingly. Sponsored-by: On-Waves ehf --- include/osmocom/core/msgb.h | 3 ++ src/msgb.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 644a639..9ffc64e 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -74,6 +74,9 @@ extern struct msgb *msgb_dequeue(struct llist_head *queue); extern void msgb_reset(struct msgb *m); uint16_t msgb_length(const struct msgb *msg); extern const char *msgb_hexdump(const struct msgb *msg); +extern int msgb_resize_area(struct msgb *msg, uint8_t *area, + int old_size, int new_size); +extern struct msgb *msgb_copy(const struct msgb *msg, const char *name); #ifdef MSGB_DEBUG #include diff --git a/src/msgb.c b/src/msgb.c index b2fe1d2..3132644 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -153,6 +153,97 @@ void msgb_set_talloc_ctx(void *ctx) tall_msgb_ctx = ctx; } +/*! \brief Copy an msgb. + * + * This function allocates a new msgb, copies the data buffer of msg, + * and adjusts the pointers (incl l1h-l4h) accordingly. The cb part + * is not copied. + * \param[in] msg The old msgb object + * \param[in] name Human-readable name to be associated with msgb + */ +struct msgb *msgb_copy(const struct msgb *msg, const char *name) +{ + struct msgb *new_msg; + + new_msg = msgb_alloc(msg->data_len, name); + if (!new_msg) + return NULL; + + /* copy data */ + memcpy(new_msg->_data, msg->_data, new_msg->data_len); + + /* copy header */ + new_msg->len = msg->len; + new_msg->data += msg->data - msg->_data; + new_msg->head += msg->head - msg->_data; + new_msg->tail += msg->tail - msg->_data; + + if (msg->l1h) + new_msg->l1h = new_msg->_data + (msg->l1h - msg->_data); + if (msg->l2h) + new_msg->l2h = new_msg->_data + (msg->l2h - msg->_data); + if (msg->l3h) + new_msg->l3h = new_msg->_data + (msg->l3h - msg->_data); + if (msg->l4h) + new_msg->l4h = new_msg->_data + (msg->l4h - msg->_data); + + return new_msg; +} + +/*! \brief Resize an area within an msgb + * + * This resizes a sub area of the msgb data and adjusts the pointers (incl + * l1h-l4h) accordingly. The cb part is not updated. If the area is extended, + * the contents of the extension is undefined. The complete sub area must be a + * part of [data,tail]. + * + * \param[inout] msg The msgb object + * \param[in] area A pointer to the sub-area + * \param[in] old_size The old size of the sub-area + * \param[in] new_size The new size of the sub-area + * \returns 0 on success, -1 if there is not enough space to extend the area + */ +int msgb_resize_area(struct msgb *msg, uint8_t *area, + int old_size, int new_size) +{ + int rc; + uint8_t *post_start = area + old_size; + int pre_len = area - msg->data; + int post_len = msg->len - old_size - pre_len; + int delta_size = new_size - old_size; + + if (old_size < 0 || new_size < 0) + MSGB_ABORT(msg, "Negative sizes are not allowed\n"); + if (area < msg->data || post_start > msg->tail) + MSGB_ABORT(msg, "Sub area is not fully contained in the msg data\n"); + + if (delta_size == 0) + return 0; + + if (delta_size > 0) { + rc = msgb_trim(msg, msg->len + delta_size); + if (rc < 0) + return rc; + } + + memmove(area + new_size, area + old_size, post_len); + + if (msg->l1h >= post_start) + msg->l1h += delta_size; + if (msg->l2h >= post_start) + msg->l2h += delta_size; + if (msg->l3h >= post_start) + msg->l3h += delta_size; + if (msg->l4h >= post_start) + msg->l4h += delta_size; + + if (delta_size < 0) + msgb_trim(msg, msg->len + delta_size); + + return 0; +} + + /*! \brief Return a (static) buffer containing a hexdump of the msg * \param[in] msg message buffer * \returns a pointer to a static char array -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:15 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:15 +0100 Subject: [PATCH 3/8] msgb: Add msgb_test_invariant function In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-4-git-send-email-jerlbeck@sysmocom.de> This adds a function that verifies whether a mgsb is consistent. Sponsored-by: On-Waves ehf --- include/osmocom/core/msgb.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 9ffc64e..9c99cad 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -77,6 +77,7 @@ extern const char *msgb_hexdump(const struct msgb *msg); extern int msgb_resize_area(struct msgb *msg, uint8_t *area, int old_size, int new_size); extern struct msgb *msgb_copy(const struct msgb *msg, const char *name); +static int msgb_test_invariant(const struct msgb *msg) __attribute__((pure)); #ifdef MSGB_DEBUG #include @@ -412,6 +413,45 @@ static inline struct msgb *msgb_alloc_headroom(int size, int headroom, return msg; } +/*! \brief Check a message buffer for consistency + * \param[in] msg message buffer + * \returns 0 (false) if inconsistent, != 0 (true) otherwise + */ +static inline int msgb_test_invariant(const struct msgb *msg) +{ + const unsigned char *lbound; + if (!msg || !msg->data || !msg->tail || + (msg->data + msg->len != msg->tail) || + (msg->data < msg->head) || + (msg->tail > msg->head + msg->data_len)) + return 0; + + lbound = msg->head; + + if (msg->l1h) { + if (msg->l1h < lbound) + return 0; + lbound = msg->l1h; + } + if (msg->l2h) { + if (msg->l2h < lbound) + return 0; + lbound = msg->l2h; + } + if (msg->l3h) { + if (msg->l3h < lbound) + return 0; + lbound = msg->l3h; + } + if (msg->l4h) { + if (msg->l4h < lbound) + return 0; + lbound = msg->l4h; + } + + return lbound <= msg->head + msg->data_len; +} + /* non inline functions to ease binding */ uint8_t *msgb_data(const struct msgb *msg); -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:16 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:16 +0100 Subject: [PATCH 4/8] msgb/test: Add test for msgb message buffers In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-5-git-send-email-jerlbeck@sysmocom.de> This tests several API functions of the msgb by checking the invariant and by dumping resulting message buffers as hex. Sponsored-by: On-Waves ehf Conflicts: tests/Makefile.am --- tests/Makefile.am | 9 ++++- tests/msgb/msgb_test.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/msgb/msgb_test.ok | 21 ++++++++++ tests/testsuite.at | 6 +++ 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 tests/msgb/msgb_test.c create mode 100644 tests/msgb/msgb_test.ok diff --git a/tests/Makefile.am b/tests/Makefile.am index 4442355..edf25a0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,7 +10,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ logging/logging_test fr/fr_test \ loggingrb/loggingrb_test strrb/strrb_test \ vty/vty_test comp128/comp128_test utils/utils_test \ - smscb/gsm0341_test stats/stats_test + smscb/gsm0341_test stats/stats_test \ + msgb/msgb_test if ENABLE_MSGFILE check_PROGRAMS += msgfile/msgfile_test @@ -52,6 +53,9 @@ gprs_gprs_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gs lapd_lapd_test_SOURCES = lapd/lapd_test.c lapd_lapd_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la +msgb_msgb_test_SOURCES = msgb/msgb_test.c +msgb_msgb_test_LDADD = $(top_builddir)/src/libosmocore.la + msgfile_msgfile_test_SOURCES = msgfile/msgfile_test.c msgfile_msgfile_test_LDADD = $(top_builddir)/src/libosmocore.la @@ -127,7 +131,8 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ fr/fr_test.ok loggingrb/logging_test.ok \ loggingrb/logging_test.err strrb/strrb_test.ok \ vty/vty_test.ok comp128/comp128_test.ok \ - utils/utils_test.ok stats/stats_test.ok + utils/utils_test.ok stats/stats_test.ok \ + msgb/msgb_test.ok DISTCLEANFILES = atconfig diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c new file mode 100644 index 0000000..7592509 --- /dev/null +++ b/tests/msgb/msgb_test.c @@ -0,0 +1,104 @@ +/* + * (C) 2014 by On-Waves + * 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 + +#define CHECK_RC(rc) \ + if (rc != 0) { \ + printf("Operation failed rc=%d on %s:%d\n", rc, __FILE__, __LINE__); \ + abort(); \ + } + +static void test_msgb_api() +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + unsigned char *cptr = NULL; + int rc; + + printf("Testing the msgb API\n"); + + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l1h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l2h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l3h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + cptr = msg->l4h = msgb_put(msg, 4); + printf("put(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + OSMO_ASSERT(msgb_length(msg) == 16); + cptr = msgb_push(msg, 4); + printf("push(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + OSMO_ASSERT(msgb_length(msg) == 20); + rc = msgb_trim(msg, 16); + printf("trim(16) -> %d\n", rc); + CHECK_RC(rc); + OSMO_ASSERT(msgb_test_invariant(msg)); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_length(msg) == 16); + + cptr = msgb_get(msg, 4); + printf("get(4) -> data%+d\n", cptr - msg->data); + printf("Buffer: %s\n", msgb_hexdump(msg)); + OSMO_ASSERT(msgb_test_invariant(msg)); + OSMO_ASSERT(msgb_length(msg) == 12); + + printf("Test msgb_hexdump\n"); + msg->l1h = msg->head; + printf("Buffer: %s\n", msgb_hexdump(msg)); + msg->l3h = msg->data; + printf("Buffer: %s\n", msgb_hexdump(msg)); + msg->l3h = msg->head - 1; + printf("Buffer: %s\n", msgb_hexdump(msg)); + + msgb_free(msg); +} + +static struct log_info info = {}; + +int main(int argc, char **argv) +{ + osmo_init_logging(&info); + + test_msgb_api(); + + printf("Success.\n"); + + return 0; +} diff --git a/tests/msgb/msgb_test.ok b/tests/msgb/msgb_test.ok new file mode 100644 index 0000000..f8de0cd --- /dev/null +++ b/tests/msgb/msgb_test.ok @@ -0,0 +1,21 @@ +Testing the msgb API +Buffer: +put(4) -> data+0 +Buffer: [L1]> 00 00 00 00 +put(4) -> data+4 +Buffer: [L1]> 00 00 00 00 [L2]> 00 00 00 00 +put(4) -> data+8 +Buffer: [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 +put(4) -> data+12 +Buffer: [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 [L4]> 00 00 00 00 +push(4) -> data+0 +Buffer: 00 00 00 00 [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 [L4]> 00 00 00 00 +trim(16) -> 0 +Buffer: 00 00 00 00 [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> 00 00 00 00 [L4]> +get(4) -> data+12 +Buffer: 00 00 00 00 [L1]> 00 00 00 00 [L2]> 00 00 00 00 [L3]> (L4=tail+4) +Test msgb_hexdump +Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 [L3]> (L4=tail+4) +Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> (L3+8) 00 00 00 00 (L4=tail+4) +Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 (L3 out of range) (L4=tail+4) +Success. diff --git a/tests/testsuite.at b/tests/testsuite.at index 85c3e8b..12199e3 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -27,6 +27,12 @@ cat $abs_srcdir/conv/conv_test.ok > expout AT_CHECK([$abs_top_builddir/tests/conv/conv_test], [0], [expout]) AT_CLEANUP +AT_SETUP([msgb]) +AT_KEYWORDS([msgb]) +cat $abs_srcdir/msgb/msgb_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/msgb/msgb_test], [0], [expout]) +AT_CLEANUP + if ENABLE_MSGFILE AT_SETUP([msgfile]) AT_KEYWORDS([msgfile]) -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:17 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:17 +0100 Subject: [PATCH 5/8] msgb/test: Add functions to catch and check exceptions In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-6-git-send-email-jerlbeck@sysmocom.de> Currently the msgb error handling cannot be fully tested, since in many cases osmo_panic will be called. This will in turn call abort(). Using an osmo_panic_handler that just returns will not help, since many msgb functions rely on MSGB_ABORT to not return at all. This commit uses an alternative osmo_panic_raise handler that just calls longjmp to return to the test function. Since some of this activity is logged to stderr where the strings may contain variable parts like pointer addresses, stderr checking is disabled in testsuite.at. Sponsored-by: On-Waves ehf --- tests/msgb/msgb_test.c | 31 +++++++++++++++++++++++++++++++ tests/testsuite.at | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c index 7592509..260aca5 100644 --- a/tests/msgb/msgb_test.c +++ b/tests/msgb/msgb_test.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -34,6 +35,36 @@ abort(); \ } +static jmp_buf jmp_env; +static int jmp_env_valid = 0; +static void osmo_panic_raise(const char *fmt, va_list args) +{ + /* + * The args can include pointer values which are not suitable for + * regression testing. So just write the (hopefully constant) format + * string to stdout and write the full message to stderr. + */ + printf("%s", fmt); + vfprintf(stderr, fmt, args); + if (!jmp_env_valid) + abort(); + longjmp(jmp_env, 1); +} + +/* Note that this does not nest */ +#define OSMO_PANIC_TRY(pE) (osmo_panic_try(pE, setjmp(jmp_env))) + +static int osmo_panic_try(volatile int *exception, int setjmp_result) +{ + jmp_env_valid = setjmp_result == 0; + *exception = setjmp_result; + + if (setjmp_result) + fprintf(stderr, "Exception caught: %d\n", setjmp_result); + + return *exception == 0; +} + static void test_msgb_api() { struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); diff --git a/tests/testsuite.at b/tests/testsuite.at index 12199e3..bd3fa1b 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -30,7 +30,7 @@ AT_CLEANUP AT_SETUP([msgb]) AT_KEYWORDS([msgb]) cat $abs_srcdir/msgb/msgb_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/msgb/msgb_test], [0], [expout]) +AT_CHECK([$abs_top_builddir/tests/msgb/msgb_test], [0], [expout], [ignore]) AT_CLEANUP if ENABLE_MSGFILE -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:18 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:18 +0100 Subject: [PATCH 6/8] msgb/test: Add tests for msgb_resize_area and msgb_copy In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-7-git-send-email-jerlbeck@sysmocom.de> Sponsored-by: On-Waves ehf --- tests/msgb/msgb_test.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/msgb/msgb_test.ok | 12 +++++ 2 files changed, 149 insertions(+) diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c index 260aca5..e6cb33e 100644 --- a/tests/msgb/msgb_test.c +++ b/tests/msgb/msgb_test.c @@ -121,6 +121,141 @@ static void test_msgb_api() msgb_free(msg); } +static void test_msgb_copy() +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + struct msgb *msg2; + int i; + + printf("Testing msgb_copy\n"); + + msg->l1h = msgb_put(msg, 20); + msg->l2h = msgb_put(msg, 20); + msg->l3h = msgb_put(msg, 20); + msg->l4h = msgb_put(msg, 20); + + OSMO_ASSERT(msgb_length(msg) == 80); + for (i = 0; i < msgb_length(msg); i++) + msg->data[i] = (uint8_t)i; + + msg2 = msgb_copy(msg, "copy"); + + OSMO_ASSERT(msgb_length(msg) == msgb_length(msg2)); + OSMO_ASSERT(msgb_l1len(msg) == msgb_l1len(msg2)); + OSMO_ASSERT(msgb_l2len(msg) == msgb_l2len(msg2)); + OSMO_ASSERT(msgb_l3len(msg) == msgb_l3len(msg2)); + OSMO_ASSERT(msg->tail - msg->l4h == msg2->tail - msg2->l4h); + + for (i = 0; i < msgb_length(msg2); i++) + OSMO_ASSERT(msg2->data[i] == (uint8_t)i); + + printf("Src: %s\n", msgb_hexdump(msg)); + printf("Dst: %s\n", msgb_hexdump(msg)); + + msgb_free(msg); + msgb_free(msg2); +} + +static void test_msgb_resize_area() +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + int rc; + volatile int e = 0; + int i, saved_i; + uint8_t *cptr, *old_l3h; + + osmo_set_panic_handler(osmo_panic_raise); + + rc = msgb_resize_area(msg, msg->data, 0, 0); + OSMO_ASSERT(rc >= 0); + + if (OSMO_PANIC_TRY(&e)) + msgb_resize_area(msg, NULL, 0, 0); + OSMO_ASSERT(e != 0); + + if (OSMO_PANIC_TRY(&e)) + msgb_resize_area(msg, NULL, (int)msg->data, 0); + OSMO_ASSERT(e != 0); + + if (OSMO_PANIC_TRY(&e)) + msgb_resize_area(msg, msg->data, 20, 0); + OSMO_ASSERT(e != 0); + + if (OSMO_PANIC_TRY(&e)) + msgb_resize_area(msg, msg->data, -1, 0); + OSMO_ASSERT(e != 0); + + if (OSMO_PANIC_TRY(&e)) + msgb_resize_area(msg, msg->data, 0, -1); + OSMO_ASSERT(e != 0); + + printf("Testing msgb_resize_area\n"); + + msg->l1h = msgb_put(msg, 20); + msg->l2h = msgb_put(msg, 20); + msg->l3h = msgb_put(msg, 20); + msg->l4h = msgb_put(msg, 20); + + for (i = 0; i < msgb_length(msg); i++) + msg->data[i] = (uint8_t)i; + + printf("Original: %s\n", msgb_hexdump(msg)); + + /* Extend area */ + saved_i = msg->l3h[0]; + old_l3h = msg->l3h; + + rc = msgb_resize_area(msg, msg->l2h, 20, 20 + 30); + + /* Reset the undefined part to allow printing the buffer to stdout */ + memset(old_l3h, 0, msg->l3h - old_l3h); + + printf("Extended: %s\n", msgb_hexdump(msg)); + + OSMO_ASSERT(rc >= 0); + OSMO_ASSERT(msgb_length(msg) == 80 + 30); + OSMO_ASSERT(msgb_l1len(msg) == 80 + 30); + OSMO_ASSERT(msgb_l2len(msg) == 60 + 30); + OSMO_ASSERT(msgb_l3len(msg) == 40); + OSMO_ASSERT(msg->tail - msg->l4h == 20); + + for (cptr = msgb_data(msg), i = 0; cptr < old_l3h; cptr++, i++) + OSMO_ASSERT(*cptr == (uint8_t)i); + + for (cptr = msg->l3h, i = saved_i; cptr < msg->tail; cptr++, i++) + OSMO_ASSERT(*cptr == (uint8_t)i); + + rc = msgb_resize_area(msg, msg->l2h, 50, 8000); + OSMO_ASSERT(rc == -1); + + /* Shrink area */ + saved_i = msg->l4h[0]; + OSMO_ASSERT(saved_i == (uint8_t)(msg->l4h[-1] + 1)); + + rc = msgb_resize_area(msg, msg->l3h, 20, 10); + + printf("Shrinked: %s\n", msgb_hexdump(msg)); + + OSMO_ASSERT(rc >= 0); + OSMO_ASSERT(msgb_length(msg) == 80 + 30 - 10); + OSMO_ASSERT(msgb_l1len(msg) == 80 + 30 - 10); + OSMO_ASSERT(msgb_l2len(msg) == 60 + 30 - 10); + OSMO_ASSERT(msgb_l3len(msg) == 40 - 10); + OSMO_ASSERT(msg->tail - msg->l4h == 20); + + OSMO_ASSERT(msg->l4h[0] != msg->l4h[-1] - 1); + + for (cptr = msg->l4h, i = saved_i; cptr < msg->tail; cptr++, i++) + OSMO_ASSERT(*cptr == (uint8_t)i); + + rc = msgb_resize_area(msg, msg->l2h, 50, 8000); + OSMO_ASSERT(rc == -1); + + msgb_free(msg); + + osmo_set_panic_handler(NULL); +} + static struct log_info info = {}; int main(int argc, char **argv) @@ -128,6 +263,8 @@ int main(int argc, char **argv) osmo_init_logging(&info); test_msgb_api(); + test_msgb_copy(); + test_msgb_resize_area(); printf("Success.\n"); diff --git a/tests/msgb/msgb_test.ok b/tests/msgb/msgb_test.ok index f8de0cd..4cb76a9 100644 --- a/tests/msgb/msgb_test.ok +++ b/tests/msgb/msgb_test.ok @@ -18,4 +18,16 @@ Test msgb_hexdump Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 [L3]> (L4=tail+4) Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> (L3+8) 00 00 00 00 (L4=tail+4) Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 (L3 out of range) (L4=tail+4) +Testing msgb_copy +Src: [L1]> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 [L2]> 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 [L3]> 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b [L4]> 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +Dst: [L1]> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 [L2]> 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 [L3]> 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b [L4]> 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +msgb(%p): Sub area is not fully contained in the msg data +msgb(%p): Sub area is not fully contained in the msg data +msgb(%p): Sub area is not fully contained in the msg data +msgb(%p): Negative sizes are not allowed +msgb(%p): Negative sizes are not allowed +Testing msgb_resize_area +Original: [L1]> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 [L2]> 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 [L3]> 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b [L4]> 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +Extended: [L1]> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 [L2]> 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [L3]> 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b [L4]> 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +Shrinked: [L1]> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 [L2]> 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [L3]> 28 29 2a 2b 2c 2d 2e 2f 30 31 [L4]> 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Success. -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:19 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:19 +0100 Subject: [PATCH 7/8] msgb: Assert len >= 0 in msgb_trim In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-8-git-send-email-jerlbeck@sysmocom.de> Currently msgb_trim only checks for len > data_len and returns -1 in that case, allowing the caller to fix it somehow. Using a negative length will always lead to a corrupt msgb, but this is not being checked. This commit adds a check for len < 0 and a conditional call to MSGB_ABORT. Sponsored-by: On-Waves ehf --- include/osmocom/core/msgb.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 9c99cad..b057caa 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -373,6 +373,8 @@ static inline void msgb_reserve(struct msgb *msg, int len) */ static inline int msgb_trim(struct msgb *msg, int len) { + if (len < 0) + MSGB_ABORT(msg, "Negative length is not allowed\n"); if (len > msg->data_len) return -1; -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:20 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:20 +0100 Subject: [PATCH 8/8] msgb/test: Add test case for error cases In-Reply-To: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-9-git-send-email-jerlbeck@sysmocom.de> Include a test for msgb_trim. Sponsored-by: On-Waves ehf --- tests/msgb/msgb_test.c | 22 ++++++++++++++++++++++ tests/msgb/msgb_test.ok | 2 ++ 2 files changed, 24 insertions(+) diff --git a/tests/msgb/msgb_test.c b/tests/msgb/msgb_test.c index e6cb33e..8839a2e 100644 --- a/tests/msgb/msgb_test.c +++ b/tests/msgb/msgb_test.c @@ -121,6 +121,27 @@ static void test_msgb_api() msgb_free(msg); } +static void test_msgb_api_errors() +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + volatile int e = 0; + int rc; + + printf("Testing the msgb API error handling\n"); + + osmo_set_panic_handler(osmo_panic_raise); + + if (OSMO_PANIC_TRY(&e)) + msgb_trim(msg, -1); + OSMO_ASSERT(e != 0); + + rc = msgb_trim(msg, 4096 + 500); + OSMO_ASSERT(rc == -1); + + msgb_free(msg); + osmo_set_panic_handler(NULL); +} + static void test_msgb_copy() { struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); @@ -263,6 +284,7 @@ int main(int argc, char **argv) osmo_init_logging(&info); test_msgb_api(); + test_msgb_api_errors(); test_msgb_copy(); test_msgb_resize_area(); diff --git a/tests/msgb/msgb_test.ok b/tests/msgb/msgb_test.ok index 4cb76a9..6603fe7 100644 --- a/tests/msgb/msgb_test.ok +++ b/tests/msgb/msgb_test.ok @@ -18,6 +18,8 @@ Test msgb_hexdump Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 [L3]> (L4=tail+4) Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> (L3+8) 00 00 00 00 (L4=tail+4) Buffer: (L1=data-124) 00 00 00 00 00 00 00 00 [L2]> 00 00 00 00 (L3 out of range) (L4=tail+4) +Testing the msgb API error handling +msgb(%p): Negative length is not allowed Testing msgb_copy Src: [L1]> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 [L2]> 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 [L3]> 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b [L4]> 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f Dst: [L1]> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 [L2]> 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 [L3]> 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b [L4]> 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f -- 1.9.1 From jerlbeck at sysmocom.de Fri Nov 27 12:26:12 2015 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 27 Nov 2015 13:26:12 +0100 Subject: New MSGB patch set In-Reply-To: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> References: <1447753069-17466-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1448627180-10603-1-git-send-email-jerlbeck@sysmocom.de> Hi, I have reworked the patches (thanks go to Neels for comments), fixed some additional flaws, and improved the test cases. Jacob From sipos.csaba at kvk.uni-obuda.hu Sat Nov 28 12:35:19 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Sat, 28 Nov 2015 13:35:19 +0100 (CET) Subject: OpenBSC compile error --> tests --> GTP hub In-Reply-To: <697834374.10869705.1448714038091.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <569979521.10869842.1448714119383.JavaMail.zimbra@kvk.uni-obuda.hu> Dear Neels, Today just grabbed the latest OpenBSC master, and got this compile error: Making all in gtphub make[3]: Entering directory `/root/new_osmocom/openbsc/openbsc/tests/gtphub' CC gtphub_test.o CC ../../src/gprs/gtphub.o ../../src/gprs/gtphub.c:2191:1: fatal error: opening dependency file .deps/../../src/gprs/gtphub.Tpo: No such file or directory } ^ compilation terminated. make[3]: *** [../../src/gprs/gtphub.o] Error 1 make[3]: Leaving directory `/root/new_osmocom/openbsc/openbsc/tests/gtphub' make[2]: *** [all-recursive] Error 1 make[2]: Leaving directory `/root/new_osmocom/openbsc/openbsc/tests' make[1]: *** [all-recursive] Error 1 make[1]: Leaving directory `/root/new_osmocom/openbsc/openbsc' make: *** [all] Error 2 Do you have any idea why is this happening? Regards, Csaba From sipos.csaba at kvk.uni-obuda.hu Sat Nov 28 12:39:52 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Sat, 28 Nov 2015 13:39:52 +0100 (CET) Subject: OpenBSC compile error --> tests --> GTP hub In-Reply-To: <569979521.10869842.1448714119383.JavaMail.zimbra@kvk.uni-obuda.hu> References: <569979521.10869842.1448714119383.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <1456819885.10870106.1448714392116.JavaMail.zimbra@kvk.uni-obuda.hu> Sorry, it was the missing libc-ares-dev package. Its interesting because the configure script is recognising the missing package but not complaining about it, and it causes compile time issues. Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Sipos Csaba" C?mzett: nhofmeyr at sysmocom.de M?solatot kap: "OpenBSC Mailing List" Elk?ld?tt ?zenetek: Szombat, 2015. November 28. 13:35:19 T?rgy: OpenBSC compile error --> tests --> GTP hub Dear Neels, Today just grabbed the latest OpenBSC master, and got this compile error: Making all in gtphub make[3]: Entering directory `/root/new_osmocom/openbsc/openbsc/tests/gtphub' CC gtphub_test.o CC ../../src/gprs/gtphub.o ../../src/gprs/gtphub.c:2191:1: fatal error: opening dependency file .deps/../../src/gprs/gtphub.Tpo: No such file or directory } ^ compilation terminated. make[3]: *** [../../src/gprs/gtphub.o] Error 1 make[3]: Leaving directory `/root/new_osmocom/openbsc/openbsc/tests/gtphub' make[2]: *** [all-recursive] Error 1 make[2]: Leaving directory `/root/new_osmocom/openbsc/openbsc/tests' make[1]: *** [all-recursive] Error 1 make[1]: Leaving directory `/root/new_osmocom/openbsc/openbsc' make: *** [all] Error 2 Do you have any idea why is this happening? Regards, Csaba From holger at freyther.de Sat Nov 28 14:50:19 2015 From: holger at freyther.de (Holger Freyther) Date: Sat, 28 Nov 2015 15:50:19 +0100 Subject: OpenBSC compile error --> tests --> GTP hub In-Reply-To: <1456819885.10870106.1448714392116.JavaMail.zimbra@kvk.uni-obuda.hu> References: <569979521.10869842.1448714119383.JavaMail.zimbra@kvk.uni-obuda.hu> <1456819885.10870106.1448714392116.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: > On 28 Nov 2015, at 13:39, Sipos Csaba wrote: > > Sorry, it was the missing libc-ares-dev package. > > Its interesting because the configure script is recognising the missing package but not complaining about it, and it causes compile time issues. it shouldn't build the gtphub then. holger From sipos.csaba at kvk.uni-obuda.hu Sat Nov 28 15:07:19 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Sat, 28 Nov 2015 16:07:19 +0100 (CET) Subject: <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf In-Reply-To: <58410640.10876492.1448722401722.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <988124267.10877329.1448723239094.JavaMail.zimbra@kvk.uni-obuda.hu> Dear List, I am in the process of further updating the following Wiki article: The goal is to have a clean, up to date manual which tells in detail how to set up OpenBSC. In the light of recent changes I decided to change this already working setup to use the "master" branches of every involved Osmocom project. It is finally possible to compile and run every project after the proper dependencies are met. But some new problem popped up I haven't seen before. After everything is started up (OpenBSC, GGSN, SGSN, LCR, TRX, and PCU), when a phone tries to RACH, this is what I get in the BSC log: Sat Nov 28 14:09:08 2015 <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf Sat Nov 28 14:09:19 2015 <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0x6 Sat Nov 28 14:09:30 2015 <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0x6 On the BTS side, this is what I get: <0006> scheduler.c:1186 Received Access Burst on RACH fn=9868 toa=5.88 <0006> scheduler.c:1192 Received bad AB frame at fn=9868 (25/51) <0006> scheduler.c:1186 Received Access Burst on RACH fn=52459 toa=-1.50 <0006> scheduler.c:1192 Received bad AB frame at fn=52459 (31/51) <0006> scheduler.c:1186 Received Access Burst on RACH fn=67956 toa=-0.06 <0006> scheduler.c:1192 Received bad AB frame at fn=67956 (24/51) Because I used exactly the same config files I used before when it all worked, I analyzed the logs a littlebit more. In the BTS log, during the OML setup this is what I found: <0001> oml.c:802 ADM state already was Unlocked <0001> oml.c:256 OC=BASEBAND-TRANSCEIVER INST=(00,00,ff) OPER STATE NULL -> Enabled <0001> oml.c:217 OC=BASEBAND-TRANSCEIVER INST=(00,00,ff) Tx STATE CHG REP <000b> trx_if.c:366 Response message 'RSP ERR 1' does not match command message 'CMD SETBSIC 62' !!!!!! <0001> oml.c:1059 Rx IPA RSL CONNECT IP=127.0.0.1 PORT=3003 STREAM=0x00 <0011> input/ipa.c:129 connection done. <0011> input/ipaccess.c:693 received ID get <0000> rsl.c:279 Tx RSL RF RESource INDication Maybe the recent changes in the BSIC/TSC handling part is causing this? Anyway it seems that the BSIC I set in the BSC is the correct one the BTS tries to configure during the timeslot, transceiver and BTS setup. I attached the corresponding OML trace, and the logs. If someone has any ideas, please let me know. Regards, Csaba -------------- next part -------------- A non-text attachment was scrubbed... Name: oml_error_bsc.log Type: text/x-log Size: 2772 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: oml_log_v2.pcapng Type: application/octet-stream Size: 17824 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: oml_error_bts.log Type: text/x-log Size: 14603 bytes Desc: not available URL: From laforge at gnumonks.org Sat Nov 28 18:09:03 2015 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 28 Nov 2015 19:09:03 +0100 Subject: Using Gerrit for libosmocore/lib../OpenBSC? In-Reply-To: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> References: <74424E06-4311-49A1-B5D3-BCE1DE8D8A7B@freyther.de> Message-ID: <20151128180903.GD5011@nataraja> I have never really looked at gerrit in detail, but if my understanding is correct, it requires the use of a web-based interface? I really hate web-based intefaces, as they require an online connection. The way how I read and process e-mails is store-and-forward, and I often work on them while I'm offline (in a plane, on a train, ...) It's not that I'm not particularly known for doing most of the review in recent years, but I would consider a move to mandatory use such tools as somewhat of a step of "alienation" between the project and me. It's not that the number of submissions we're getting (at least so far) is _that_ lage that it's so easy to loose track of them. Rather, there are contribuions that are not merged as a) there's not sufficient time for senior project members like Holger or me to review, or b) the original submitter is not followin up (quickly) adressing changes by the maintainer(s), or c) code that exists in some branches which is never submitted to the list in the first place I don't expect any tools to help with the issues above :/ Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Sat Nov 28 17:54:30 2015 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 28 Nov 2015 18:54:30 +0100 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: <9F7EB648-8E99-47EF-BA9E-323C0550D7D8@freyther.de> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> <9F7EB648-8E99-47EF-BA9E-323C0550D7D8@freyther.de> Message-ID: <20151128175430.GC5011@nataraja> Hi all, On Wed, Nov 25, 2015 at 03:20:16PM +0100, Holger Freyther wrote: > That would be appreciated and help us making the decision if we want > to go with SMPP or a custom protocol. When there were customer > requests at sysmocom we had always quoted SMPP work. I think I could never figure out how to model the session-oriented properties of USSD on top of SMPP. I might have missed something and never really investigaed it all the way, but it seemed that SMPP can only be used for 'single shot' USSD transactions, rether than an USSD session with multiple messages. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From alexander.chemeris at gmail.com Sun Nov 29 03:47:38 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Sat, 28 Nov 2015 22:47:38 -0500 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: <20151128175430.GC5011@nataraja> References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> <9F7EB648-8E99-47EF-BA9E-323C0550D7D8@freyther.de> <20151128175430.GC5011@nataraja> Message-ID: On Sat, Nov 28, 2015 at 12:54 PM, Harald Welte wrote: > Hi all, > > On Wed, Nov 25, 2015 at 03:20:16PM +0100, Holger Freyther wrote: >> That would be appreciated and help us making the decision if we want >> to go with SMPP or a custom protocol. When there were customer >> requests at sysmocom we had always quoted SMPP work. > > I think I could never figure out how to model the session-oriented > properties of USSD on top of SMPP. I might have missed something and > never really investigaed it all the way, but it seemed that SMPP can > only be used for 'single shot' USSD transactions, rether than an USSD > session with multiple messages. To add to this discussion - one of the reasons we chose SUP over SMPP is that we're going to export other SS services as well. -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From alexander.chemeris at gmail.com Sun Nov 29 04:04:04 2015 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Sat, 28 Nov 2015 23:04:04 -0500 Subject: [PATCH 1/8] debug: Add DSS category for supplementary service In-Reply-To: References: <1448449439-10546-1-git-send-email-Sergey.Kostanbaev@moex.com> <2816DC58-20C7-48C7-A094-AA10FAAE8EF3@freyther.de> Message-ID: Hi Holger, On Wed, Nov 25, 2015 at 8:12 AM, Holger Freyther wrote: > >> On 25 Nov 2015, at 14:07, sergey kostanbaev wrote: >> >> Yes, initially I thought about using SMPP for USSD. But it looked really complicated since only few external SMPP libraries have support of USSD and most of that few are in C#/Java/etc. Moreover I didn't have any working software for USSD over SMPP to test interoperability with. > > Hmm. We try to follow standard protocol when they exist. Actually, our end goal is to support TS 124 390 or at least get close enough to it. When we discussed integration of SIP into OsmoNITB there was a strong opposition from you and Harald, so we were looking for the best way to export required functionality from OsmoNITB to avoid adding SIP into the OsmoNITB itself. Within this logic SMPP just adds overhead and extra complexity without offering any benefits. -- Regards, Alexander Chemeris. CEO, Fairwaves, Inc. https://fairwaves.co From sipos.csaba at kvk.uni-obuda.hu Sun Nov 29 16:30:48 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Sun, 29 Nov 2015 17:30:48 +0100 (CET) Subject: <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf In-Reply-To: <988124267.10877329.1448723239094.JavaMail.zimbra@kvk.uni-obuda.hu> References: <988124267.10877329.1448723239094.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <1830219613.10947596.1448814648043.JavaMail.zimbra@kvk.uni-obuda.hu> Just to further add to this issue: Both "fairwaves/master" and "201509-fairwaves-rebase" branches of Osmo-BTS are working fine (all other Osmocom projects are latest master), only the "master" branch of Osmo-BTS is affected with this issue. Because the 201509rebease is introducing a lot of important fixes and features (and it seems to be working fine), I am now changing the Wiki to suggest to use "master" for OpenBSC, and "201509-fairwaves-rebase" for Osmo-BTS, but maybe this would be a good time to finally get the projects in sync, so we can use the master branches for every projects onwards. Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Sipos Csaba" C?mzett: "OpenBSC Mailing List" Elk?ld?tt ?zenetek: Szombat, 2015. November 28. 16:07:19 T?rgy: <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf Dear List, I am in the process of further updating the following Wiki article: The goal is to have a clean, up to date manual which tells in detail how to set up OpenBSC. In the light of recent changes I decided to change this already working setup to use the "master" branches of every involved Osmocom project. It is finally possible to compile and run every project after the proper dependencies are met. But some new problem popped up I haven't seen before. After everything is started up (OpenBSC, GGSN, SGSN, LCR, TRX, and PCU), when a phone tries to RACH, this is what I get in the BSC log: Sat Nov 28 14:09:08 2015 <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf Sat Nov 28 14:09:19 2015 <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0x6 Sat Nov 28 14:09:30 2015 <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0x6 On the BTS side, this is what I get: <0006> scheduler.c:1186 Received Access Burst on RACH fn=9868 toa=5.88 <0006> scheduler.c:1192 Received bad AB frame at fn=9868 (25/51) <0006> scheduler.c:1186 Received Access Burst on RACH fn=52459 toa=-1.50 <0006> scheduler.c:1192 Received bad AB frame at fn=52459 (31/51) <0006> scheduler.c:1186 Received Access Burst on RACH fn=67956 toa=-0.06 <0006> scheduler.c:1192 Received bad AB frame at fn=67956 (24/51) Because I used exactly the same config files I used before when it all worked, I analyzed the logs a littlebit more. In the BTS log, during the OML setup this is what I found: <0001> oml.c:802 ADM state already was Unlocked <0001> oml.c:256 OC=BASEBAND-TRANSCEIVER INST=(00,00,ff) OPER STATE NULL -> Enabled <0001> oml.c:217 OC=BASEBAND-TRANSCEIVER INST=(00,00,ff) Tx STATE CHG REP <000b> trx_if.c:366 Response message 'RSP ERR 1' does not match command message 'CMD SETBSIC 62' !!!!!! <0001> oml.c:1059 Rx IPA RSL CONNECT IP=127.0.0.1 PORT=3003 STREAM=0x00 <0011> input/ipa.c:129 connection done. <0011> input/ipaccess.c:693 received ID get <0000> rsl.c:279 Tx RSL RF RESource INDication Maybe the recent changes in the BSIC/TSC handling part is causing this? Anyway it seems that the BSIC I set in the BSC is the correct one the BTS tries to configure during the timeslot, transceiver and BTS setup. I attached the corresponding OML trace, and the logs. If someone has any ideas, please let me know. Regards, Csaba From laforge at gnumonks.org Sun Nov 29 17:41:38 2015 From: laforge at gnumonks.org (Harald Welte) Date: Sun, 29 Nov 2015 18:41:38 +0100 Subject: <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf In-Reply-To: <1830219613.10947596.1448814648043.JavaMail.zimbra@kvk.uni-obuda.hu> References: <988124267.10877329.1448723239094.JavaMail.zimbra@kvk.uni-obuda.hu> <1830219613.10947596.1448814648043.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <20151129174138.GV5011@nataraja> Hi Sipos, On Sun, Nov 29, 2015 at 05:30:48PM +0100, Sipos Csaba wrote: > but maybe this would be a good time to finally get the projects in > sync, so we can use the master branches for every projects onwards. As indicated, I am waiting for the proponents and users of osmo-bts-trx to submit any fixes that they may have in other branches. I think I did my fair share by re-basing and brining forward the code, but that's all I could do. Submitting patches and maintaining a particular hardware port is always up to the users of that particular hardware, I think that's only fair. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Sun Nov 29 18:14:06 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sun, 29 Nov 2015 19:14:06 +0100 Subject: OpenBSC compile error --> tests --> GTP hub In-Reply-To: <1456819885.10870106.1448714392116.JavaMail.zimbra@kvk.uni-obuda.hu> References: <569979521.10869842.1448714119383.JavaMail.zimbra@kvk.uni-obuda.hu> <1456819885.10870106.1448714392116.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <20151129181406.GB7847@dub5> On Sat, Nov 28, 2015 at 01:39:52PM +0100, Sipos Csaba wrote: > Sorry, it was the missing libc-ares-dev package. > > Its interesting because the configure script is recognising the missing package but not complaining about it, and it causes compile time issues. I can reproduce the problem. Thanks for the heads up! I've fixed the build failure: the gtphub_test binary was being built, but gtphub.o was not (ff252bb80). However, I've noticed that the gtphub shows as FAILED instead of skipped, just like the sgsn and oap tests. The cause is: openbsc/tests/atlocal.in: enable_sgsn_test='@found_libgtp@' enable_gtphub_test='@found_libgtp@' It should be something like enable_sgsn_test='@found_libgtp@ and @found_libcares@' I'm not sure how best to achieve that. Maybe like this? [[[ --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -84,6 +84,12 @@ PKG_CHECK_MODULES([LIBCARES], [libcares], [], [found_libcares=no]) AM_CONDITIONAL(HAVE_LIBCARES, test "$found_libcares" = yes) AC_SUBST(found_libcares) +found_libgtp_and_libcares=no +if test "$found_libgtp" = "yes" -a "$found_libcares" = "yes"; then + found_libgtp_and_libcares=yes +fi +AC_SUBST(found_libgtp_and_libcares) + dnl checks for header files AC_HEADER_STDC AC_CHECK_HEADERS(dahdi/user.h,,AC_MSG_WARN(DAHDI input driver will not be built)) diff --git a/openbsc/tests/atlocal.in b/openbsc/tests/atlocal.in index 7475f63..362bfa9 100644 --- a/openbsc/tests/atlocal.in +++ b/openbsc/tests/atlocal.in @@ -2,5 +2,6 @@ enable_nat_test='@osmo_ac_build_nat@' enable_smpp_test='@osmo_ac_build_smpp@' enable_bsc_test='@osmo_ac_build_bsc@' enable_mgcp_transcoding_test='@osmo_ac_mgcp_transcoding@' -enable_sgsn_test='@found_libgtp@' -enable_gtphub_test='@found_libgtp@' +enable_sgsn_test='@found_libgtp_and_libcares@' +enable_oap_test='@found_libgtp_and_libcares@' +enable_gtphub_test='@found_libgtp_and_libcares@' ]]] And also, the OAP tests don't depend on GTP nor c-ares, but OAP compilation is currently closely tied to the SGSN binary. Is it worthwhile to separate at this point? Thanks! ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From sipos.csaba at kvk.uni-obuda.hu Sun Nov 29 21:30:39 2015 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Sun, 29 Nov 2015 22:30:39 +0100 (CET) Subject: <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf In-Reply-To: <20151129174138.GV5011@nataraja> References: <988124267.10877329.1448723239094.JavaMail.zimbra@kvk.uni-obuda.hu> <1830219613.10947596.1448814648043.JavaMail.zimbra@kvk.uni-obuda.hu> <20151129174138.GV5011@nataraja> Message-ID: <1752014888.10966100.1448832639922.JavaMail.zimbra@kvk.uni-obuda.hu> Dear Harald, > I think I did my fair share Nobody sais or implicates the opposite :-) I just put you on this mail because I thought maybe you have some ideas what might trigger an issue like this. The interesting part is that between the osmo-bts master and the fairwaves rebase branch there is not a lot of difference, and I do not see anything that can relate to an issue like this. Will continue to look at the code, maybe I can find what causes it. Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Harald Welte" C?mzett: "Sipos Csaba" M?solatot kap: "OpenBSC Mailing List" , "Alexander Chemeris" Elk?ld?tt ?zenetek: Vas?rnap, 2015. November 29. 18:41:38 T?rgy: Re: <0004> abis_rsl.c:1423 BTS 0 CHAN RQD: no resources for SDCCH 0xf Hi Sipos, On Sun, Nov 29, 2015 at 05:30:48PM +0100, Sipos Csaba wrote: > but maybe this would be a good time to finally get the projects in > sync, so we can use the master branches for every projects onwards. As indicated, I am waiting for the proponents and users of osmo-bts-trx to submit any fixes that they may have in other branches. I think I did my fair share by re-basing and brining forward the code, but that's all I could do. Submitting patches and maintaining a particular hardware port is always up to the users of that particular hardware, I think that's only fair. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Mon Nov 30 11:47:47 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 30 Nov 2015 12:47:47 +0100 Subject: [PATCH] gtphub: add to debian build In-Reply-To: References: <1448368818-21121-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20151130114747.GA1394@dub5> On Wed, Nov 25, 2015 at 09:23:37PM +0100, Holger Freyther wrote: > > On 24 Nov 2015, at 13:40, Neels Hofmeyr wrote: > > By the example of osmo-sgsn, package osmo-gtphub for debian. > you walked into an issue/inconcistency I created and we should fix to move forward. "Fixed" and merged to master. I left the others (osmocom-sgsn...) as they are. > the next change is to modify osmoappdesc.py so gtphub will get some of > the "automatic" VTY testing we have. Added awareness of it (in my head), added gtphub (in osmoappdesc.py) and merged to master. ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Nov 30 20:08:07 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 30 Nov 2015 21:08:07 +0100 Subject: Meas_web and meas_json In-Reply-To: <202801686.10432917.1448484764454.JavaMail.zimbra@kvk.uni-obuda.hu> References: <1510240027.5443523.1445891932058.JavaMail.zimbra@kvk.uni-obuda.hu> <1010582984.5443937.1445892326559.JavaMail.zimbra@kvk.uni-obuda.hu> <213728024.5449223.1445896264483.JavaMail.zimbra@kvk.uni-obuda.hu> <687363025.6773365.1446628686520.JavaMail.zimbra@kvk.uni-obuda.hu> <1503579201.10420115.1448476669036.JavaMail.zimbra@kvk.uni-obuda.hu> <202801686.10432917.1448484764454.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <20151130200807.GA2465@dub5> On Wed, Nov 25, 2015 at 09:52:44PM +0100, Sipos Csaba wrote: > My personal opinion is that the biggest miss of electrical engineering education (where telecommunication is "wired" to) is that it does not focus enough on actual coding. My studies' first half was Bachelor of Electric and Electronic Engineering in South Africa, second half Technische Informatik in Germany. I did learn how to code, but certainly not during my studies. For me it was mostly the accumulated knowledge of stupid mistakes made while tossing up more or less useless software as a teenager... :P The studies were mostly theoretical and could not provide that practice. ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Nov 30 21:07:49 2015 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 30 Nov 2015 22:07:49 +0100 Subject: [PATCH 3/3] gtphub: nr_map: add min,max and wrap. In-Reply-To: <56581B98.7000701@sysmocom.de> References: <1447767527-27316-1-git-send-email-nhofmeyr@sysmocom.de> <1447767527-27316-3-git-send-email-nhofmeyr@sysmocom.de> <20151126165152.GD3629@dub5> <56581B98.7000701@sysmocom.de> Message-ID: <20151130210749.GB2465@dub5> On Fri, Nov 27, 2015 at 10:00:08AM +0100, Jacob Erlbeck wrote: > On 26.11.2015 17:51, Neels Hofmeyr wrote: > > On Wed, Nov 25, 2015 at 09:05:40PM +0100, Holger Freyther wrote: > > >> E.g. a unit test that exhausts the entire number space should be > feasible. > > > > Really? 4.294.967.295 TEI mappings?? Thats 4*sizeof(mapping) gigabytes and > > might need special memory model options to work, and the testing > > machine needs that many gigs of ram and will take quite a while: O(n?)... > > I am fond of exhausting tests, too. I think it would be best to artificially limit the range to 1..16 to test exhaustion. We wouldn't have to run through 2^32 (!) mappings then. Let me outline the two number spaces again... There's the TEI space (32 bits of space), random per PDP context, and the sequence number space (16 bits of space), ++ per GTP Request. I really doubt that anyone will manage to exaust TEIs ("64 kilobytes of RAM ought to be enough for anyone!"), but I accept the argument, and the randomness, too. So for the TEIs, I have added code that runs through all the tunnels and ensures that a TEI is not mapped twice. If it is, the code tries to pick an unused TEI outside the seen min..max range of TEIs. But it can't yet reliably find open gaps in the middle, which would require having a sorted list. If no TEI guaranteed to be unused is found in that way, gtphub will abort(). (It could just drop packets instead, but maybe abort() is better until we have a test for it.) TEIs are so far picked sequentially, but should (TM) be picked randomly. Again, a sorted list would solve. Sequence numbers are different because - they time out after 30 seconds (I picked 30 seconds off the top of my head, haven't really searched for a timeout in the specs yet.) - they are specified to be sequential. Exhausting 65535 sequence numbers in 30 seconds sounds possible; note, this is a general limitation of GTP. If a packet is resent again and again with the same sequence number (common strategy when no reply is received), a given sequence mapping can linger for more than 30 seconds; but the retries should in turn cease within another 30 seconds or so. So on the one hand sequence nrs are more likely to wrap (space is only 2^16), on the other hand less likely to stick around. I'm not checking sequence nr collisions yet. Sequence numbers are supposed to be sequential, so for those, gtphub could remember the range of used sequence nrs as head..tail, and advance head as used ones are discarded. If a discarded number is != head, store that in a list; advance head, emptying the list as appropriate, once head is released (because of the sequential nature, that list would usually stay pretty short). If sequence numbers' tail catches up with head, the GTP space of pending responses is exhausted, and gtphub should probably drop any further requests to that peer until head has advanced (and ensure its timeout is valid or something). Any thoughts are welcome! BTW, the same situations can arise in osmo-sgsn and openggsn. While obsessing about this in gtphub, we should probably visit the others as well...? ;) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: