pax_global_header00006660000000000000000000000064126160710350014513gustar00rootroot0000000000000052 comment=efb9af4dada5e2426e69d670f4549f8fec3c9cb2 libosmo-netif-0.0.6/000077500000000000000000000000001261607103500142655ustar00rootroot00000000000000libosmo-netif-0.0.6/.gitignore000066400000000000000000000013741261607103500162620ustar00rootroot00000000000000Makefile Makefile.in .deps .libs *.o *.lo *.la *.pc aclocal.m4 acinclude.m4 aminclude.am m4/*.m4 autom4te.cache compile config.h* config.sub config.log config.status config.guess configure depcomp missing ltmain.sh install-sh stamp-h1 libtool .tarball-version .version tests/atconfig tests/package.m4 tests/testsuite tests/osmux/osmux_test tests/testsuite.log examples/channel/abis_ipa_stream_client examples/channel/abis_ipa_stream_server examples/ipa-stream-client examples/ipa-stream-server examples/lapd-over-datagram-network examples/lapd-over-datagram-user examples/osmux-test-input examples/osmux-test-output examples/rs232-read examples/rs232-write examples/rtp-udp-test-client examples/rtp-udp-test-server examples/stream-client examples/stream-server libosmo-netif-0.0.6/COPYING000066400000000000000000000431031261607103500153210ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. libosmo-netif-0.0.6/Makefile.am000066400000000000000000000005451261607103500163250ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 ACLOCAL_AMFLAGS = -I m4 SUBDIRS = include src examples tests pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libosmo-netif.pc EXTRA_DIST = .version BUILT_SOURCES = $(top_srcdir)/.version $(top_srcdir)/.version: echo $(VERSION) > $@-t && mv $@-t $@ dist-hook: echo $(VERSION) > $(distdir)/.tarball-version libosmo-netif-0.0.6/configure.ac000066400000000000000000000030551261607103500165560ustar00rootroot00000000000000AC_INIT([libosmo-netif], m4_esyscmd([./git-version-gen .tarball-version]), [openbsc-devel@lists.openbsc.org]) AM_INIT_AUTOMAKE([subdir-objects dist-bzip2]) AC_CONFIG_TESTDIR(tests) dnl kernel style compile messages m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) dnl checks for programs AC_PROG_MAKE_SET AC_PROG_CC AC_PROG_INSTALL LT_INIT AC_PROG_LIBTOOL AC_CONFIG_MACRO_DIR([m4]) dnl checks for header files AC_HEADER_STDC AC_CHECK_HEADERS(execinfo.h sys/select.h sys/socket.h syslog.h ctype.h) # The following test is taken from WebKit's webkit.m4 saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden " AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])], [ AC_MSG_RESULT([yes]) SYMBOL_VISIBILITY="-fvisibility=hidden"], AC_MSG_RESULT([no])) CFLAGS="$saved_CFLAGS" AC_SUBST(SYMBOL_VISIBILITY) dnl Generate the output AM_CONFIG_HEADER(config.h) PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.3.0) dnl FIXME: We depend on libosmoabis by now until we can move LAPD code here PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.0.7) PKG_CHECK_MODULES(ORTP, ortp >= 0.15.0) AC_CHECK_HEADERS(dahdi/user.h,,AC_MSG_WARN(DAHDI input driver will not be built)) AC_OUTPUT( libosmo-netif.pc include/Makefile include/osmocom/Makefile include/osmocom/netif/Makefile include/osmocom/netif/channel/Makefile src/Makefile src/channel/Makefile src/channel/abis/Makefile examples/Makefile examples/channel/Makefile tests/Makefile Makefile) libosmo-netif-0.0.6/debian/000077500000000000000000000000001261607103500155075ustar00rootroot00000000000000libosmo-netif-0.0.6/debian/changelog000066400000000000000000000020341261607103500173600ustar00rootroot00000000000000libosmo-netif (0.0.6) unstable; urgency=medium * Drop libosmovty dependency. -- Holger Hans Peter Freyther Tue, 03 Nov 2015 09:36:32 +0100 libosmo-netif (0.0.5) unstable; urgency=medium * New upstream release. -- Holger Hans Peter Freyther Sun, 23 Aug 2015 18:01:53 +0200 libosmo-netif (0.0.3) unstable; urgency=medium * Bump API due the AMR header structure now being packed and potentially having different storage requirements. -- Holger Hans Peter Freyther Mon, 28 Apr 2014 20:50:18 +0200 libosmo-netif (0.0.2-z6) unstable; urgency=low * Upgrade with increased test coverage. * More changes * Fix use after free issue. * Fix osmux_snprintf for multiple batched messages * Clean-ups. -- Holger Hans Peter Freyther Sat, 25 May 2013 09:42:30 +0200 libosmo-netif (0.0.2-z1) testing; urgency=low * Initial release. * Post 0.0.2 -- Holger Hans Peter Freyther Tue, 21 May 2013 18:53:08 +0200 libosmo-netif-0.0.6/debian/compat000066400000000000000000000000021261607103500167050ustar00rootroot000000000000009 libosmo-netif-0.0.6/debian/control000066400000000000000000000020741261607103500171150ustar00rootroot00000000000000Source: libosmo-netif Section: libs Priority: optional Maintainer: Holger Hans Peter Freyther Build-Depends: debhelper (>= 9), autotools-dev, autoconf, automake, libtool, dh-autoreconf, libdpkg-perl, git, libosmocore-dev, libosmo-abis-dev, pkg-config, libortp-dev Standards-Version: 3.9.6 Vcs-Git: git://git.osmocom.org/libosmo-netif.git Vcs-Browser: http://git.osmocom.org/gitweb?p=libosmo-netif.git;a=summary Package: libosmonetif2 Section: libs Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Multi-Arch: same Description: Library containing common/shared code regarding network interface Package: libosmo-netif-dev Section: libdevel Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore, libosmonetif2 (= ${binary:Version}) Multi-Arch: same Description: Development headers for Osmocom network interface Package: libosmo-netif-dbg Section: debug Architecture: any Priority: extra Depends: libosmonetif2 (= ${binary:Version}), ${misc:Depends} Multi-Arch: same Description: Debug symbols for Osmocom network interface libosmo-netif-0.0.6/debian/libosmo-netif-dev.install000066400000000000000000000001311261607103500224150ustar00rootroot00000000000000usr/include/* usr/lib/*/lib*.a usr/lib/*/lib*.so usr/lib/*/lib*.la usr/lib/*/pkgconfig/* libosmo-netif-0.0.6/debian/libosmonetif2.install000066400000000000000000000000351261607103500216510ustar00rootroot00000000000000usr/lib/*/libosmonetif*.so.* libosmo-netif-0.0.6/debian/rules000077500000000000000000000010411261607103500165630ustar00rootroot00000000000000#!/usr/bin/make -f DEBIAN := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2) DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1) VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g') #export DH_VERBOSE=1 export DEB_BUILD_HARDENING=1 %: dh $@ --with autoreconf --fail-missing override_dh_strip: dh_strip --dbg-package=libosmo-netif-dbg override_dh_autoreconf: echo $(VERSION) > .tarball-version dh_autoreconf override_dh_install: dh_install sed -i "/dependency_libs/ s/'.*'/''/" `find . -name '*.la'` libosmo-netif-0.0.6/debian/source/000077500000000000000000000000001261607103500170075ustar00rootroot00000000000000libosmo-netif-0.0.6/debian/source/format000066400000000000000000000000151261607103500202160ustar00rootroot000000000000003.0 (native) libosmo-netif-0.0.6/examples/000077500000000000000000000000001261607103500161035ustar00rootroot00000000000000libosmo-netif-0.0.6/examples/Makefile.am000066400000000000000000000045321261607103500201430ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) SUBDIRS = channel noinst_PROGRAMS = ipa-stream-client \ ipa-stream-server \ lapd-over-datagram-user \ lapd-over-datagram-network \ stream-client \ stream-server \ rs232-read \ rs232-write \ rtp-udp-test-client \ rtp-udp-test-server \ osmux-test-input \ osmux-test-output ipa_stream_client_SOURCES = ipa-stream-client.c ipa_stream_client_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) ipa_stream_server_SOURCES = ipa-stream-server.c ipa_stream_server_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) lapd_over_datagram_user_SOURCES = lapd-over-datagram-user.c lapd_over_datagram_user_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \ $(LIBOSMOABIS_LIBS) lapd_over_datagram_network_SOURCES = lapd-over-datagram-network.c lapd_over_datagram_network_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \ $(LIBOSMOABIS_LIBS) stream_client_SOURCES = stream-client.c stream_client_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) stream_server_SOURCES = stream-server.c stream_server_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) rs232_read_SOURCES = rs232-read.c rs232_read_LDADD = $(top_builddir)/src/libosmonetif.la $(LIBOSMOCORE_LIBS) rs232_write_SOURCES = rs232-write.c rs232_write_LDADD = $(top_builddir)/src/libosmonetif.la $(LIBOSMOCORE_LIBS) rtp_udp_test_client_SOURCES = rtp-udp-test-client.c rtp_udp_test_client_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) rtp_udp_test_server_SOURCES = rtp-udp-test-server.c rtp_udp_test_server_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) osmux_test_input_SOURCES = osmux-test-input.c osmux_test_input_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) osmux_test_output_SOURCES = osmux-test-output.c osmux_test_output_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) libosmo-netif-0.0.6/examples/channel/000077500000000000000000000000001261607103500175135ustar00rootroot00000000000000libosmo-netif-0.0.6/examples/channel/Makefile.am000066400000000000000000000011311261607103500215430ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) noinst_PROGRAMS = abis_ipa_stream_server \ abis_ipa_stream_client abis_ipa_stream_server_SOURCES = abis_ipa_stream_server.c abis_ipa_stream_server_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) abis_ipa_stream_client_SOURCES = abis_ipa_stream_client.c abis_ipa_stream_client_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) libosmo-netif-0.0.6/examples/channel/abis_ipa_stream_client.c000066400000000000000000000041231261607103500243370ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include static void *tall_example; #define DEXAMPLE 0 struct log_info_cat example_cat[] = { [DEXAMPLE] = { .name = "DEXAMPLE", .description = "example", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info example_log_info = { .filter_fn = NULL, .cat = example_cat, .num_cat = ARRAY_SIZE(example_cat), }; void sighandler(int foo) { LOGP(DEXAMPLE, LOGL_NOTICE, "closing test.\n"); exit(EXIT_SUCCESS); } static void signal_msg_cb(struct msgb *msg, int type) { LOGP(DEXAMPLE, LOGL_NOTICE, "received signal message\n"); } static struct osmo_chan *chan; int main(void) { struct osmo_ipa_unit *unit; tall_example = talloc_named_const(NULL, 1, "example"); osmo_init_logging(&example_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); /* initialize channel infrastructure. */ osmo_chan_init(tall_example); /* create channel. */ chan = osmo_chan_create(OSMO_CHAN_ABIS_IPA_CLI, OSMO_SUBCHAN_STREAM); if (chan == NULL) { LOGP(DEXAMPLE, LOGL_ERROR, "Cannot create A-bis IPA client\n"); exit(EXIT_FAILURE); } /* set specific parameters (depends on channel type). */ osmo_abis_ipa_cli_set_oml_addr(chan, "127.0.0.1"); osmo_abis_ipa_cli_set_rsl_addr(chan, "127.0.0.1"); unit = osmo_ipa_unit_alloc(0); if (unit == NULL) { LOGP(DEXAMPLE, LOGL_ERROR, "Cannot create IPA unit\n"); exit(EXIT_FAILURE); } osmo_ipa_unit_set_site_id(unit, 1801); osmo_abis_ipa_cli_set_unit(chan, unit); osmo_abis_ipa_cli_set_cb_signalmsg(chan, signal_msg_cb); /* open channel. */ if (osmo_chan_open(chan) < 0) { LOGP(DEXAMPLE, LOGL_ERROR, "Cannot create A-bis IPA client\n"); exit(EXIT_FAILURE); } LOGP(DEXAMPLE, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/channel/abis_ipa_stream_server.c000066400000000000000000000033661261607103500243770ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include static void *tall_example; #define DEXAMPLE 0 struct log_info_cat example_cat[] = { [DEXAMPLE] = { .name = "DEXAMPLE", .description = "example", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info example_log_info = { .filter_fn = NULL, .cat = example_cat, .num_cat = ARRAY_SIZE(example_cat), }; void sighandler(int foo) { LOGP(DEXAMPLE, LOGL_NOTICE, "closing test.\n"); exit(EXIT_SUCCESS); } static void signal_msg_cb(struct msgb *msg, int type) { LOGP(DEXAMPLE, LOGL_NOTICE, "received signal message\n"); } static struct osmo_chan *chan; int main(void) { tall_example = talloc_named_const(NULL, 1, "example"); osmo_init_logging(&example_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); /* initialize channel infrastructure. */ osmo_chan_init(tall_example); /* create channel. */ chan = osmo_chan_create(OSMO_CHAN_ABIS_IPA_SRV, OSMO_SUBCHAN_STREAM); if (chan == NULL) { LOGP(DEXAMPLE, LOGL_ERROR, "Cannot create A-bis IPA server\n"); exit(EXIT_FAILURE); } /* set specific parameters (depends on channel type). */ osmo_abis_ipa_srv_set_cb_signalmsg(chan, signal_msg_cb); osmo_abis_ipa_unit_add(chan, 1801, 0); /* open channel. */ if (osmo_chan_open(chan) < 0) { LOGP(DEXAMPLE, LOGL_ERROR, "Cannot create A-bis IPA server\n"); exit(EXIT_FAILURE); } LOGP(DEXAMPLE, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/ipa-stream-client.c000066400000000000000000000106321261607103500215670ustar00rootroot00000000000000/* IPA stream client example. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static LLIST_HEAD(msg_sent_list); struct msg_sent { struct llist_head head; struct msgb *msg; int num; struct timeval tv; }; #define DIPATEST 0 struct log_info_cat osmo_stream_client_test_cat[] = { [DIPATEST] = { .name = "DIPATEST", .description = "STREAMCLIENT-mode test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_NOTICE, }, }; const struct log_info osmo_stream_client_test_log_info = { .filter_fn = NULL, .cat = osmo_stream_client_test_cat, .num_cat = ARRAY_SIZE(osmo_stream_client_test_cat), }; static struct osmo_stream_cli *conn; void sighandler(int foo) { LOGP(DIPATEST, LOGL_NOTICE, "closing stream.\n"); exit(EXIT_SUCCESS); } static int connect_cb(struct osmo_stream_cli *conn) { int *__num_msgs = osmo_stream_cli_get_data(conn); int num_msgs = *__num_msgs, i; LOGP(DIPATEST, LOGL_NOTICE, "connected\n"); for (i=0; imsg = msg; gettimeofday(&msg_sent->tv, NULL); msg_sent->num = i; llist_add(&msg_sent->head, &msg_sent_list); osmo_ipa_msg_push_header(msg, IPAC_PROTO_OSMO); osmo_stream_cli_send(conn, msg); LOGP(DIPATEST, LOGL_DEBUG, "enqueueing msg %d of " "%d bytes to be sent\n", i, msg->len); } return 0; } static int read_cb(struct osmo_stream_cli *conn) { struct msgb *msg; LOGP(DIPATEST, LOGL_DEBUG, "received message from stream\n"); msg = osmo_ipa_msg_alloc(0); if (msg == NULL) { LOGP(DIPATEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } if (osmo_stream_cli_recv(conn, msg) <= 0) { LOGP(DIPATEST, LOGL_ERROR, "cannot receive message\n"); return 0; } if (osmo_ipa_process_msg(msg) < 0) { LOGP(DIPATEST, LOGL_ERROR, "bad IPA message\n"); return 0; } int num; struct msg_sent *cur, *tmp, *found = NULL; num = ntohl(*((int *)(msg->data + sizeof(struct ipa_head)))); LOGP(DLINP, LOGL_DEBUG, "received msg number %d\n", num); llist_for_each_entry_safe(cur, tmp, &msg_sent_list, head) { if (cur->num == num) { llist_del(&cur->head); found = cur; break; } } if (found) { struct timeval tv, diff; gettimeofday(&tv, NULL); timersub(&tv, &found->tv, &diff); LOGP(DLINP, LOGL_NOTICE, "message %d replied " "in %lu.%.6lu\n", num, diff.tv_sec, diff.tv_usec); talloc_free(found); } else { LOGP(DLINP, LOGL_ERROR, "message %d not found!\n", num); } return 0; } static void *tall_test; int main(int argc, char *argv[]) { int num_msgs; signal(SIGINT, sighandler); if (argc != 2) { printf("Usage: %s [num_msgs]\n", argv[0]); exit(EXIT_FAILURE); } num_msgs = atoi(argv[1]); tall_test = talloc_named_const(NULL, 1, "osmo_stream_client_test"); osmo_init_logging(&osmo_stream_client_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_NOTICE); /* * initialize stream client. */ conn = osmo_stream_cli_create(tall_test); if (conn == NULL) { fprintf(stderr, "cannot create client\n"); exit(EXIT_FAILURE); } osmo_stream_cli_set_addr(conn, "127.0.0.1"); osmo_stream_cli_set_port(conn, 10000); osmo_stream_cli_set_connect_cb(conn, connect_cb); osmo_stream_cli_set_read_cb(conn, read_cb); osmo_stream_cli_set_data(conn, &num_msgs); if (osmo_stream_cli_open(conn) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } int on = 1, ret; struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn); ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); if (ret < 0) { LOGP(DIPATEST, LOGL_ERROR, "cannot disable Nagle\n"); exit(EXIT_FAILURE); } LOGP(DIPATEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/ipa-stream-server.c000066400000000000000000000060711261607103500216210ustar00rootroot00000000000000/* IPA stream srv example */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void *tall_test; #define DSTREAMTEST 0 struct log_info_cat osmo_stream_srv_test_cat[] = { [DSTREAMTEST] = { .name = "DSTREAMTEST", .description = "STREAMSERVER-mode test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_NOTICE, }, }; const struct log_info osmo_stream_srv_test_log_info = { .filter_fn = NULL, .cat = osmo_stream_srv_test_cat, .num_cat = ARRAY_SIZE(osmo_stream_srv_test_cat), }; static struct osmo_stream_srv_link *srv; static struct osmo_stream_srv *conn; void sighandler(int foo) { LOGP(DSTREAMTEST, LOGL_NOTICE, "closing STREAMSERVER.\n"); exit(EXIT_SUCCESS); } int read_cb(struct osmo_stream_srv *conn) { struct msgb *msg; LOGP(DSTREAMTEST, LOGL_DEBUG, "received message from stream\n"); msg = osmo_ipa_msg_alloc(0); if (msg == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } if (osmo_stream_srv_recv(conn, msg) <= 0) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot receive message\n"); osmo_stream_srv_destroy(conn); msgb_free(msg); return 0; } if (osmo_ipa_process_msg(msg) < 0) { LOGP(DSTREAMTEST, LOGL_ERROR, "Bad IPA message\n"); msgb_free(msg); return 0; } osmo_stream_srv_send(conn, msg); return 0; } static int close_cb(struct osmo_stream_srv *dummy) { conn = NULL; return 0; } static int accept_cb(struct osmo_stream_srv_link *srv, int fd) { if (conn != NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "Sorry, this example only " "support one client simultaneously\n"); return -1; } conn = osmo_stream_srv_create(tall_test, srv, fd, read_cb, close_cb, NULL); if (conn == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "error while creating connection\n"); return -1; } return 0; } int main(void) { tall_test = talloc_named_const(NULL, 1, "osmo_stream_srv_test"); osmo_init_logging(&osmo_stream_srv_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_NOTICE); /* * initialize stream srv. */ srv = osmo_stream_srv_link_create(tall_test); if (srv == NULL) { fprintf(stderr, "cannot create client\n"); exit(EXIT_FAILURE); } osmo_stream_srv_link_set_addr(srv, "127.0.0.1"); osmo_stream_srv_link_set_port(srv, 10000); osmo_stream_srv_link_set_accept_cb(srv, accept_cb); int on = 1, ret; struct osmo_fd *ofd = osmo_stream_srv_link_get_ofd(srv); if (osmo_stream_srv_link_open(srv) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); if (ret < 0) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot disable Nagle\n"); exit(EXIT_FAILURE); } LOGP(DSTREAMTEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/lapd-over-datagram-network.c000066400000000000000000000101011261607103500233760ustar00rootroot00000000000000/* LAPD over datagram network-mode example. */ #include #include #include #include #include #include #include #include #include #include #include static void *tall_test; #define DLAPDTEST 0 struct log_info_cat lapd_test_cat[] = { [DLAPDTEST] = { .name = "DLAPDTEST", .description = "LAPD-mode test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info lapd_test_log_info = { .filter_fn = NULL, .cat = lapd_test_cat, .num_cat = ARRAY_SIZE(lapd_test_cat), }; static struct osmo_dgram *conn; static struct lapd_instance *lapd; static int sapi = 63, tei = 0; void sighandler(int foo) { lapd_instance_free(lapd); LOGP(DLAPDTEST, LOGL_NOTICE, "closing LAPD.\n"); exit(EXIT_SUCCESS); } int read_cb(struct osmo_dgram *conn) { int error; struct msgb *msg; LOGP(DLAPDTEST, LOGL_DEBUG, "received message from datagram\n"); msg = msgb_alloc(1200, "LAPD/test"); if (msg == NULL) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot allocate message\n"); return -1; } if (osmo_dgram_recv(conn, msg) < 0) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot receive message\n"); return -1; } if (lapd_receive(lapd, msg, &error) < 0) { LOGP(DLAPDTEST, LOGL_ERROR, "lapd_receive returned error!\n"); return -1; } return 0; } void lapd_tx_cb(struct msgb *msg, void *cbdata) { struct osmo_dgram *conn = cbdata; LOGP(DLAPDTEST, LOGL_DEBUG, "sending message over datagram\n"); osmo_dgram_send(conn, msg); } void lapd_rx_cb(struct osmo_dlsap_prim *dp, uint8_t tei, uint8_t sapi, void *rx_cbdata) { struct msgb *msg = dp->oph.msg; switch (dp->oph.primitive) { case PRIM_DL_EST: DEBUGP(DLAPDTEST, "DL_EST: sapi(%d) tei(%d)\n", sapi, tei); break; case PRIM_DL_REL: DEBUGP(DLAPDTEST, "DL_REL: sapi(%d) tei(%d)\n", sapi, tei); break; case PRIM_DL_DATA: case PRIM_DL_UNIT_DATA: if (dp->oph.operation == PRIM_OP_INDICATION) { struct msgb *nmsg; char *ptr; int x; msg->l2h = msg->l3h; DEBUGP(DLAPDTEST, "RX: %s sapi=%d tei=%d\n", osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)), sapi, tei); LOGP(DLAPDTEST, LOGL_DEBUG, "forwarding message\n"); nmsg = msgb_alloc(1024, "LAPD/test"); if (nmsg == NULL) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot alloc msg\n"); return; } ptr = (char *)msgb_put(nmsg, sizeof(int)); x = *((int *)msg->data); memcpy(ptr, &x, sizeof(int)); /* send the message back to client over LAPD */ lapd_transmit(lapd, tei, sapi, msg); return; } break; case PRIM_MDL_ERROR: DEBUGP(DLMI, "MDL_EERROR: cause(%d)\n", dp->u.error_ind.cause); break; default: printf("ERROR: unknown prim\n"); break; } } int main(int argc, char *argv[]) { int teip; tall_test = talloc_named_const(NULL, 1, "lapd_test"); osmo_init_logging(&lapd_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_NOTICE); /* * initialize datagram server. */ conn = osmo_dgram_create(tall_test); if (conn == NULL) { fprintf(stderr, "cannot create client\n"); exit(EXIT_FAILURE); } osmo_dgram_set_local_addr(conn, "127.0.0.1"); osmo_dgram_set_local_port(conn, 10001); osmo_dgram_set_remote_addr(conn, "127.0.0.1"); osmo_dgram_set_remote_port(conn, 10000); osmo_dgram_set_read_cb(conn, read_cb); lapd = lapd_instance_alloc(1, lapd_tx_cb, conn, lapd_rx_cb, conn, &lapd_profile_sat); if (lapd == NULL) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot allocate instance\n"); exit(EXIT_FAILURE); } teip = lapd_tei_alloc(lapd, tei); if (teip == 0) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot assign TEI\n"); exit(EXIT_FAILURE); } if (osmo_dgram_open(conn) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } LOGP(DLAPDTEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/lapd-over-datagram-user.c000066400000000000000000000124211261607103500226720ustar00rootroot00000000000000/* LAPD over datagram user-mode example. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static LLIST_HEAD(msg_sent_list); struct msg_sent { struct llist_head head; struct msgb *msg; int num; struct timeval tv; }; #define DLAPDTEST 0 struct log_info_cat lapd_test_cat[] = { [DLAPDTEST] = { .name = "DLAPDTEST", .description = "LAPD-mode test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info lapd_test_log_info = { .filter_fn = NULL, .cat = lapd_test_cat, .num_cat = ARRAY_SIZE(lapd_test_cat), }; static struct osmo_dgram *conn; static struct lapd_instance *lapd; static int sapi = 63, tei = 0; void sighandler(int foo) { lapd_sap_stop(lapd, tei, sapi); lapd_instance_free(lapd); LOGP(DLINP, LOGL_NOTICE, "closing LAPD.\n"); exit(EXIT_SUCCESS); } static int read_cb(struct osmo_dgram *conn) { int error; struct msgb *msg; msg = msgb_alloc(1200, "LAPD/test"); if (msg == NULL) { LOGP(DLAPDTEST, LOGL_ERROR, "cannot allocate message\n"); return -1; } if (osmo_dgram_recv(conn, msg) < 0) { msgb_free(msg); LOGP(DLAPDTEST, LOGL_ERROR, "cannot receive message\n"); return -1; } if (lapd_receive(lapd, msg, &error) < 0) { msgb_free(msg); LOGP(DLINP, LOGL_ERROR, "lapd_receive returned error!\n"); return -1; } return 0; } static void *tall_test; void lapd_tx_cb(struct msgb *msg, void *cbdata) { LOGP(DLINP, LOGL_DEBUG, "sending message over datagram\n"); osmo_dgram_send(conn, msg); } void lapd_rx_cb(struct osmo_dlsap_prim *dp, uint8_t tei, uint8_t sapi, void *rx_cbdata) { struct msgb *msg = dp->oph.msg; int *__msgs = rx_cbdata; int num_msgs = *__msgs; switch (dp->oph.primitive) { case PRIM_DL_EST: DEBUGP(DLAPDTEST, "DL_EST: sapi(%d) tei(%d)\n", sapi, tei); int i; for (i=0; imsg = msg; gettimeofday(&msg_sent->tv, NULL); msg_sent->num = i; llist_add(&msg_sent->head, &msg_sent_list); lapd_transmit(lapd, tei, sapi, msg); LOGP(DLAPDTEST, LOGL_DEBUG, "enqueueing msg %d of " "%d bytes to be sent over LAPD\n", i, msg->len); } break; case PRIM_DL_REL: DEBUGP(DLAPDTEST, "DL_REL: sapi(%d) tei(%d)\n", sapi, tei); break; case PRIM_DL_DATA: case PRIM_DL_UNIT_DATA: if (dp->oph.operation == PRIM_OP_INDICATION) { msg->l2h = msg->l3h; DEBUGP(DLAPDTEST, "RX: %s sapi=%d tei=%d\n", osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)), sapi, tei); int num; struct msg_sent *cur, *tmp, *found = NULL; num = ntohl(*((int *)msg->data)); LOGP(DLINP, LOGL_DEBUG, "received msg number %d\n", num); llist_for_each_entry_safe(cur, tmp, &msg_sent_list, head) { if (cur->num == num) { llist_del(&cur->head); found = cur; break; } } if (found) { struct timeval tv, diff; gettimeofday(&tv, NULL); timersub(&tv, &found->tv, &diff); LOGP(DLINP, LOGL_NOTICE, "message %d replied " "in %lu.%.6lu\n", num, diff.tv_sec, diff.tv_usec); talloc_free(found); } else { LOGP(DLINP, LOGL_ERROR, "message %d not found!\n", num); } } break; case PRIM_MDL_ERROR: DEBUGP(DLMI, "MDL_EERROR: cause(%d)\n", dp->u.error_ind.cause); break; default: printf("ERROR: unknown prim\n"); break; } } int main(int argc, char *argv[]) { int num_msgs; signal(SIGINT, sighandler); if (argc != 2) { printf("Usage: %s [num_msgs]\n", argv[0]); exit(EXIT_FAILURE); } num_msgs = atoi(argv[1]); tall_test = talloc_named_const(NULL, 1, "lapd_test"); osmo_init_logging(&lapd_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_NOTICE); /* * initialize LAPD stuff. */ lapd = lapd_instance_alloc(0, lapd_tx_cb, NULL, lapd_rx_cb, &num_msgs, &lapd_profile_sat); if (lapd == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot allocate instance\n"); exit(EXIT_FAILURE); } /* * initialize datagram socket. */ conn = osmo_dgram_create(tall_test); if (conn == NULL) { fprintf(stderr, "cannot create client\n"); exit(EXIT_FAILURE); } osmo_dgram_set_local_addr(conn, "127.0.0.1"); osmo_dgram_set_local_port(conn, 10000); osmo_dgram_set_remote_addr(conn, "127.0.0.1"); osmo_dgram_set_remote_port(conn, 10001); osmo_dgram_set_read_cb(conn, read_cb); if (osmo_dgram_open(conn) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } if (lapd_sap_start(lapd, tei, sapi) < 0) { LOGP(DLINP, LOGL_ERROR, "cannot start user-side LAPD\n"); exit(EXIT_FAILURE); } LOGP(DLINP, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/osmux-test-input.c000066400000000000000000000126421261607103500215410ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DOSMUX_TEST 0 struct log_info_cat osmux_test_cat[] = { [DOSMUX_TEST] = { .name = "DOSMUX_TEST", .description = "osmux test input", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info osmux_test_log_info = { .filter_fn = NULL, .cat = osmux_test_cat, .num_cat = ARRAY_SIZE(osmux_test_cat), }; static int fd; static void amr_open(void) { fd = open("/tmp/input.amr", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } write(fd, "#!AMR\n", strlen("#!AMR\n")); } static void amr_close(void) { close(fd); } static void amr_write(struct msgb *msg) { struct rtp_hdr *rtph; void *amr; unsigned int len; /* as described by rfc4867, see page 35 */ rtph = osmo_rtp_get_hdr(msg); amr = osmo_rtp_get_payload(rtph, msg, &len); write(fd, (uint8_t *)amr + 1, len - 1); } static struct osmo_dgram *conn; static struct osmo_rtp_handle *rtp; static void osmux_deliver(struct msgb *batch_msg, void *data) { char buf[1024]; osmux_snprintf(buf, sizeof(buf), batch_msg); LOGP(DOSMUX_TEST, LOGL_DEBUG, "sending batch (len=%d): %s\n", batch_msg->len, buf); osmo_dgram_send(conn, batch_msg); } /* * This is the input handle for osmux. It stores the last osmux sequence that * has been used and the deliver function that sends the osmux batch. */ struct osmux_in_handle h_input = { .osmux_seq = 0, /* sequence number to start OSmux message from */ .batch_factor = 4, /* batch up to 4 RTP messages */ .deliver = osmux_deliver, }; #define MAX_CONCURRENT_CALLS 8 static int ccid[MAX_CONCURRENT_CALLS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; static int get_ccid(uint32_t ssrc) { int i, found = 0; for (i=0; ipayload_type); if (rtph->payload_type == RTP_PT_AMR) amr_write(msg); char buf[1024]; osmo_rtp_snprintf(buf, sizeof(buf), msg); LOGP(DOSMUX_TEST, LOGL_DEBUG, "received RTP (len=%d): %s\n", msg->len, buf); ccid = get_ccid(rtph->ssrc); if (ccid < 0) register_ccid(rtph->ssrc); while ((ret = osmux_xfrm_input(&h_input, msg, ccid)) > 0) { /* batch full, deliver it */ osmux_xfrm_input_deliver(&h_input); } if (ret == -1) printf("something is wrong\n"); return 0; } void sighandler(int foo) { LOGP(DOSMUX_TEST, LOGL_NOTICE, "closing test.\n"); osmo_dgram_close(conn); osmo_dgram_destroy(conn); osmo_rtp_handle_free(rtp); amr_close(); exit(EXIT_SUCCESS); } static void *tall_test; /* * This is the output handle for osmux, it stores last RTP sequence and * timestamp that has been used. There should be one per circuit ID. */ int main(int argc, char *argv[]) { amr_open(); signal(SIGINT, sighandler); tall_test = talloc_named_const(NULL, 1, "osmux_test"); osmo_init_logging(&osmux_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); /* * initialize RTP handler. */ rtp = osmo_rtp_handle_create(tall_test); if (rtp == NULL) { LOGP(DOSMUX_TEST, LOGL_ERROR, "Error init RTP handler\n"); exit(EXIT_FAILURE); } osmo_rtp_handle_tx_set_sequence(rtp, random()); osmo_rtp_handle_tx_set_ssrc(rtp, random()); osmo_rtp_handle_tx_set_timestamp(rtp, time(NULL)); /* * initialize OSMUX handlers. */ osmux_xfrm_input_init(&h_input); /* * initialize datagram server. */ conn = osmo_dgram_create(tall_test); if (conn == NULL) { LOGP(DOSMUX_TEST, LOGL_ERROR, "cannot create UDP socket\n"); exit(EXIT_FAILURE); } osmo_dgram_set_local_addr(conn, "127.0.0.1"); osmo_dgram_set_local_port(conn, 20000); osmo_dgram_set_remote_addr(conn, "127.0.0.1"); osmo_dgram_set_remote_port(conn, 20001); osmo_dgram_set_read_cb(conn, read_cb); if (osmo_dgram_open(conn) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } LOGP(DOSMUX_TEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/osmux-test-output.c000066400000000000000000000100511261607103500217320ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DOSMUX_TEST 0 struct log_info_cat osmux_test_cat[] = { [DOSMUX_TEST] = { .name = "DOSMUX_TEST", .description = "osmux test output", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info osmux_test_log_info = { .filter_fn = NULL, .cat = osmux_test_cat, .num_cat = ARRAY_SIZE(osmux_test_cat), }; static struct osmo_dgram *conn; static struct osmo_rtp_handle *rtp; /* * This is the output handle for osmux, it stores last RTP sequence and * timestamp that has been used. There should be one per circuit ID. */ static struct osmux_out_handle h_output; static int fd; static void amr_open(void) { fd = open("/tmp/output.amr", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); exit(1); } write(fd, "#!AMR\n", strlen("#!AMR\n")); } static void amr_close(void) { close(fd); } static void amr_write(struct msgb *msg) { struct rtp_hdr *rtph; void *amr; unsigned int len; rtph = osmo_rtp_get_hdr(msg); amr = osmo_rtp_get_payload(rtph, msg, &len); write(fd, (uint8_t *)amr + 1, len - 1); } static void tx_cb(struct msgb *msg, void *data) { char buf[4096]; osmo_rtp_snprintf(buf, sizeof(buf), msg); LOGP(DOSMUX_TEST, LOGL_DEBUG, "sending: %s\n", buf); osmo_dgram_send(conn, msg); amr_write(msg); } int read_cb(struct osmo_dgram *conn) { struct msgb *msg; struct osmux_hdr *osmuxh; struct llist_head list; LOGP(DOSMUX_TEST, LOGL_DEBUG, "received message from datagram\n"); msg = msgb_alloc(RTP_MSGB_SIZE, "OSMUX/test"); if (msg == NULL) { LOGP(DOSMUX_TEST, LOGL_ERROR, "cannot allocate message\n"); return -1; } if (osmo_dgram_recv(conn, msg) < 0) { LOGP(DOSMUX_TEST, LOGL_ERROR, "cannot receive message\n"); return -1; } char buf[1024]; osmux_snprintf(buf, sizeof(buf), msg); LOGP(DOSMUX_TEST, LOGL_DEBUG, "received OSMUX message (len=%d) %s\n", msg->len, buf); while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) { osmux_xfrm_output(osmuxh, &h_output, &list); osmux_tx_sched(&list, tx_cb, NULL); } return 0; } void sighandler(int foo) { LOGP(DOSMUX_TEST, LOGL_NOTICE, "closing OSMUX.\n"); osmo_dgram_close(conn); osmo_dgram_destroy(conn); osmo_rtp_handle_free(rtp); amr_close(); exit(EXIT_SUCCESS); } static void *tall_test; /* * This is the output handle for osmux, it stores last RTP sequence and * timestamp that has been used. There should be one per circuit ID. */ int main(int argc, char *argv[]) { amr_open(); signal(SIGINT, sighandler); tall_test = talloc_named_const(NULL, 1, "osmux_test"); osmo_init_logging(&osmux_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); /* * initialize RTP handler. */ rtp = osmo_rtp_handle_create(tall_test); if (rtp == NULL) { LOGP(DOSMUX_TEST, LOGL_ERROR, "Error init OSMUX handler\n"); exit(EXIT_FAILURE); } osmo_rtp_handle_tx_set_sequence(rtp, random()); osmo_rtp_handle_tx_set_ssrc(rtp, random()); osmo_rtp_handle_tx_set_timestamp(rtp, time(NULL)); /* * initialize OSMUX handlers. */ osmux_xfrm_output_init(&h_output, random()); /* * initialize datagram server. */ conn = osmo_dgram_create(tall_test); if (conn == NULL) { LOGP(DOSMUX_TEST, LOGL_ERROR, "cannot create UDP socket\n"); exit(EXIT_FAILURE); } osmo_dgram_set_local_addr(conn, "127.0.0.1"); osmo_dgram_set_local_port(conn, 20001); osmo_dgram_set_remote_addr(conn, "127.0.0.1"); osmo_dgram_set_remote_port(conn, 20002); osmo_dgram_set_read_cb(conn, read_cb); if (osmo_dgram_open(conn) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } LOGP(DOSMUX_TEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/rs232-read.c000066400000000000000000000037151261607103500200410ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #define DRS232TEST 0 struct log_info_cat osmo_rs232_test_cat[] = { [DRS232TEST] = { .name = "DRS232TEST", .description = "rs232 test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info osmo_rs232_test_log_info = { .filter_fn = NULL, .cat = osmo_rs232_test_cat, .num_cat = ARRAY_SIZE(osmo_rs232_test_cat), }; static struct osmo_rs232 *r; void sighandler(int foo) { LOGP(DRS232TEST, LOGL_NOTICE, "closing rs232.\n"); osmo_rs232_close(r); osmo_rs232_destroy(r); exit(EXIT_SUCCESS); } static int read_cb(struct osmo_rs232 *r) { struct msgb *msg; LOGP(DRS232TEST, LOGL_DEBUG, "received data from rs232\n"); msg = msgb_alloc(1024, "rs232/test"); if (msg == NULL) { LOGP(DRS232TEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } if (osmo_rs232_read(r, msg) < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot read from rs232\n"); return 0; } LOGP(DRS232TEST, LOGL_DEBUG, "received %d bytes\n", msg->len); printf("%s", msg->data); msgb_free(msg); return 0; } static void *tall_test; int main(void) { tall_test = talloc_named_const(NULL, 1, "osmo_rs232_test"); osmo_init_logging(&osmo_rs232_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_NOTICE); r = osmo_rs232_create(tall_test); if (r == NULL) { LOGP(DRS232TEST, LOGL_ERROR, "cannot create rs232 object\n"); exit(EXIT_FAILURE); } osmo_rs232_set_serial_port(r, "/dev/ttyACM0"); osmo_rs232_set_baudrate(r, 9600); osmo_rs232_set_read_cb(r, read_cb); if (osmo_rs232_open(r) < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot open rs232\n"); exit(EXIT_FAILURE); } LOGP(DRS232TEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/rs232-write.c000066400000000000000000000216471261607103500202640ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #define DRS232TEST 0 struct log_info_cat osmo_rs232_test_cat[] = { [DRS232TEST] = { .name = "DRS232TEST", .description = "rs232 test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info osmo_rs232_test_log_info = { .filter_fn = NULL, .cat = osmo_rs232_test_cat, .num_cat = ARRAY_SIZE(osmo_rs232_test_cat), }; static struct osmo_rs232 *r; void sighandler(int foo) { LOGP(DRS232TEST, LOGL_NOTICE, "closing rs232.\n"); osmo_rs232_close(r); osmo_rs232_destroy(r); exit(EXIT_SUCCESS); } static int read_cb(struct osmo_rs232 *r) { struct msgb *msg; LOGP(DRS232TEST, LOGL_DEBUG, "received data from rs232\n"); msg = msgb_alloc(1024, "rs232/test"); if (msg == NULL) { LOGP(DRS232TEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } if (osmo_rs232_read(r, msg) < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot receive message\n"); return 0; } LOGP(DRS232TEST, LOGL_DEBUG, "received %d bytes\n", msg->len); printf("received %d bytes ", msg->len); int i; printf("("); for (i=0; ilen; i++) printf("\\x%.2x", 0xff & msg->data[i]); printf(") %s\n", msg->data); msgb_free(msg); return 0; } static void *tall_test; /* u-blox6_ReceiverDescriptionProtocolSpec_(GPS.G6-SW-10018).pdf */ /* See Sect 23. */ struct ubx_hdr { uint8_t sync_char1; /* 0xb5 */ uint8_t sync_char2; /* 0x62 */ uint8_t class; uint8_t id; } __attribute__((packed)); static void ubx_header(struct msgb *msg, uint8_t class, uint8_t id) { /* See Sect. 31.24 */ struct ubx_hdr ubxhdr = { .sync_char1 = 0xb5, .sync_char2 = 0x62, .class = class, .id = id, }; memcpy(msg->data, &ubxhdr, sizeof(struct ubx_hdr)); msgb_put(msg, sizeof(struct ubx_hdr)); } /* See Sect 26. */ static void ubx_checksum(struct msgb *msg, uint8_t *ck) { struct ubx_hdr *ubxhdr = (struct ubx_hdr *)msg->data; /* skip sync chars in checksum calculation. */ uint8_t *buf = ((uint8_t *)ubxhdr) + 2; int i; memset(ck, 0, sizeof(uint16_t)); for (i=0; ilen-2; i++) { ck[0] += buf[i]; ck[1] += ck[0]; } } # if OSMO_IS_LITTLE_ENDIAN # define utohl(x) (x) # define utohs(x) (x) # define htoul(x) (x) # define htous(x) (x) # else # if OSMO_IS_BIG_ENDIAN # define utohl(x) __bswap_32 (x) # define utohs(x) __bswap_16 (x) # define htoul(x) __bswap_32 (x) # define htous(x) __bswap_16 (x) # endif # endif static void ubx_payload_start(struct msgb *msg) { uint16_t len = 0; /* make room for payload length. */ memcpy(msg->data + msg->len, &len, sizeof(len)); msgb_put(msg, sizeof(len)); } static void ubx_payload_put_u8(struct msgb *msg, uint8_t data) { memcpy(msg->data + msg->len, &data, sizeof(data)); msgb_put(msg, sizeof(data)); } static void ubx_payload_put_le16(struct msgb *msg, uint16_t data) { uint16_t le_data = htous(data); memcpy(msg->data + msg->len, &le_data, sizeof(data)); msgb_put(msg, sizeof(data)); } static void ubx_payload_put_le32(struct msgb *msg, uint32_t data) { uint32_t le_data = htoul(data); memcpy(msg->data + msg->len, &le_data, sizeof(data)); msgb_put(msg, sizeof(data)); } static void ubx_payload_stop(struct msgb *msg) { uint16_t *length = (uint16_t *) &(msg->data[4]); uint8_t checksum[2]; /* length does not includes the header, ID, length. * note that checksum has not been yet added. */ *length = htous(msg->len - 6); ubx_checksum(msg, checksum); memcpy(msg->data + msg->len, checksum, sizeof(checksum)); msgb_put(msg, sizeof(checksum)); } static void cfg_prt(void) { struct msgb *msg; msg = msgb_alloc(512, "CFG-PRT for USB"); if (msg == NULL) exit(EXIT_FAILURE); ubx_header(msg, 0x06, 0x00); /* CFG-PRT */ ubx_payload_start(msg); ubx_payload_put_u8(msg, 0x03); /* Port ID is (=3 USB). */ ubx_payload_put_u8(msg, 0x00); /* Reserved. */ ubx_payload_put_le16(msg, 0x0000); /* TX ready. */ ubx_payload_put_le32(msg, 0x00000000); /* Reserved. */ ubx_payload_put_le32(msg, 0x00000000); /* Reserved. */ ubx_payload_put_le16(msg, 0x0003); /* InProtoMask (NMEA+UBX). */ ubx_payload_put_le16(msg, 0x0001); /* OutProtoMask (UBX). */ ubx_payload_put_le16(msg, 0x0000); /* Flags. */ ubx_payload_put_le16(msg, 0x0000); /* Reserved. */ ubx_payload_stop(msg); int i; for (i=0; ilen; i++) printf("\\x%.2x", 0xff & msg->data[i]); printf("\n"); if (osmo_rs232_write(r, msg) < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n"); exit(EXIT_FAILURE); } } static int nmea_checksum(char *nmea_cmd, uint8_t *checksum) { int i, ret = 0; uint8_t from, to; char *start, *end; /* find starting $ */ start = strtok(nmea_cmd, "$"); if (start == NULL) return -1; from = start - nmea_cmd; end = strtok(start+1, "*"); if (end == NULL) return -1; to = end - nmea_cmd; ret = (uint8_t)nmea_cmd[0]; for (i=from+1; idata, nmea_cmd, strlen(nmea_cmd)); msgb_put(msg, strlen(nmea_cmd)); if (osmo_rs232_write(r, msg) < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n"); exit(EXIT_FAILURE); } } static void cfg_tp5(void) { struct msgb *msg; msg = msgb_alloc(512, "CFG-TP5 for USB"); if (msg == NULL) exit(EXIT_FAILURE); ubx_header(msg, 0x06, 0x31); /* CFG-TP5 */ ubx_payload_start(msg); ubx_payload_put_u8(msg, 0x01); /* TIMEPULSE2 (=1) */ ubx_payload_put_u8(msg, 0x00); /* Reserved. */ ubx_payload_put_le16(msg, 0x0000); /* Reserved. */ ubx_payload_put_le16(msg, 0); /* Antenna Delay (ns) */ ubx_payload_put_le16(msg, 0); /* RF Group Delay (ns) */ ubx_payload_put_le32(msg, 8192000); /* freqPeriod (Hz/us) */ ubx_payload_put_le32(msg, 8192000); /* freqPeriodLoc (Hz/us) */ ubx_payload_put_le32(msg, 0x80000000); /* pulseLenRation: 1/2^-32 (us() */ ubx_payload_put_le32(msg, 0x80000000); /* pulseLenRationLock: 1/2^-32 (us() */ ubx_payload_put_le32(msg, 0); /* userConfigDelay (ns) */ ubx_payload_put_le32(msg, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)); /* flags: bits 0, 1 and 3. */ ubx_payload_stop(msg); int i; for (i=0; ilen; i++) printf("\\x%.2x", 0xff & msg->data[i]); printf("\n"); if (osmo_rs232_write(r, msg) < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n"); exit(EXIT_FAILURE); } } static int kbd_cb(struct osmo_fd *fd, unsigned int what) { char buf[1024]; int ret, val; ret = read(STDIN_FILENO, buf, sizeof(buf)); if (ret < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot write to read from " "keyboard\n"); exit(EXIT_FAILURE); } val = atoi(buf); switch(val) { case 1: printf("sending command PUBX to switch to UBX mode\n"); send_pubx(); break; case 2: printf("sending command TP5\n"); cfg_tp5(); break; case 3: printf("sending command CFG-PRT\n"); cfg_prt(); break; default: printf("wrong option: select 1, 2 or 3\n"); break; } return 0; } int main(void) { struct osmo_fd *kbd_ofd; tall_test = talloc_named_const(NULL, 1, "osmo_rs232_test"); osmo_init_logging(&osmo_rs232_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_NOTICE); r = osmo_rs232_create(tall_test); if (r == NULL) { LOGP(DRS232TEST, LOGL_ERROR, "cannot create rs232 object\n"); exit(EXIT_FAILURE); } osmo_rs232_set_serial_port(r, "/dev/ttyACM0"); osmo_rs232_set_baudrate(r, 9600); osmo_rs232_set_delay_us(r, 3330); osmo_rs232_set_read_cb(r, read_cb); if (osmo_rs232_open(r) < 0) { LOGP(DRS232TEST, LOGL_ERROR, "cannot open rs232\n"); exit(EXIT_FAILURE); } LOGP(DRS232TEST, LOGL_NOTICE, "Entering main loop\n"); kbd_ofd = talloc_zero(tall_test, struct osmo_fd); if (!kbd_ofd) { LOGP(DRS232TEST, LOGL_ERROR, "OOM\n"); exit(EXIT_FAILURE); } kbd_ofd->fd = STDIN_FILENO; kbd_ofd->when = BSC_FD_READ; kbd_ofd->data = NULL; kbd_ofd->cb = kbd_cb; osmo_fd_register(kbd_ofd); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/rtp-udp-test-client.c000066400000000000000000000061601261607103500220760ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DRTP_TEST 0 struct log_info_cat rtp_test_cat[] = { [DRTP_TEST] = { .name = "DRTP_TEST", .description = "RTP client test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info rtp_test_log_info = { .filter_fn = NULL, .cat = rtp_test_cat, .num_cat = ARRAY_SIZE(rtp_test_cat), }; static struct osmo_dgram *conn; static struct osmo_rtp_handle *rtp; static int read_cb(struct osmo_dgram *conn) { struct msgb *msg; struct rtp_hdr *rtph; LOGP(DLINP, LOGL_DEBUG, "received message\n"); msg = msgb_alloc(RTP_MSGB_SIZE, "RTP/test"); if (msg == NULL) { LOGP(DRTP_TEST, LOGL_ERROR, "cannot allocate message\n"); return -1; } if (osmo_dgram_recv(conn, msg) < 0) { msgb_free(msg); LOGP(DRTP_TEST, LOGL_ERROR, "cannot receive message\n"); return -1; } rtph = osmo_rtp_get_hdr(msg); if (rtph == NULL) { msgb_free(msg); LOGP(DRTP_TEST, LOGL_ERROR, "cannot parse RTP message\n"); return -1; } LOGP(DLINP, LOGL_DEBUG, "received message with payload type: %d\n", rtph->payload_type); msgb_free(msg); return 0; } void sighandler(int foo) { LOGP(DLINP, LOGL_NOTICE, "closing RTP.\n"); osmo_dgram_close(conn); osmo_dgram_destroy(conn); osmo_rtp_handle_free(rtp); exit(EXIT_SUCCESS); } static void *tall_test; int main(int argc, char *argv[]) { int i; char dummy_data[RTP_PT_GSM_FULL_PAYLOAD_LEN] = "payload test"; signal(SIGINT, sighandler); tall_test = talloc_named_const(NULL, 1, "rtp_test"); osmo_init_logging(&rtp_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); /* * initialize RTP stuff. */ rtp = osmo_rtp_handle_create(tall_test); if (rtp == NULL) { LOGP(DLINP, LOGL_ERROR, "creating RTP handler\n"); exit(EXIT_FAILURE); } osmo_rtp_handle_tx_set_sequence(rtp, random()); osmo_rtp_handle_tx_set_ssrc(rtp, random()); osmo_rtp_handle_tx_set_timestamp(rtp, time(NULL)); /* * initialize datagram socket. */ conn = osmo_dgram_create(tall_test); if (conn == NULL) { fprintf(stderr, "cannot create client\n"); exit(EXIT_FAILURE); } osmo_dgram_set_local_addr(conn, "127.0.0.1"); osmo_dgram_set_local_port(conn, 20001); osmo_dgram_set_remote_addr(conn, "127.0.0.1"); osmo_dgram_set_remote_port(conn, 20000); osmo_dgram_set_read_cb(conn, read_cb); if (osmo_dgram_open(conn) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } for(i=0; i<10; i++) { struct msgb *msg; msg = osmo_rtp_build(rtp, RTP_PT_GSM_FULL, RTP_PT_GSM_FULL_PAYLOAD_LEN, dummy_data, RTP_PT_GSM_FULL_DURATION); if (msg == NULL) { LOGP(DLINP, LOGL_ERROR, "OOM\n"); continue; } osmo_dgram_send(conn, msg); } LOGP(DLINP, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/rtp-udp-test-server.c000066400000000000000000000065161261607103500221330ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #define DRTP_TEST 0 struct log_info_cat rtp_test_cat[] = { [DRTP_TEST] = { .name = "DRTP_TEST", .description = "RPT-server test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info rtp_test_log_info = { .filter_fn = NULL, .cat = rtp_test_cat, .num_cat = ARRAY_SIZE(rtp_test_cat), }; static struct osmo_dgram *conn; static struct osmo_rtp_handle *rtp; int read_cb(struct osmo_dgram *conn) { struct msgb *msg; char dummy_data[RTP_PT_GSM_FULL_PAYLOAD_LEN] = "payload test"; struct rtp_hdr *rtph; LOGP(DRTP_TEST, LOGL_DEBUG, "received message from datagram\n"); msg = msgb_alloc(RTP_MSGB_SIZE, "RTP/test"); if (msg == NULL) { LOGP(DRTP_TEST, LOGL_ERROR, "cannot allocate message\n"); return -1; } if (osmo_dgram_recv(conn, msg) < 0) { LOGP(DRTP_TEST, LOGL_ERROR, "cannot receive message\n"); return -1; } rtph = osmo_rtp_get_hdr(msg); if (rtph == NULL) { msgb_free(msg); LOGP(DRTP_TEST, LOGL_ERROR, "cannot parse RTP message\n"); return -1; } LOGP(DLINP, LOGL_DEBUG, "received message with RTP payload type: %d\n", rtph->payload_type); /* * ... now build gsm_data_frame, set callref and msg_type based * on the rtp payload type (map RTP_PT_GSM_FULL to GSM_THCF_FRAME). * Then, pass it to the RSL layer. */ msg = msgb_alloc(1200, "RTP/test"); if (msg == NULL) { LOGP(DRTP_TEST, LOGL_ERROR, "cannot allocate message\n"); return -1; } /* build reply. */ msg = osmo_rtp_build(rtp, RTP_PT_GSM_FULL, RTP_PT_GSM_FULL_PAYLOAD_LEN, dummy_data, RTP_PT_GSM_FULL_DURATION); if (msg == NULL) { LOGP(DLINP, LOGL_ERROR, "OOM\n"); return -1; } osmo_dgram_send(conn, msg); return 0; } void sighandler(int foo) { LOGP(DLINP, LOGL_NOTICE, "closing RTP.\n"); osmo_dgram_close(conn); osmo_dgram_destroy(conn); osmo_rtp_handle_free(rtp); exit(EXIT_SUCCESS); } static void *tall_test; int main(int argc, char *argv[]) { signal(SIGINT, sighandler); tall_test = talloc_named_const(NULL, 1, "udp_rtp_test"); osmo_init_logging(&rtp_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); /* * initialize RTP handler. */ rtp = osmo_rtp_handle_create(tall_test); if (rtp == NULL) { LOGP(DRTP_TEST, LOGL_ERROR, "Error init RTP handler\n"); exit(EXIT_FAILURE); } osmo_rtp_handle_tx_set_sequence(rtp, random()); osmo_rtp_handle_tx_set_ssrc(rtp, random()); osmo_rtp_handle_tx_set_timestamp(rtp, time(NULL)); /* * initialize datagram server. */ conn = osmo_dgram_create(tall_test); if (conn == NULL) { LOGP(DRTP_TEST, LOGL_ERROR, "cannot create UDP socket\n"); exit(EXIT_FAILURE); } osmo_dgram_set_local_addr(conn, "127.0.0.1"); osmo_dgram_set_local_port(conn, 20000); osmo_dgram_set_remote_addr(conn, "127.0.0.1"); osmo_dgram_set_remote_port(conn, 20001); osmo_dgram_set_read_cb(conn, read_cb); if (osmo_dgram_open(conn) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } LOGP(DRTP_TEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/stream-client.c000066400000000000000000000057171261607103500210300ustar00rootroot00000000000000/* stream client example. */ #include #include #include #include #include #include #include #include #include #include #define DSTREAMTEST 0 struct log_info_cat osmo_stream_cli_test_cat[] = { [DSTREAMTEST] = { .name = "DSTREAMTEST", .description = "STREAMCLIENT-mode test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info osmo_stream_cli_test_log_info = { .filter_fn = NULL, .cat = osmo_stream_cli_test_cat, .num_cat = ARRAY_SIZE(osmo_stream_cli_test_cat), }; static struct osmo_stream_cli *conn; void sighandler(int foo) { LOGP(DSTREAMTEST, LOGL_NOTICE, "closing stream.\n"); exit(EXIT_SUCCESS); } static int connect_cb(struct osmo_stream_cli *conn) { LOGP(DSTREAMTEST, LOGL_NOTICE, "connected\n"); return 0; } static int read_cb(struct osmo_stream_cli *conn) { struct msgb *msg; LOGP(DSTREAMTEST, LOGL_NOTICE, "received message from stream\n"); msg = msgb_alloc(1024, "STREAMCLIENT/test"); if (msg == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } if (osmo_stream_cli_recv(conn, msg) < 0) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot receive message\n"); return 0; } msgb_free(msg); return 0; } static void *tall_test; static int kbd_cb(struct osmo_fd *fd, unsigned int what) { char buf[1024]; struct msgb *msg; uint8_t *ptr; int ret; ret = read(STDIN_FILENO, buf, sizeof(buf)); LOGP(DSTREAMTEST, LOGL_NOTICE, "read %d byte from keyboard\n", ret); msg = msgb_alloc(1024, "STREAMCLIENT/test"); if (msg == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } ptr = msgb_put(msg, strlen(buf)); memcpy(ptr, buf, ret); osmo_stream_cli_send(conn, msg); LOGP(DSTREAMTEST, LOGL_NOTICE, "message of %d bytes sent\n", msg->len); return 0; } int main(void) { struct osmo_fd *kbd_ofd; tall_test = talloc_named_const(NULL, 1, "osmo_stream_cli_test"); osmo_init_logging(&osmo_stream_cli_test_log_info); log_set_log_level(osmo_stderr_target, 1); /* * initialize stream cli. */ conn = osmo_stream_cli_create(tall_test); if (conn == NULL) { fprintf(stderr, "cannot create cli\n"); exit(EXIT_FAILURE); } osmo_stream_cli_set_addr(conn, "127.0.0.1"); osmo_stream_cli_set_port(conn, 10000); osmo_stream_cli_set_connect_cb(conn, connect_cb); osmo_stream_cli_set_read_cb(conn, read_cb); if (osmo_stream_cli_open(conn) < 0) { fprintf(stderr, "cannot open cli\n"); exit(EXIT_FAILURE); } kbd_ofd = talloc_zero(tall_test, struct osmo_fd); if (!kbd_ofd) { LOGP(DSTREAMTEST, LOGL_ERROR, "OOM\n"); exit(EXIT_FAILURE); } kbd_ofd->fd = STDIN_FILENO; kbd_ofd->when = BSC_FD_READ; kbd_ofd->data = conn; kbd_ofd->cb = kbd_cb; osmo_fd_register(kbd_ofd); LOGP(DSTREAMTEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/examples/stream-server.c000066400000000000000000000067041261607103500210550ustar00rootroot00000000000000/* stream server example */ #include #include #include #include #include #include #include #include #include #include static void *tall_test; #define DSTREAMTEST 0 struct log_info_cat osmo_stream_srv_test_cat[] = { [DSTREAMTEST] = { .name = "DSTREAMTEST", .description = "STREAMSERVER-mode test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info osmo_stream_srv_test_log_info = { .filter_fn = NULL, .cat = osmo_stream_srv_test_cat, .num_cat = ARRAY_SIZE(osmo_stream_srv_test_cat), }; static struct osmo_stream_srv_link *srv; static struct osmo_stream_srv *conn; void sighandler(int foo) { LOGP(DSTREAMTEST, LOGL_NOTICE, "closing STREAMSERVER.\n"); exit(EXIT_SUCCESS); } int read_cb(struct osmo_stream_srv *conn) { struct msgb *msg; LOGP(DSTREAMTEST, LOGL_NOTICE, "received message from stream\n"); msg = msgb_alloc(1024, "STREAMSERVER/test"); if (msg == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } if (osmo_stream_srv_recv(conn, msg) < 0) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot receive message\n"); return 0; } msgb_free(msg); return 0; } static int close_cb(struct osmo_stream_srv *dummy) { conn = NULL; return 0; } static int accept_cb(struct osmo_stream_srv_link *srv, int fd) { if (conn != NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "Sorry, this example only " "support one client simultaneously\n"); return -1; } conn = osmo_stream_srv_create(tall_test, srv, fd, read_cb, close_cb, NULL); if (conn == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "error while creating connection\n"); return -1; } return 0; } static int kbd_cb(struct osmo_fd *fd, unsigned int what) { char buf[1024]; struct msgb *msg; uint8_t *ptr; int ret; ret = read(STDIN_FILENO, buf, sizeof(buf)); LOGP(DSTREAMTEST, LOGL_NOTICE, "read %d byte from keyboard\n", ret); if (conn == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "no client, skipping\n"); return 0; } msg = msgb_alloc(1024, "osmo_stream_srv_test"); if (msg == NULL) { LOGP(DSTREAMTEST, LOGL_ERROR, "cannot allocate message\n"); return 0; } ptr = msgb_put(msg, strlen(buf)); memcpy(ptr, buf, strlen(buf)); osmo_stream_srv_send(conn, msg); LOGP(DSTREAMTEST, LOGL_NOTICE, "message of %d bytes sent\n", msg->len); return 0; } int main(void) { struct osmo_fd *kbd_ofd; tall_test = talloc_named_const(NULL, 1, "osmo_stream_srv_test"); osmo_init_logging(&osmo_stream_srv_test_log_info); log_set_log_level(osmo_stderr_target, 1); /* * initialize stream srv. */ srv = osmo_stream_srv_link_create(tall_test); if (srv == NULL) { fprintf(stderr, "cannot create client\n"); exit(EXIT_FAILURE); } osmo_stream_srv_link_set_addr(srv, "127.0.0.1"); osmo_stream_srv_link_set_port(srv, 10000); osmo_stream_srv_link_set_accept_cb(srv, accept_cb); if (osmo_stream_srv_link_open(srv) < 0) { fprintf(stderr, "cannot open client\n"); exit(EXIT_FAILURE); } kbd_ofd = talloc_zero(tall_test, struct osmo_fd); if (!kbd_ofd) { LOGP(DSTREAMTEST, LOGL_ERROR, "OOM\n"); exit(EXIT_FAILURE); } kbd_ofd->fd = STDIN_FILENO; kbd_ofd->when = BSC_FD_READ; kbd_ofd->data = srv; kbd_ofd->cb = kbd_cb; osmo_fd_register(kbd_ofd); LOGP(DSTREAMTEST, LOGL_NOTICE, "Entering main loop\n"); while(1) { osmo_select_main(0); } } libosmo-netif-0.0.6/git-version-gen000077500000000000000000000125001261607103500172260ustar00rootroot00000000000000#!/bin/sh # Print a version string. scriptversion=2010-01-28.01 # Copyright (C) 2007-2010 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. # It may be run two ways: # - from a git repository in which the "git describe" command below # produces useful output (thus requiring at least one signed tag) # - from a non-git-repo directory containing a .tarball-version file, which # presumes this script is invoked like "./git-version-gen .tarball-version". # In order to use intra-version strings in your project, you will need two # separate generated version string files: # # .tarball-version - present only in a distribution tarball, and not in # a checked-out repository. Created with contents that were learned at # the last time autoconf was run, and used by git-version-gen. Must not # be present in either $(srcdir) or $(builddir) for git-version-gen to # give accurate answers during normal development with a checked out tree, # but must be present in a tarball when there is no version control system. # Therefore, it cannot be used in any dependencies. GNUmakefile has # hooks to force a reconfigure at distribution time to get the value # correct, without penalizing normal development with extra reconfigures. # # .version - present in a checked-out repository and in a distribution # tarball. Usable in dependencies, particularly for files that don't # want to depend on config.h but do want to track version changes. # Delete this file prior to any autoconf run where you want to rebuild # files to pick up a version string change; and leave it stale to # minimize rebuild time after unrelated changes to configure sources. # # It is probably wise to add these two files to .gitignore, so that you # don't accidentally commit either generated file. # # Use the following line in your configure.ac, so that $(VERSION) will # automatically be up-to-date each time configure is run (and note that # since configure.ac no longer includes a version string, Makefile rules # should not depend on configure.ac for version updates). # # AC_INIT([GNU project], # m4_esyscmd([build-aux/git-version-gen .tarball-version]), # [bug-project@example]) # # Then use the following lines in your Makefile.am, so that .version # will be present for dependencies, and so that .tarball-version will # exist in distribution tarballs. # # BUILT_SOURCES = $(top_srcdir)/.version # $(top_srcdir)/.version: # echo $(VERSION) > $@-t && mv $@-t $@ # dist-hook: # echo $(VERSION) > $(distdir)/.tarball-version case $# in 1) ;; *) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;; esac tarball_version_file=$1 nl=' ' # First see if there is a tarball-only version file. # then try "git describe", then default. if test -f $tarball_version_file then v=`cat $tarball_version_file` || exit 1 case $v in *$nl*) v= ;; # reject multi-line output [0-9]*) ;; *) v= ;; esac test -z "$v" \ && echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2 fi if test -n "$v" then : # use $v elif v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \ || git describe --abbrev=4 HEAD 2>/dev/null` \ && case $v in [0-9]*) ;; v[0-9]*) ;; *) (exit 1) ;; esac then # Is this a new git that lists number of commits since the last # tag or the previous older version that did not? # Newer: v6.10-77-g0f8faeb # Older: v6.10-g0f8faeb case $v in *-*-*) : git describe is okay three part flavor ;; *-*) : git describe is older two part flavor # Recreate the number of commits and rewrite such that the # result is the same as if we were using the newer version # of git describe. vtag=`echo "$v" | sed 's/-.*//'` numcommits=`git rev-list "$vtag"..HEAD | wc -l` v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; ;; esac # Change the first '-' to a '.', so version-comparing tools work properly. # Remove the "g" in git describe's output string, to save a byte. v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`; else v=UNKNOWN fi v=`echo "$v" |sed 's/^v//'` # Don't declare a version "dirty" merely because a time stamp has changed. git status > /dev/null 2>&1 dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty= case "$dirty" in '') ;; *) # Append the suffix only if there isn't one already. case $v in *-dirty) ;; *) v="$v-dirty" ;; esac ;; esac # Omit the trailing newline, so that m4_esyscmd can use the result directly. echo "$v" | tr -d '\012' # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: libosmo-netif-0.0.6/include/000077500000000000000000000000001261607103500157105ustar00rootroot00000000000000libosmo-netif-0.0.6/include/Makefile.am000066400000000000000000000000201261607103500177340ustar00rootroot00000000000000SUBDIRS=osmocom libosmo-netif-0.0.6/include/osmocom/000077500000000000000000000000001261607103500173645ustar00rootroot00000000000000libosmo-netif-0.0.6/include/osmocom/Makefile.am000066400000000000000000000000161261607103500214150ustar00rootroot00000000000000SUBDIRS=netif libosmo-netif-0.0.6/include/osmocom/netif/000077500000000000000000000000001261607103500204715ustar00rootroot00000000000000libosmo-netif-0.0.6/include/osmocom/netif/Makefile.am000066400000000000000000000003461261607103500225300ustar00rootroot00000000000000SUBDIRS = channel osmonetif_HEADERS = amr.h \ channel.h \ datagram.h \ osmux.h \ ipa.h \ ipa_unit.h \ rs232.h \ rtp.h \ stream.h osmonetifdir = $(includedir)/osmocom/netif libosmo-netif-0.0.6/include/osmocom/netif/amr.h000066400000000000000000000036251261607103500214270ustar00rootroot00000000000000#ifndef _OSMO_AMR_H_ #define _OSMO_AMR_H_ #include /* As defined by RFC3267: Adaptive Multi-Rate (AMR) */ /* * +----------------+-------------------+---------------- * | payload header | table of contents | speech data ... * +----------------+-------------------+---------------- */ /* * 4.4. Octet-aligned Mode: * * 4.4.1. The Payload Header: * * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * | CMR |X X X X| * +-+-+-+-+-+-+-+-+ * * According to: 3GPP TS 26.201 "AMR Wideband speech codec; Frame Structure", * version 5.0.0 (2001-03), 3rd Generation Partnership Project (3GPP): * * Possible Frame type / CMR values: * * 0-8 for AMR-WB (from 6.60 kbit/s to 23.85 kbit/s) * 9 (SID) confort noise. * 10-13 future use. * 14 means lost speech frame (only available for AMR-WB) * 15 means no data * * 4.4.2. The table of contents: * * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |F| FT |Q|X X| * +-+-+-+-+-+-+-+-+ * * X means padding. */ struct amr_hdr { #if OSMO_IS_BIG_ENDIAN /* Payload Header */ uint8_t cmr:4, /* Codec Mode Request */ pad1:4; /* Table of Contents */ uint8_t f:1, /* followed by another speech frame? */ ft:4, /* coding mode */ q:1, /* OK (not damaged) at origin? */ pad2:2; #elif OSMO_IS_LITTLE_ENDIAN /* Payload Header */ uint8_t pad1:4, cmr:4; /* Table of Contents */ uint8_t pad2:2, q:1, ft:4, f:1; #endif } __attribute__((packed)); static inline void *osmo_amr_get_payload(struct amr_hdr *amrh) { return (uint8_t *)amrh + sizeof(struct amr_hdr); } #define AMR_FT_0 0 /* 4.75 */ #define AMR_FT_1 1 /* 5.15 */ #define AMR_FT_2 2 /* 5.90 */ #define AMR_FT_3 3 /* 6.70 */ #define AMR_FT_4 4 /* 7.40 */ #define AMR_FT_5 5 /* 7.95 */ #define AMR_FT_6 6 /* 10.2 */ #define AMR_FT_7 7 /* 12.2 */ #define AMR_FT_SID 8 /* SID */ #define AMR_FT_MAX 9 int osmo_amr_ft_valid(uint8_t amr_ft); size_t osmo_amr_bytes(uint8_t amr_cmr); #endif libosmo-netif-0.0.6/include/osmocom/netif/channel.h000066400000000000000000000017531261607103500222600ustar00rootroot00000000000000#ifndef _CHANNEL_H_ #define _CHANNEL_H_ #include /* channel types */ enum { OSMO_CHAN_NONE, OSMO_CHAN_ABIS_IPA_SRV, OSMO_CHAN_ABIS_IPA_CLI, OSMO_CHAN_MAX, }; /* channel subtypes */ enum { OSMO_SUBCHAN_STREAM, OSMO_SUBCHAN_MAX, }; struct osmo_chan; struct msgb; struct osmo_chan_type { struct llist_head head; char *name; int type; int subtype; int datasiz; int (*create)(struct osmo_chan *chan); void (*destroy)(struct osmo_chan *chan); int (*open)(struct osmo_chan *chan); void (*close)(struct osmo_chan *chan); int (*enqueue)(struct osmo_chan *chan, struct msgb *msg); }; struct osmo_chan { void *ctx; struct osmo_chan_type *ops; char data[0]; }; void osmo_chan_init(void *ctx); struct osmo_chan *osmo_chan_create(int type, int subtype); void osmo_chan_destroy(struct osmo_chan *c); int osmo_chan_open(struct osmo_chan *c); void osmo_chan_close(struct osmo_chan *c); int osmo_chan_enqueue(struct osmo_chan *c, struct msgb *msg); #endif /* _CHANNEL_H_ */ libosmo-netif-0.0.6/include/osmocom/netif/channel/000077500000000000000000000000001261607103500221015ustar00rootroot00000000000000libosmo-netif-0.0.6/include/osmocom/netif/channel/Makefile.am000066400000000000000000000001741261607103500241370ustar00rootroot00000000000000osmonetif_channel_HEADERS = abis_ipa_server.h abis_ipa_client.h osmonetif_channeldir = $(includedir)/osmocom/netif/channel libosmo-netif-0.0.6/include/osmocom/netif/channel/abis_ipa_client.h000066400000000000000000000011531261607103500253570ustar00rootroot00000000000000#ifndef _OSMO_ABIS_IPA_CLIENT_H_ #define _OSMO_ABIS_IPA_CLIENT_H_ struct osmo_ipa_unit; void osmo_abis_ipa_cli_set_oml_addr(struct osmo_chan *c, const char *addr); void osmo_abis_ipa_cli_set_oml_port(struct osmo_chan *c, uint16_t port); void osmo_abis_ipa_cli_set_rsl_addr(struct osmo_chan *c, const char *addr); void osmo_abis_ipa_cli_set_rsl_port(struct osmo_chan *c, uint16_t port); void osmo_abis_ipa_cli_set_unit(struct osmo_chan *c, struct osmo_ipa_unit *unit); void osmo_abis_ipa_cli_set_cb_signalmsg(struct osmo_chan *c, void (*signal_msg)(struct msgb *msg, int type)); #endif /* _OSMO_ABIS_IPA_CLIENT_H_ */ libosmo-netif-0.0.6/include/osmocom/netif/channel/abis_ipa_server.h000066400000000000000000000010601261607103500254040ustar00rootroot00000000000000#ifndef _ABIS_IPA_SERVER_H_ #define _ABIS_IPA_SERVER_H_ void osmo_abis_ipa_srv_set_oml_addr(struct osmo_chan *c, const char *addr); void osmo_abis_ipa_srv_set_oml_port(struct osmo_chan *c, uint16_t port); void osmo_abis_ipa_srv_set_rsl_addr(struct osmo_chan *c, const char *addr); void osmo_abis_ipa_srv_set_rsl_port(struct osmo_chan *c, uint16_t port); void osmo_abis_ipa_srv_set_cb_signalmsg(struct osmo_chan *c, void (*signal_msg)(struct msgb *msg, int type)); int osmo_abis_ipa_unit_add(struct osmo_chan *c, uint16_t site_id, uint16_t bts_id); #endif libosmo-netif-0.0.6/include/osmocom/netif/datagram.h000066400000000000000000000037221261607103500224260ustar00rootroot00000000000000#ifndef _OSMO_DGRAM_H_ #define _OSMO_DGRAM_H_ struct osmo_dgram_tx; struct osmo_dgram_tx *osmo_dgram_tx_create(void *crx); void osmo_dgram_tx_destroy(struct osmo_dgram_tx *conn); void osmo_dgram_tx_set_addr(struct osmo_dgram_tx *conn, const char *addr); void osmo_dgram_tx_set_port(struct osmo_dgram_tx *conn, uint16_t port); void osmo_dgram_tx_set_data(struct osmo_dgram_tx *conn, void *data); int osmo_dgram_tx_open(struct osmo_dgram_tx *conn); void osmo_dgram_tx_close(struct osmo_dgram_tx *conn); void osmo_dgram_tx_send(struct osmo_dgram_tx *conn, struct msgb *msg); struct osmo_dgram_rx; struct osmo_dgram_rx *osmo_dgram_rx_create(void *crx); void osmo_dgram_rx_set_addr(struct osmo_dgram_rx *conn, const char *addr); void osmo_dgram_rx_set_port(struct osmo_dgram_rx *conn, uint16_t port); void osmo_dgram_rx_set_read_cb(struct osmo_dgram_rx *conn, int (*read_cb)(struct osmo_dgram_rx *conn)); void osmo_dgram_rx_destroy(struct osmo_dgram_rx *conn); int osmo_dgram_rx_open(struct osmo_dgram_rx *conn); void osmo_dgram_rx_close(struct osmo_dgram_rx *conn); int osmo_dgram_rx_recv(struct osmo_dgram_rx *conn, struct msgb *msg); struct osmo_dgram; struct osmo_dgram *osmo_dgram_create(void *crx); void osmo_dgram_destroy(struct osmo_dgram *conn); int osmo_dgram_open(struct osmo_dgram *conn); void osmo_dgram_close(struct osmo_dgram *conn); void osmo_dgram_set_local_addr(struct osmo_dgram *conn, const char *addr); void osmo_dgram_set_remote_addr(struct osmo_dgram *conn, const char *addr); void osmo_dgram_set_local_port(struct osmo_dgram *conn, uint16_t port); void osmo_dgram_set_remote_port(struct osmo_dgram *conn, uint16_t port); void osmo_dgram_set_read_cb(struct osmo_dgram *conn, int (*read_cb)(struct osmo_dgram *conn)); void osmo_dgram_set_data(struct osmo_dgram *conn, void *data); void *osmo_dgram_get_data(struct osmo_dgram *conn); void osmo_dgram_send(struct osmo_dgram *conn, struct msgb *msg); int osmo_dgram_recv(struct osmo_dgram *conn, struct msgb *msg); #endif libosmo-netif-0.0.6/include/osmocom/netif/ipa.h000066400000000000000000000041221261607103500214120ustar00rootroot00000000000000#ifndef _OSMO_NETIF_IPA_H_ #define _OSMO_NETIF_IPA_H_ struct ipa_head { uint16_t len; /* network byte order */ uint8_t proto; uint8_t data[0]; } __attribute__ ((packed)); /* IPA protocols. */ #define IPAC_PROTO_RSL 0x00 #define IPAC_PROTO_IPACCESS 0xfe #define IPAC_PROTO_SCCP 0xfd #define IPAC_PROTO_OML 0xff #define IPAC_PROTO_OSMO 0xee /* OpenBSC extension. */ #define IPAC_PROTO_MGCP_OLD 0xfc /* OpenBSC extension. */ struct ipa_head_ext { uint8_t proto; uint8_t data[0]; } __attribute__ ((packed)); /* Protocol extensions. */ #define IPAC_PROTO_EXT_CTRL 0x00 #define IPAC_PROTO_EXT_MGCP 0x01 #define IPAC_PROTO_EXT_LAC 0x02 /* Message types. */ #define IPAC_MSGT_PING 0x00 #define IPAC_MSGT_PONG 0x01 #define IPAC_MSGT_ID_GET 0x04 #define IPAC_MSGT_ID_RESP 0x05 #define IPAC_MSGT_ID_ACK 0x06 #define IPAC_MSGT_SCCP_OLD 0xff /* OpenBSC extension */ enum ipaccess_id_tags { IPAC_IDTAG_SERNR = 0x00, IPAC_IDTAG_UNITNAME = 0x01, IPAC_IDTAG_LOCATION1 = 0x02, IPAC_IDTAG_LOCATION2 = 0x03, IPAC_IDTAG_EQUIPVERS = 0x04, IPAC_IDTAG_SWVERSION = 0x05, IPAC_IDTAG_IPADDR = 0x06, IPAC_IDTAG_MACADDR = 0x07, IPAC_IDTAG_UNIT = 0x08, }; struct msgb *osmo_ipa_msg_alloc(int headroom); void osmo_ipa_msg_push_header(struct msgb *msg, uint8_t proto); int osmo_ipa_process_msg(struct msgb *msg); struct ipaccess_unit { uint16_t site_id; uint16_t bts_id; uint16_t trx_id; char *unit_name; char *equipvers; char *swversion; uint8_t mac_addr[6]; char *location1; char *location2; char *serno; }; struct osmo_fd; struct tlv_parsed; int osmo_ipa_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd, int server); int osmo_ipa_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len); int osmo_ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data); int ipaccess_send_pong(int fd); int ipaccess_send_id_ack(int fd); int ipaccess_send_id_req(int fd); struct osmo_ipa_unit; struct msgb *ipa_cli_id_resp(struct osmo_ipa_unit *dev, uint8_t *data, int len); struct msgb *ipa_cli_id_ack(void); int osmo_ipa_parse_msg_id_resp(struct msgb *msg, struct ipaccess_unit *unit_data); #endif libosmo-netif-0.0.6/include/osmocom/netif/ipa_unit.h000066400000000000000000000052041261607103500224530ustar00rootroot00000000000000#ifndef _IPA_UNIT_H_ #define _IPA_UNIT_H_ struct osmo_ipa_unit; struct osmo_ipa_unit *osmo_ipa_unit_alloc(size_t datalen); void osmo_ipa_unit_free(struct osmo_ipa_unit *unit); void *osmo_ipa_unit_get_data(struct osmo_ipa_unit *unit); void osmo_ipa_unit_set_site_id(struct osmo_ipa_unit *unit, uint16_t site_id); void osmo_ipa_unit_set_bts_id(struct osmo_ipa_unit *unit, uint16_t bts_id); void osmo_ipa_unit_set_trx_id(struct osmo_ipa_unit *unit, uint16_t trx_id); void osmo_ipa_unit_set_unit_name(struct osmo_ipa_unit *unit, const char *name); void osmo_ipa_unit_set_unit_hwvers(struct osmo_ipa_unit *unit, const char *vers); void osmo_ipa_unit_set_unit_swvers(struct osmo_ipa_unit *unit, const char *vers); void osmo_ipa_unit_set_unit_mac_addr(struct osmo_ipa_unit *unit, uint8_t *addr); void osmo_ipa_unit_set_unit_loc1(struct osmo_ipa_unit *unit, const char *loc); void osmo_ipa_unit_set_unit_loc2(struct osmo_ipa_unit *unit, const char *loc); void osmo_ipa_unit_set_unit_serno(struct osmo_ipa_unit *unit, const char *serno); uint16_t osmo_ipa_unit_get_site_id(struct osmo_ipa_unit *unit); uint16_t osmo_ipa_unit_get_bts_id(struct osmo_ipa_unit *unit); uint16_t osmo_ipa_unit_get_trx_id(struct osmo_ipa_unit *unit); const char *osmo_ipa_unit_get_unit_name(struct osmo_ipa_unit *unit); const char *osmo_ipa_unit_get_unit_hwvers(struct osmo_ipa_unit *unit); const char *osmo_ipa_unit_get_unit_swvers(struct osmo_ipa_unit *unit); uint8_t *osmo_ipa_unit_get_unit_mac_addr(struct osmo_ipa_unit *unit); const char *osmo_ipa_unit_get_unit_loc1(struct osmo_ipa_unit *unit); const char *osmo_ipa_unit_get_unit_loc2(struct osmo_ipa_unit *unit); const char *osmo_ipa_unit_get_unit_serno(struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_mac_addr(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_name(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_loc1(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_loc2(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_hwvers(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_swvers(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_swvers(char *buf, size_t size, struct osmo_ipa_unit *unit); int osmo_ipa_unit_snprintf_serno(char *buf, size_t size, struct osmo_ipa_unit *unit); struct osmo_ipa_unit *osmo_ipa_unit_find(struct llist_head *list, uint16_t site_id, uint16_t bts_id); void osmo_ipa_unit_add(struct llist_head *list, struct osmo_ipa_unit *unit); #endif /* _IPA_UNIT_H_ */ libosmo-netif-0.0.6/include/osmocom/netif/osmux.h000066400000000000000000000051011261607103500220120ustar00rootroot00000000000000#ifndef _OSMUX_H_ #define _OSMUX_H_ #include /* OSmux header: * * ft (3 bits): 0=signalling, 1=voice, 2=dummy * ctr (3 bits): Number of batched AMR payloads (starting 0) * amr_f (1 bit): AMR F field (RFC3267) * amr_q (1 bit): AMR Q field (RFC3267) * seq (8 bits): Combination of RTP timestamp and seq. number * circuit_id (8 bits): Circuit ID, ie. Call identifier. * amr_ft (4 bits): AMR FT field (RFC3267) * amr_cmr (4 bits): AMR CMT field (RFC3267) */ #define OSMUX_FT_SIGNAL 0 #define OSMUX_FT_VOICE_AMR 1 #define OSMUX_FT_DUMMY 2 struct osmux_hdr { #if OSMO_IS_BIG_ENDIAN uint8_t ft:3, ctr:3, amr_f:1, amr_q:1; #elif OSMO_IS_LITTLE_ENDIAN uint8_t amr_q:1, amr_f:1, ctr:3, ft:3; #endif uint8_t seq; #define OSMUX_CID_MAX 255 /* determined by circuit_id */ uint8_t circuit_id; #if OSMO_IS_BIG_ENDIAN uint8_t amr_ft:4, amr_cmr:4; #elif OSMO_IS_LITTLE_ENDIAN uint8_t amr_cmr:4, amr_ft:4; #endif } __attribute__((packed)); /* one to handle all existing RTP flows */ struct osmux_in_handle { uint8_t osmux_seq; uint8_t batch_factor; uint16_t batch_size; struct { uint32_t input_rtp_msgs; uint32_t output_osmux_msgs; uint64_t input_rtp_bytes; uint64_t output_osmux_bytes; } stats; void (*deliver)(struct msgb *msg, void *data); void *data; char *internal_data; /* internal data to store batch */ }; #define OSMUX_MAX_CONCURRENT_CALLS 8 /* one per OSmux circuit_id, ie. one per RTP flow. */ struct osmux_out_handle { uint16_t rtp_seq; uint32_t rtp_timestamp; uint32_t rtp_ssrc; }; static inline uint8_t *osmux_get_payload(struct osmux_hdr *osmuxh) { return (uint8_t *)osmuxh + sizeof(struct osmux_hdr); } int osmux_snprintf(char *buf, size_t size, struct msgb *msg); /* 1500 - sizeof(iphdr) = 20 bytes - sizeof(udphdr) = 8 bytes. */ #define OSMUX_BATCH_DEFAULT_MAX 1472 void osmux_xfrm_input_init(struct osmux_in_handle *h); void osmux_xfrm_input_fini(struct osmux_in_handle *h); int osmux_xfrm_input_open_circuit(struct osmux_in_handle *h, int ccid, int dummy); void osmux_xfrm_input_close_circuit(struct osmux_in_handle *h, int ccid); int osmux_xfrm_input(struct osmux_in_handle *h, struct msgb *msg, int ccid); void osmux_xfrm_input_deliver(struct osmux_in_handle *h); void osmux_xfrm_output_init(struct osmux_out_handle *h, uint32_t rtp_ssrc); int osmux_xfrm_output(struct osmux_hdr *osmuxh, struct osmux_out_handle *h, struct llist_head *list); struct osmux_hdr *osmux_xfrm_output_pull(struct msgb *msg); void osmux_tx_sched(struct llist_head *list, void (*tx_cb)(struct msgb *msg, void *data), void *data); #endif libosmo-netif-0.0.6/include/osmocom/netif/rs232.h000066400000000000000000000013011261607103500215100ustar00rootroot00000000000000#ifndef _OSMO_RS232_H_ #define _OSMO_RS232_H_ struct osmo_rs232; struct osmo_rs232 *osmo_rs232_create(void *ctx); void osmo_rs232_set_serial_port(struct osmo_rs232 *, const char *serial_port); void osmo_rs232_set_delay_us(struct osmo_rs232 *, int delay_us); void osmo_rs232_set_baudrate(struct osmo_rs232 *, int baudrate); void osmo_rs232_set_read_cb(struct osmo_rs232 *r, int (*read_cb)(struct osmo_rs232 *r)); int osmo_rs232_open(struct osmo_rs232 *r); int osmo_rs232_read(struct osmo_rs232 *r, struct msgb *msg); int osmo_rs232_write(struct osmo_rs232 *r, struct msgb *msg); void osmo_rs232_close(struct osmo_rs232 *r); void osmo_rs232_destroy(struct osmo_rs232 *r); #endif /* _OSMO_RS232_H_ */ libosmo-netif-0.0.6/include/osmocom/netif/rtp.h000066400000000000000000000045601261607103500214540ustar00rootroot00000000000000#ifndef _OSMO_RTP_H_ #define _OSMO_RTP_H_ #include /* RTP header as defined by RFC 3550 */ struct rtp_hdr { #if OSMO_IS_LITTLE_ENDIAN uint8_t csrc_count:4, extension:1, padding:1, version:2; uint8_t payload_type:7, marker:1; #elif OSMO_IS_BIG_ENDIAN uint8_t version:2, padding:1, extension:1, csrc_count:4; uint8_t marker:1, payload_type:7; #endif uint16_t sequence; uint32_t timestamp; uint32_t ssrc; uint8_t data[0]; } __attribute__((packed)); #define RTP_VERSION 2 /* 5.3.1 RTP Header Extension * * If the X bit in the RTP header is one, a variable-length header * extension MUST be appended to the RTP header, following the CSRC list * if present. The header extension contains a 16-bit length field that * counts the number of 32-bit words in the extension, excluding the * four-octet extension header (therefore zero is a valid length). Only * a single extension can be appended to the RTP data header. */ struct rtp_x_hdr { uint16_t by_profile; uint16_t length; } __attribute__((packed)); /* RTPC header. */ struct rtcp_hdr { uint8_t byte0; uint8_t type; uint16_t length; } __attribute__((packed)); /* XXX: RFC specifies that MTU should used, add generic function to obtain existing MTU. */ #define RTP_MSGB_SIZE 1500 struct msgb; struct osmo_rtp_handle *osmo_rtp_handle_create(void *ctx); void osmo_rtp_handle_free(struct osmo_rtp_handle *h); int osmo_rtp_handle_tx_set_sequence(struct osmo_rtp_handle *h, uint16_t seq); int osmo_rtp_handle_tx_set_ssrc(struct osmo_rtp_handle *h, uint32_t ssrc); int osmo_rtp_handle_tx_set_timestamp(struct osmo_rtp_handle *h, uint32_t timestamp); struct rtp_hdr *osmo_rtp_get_hdr(struct msgb *msg); void *osmo_rtp_get_payload(struct rtp_hdr *rtph, struct msgb *msg, uint32_t *plen); struct msgb *osmo_rtp_build(struct osmo_rtp_handle *h, uint8_t payload_type, uint32_t payload_len, const void *data, uint32_t duration); int osmo_rtp_snprintf(char *buf, size_t size, struct msgb *msg); /* supported RTP payload types. */ #define RTP_PT_RTCP 72 /* RFC 3551: 72-76 for RTCP */ #define RTP_PT_GSM_FULL 3 #define RTP_PT_GSM_FULL_PAYLOAD_LEN 33 #define RTP_PT_GSM_FULL_DURATION 160 /* in samples. */ #define RTP_PT_GSM_HALF 96 #define RTP_PT_GSM_EFR 97 #define RTP_PT_GSM_EFR_PAYLOAD_LEN 31 #define RTP_PT_GSM_EFR_DURATION 160 /* in samples. */ #define RTP_PT_AMR 98 #endif libosmo-netif-0.0.6/include/osmocom/netif/stream.h000066400000000000000000000052311261607103500221360ustar00rootroot00000000000000#ifndef _OSMO_STREAM_H_ #define _OSMO_STREAM_H_ struct osmo_stream_srv_link; struct osmo_stream_srv_link *osmo_stream_srv_link_create(void *ctx); void osmo_stream_srv_link_destroy(struct osmo_stream_srv_link *link); void osmo_stream_srv_link_set_addr(struct osmo_stream_srv_link *link, const char *addr); void osmo_stream_srv_link_set_port(struct osmo_stream_srv_link *link, uint16_t port); void osmo_stream_srv_link_set_accept_cb(struct osmo_stream_srv_link *link, int (*accept_cb)(struct osmo_stream_srv_link *link, int fd)); void osmo_stream_srv_link_set_data(struct osmo_stream_srv_link *link, void *data); void *osmo_stream_srv_link_get_data(struct osmo_stream_srv_link *link); struct osmo_fd *osmo_stream_srv_link_get_ofd(struct osmo_stream_srv_link *link); int osmo_stream_srv_link_open(struct osmo_stream_srv_link *link); void osmo_stream_srv_link_close(struct osmo_stream_srv_link *link); struct osmo_stream_srv; struct osmo_stream_srv *osmo_stream_srv_create(void *ctx, struct osmo_stream_srv_link *link, int fd, int (*cb)(struct osmo_stream_srv *conn), int (*closed_cb)(struct osmo_stream_srv *conn), void *data); void *osmo_stream_srv_get_data(struct osmo_stream_srv *conn); struct osmo_stream_srv_link *osmo_stream_srv_get_master(struct osmo_stream_srv *conn); struct osmo_fd *osmo_stream_srv_get_ofd(struct osmo_stream_srv *srv); void osmo_stream_srv_destroy(struct osmo_stream_srv *conn); void osmo_stream_srv_set_data(struct osmo_stream_srv *conn, void *data); void osmo_stream_srv_send(struct osmo_stream_srv *conn, struct msgb *msg); int osmo_stream_srv_recv(struct osmo_stream_srv *conn, struct msgb *msg); struct osmo_stream_cli; void osmo_stream_cli_set_addr(struct osmo_stream_cli *cli, const char *addr); void osmo_stream_cli_set_port(struct osmo_stream_cli *cli, uint16_t port); void osmo_stream_cli_set_data(struct osmo_stream_cli *cli, void *data); void osmo_stream_cli_set_reconnect_timeout(struct osmo_stream_cli *cli, int timeout); void *osmo_stream_cli_get_data(struct osmo_stream_cli *cli); struct osmo_fd *osmo_stream_cli_get_ofd(struct osmo_stream_cli *cli); void osmo_stream_cli_set_connect_cb(struct osmo_stream_cli *cli, int (*connect_cb)(struct osmo_stream_cli *cli)); void osmo_stream_cli_set_read_cb(struct osmo_stream_cli *cli, int (*read_cb)(struct osmo_stream_cli *cli)); struct osmo_stream_cli *osmo_stream_cli_create(void *ctx); void osmo_stream_cli_destroy(struct osmo_stream_cli *cli); int osmo_stream_cli_open(struct osmo_stream_cli *cli); void osmo_stream_cli_close(struct osmo_stream_cli *cli); void osmo_stream_cli_send(struct osmo_stream_cli *cli, struct msgb *msg); int osmo_stream_cli_recv(struct osmo_stream_cli *conn, struct msgb *msg); #endif libosmo-netif-0.0.6/libosmo-netif.pc.in000066400000000000000000000003441261607103500177660ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: Osmocom network interface library Description: C Utility Library Version: @VERSION@ Libs: -L${libdir} -losmonetif Cflags: -I${includedir}/ libosmo-netif-0.0.6/m4/000077500000000000000000000000001261607103500146055ustar00rootroot00000000000000libosmo-netif-0.0.6/m4/.gitignore000066400000000000000000000000241261607103500165710ustar00rootroot00000000000000/libtool.m4 /lt*.m4 libosmo-netif-0.0.6/src/000077500000000000000000000000001261607103500150545ustar00rootroot00000000000000libosmo-netif-0.0.6/src/Makefile.am000066400000000000000000000014171261607103500171130ustar00rootroot00000000000000# This is _NOT_ the library release version, it's an API version. # Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification LIBVERSION=3:0:0 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS= -fPIC -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) SUBDIRS = channel lib_LTLIBRARIES = libosmonetif.la libosmonetif_la_LIBADD = channel/abis/libosmonetif-abis.la $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) libosmonetif_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined libosmonetif_la_SOURCES = amr.c \ channel.c \ datagram.c \ ipa.c \ ipa_unit.c \ osmux.c \ rs232.c \ rtp.c \ stream.c libosmo-netif-0.0.6/src/amr.c000066400000000000000000000027331261607103500160040ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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. */ #include #include #include /* According to TS 26.101: * * Frame type AMR code bits bytes * 0 4.75 95 12 * 1 5.15 103 13 * 2 5.90 118 15 * 3 6.70 134 17 * 4 7.40 148 19 * 5 7.95 159 20 * 6 10.20 204 26 * 7 12.20 244 31 */ static size_t amr_ft_to_bytes[AMR_FT_MAX] = { [AMR_FT_0] = 12, [AMR_FT_1] = 13, [AMR_FT_2] = 15, [AMR_FT_3] = 17, [AMR_FT_4] = 19, [AMR_FT_5] = 20, [AMR_FT_6] = 26, [AMR_FT_7] = 31, [AMR_FT_SID] = 6, }; size_t osmo_amr_bytes(uint8_t amr_ft) { return amr_ft_to_bytes[amr_ft]; } int osmo_amr_ft_valid(uint8_t amr_ft) { /* * Extracted from RFC3267: * * "... with a FT value in the range 9-14 for AMR ... the whole packet * SHOULD be discarded." * * "... packets containing only NO_DATA frames (FT=15) SHOULD NOT be * transmitted." * * So, let's discard frames with a AMR FT >= 9. */ if (amr_ft >= AMR_FT_MAX) return 0; return 1; } libosmo-netif-0.0.6/src/channel.c000066400000000000000000000040721261607103500166330ustar00rootroot00000000000000#include #include #include #include #include static LLIST_HEAD(channel_list); extern struct osmo_chan_type chan_abis_ipa_srv; extern struct osmo_chan_type chan_abis_ipa_cli; static void *osmo_chan_ctx; void osmo_chan_init(void *ctx) { osmo_chan_ctx = ctx; llist_add(&chan_abis_ipa_srv.head, &channel_list); llist_add(&chan_abis_ipa_cli.head, &channel_list); /* add your new channel type here */ } struct osmo_chan *osmo_chan_create(int type_id, int subtype_id) { struct osmo_chan_type *cur = NULL; int found = 0, found_partial = 0; struct osmo_chan *c; if (type_id > OSMO_CHAN_MAX) { LOGP(DLINP, LOGL_ERROR, "unsupported channel type " "number `%u'\n", type_id); return NULL; } if (subtype_id > OSMO_SUBCHAN_MAX) { LOGP(DLINP, LOGL_ERROR, "unsupported subchannel type " "number `%u'\n", type_id); return NULL; } llist_for_each_entry(cur, &channel_list, head) { if (type_id == cur->type && subtype_id == cur->subtype) { found = 1; break; } else if (type_id == cur->type) { found_partial = 1; break; } } if (!found) { LOGP(DLINP, LOGL_ERROR, "unsupported channel type `%s'\n", cur->name); return NULL; } if (found_partial) { LOGP(DLINP, LOGL_ERROR, "Sorry, channel type `%s' does not " "support subtype `%u'\n", cur->name, subtype_id); return NULL; } c = talloc_zero_size(osmo_chan_ctx, sizeof(struct osmo_chan) + cur->datasiz); if (c == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot allocate channel data\n"); return NULL; } c->ops = cur; if (c->ops->create(c) < 0) { LOGP(DLINP, LOGL_ERROR, "cannot create channel\n"); talloc_free(c); return NULL; } return c; } void osmo_chan_destroy(struct osmo_chan *c) { c->ops->destroy(c); talloc_free(c); } int osmo_chan_open(struct osmo_chan *c) { return c->ops->open(c); } void osmo_chan_close(struct osmo_chan *c) { c->ops->close(c); } int osmo_chan_enqueue(struct osmo_chan *c, struct msgb *msg) { return c->ops->enqueue(c, msg); } libosmo-netif-0.0.6/src/channel/000077500000000000000000000000001261607103500164645ustar00rootroot00000000000000libosmo-netif-0.0.6/src/channel/Makefile.am000066400000000000000000000000171261607103500205160ustar00rootroot00000000000000SUBDIRS = abis libosmo-netif-0.0.6/src/channel/abis/000077500000000000000000000000001261607103500174025ustar00rootroot00000000000000libosmo-netif-0.0.6/src/channel/abis/Makefile.am000066400000000000000000000006321261607103500214370ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS= -fPIC -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) noinst_LTLIBRARIES = libosmonetif-abis.la libosmonetif_abis_la_SOURCES = ipa_stream_server.c \ ipa_stream_client.c libosmonetif_abis_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) libosmo-netif-0.0.6/src/channel/abis/ipa_stream_client.c000066400000000000000000000156711261607103500232420ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CHAN_SIGN_OML 0 #define CHAN_SIGN_RSL 1 /* default IPA cli ports. */ #define IPA_TCP_PORT_OML 3002 #define IPA_TCP_PORT_RSL 3003 static void *abis_ipa_cli_tall; struct chan_abis_ipa_cli { struct osmo_ipa_unit *unit; struct osmo_stream_cli *oml; struct osmo_stream_cli *rsl; void (*signal_msg)(struct msgb *msg, int type); }; static int oml_read_cb(struct osmo_stream_cli *conn); static int rsl_read_cb(struct osmo_stream_cli *conn); static int chan_abis_ipa_cli_create(struct osmo_chan *chan) { struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data; c->unit = osmo_ipa_unit_alloc(0); if (c->unit == NULL) goto err; c->oml = osmo_stream_cli_create(abis_ipa_cli_tall); if (c->oml == NULL) goto err_oml; /* default address and port for OML. */ osmo_stream_cli_set_addr(c->oml, "0.0.0.0"); osmo_stream_cli_set_port(c->oml, IPA_TCP_PORT_OML); osmo_stream_cli_set_read_cb(c->oml, oml_read_cb); osmo_stream_cli_set_data(c->oml, chan); c->rsl = osmo_stream_cli_create(abis_ipa_cli_tall); if (c->rsl == NULL) goto err_rsl; /* default address and port for RSL. */ osmo_stream_cli_set_addr(c->rsl, "0.0.0.0"); osmo_stream_cli_set_port(c->rsl, IPA_TCP_PORT_RSL); osmo_stream_cli_set_read_cb(c->rsl, rsl_read_cb); osmo_stream_cli_set_data(c->rsl, chan); return 0; err_rsl: osmo_stream_cli_destroy(c->oml); err_oml: osmo_ipa_unit_free(c->unit); err: return -1; } static void chan_abis_ipa_cli_destroy(struct osmo_chan *chan) { struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data; osmo_ipa_unit_free(c->unit); talloc_free(c->rsl); talloc_free(c->oml); } static int chan_abis_ipa_cli_open(struct osmo_chan *chan) { struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data; struct osmo_fd *ofd; int ret, on = 1; if (osmo_stream_cli_open(c->oml) < 0) goto err; ofd = osmo_stream_cli_get_ofd(c->oml); ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); if (ret < 0) goto err_oml; if (osmo_stream_cli_open(c->rsl) < 0) goto err_oml; ofd = osmo_stream_cli_get_ofd(c->rsl); ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); if (ret < 0) goto err_rsl; return 0; err_rsl: osmo_stream_cli_close(c->rsl); err_oml: osmo_stream_cli_close(c->oml); err: return -1; } static void chan_abis_ipa_cli_close(struct osmo_chan *chan) { struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data; osmo_stream_cli_close(c->oml); osmo_stream_cli_close(c->rsl); } static int chan_abis_ipa_cli_enqueue(struct osmo_chan *c, struct msgb *msg) { osmo_stream_cli_send(msg->dst, msg); return 0; } void osmo_abis_ipa_cli_set_oml_addr(struct osmo_chan *c, const char *addr) { struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data; osmo_stream_cli_set_addr(s->oml, addr); } void osmo_abis_ipa_cli_set_oml_port(struct osmo_chan *c, uint16_t port) { struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data; osmo_stream_cli_set_port(s->oml, port); } void osmo_abis_ipa_cli_set_rsl_addr(struct osmo_chan *c, const char *addr) { struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data; osmo_stream_cli_set_addr(s->rsl, addr); } void osmo_abis_ipa_cli_set_rsl_port(struct osmo_chan *c, uint16_t port) { struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data; osmo_stream_cli_set_port(s->rsl, port); } void osmo_abis_ipa_cli_set_unit(struct osmo_chan *c, struct osmo_ipa_unit *unit) { struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data; osmo_ipa_unit_free(s->unit); s->unit = unit; } void osmo_abis_ipa_cli_set_cb_signalmsg(struct osmo_chan *c, void (*signal_msg)(struct msgb *msg, int type)) { struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data; s->signal_msg = signal_msg; } static int abis_ipa_cli_rcvmsg(struct osmo_chan *c, struct osmo_stream_cli *conn, struct msgb *msg, int type) { uint8_t msg_type = *(msg->l2h); struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn); struct chan_abis_ipa_cli *chan = (struct chan_abis_ipa_cli *)&c->data; int ret; /* Handle IPA PING, PONG and ID_ACK messages. */ if (osmo_ipa_rcvmsg_base(msg, ofd, 0)) /* XXX: 0 indicates client */ return 0; if (msg_type == IPAC_MSGT_ID_GET) { struct msgb *rmsg; uint8_t *data = msgb_l2(msg); int len = msgb_l2len(msg); LOGP(DLINP, LOGL_NOTICE, "received ID get\n"); rmsg = ipa_cli_id_resp(chan->unit, data + 1, len - 1); osmo_stream_cli_send(conn, rmsg); /* send ID_ACK. */ rmsg = ipa_cli_id_ack(); osmo_stream_cli_send(conn, rmsg); ret = 0; } else { LOGP(DLINP, LOGL_ERROR, "Unknown IPA message type\n"); ret = -EINVAL; } return ret; } static int read_cb(struct osmo_stream_cli *conn, int type) { int ret; struct msgb *msg; struct osmo_chan *chan = osmo_stream_cli_get_data(conn); struct chan_abis_ipa_cli *s; struct ipa_head *hh; LOGP(DLINP, LOGL_DEBUG, "received message from stream\n"); msg = osmo_ipa_msg_alloc(0); if (msg == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot allocate message\n"); return 0; } ret = osmo_stream_cli_recv(conn, msg); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "cannot receive message\n"); msgb_free(msg); /* not the dummy connection, release it. */ return 0; } else if (ret == 0) { /* link has vanished, dead socket. */ LOGP(DLINP, LOGL_ERROR, "closed connection\n"); msgb_free(msg); return 0; } if (osmo_ipa_process_msg(msg) < 0) { LOGP(DLINP, LOGL_ERROR, "Bad IPA message\n"); msgb_free(msg); return -EIO; } hh = (struct ipa_head *) msg->data; if (hh->proto == IPAC_PROTO_IPACCESS) { abis_ipa_cli_rcvmsg(chan, conn, msg, type); msgb_free(msg); return -EIO; } chan = osmo_stream_cli_get_data(conn); if (chan == NULL) { LOGP(DLINP, LOGL_ERROR, "no matching signalling link\n"); msgb_free(msg); return -EIO; } if (hh->proto != IPAC_PROTO_OML && hh->proto != IPAC_PROTO_RSL) { LOGP(DLINP, LOGL_ERROR, "wrong protocol\n"); return -EIO; } msg->dst = chan; s = (struct chan_abis_ipa_cli *)chan->data; s->signal_msg(msg, type); return 0; } static int oml_read_cb(struct osmo_stream_cli *conn) { return read_cb(conn, CHAN_SIGN_OML); } static int rsl_read_cb(struct osmo_stream_cli *conn) { return read_cb(conn, CHAN_SIGN_RSL); } struct osmo_chan_type chan_abis_ipa_cli = { .type = OSMO_CHAN_ABIS_IPA_CLI, .subtype = OSMO_SUBCHAN_STREAM, .name = "A-bis IPA client", .datasiz = sizeof(struct chan_abis_ipa_cli), .create = chan_abis_ipa_cli_create, .destroy = chan_abis_ipa_cli_destroy, .open = chan_abis_ipa_cli_open, .close = chan_abis_ipa_cli_close, .enqueue = chan_abis_ipa_cli_enqueue, }; libosmo-netif-0.0.6/src/channel/abis/ipa_stream_server.c000066400000000000000000000233071261607103500232650ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CHAN_SIGN_OML 0 #define CHAN_SIGN_RSL 1 /* default IPA srv ports. */ #define IPA_TCP_PORT_OML 3002 #define IPA_TCP_PORT_RSL 3003 static void *abis_ipa_srv_tall; static int oml_accept_cb(struct osmo_stream_srv_link *srv, int fd); static int rsl_accept_cb(struct osmo_stream_srv_link *srv, int fd); struct chan_abis_ipa_srv { struct osmo_chan *chan; struct osmo_stream_srv_link *oml; struct osmo_stream_srv_link *rsl; struct llist_head bts_list; void (*signal_msg)(struct msgb *msg, int type); }; struct chan_abis_ipa_srv_conn { struct chan_abis_ipa_srv *master; struct osmo_stream_srv *oml; struct osmo_stream_srv *rsl; }; static int chan_abis_ipa_srv_create(struct osmo_chan *chan) { struct chan_abis_ipa_srv *c = (struct chan_abis_ipa_srv *)chan->data; c->oml = osmo_stream_srv_link_create(abis_ipa_srv_tall); if (c->oml == NULL) goto err_oml; /* default address and port for OML. */ osmo_stream_srv_link_set_addr(c->oml, "0.0.0.0"); osmo_stream_srv_link_set_port(c->oml, IPA_TCP_PORT_OML); osmo_stream_srv_link_set_accept_cb(c->oml, oml_accept_cb); osmo_stream_srv_link_set_data(c->oml, c); c->rsl = osmo_stream_srv_link_create(abis_ipa_srv_tall); if (c->rsl == NULL) goto err_rsl; /* default address and port for RSL. */ osmo_stream_srv_link_set_addr(c->rsl, "0.0.0.0"); osmo_stream_srv_link_set_port(c->rsl, IPA_TCP_PORT_RSL); osmo_stream_srv_link_set_accept_cb(c->rsl, rsl_accept_cb); osmo_stream_srv_link_set_data(c->rsl, c); INIT_LLIST_HEAD(&c->bts_list); return 0; err_rsl: osmo_stream_srv_link_destroy(c->oml); err_oml: return -1; } static void chan_abis_ipa_srv_destroy(struct osmo_chan *chan) { struct chan_abis_ipa_srv *c = (struct chan_abis_ipa_srv *)chan->data; osmo_stream_srv_link_destroy(c->rsl); osmo_stream_srv_link_destroy(c->oml); } static int chan_abis_ipa_srv_open(struct osmo_chan *chan) { struct chan_abis_ipa_srv *c = (struct chan_abis_ipa_srv *)chan->data; struct osmo_fd *ofd; int ret, on = 1; if (osmo_stream_srv_link_open(c->oml) < 0) goto err; ofd = osmo_stream_srv_link_get_ofd(c->oml); ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); if (ret < 0) goto err_oml; if (osmo_stream_srv_link_open(c->rsl) < 0) goto err_oml; ofd = osmo_stream_srv_link_get_ofd(c->rsl); ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); if (ret < 0) goto err_rsl; return 0; err_rsl: osmo_stream_srv_link_close(c->rsl); err_oml: osmo_stream_srv_link_close(c->oml); err: return -1; } static void chan_abis_ipa_srv_close(struct osmo_chan *chan) { struct chan_abis_ipa_srv *c = (struct chan_abis_ipa_srv *)chan->data; osmo_stream_srv_link_close(c->oml); osmo_stream_srv_link_close(c->rsl); } static int chan_abis_ipa_srv_enqueue(struct osmo_chan *c, struct msgb *msg) { osmo_stream_srv_send(msg->dst, msg); return 0; } void osmo_abis_ipa_srv_set_oml_addr(struct osmo_chan *c, const char *addr) { struct chan_abis_ipa_srv *s = (struct chan_abis_ipa_srv *)&c->data; osmo_stream_srv_link_set_addr(s->oml, addr); } void osmo_abis_ipa_srv_set_oml_port(struct osmo_chan *c, uint16_t port) { struct chan_abis_ipa_srv *s = (struct chan_abis_ipa_srv *)&c->data; osmo_stream_srv_link_set_port(s->oml, port); } void osmo_abis_ipa_srv_set_rsl_addr(struct osmo_chan *c, const char *addr) { struct chan_abis_ipa_srv *s = (struct chan_abis_ipa_srv *)&c->data; osmo_stream_srv_link_set_addr(s->rsl, addr); } void osmo_abis_ipa_srv_set_rsl_port(struct osmo_chan *c, uint16_t port) { struct chan_abis_ipa_srv *s = (struct chan_abis_ipa_srv *)&c->data; osmo_stream_srv_link_set_port(s->rsl, port); } void osmo_abis_ipa_srv_set_cb_signalmsg(struct osmo_chan *c, void (*signal_msg)(struct msgb *msg, int type)) { struct chan_abis_ipa_srv *s = (struct chan_abis_ipa_srv *)&c->data; s->signal_msg = signal_msg; } int osmo_abis_ipa_unit_add(struct osmo_chan *c, uint16_t site_id, uint16_t bts_id) { struct osmo_ipa_unit *unit; struct chan_abis_ipa_srv *s = (struct chan_abis_ipa_srv *)&c->data; struct chan_abis_ipa_srv_conn *inst; unit = osmo_ipa_unit_alloc(sizeof(struct chan_abis_ipa_srv_conn)); if (unit == NULL) return -1; osmo_ipa_unit_set_site_id(unit, site_id); osmo_ipa_unit_set_bts_id(unit, bts_id); osmo_ipa_unit_add(&s->bts_list, unit); inst = osmo_ipa_unit_get_data(unit); inst->master = s; return 0; } static int oml_read_cb(struct osmo_stream_srv *conn); static int oml_accept_cb(struct osmo_stream_srv_link *srv, int fd) { struct osmo_stream_srv *conn; struct osmo_fd *ofd; conn = osmo_stream_srv_create(abis_ipa_srv_tall, srv, fd, oml_read_cb, NULL, NULL); if (conn == NULL) { LOGP(DLINP, LOGL_ERROR, "error while creating connection\n"); return -1; } ofd = osmo_stream_srv_get_ofd(conn); /* XXX: better use chan_abis_ipa_srv_enqueue. */ ipaccess_send_id_req(ofd->fd); return 0; } static int rsl_read_cb(struct osmo_stream_srv *conn); static int rsl_accept_cb(struct osmo_stream_srv_link *srv, int fd) { struct osmo_stream_srv *conn; struct osmo_fd *ofd; conn = osmo_stream_srv_create(abis_ipa_srv_tall, srv, fd, rsl_read_cb, NULL, NULL); if (conn == NULL) { LOGP(DLINP, LOGL_ERROR, "error while creating connection\n"); return -1; } ofd = osmo_stream_srv_get_ofd(conn); /* XXX: better use chan_abis_ipa_srv_enqueue. */ ipaccess_send_id_req(ofd->fd); return 0; } static void abis_ipa_put(struct osmo_ipa_unit *unit) { struct chan_abis_ipa_srv_conn *inst = osmo_ipa_unit_get_data(unit); osmo_stream_srv_destroy(inst->oml); osmo_stream_srv_destroy(inst->rsl); inst->oml = NULL; inst->rsl = NULL; } static int abis_ipa_srv_rcvmsg(struct osmo_stream_srv *conn, struct msgb *msg, int type) { uint8_t msg_type = *(msg->l2h); struct osmo_fd *ofd = osmo_stream_srv_get_ofd(conn); struct osmo_stream_srv_link *link = osmo_stream_srv_get_master(conn); struct chan_abis_ipa_srv *s = osmo_stream_srv_link_get_data(link); struct chan_abis_ipa_srv_conn *inst; int ret; /* Handle IPA PING, PONG and ID_ACK messages */ if (osmo_ipa_rcvmsg_base(msg, ofd, 1)) /* XXX: 1 indicates server */ return 0; if (msg_type == IPAC_MSGT_ID_RESP) { struct osmo_ipa_unit *unit; struct ipaccess_unit unit_data; if (osmo_ipa_parse_msg_id_resp(msg, &unit_data) < 0) { LOGP(DLINP, LOGL_ERROR, "bad ID RESP message\n"); return -EIO; } unit = osmo_ipa_unit_find(&s->bts_list, unit_data.site_id, unit_data.bts_id); if (unit == NULL) { LOGP(DLINP, LOGL_ERROR, "Unable to find BTS " "configuration for %u/%u/%u, disconnecting\n", unit_data.site_id, unit_data.bts_id, unit_data.trx_id); return 0; } DEBUGP(DLINP, "Identified BTS %u/%u/%u\n", unit_data.site_id, unit_data.bts_id, unit_data.trx_id); inst = osmo_ipa_unit_get_data(unit); if (type == CHAN_SIGN_OML) { if (inst->oml) { /* link already exists, kill it. */ osmo_stream_srv_destroy(inst->oml); return 0; } inst->oml = conn; } else if (type == CHAN_SIGN_RSL) { if (!inst->oml) { /* no OML link? Restart from scratch. */ abis_ipa_put(unit); return 0; } if (inst->rsl) { /* RSL link already exists, kill it. */ osmo_stream_srv_destroy(inst->rsl); return 0; } inst->rsl = conn; } osmo_stream_srv_set_data(conn, unit); ret = 0; } else { LOGP(DLINP, LOGL_ERROR, "Unknown IPA message type\n"); ret = -EINVAL; } return ret; } static int read_cb(struct osmo_stream_srv *conn, int type) { int ret; struct msgb *msg; struct osmo_ipa_unit *unit = osmo_stream_srv_get_data(conn); struct chan_abis_ipa_srv_conn *inst; struct ipa_head *hh; LOGP(DLINP, LOGL_DEBUG, "received message from stream\n"); msg = osmo_ipa_msg_alloc(0); if (msg == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot allocate message\n"); return 0; } ret = osmo_stream_srv_recv(conn, msg); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "cannot receive message\n"); msgb_free(msg); if (unit != NULL) abis_ipa_put(unit); else osmo_stream_srv_destroy(conn); return 0; } else if (ret == 0) { /* link has vanished, dead socket. */ LOGP(DLINP, LOGL_ERROR, "closed connection\n"); msgb_free(msg); if (unit != NULL) abis_ipa_put(unit); else osmo_stream_srv_destroy(conn); return 0; } ret = osmo_ipa_process_msg(msg); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "invalid IPA message\n"); msgb_free(msg); } hh = (struct ipa_head *) msg->data; if (hh->proto == IPAC_PROTO_IPACCESS) { abis_ipa_srv_rcvmsg(conn, msg, type); msgb_free(msg); return -EIO; } if (unit == NULL) { LOGP(DLINP, LOGL_ERROR, "no IPA unit associated to this " "connection\n"); return -EIO; } inst = osmo_ipa_unit_get_data(unit); if (hh->proto != IPAC_PROTO_OML && hh->proto != IPAC_PROTO_RSL) { LOGP(DLINP, LOGL_ERROR, "wrong protocol\n"); return -EIO; } msg->dst = conn; inst->master->signal_msg(msg, type); return 0; } static int oml_read_cb(struct osmo_stream_srv *conn) { return read_cb(conn, CHAN_SIGN_OML); } static int rsl_read_cb(struct osmo_stream_srv *conn) { return read_cb(conn, CHAN_SIGN_RSL); } struct osmo_chan_type chan_abis_ipa_srv = { .type = OSMO_CHAN_ABIS_IPA_SRV, .subtype = OSMO_SUBCHAN_STREAM, .name = "A-bis IPA server", .datasiz = sizeof(struct chan_abis_ipa_srv), .create = chan_abis_ipa_srv_create, .destroy = chan_abis_ipa_srv_destroy, .open = chan_abis_ipa_srv_open, .close = chan_abis_ipa_srv_close, .enqueue = chan_abis_ipa_srv_enqueue, }; libosmo-netif-0.0.6/src/datagram.c000066400000000000000000000175061261607103500170110ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Client side. */ #define OSMO_DGRAM_CLI_F_RECONF (1 << 0) struct osmo_dgram_tx { struct osmo_fd ofd; struct llist_head tx_queue; const char *addr; uint16_t port; int (*write_cb)(struct osmo_dgram_tx *conn); void *data; unsigned int flags; }; void osmo_dgram_tx_close(struct osmo_dgram_tx *conn) { osmo_fd_unregister(&conn->ofd); close(conn->ofd.fd); } static int osmo_dgram_tx_write(struct osmo_dgram_tx *conn) { struct msgb *msg; struct llist_head *lh; int ret; LOGP(DLINP, LOGL_DEBUG, "sending data\n"); if (llist_empty(&conn->tx_queue)) { conn->ofd.when &= ~BSC_FD_WRITE; return 0; } lh = conn->tx_queue.next; llist_del(lh); msg = llist_entry(lh, struct msgb, list); ret = send(conn->ofd.fd, msg->data, msg->len, 0); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "error to send (%s)\n", strerror(errno)); } msgb_free(msg); return 0; } static int osmo_dgram_tx_fd_cb(struct osmo_fd *ofd, unsigned int what) { struct osmo_dgram_tx *conn = ofd->data; if (what & BSC_FD_WRITE) { LOGP(DLINP, LOGL_DEBUG, "write\n"); osmo_dgram_tx_write(conn); } return 0; } struct osmo_dgram_tx *osmo_dgram_tx_create(void *crx) { struct osmo_dgram_tx *conn; conn = talloc_zero(crx, struct osmo_dgram_tx); if (!conn) return NULL; conn->ofd.fd = -1; conn->ofd.when |= BSC_FD_READ; conn->ofd.priv_nr = 0; /* XXX */ conn->ofd.cb = osmo_dgram_tx_fd_cb; conn->ofd.data = conn; INIT_LLIST_HEAD(&conn->tx_queue); return conn; } void osmo_dgram_tx_set_addr(struct osmo_dgram_tx *conn, const char *addr) { if (conn->addr != NULL) talloc_free((void *)conn->addr); conn->addr = talloc_strdup(conn, addr); conn->flags |= OSMO_DGRAM_CLI_F_RECONF; } void osmo_dgram_tx_set_port(struct osmo_dgram_tx *conn, uint16_t port) { conn->port = port; conn->flags |= OSMO_DGRAM_CLI_F_RECONF; } void osmo_dgram_tx_set_data(struct osmo_dgram_tx *conn, void *data) { conn->data = data; } void osmo_dgram_tx_destroy(struct osmo_dgram_tx *conn) { talloc_free(conn); } int osmo_dgram_tx_open(struct osmo_dgram_tx *conn) { int ret; /* we are reconfiguring this socket, close existing first. */ if ((conn->flags & OSMO_DGRAM_CLI_F_RECONF) && conn->ofd.fd >= 0) osmo_dgram_tx_close(conn); conn->flags &= ~OSMO_DGRAM_CLI_F_RECONF; ret = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, conn->addr, conn->port, OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK); if (ret < 0) return ret; conn->ofd.fd = ret; if (osmo_fd_register(&conn->ofd) < 0) { close(ret); return -EIO; } return 0; } void osmo_dgram_tx_send(struct osmo_dgram_tx *conn, struct msgb *msg) { msgb_enqueue(&conn->tx_queue, msg); conn->ofd.when |= BSC_FD_WRITE; } /* * Server side. */ #define OSMO_DGRAM_RX_F_RECONF (1 << 0) struct osmo_dgram_rx { struct osmo_fd ofd; const char *addr; uint16_t port; int (*cb)(struct osmo_dgram_rx *conn); void *data; unsigned int flags; }; int osmo_dgram_rx_recv(struct osmo_dgram_rx *conn, struct msgb *msg) { int ret; ret = recv(conn->ofd.fd, msg->data, msg->data_len, 0); if (ret <= 0) { LOGP(DLINP, LOGL_ERROR, "error receiving data from tx\n"); return ret; } msgb_put(msg, ret); LOGP(DLINP, LOGL_DEBUG, "received %d bytes from tx\n", ret); return ret; } static void osmo_dgram_rx_read(struct osmo_dgram_rx *conn) { LOGP(DLINP, LOGL_DEBUG, "message received\n"); if (conn->cb) conn->cb(conn); } static int osmo_dgram_rx_cb(struct osmo_fd *ofd, unsigned int what) { struct osmo_dgram_rx *conn = ofd->data; LOGP(DLINP, LOGL_DEBUG, "read\n"); if (what & BSC_FD_READ) osmo_dgram_rx_read(conn); return 0; } struct osmo_dgram_rx *osmo_dgram_rx_create(void *crx) { struct osmo_dgram_rx *conn; conn = talloc_zero(crx, struct osmo_dgram_rx); if (!conn) return NULL; conn->ofd.fd = -1; conn->ofd.when |= BSC_FD_READ; conn->ofd.cb = osmo_dgram_rx_cb; conn->ofd.data = conn; return conn; } void osmo_dgram_rx_set_addr(struct osmo_dgram_rx *conn, const char *addr) { if (conn->addr != NULL) talloc_free((void *)conn->addr); conn->addr = talloc_strdup(conn, addr); conn->flags |= OSMO_DGRAM_RX_F_RECONF; } void osmo_dgram_rx_set_port(struct osmo_dgram_rx *conn, uint16_t port) { conn->port = port; conn->flags |= OSMO_DGRAM_RX_F_RECONF; } void osmo_dgram_rx_set_read_cb(struct osmo_dgram_rx *conn, int (*read_cb)(struct osmo_dgram_rx *conn)) { conn->cb = read_cb; } void osmo_dgram_rx_destroy(struct osmo_dgram_rx *conn) { talloc_free(conn); } int osmo_dgram_rx_open(struct osmo_dgram_rx *conn) { int ret; /* we are reconfiguring this socket, close existing first. */ if ((conn->flags & OSMO_DGRAM_RX_F_RECONF) && conn->ofd.fd >= 0) osmo_dgram_rx_close(conn); conn->flags &= ~OSMO_DGRAM_RX_F_RECONF; ret = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, conn->addr, conn->port, OSMO_SOCK_F_BIND); if (ret < 0) return ret; conn->ofd.fd = ret; if (osmo_fd_register(&conn->ofd) < 0) { close(ret); return -EIO; } return 0; } void osmo_dgram_rx_close(struct osmo_dgram_rx *conn) { osmo_fd_unregister(&conn->ofd); close(conn->ofd.fd); } /* * Client+Server (bidirectional communications). */ struct osmo_dgram { struct osmo_dgram_rx *rx; struct osmo_dgram_tx *tx; int (*read_cb)(struct osmo_dgram *conn); void *data; }; static int dgram_rx_cb(struct osmo_dgram_rx *rx) { struct osmo_dgram *conn = rx->data; if (conn->read_cb) return conn->read_cb(conn); return 0; } struct osmo_dgram *osmo_dgram_create(void *crx) { struct osmo_dgram *conn; conn = talloc_zero(crx, struct osmo_dgram); if (!conn) return NULL; conn->rx= osmo_dgram_rx_create(crx); if (conn->rx == NULL) return NULL; osmo_dgram_rx_set_read_cb(conn->rx, dgram_rx_cb); conn->rx->data = conn; conn->tx = osmo_dgram_tx_create(crx); if (conn->tx == NULL) { osmo_dgram_rx_destroy(conn->rx); return NULL; } return conn; } void osmo_dgram_destroy(struct osmo_dgram *conn) { osmo_dgram_rx_destroy(conn->rx); osmo_dgram_tx_destroy(conn->tx); } void osmo_dgram_set_local_addr(struct osmo_dgram *conn, const char *addr) { osmo_dgram_rx_set_addr(conn->rx, addr); } void osmo_dgram_set_remote_addr(struct osmo_dgram *conn, const char *addr) { osmo_dgram_tx_set_addr(conn->tx, addr); } void osmo_dgram_set_local_port(struct osmo_dgram *conn, uint16_t port) { osmo_dgram_rx_set_port(conn->rx, port); } void osmo_dgram_set_remote_port(struct osmo_dgram *conn, uint16_t port) { osmo_dgram_tx_set_port(conn->tx, port); } void osmo_dgram_set_read_cb(struct osmo_dgram *conn, int (*read_cb)(struct osmo_dgram *conn)) { conn->read_cb = read_cb; } void osmo_dgram_set_data(struct osmo_dgram *conn, void *data) { conn->data = data; } void *osmo_dgram_get_data(struct osmo_dgram *conn) { return conn->data; } int osmo_dgram_open(struct osmo_dgram *conn) { int ret; ret = osmo_dgram_rx_open(conn->rx); if (ret < 0) return ret; ret = osmo_dgram_tx_open(conn->tx); if (ret < 0) { osmo_dgram_rx_close(conn->rx); return ret; } return ret; } void osmo_dgram_close(struct osmo_dgram *conn) { osmo_dgram_rx_close(conn->rx); osmo_dgram_tx_close(conn->tx); } void osmo_dgram_send(struct osmo_dgram *conn, struct msgb *msg) { osmo_dgram_tx_send(conn->tx, msg); } int osmo_dgram_recv(struct osmo_dgram *conn, struct msgb *msg) { return osmo_dgram_rx_recv(conn->rx, msg); } libosmo-netif-0.0.6/src/ipa.c000066400000000000000000000201171261607103500157720ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IPA_ALLOC_SIZE 1200 /* * Common propietary IPA messages: * - PONG: in reply to PING. * - ID_REQUEST: first messages once OML has been established. * - ID_ACK: in reply to ID_ACK. */ const uint8_t ipa_pong_msg[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG }; const uint8_t ipa_id_ack_msg[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK }; const uint8_t ipa_id_req_msg[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET, 0x01, IPAC_IDTAG_UNIT, 0x01, IPAC_IDTAG_MACADDR, 0x01, IPAC_IDTAG_LOCATION1, 0x01, IPAC_IDTAG_LOCATION2, 0x01, IPAC_IDTAG_EQUIPVERS, 0x01, IPAC_IDTAG_SWVERSION, 0x01, IPAC_IDTAG_UNITNAME, 0x01, IPAC_IDTAG_SERNR, }; static const char *idtag_names[] = { [IPAC_IDTAG_SERNR] = "Serial_Number", [IPAC_IDTAG_UNITNAME] = "Unit_Name", [IPAC_IDTAG_LOCATION1] = "Location_1", [IPAC_IDTAG_LOCATION2] = "Location_2", [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version", [IPAC_IDTAG_SWVERSION] = "Software_Version", [IPAC_IDTAG_IPADDR] = "IP_Address", [IPAC_IDTAG_MACADDR] = "MAC_Address", [IPAC_IDTAG_UNIT] = "Unit_ID", }; const char *ipaccess_idtag_name(uint8_t tag) { if (tag >= ARRAY_SIZE(idtag_names)) return "unknown"; return idtag_names[tag]; } struct msgb *osmo_ipa_msg_alloc(int headroom) { struct msgb *msg; headroom += sizeof(struct ipa_head); msg = msgb_alloc_headroom(IPA_ALLOC_SIZE + headroom, headroom, "IPA"); if (msg == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot allocate message\n"); return NULL; } return msg; } void osmo_ipa_msg_push_header(struct msgb *msg, uint8_t proto) { struct ipa_head *hh; msg->l2h = msg->data; hh = (struct ipa_head *) msgb_push(msg, sizeof(*hh)); hh->proto = proto; hh->len = htons(msgb_l2len(msg)); } int osmo_ipa_process_msg(struct msgb *msg) { struct ipa_head *hh; int len; if (msg->len < sizeof(struct ipa_head)) { LOGP(DLINP, LOGL_ERROR, "too small IPA message\n"); return -EIO; } hh = (struct ipa_head *) msg->data; len = sizeof(struct ipa_head) + ntohs(hh->len); if (len > msg->len) { LOGP(DLINP, LOGL_ERROR, "bad IPA message header " "hdrlen=%u < datalen=%u\n", len, msg->len); return -EIO; } msg->l2h = msg->data + sizeof(*hh); return 0; } int osmo_ipa_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len) { uint8_t t_len; uint8_t t_tag; uint8_t *cur = buf; memset(dec, 0, sizeof(*dec)); while (len >= 2) { len -= 2; t_len = *cur++; t_tag = *cur++; if (t_len > len + 1) { LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d\n", t_len); return -EINVAL; } DEBUGPC(DLMI, "%s='%s' ", ipaccess_idtag_name(t_tag), cur); dec->lv[t_tag].len = t_len; dec->lv[t_tag].val = cur; cur += t_len; len -= t_len; } return 0; } int osmo_ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data) { unsigned long ul; char *endptr; const char *nptr; nptr = str; ul = strtoul(nptr, &endptr, 10); if (endptr <= nptr) return -EINVAL; unit_data->site_id = ul & 0xffff; if (*endptr++ != '/') return -EINVAL; nptr = endptr; ul = strtoul(nptr, &endptr, 10); if (endptr <= nptr) return -EINVAL; unit_data->bts_id = ul & 0xffff; if (*endptr++ != '/') return -EINVAL; nptr = endptr; ul = strtoul(nptr, &endptr, 10); if (endptr <= nptr) return -EINVAL; unit_data->trx_id = ul & 0xffff; return 0; } static int ipaccess_send(int fd, const void *msg, size_t msglen) { int ret; ret = write(fd, msg, msglen); if (ret < 0) return ret; if (ret < msglen) { LOGP(DLINP, LOGL_ERROR, "ipaccess_send: short write\n"); return -EIO; } return ret; } int ipaccess_send_pong(int fd) { return ipaccess_send(fd, ipa_pong_msg, sizeof(ipa_pong_msg)); } int ipaccess_send_id_ack(int fd) { return ipaccess_send(fd, ipa_id_ack_msg, sizeof(ipa_id_ack_msg)); } int ipaccess_send_id_req(int fd) { return ipaccess_send(fd, ipa_id_req_msg, sizeof(ipa_id_req_msg)); } /* base handling of the ip.access protocol */ int osmo_ipa_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd, int server) { int ipa_ccm = 0; uint8_t msg_type = *(msg->l2h); switch (msg_type) { case IPAC_MSGT_PING: LOGP(DLINP, LOGL_DEBUG, "PING!\n"); ipa_ccm = 1; ipaccess_send_pong(bfd->fd); break; case IPAC_MSGT_PONG: LOGP(DLINP, LOGL_DEBUG, "PONG!\n"); ipa_ccm = 1; break; case IPAC_MSGT_ID_ACK: if (server) { LOGP(DLINP, LOGL_DEBUG, "ID_ACK? -> ACK!\n"); ipa_ccm = 1; ipaccess_send_id_ack(bfd->fd); } else { LOGP(DLINP, LOGL_DEBUG, "ID_ACK! OK!\n"); ipa_ccm = 1; } break; } return ipa_ccm; } int ipaccess_parse_unitid(const char *str, struct ipaccess_unit *unit_data) { unsigned long ul; char *endptr; const char *nptr; nptr = str; ul = strtoul(nptr, &endptr, 10); if (endptr <= nptr) return -EINVAL; unit_data->site_id = ul & 0xffff; if (*endptr++ != '/') return -EINVAL; nptr = endptr; ul = strtoul(nptr, &endptr, 10); if (endptr <= nptr) return -EINVAL; unit_data->bts_id = ul & 0xffff; if (*endptr++ != '/') return -EINVAL; nptr = endptr; ul = strtoul(nptr, &endptr, 10); if (endptr <= nptr) return -EINVAL; unit_data->trx_id = ul & 0xffff; return 0; } struct msgb *ipa_cli_id_resp(struct osmo_ipa_unit *dev, uint8_t *data, int len) { struct msgb *nmsg; char str[64]; uint8_t *tag; nmsg = osmo_ipa_msg_alloc(0); if (nmsg == NULL) return NULL; *msgb_put(nmsg, 1) = IPAC_MSGT_ID_RESP; while (len) { if (len < 2) { LOGP(DLINP, LOGL_NOTICE, "Short read of ipaccess tag\n"); msgb_free(nmsg); return NULL; } switch (data[1]) { case IPAC_IDTAG_UNIT: osmo_ipa_unit_snprintf(str, sizeof(str), dev); break; case IPAC_IDTAG_MACADDR: osmo_ipa_unit_snprintf_mac_addr(str, sizeof(str), dev); break; case IPAC_IDTAG_LOCATION1: osmo_ipa_unit_snprintf_loc1(str, sizeof(str), dev); break; case IPAC_IDTAG_LOCATION2: osmo_ipa_unit_snprintf_loc2(str, sizeof(str), dev); break; case IPAC_IDTAG_EQUIPVERS: osmo_ipa_unit_snprintf_hwvers(str, sizeof(str), dev); break; case IPAC_IDTAG_SWVERSION: osmo_ipa_unit_snprintf_swvers(str, sizeof(str), dev); break; case IPAC_IDTAG_UNITNAME: osmo_ipa_unit_snprintf_name(str, sizeof(str), dev); break; case IPAC_IDTAG_SERNR: osmo_ipa_unit_snprintf_serno(str, sizeof(str), dev); break; default: LOGP(DLINP, LOGL_NOTICE, "Unknown ipaccess tag 0x%02x\n", *data); msgb_free(nmsg); return NULL; } LOGP(DLINP, LOGL_INFO, " tag %d: %s\n", data[1], str); tag = msgb_put(nmsg, 3 + strlen(str) + 1); tag[0] = 0x00; tag[1] = 1 + strlen(str) + 1; tag[2] = data[1]; memcpy(tag + 3, str, strlen(str) + 1); data += 2; len -= 2; } osmo_ipa_msg_push_header(nmsg, IPAC_PROTO_IPACCESS); return nmsg; } struct msgb *ipa_cli_id_ack(void) { struct msgb *nmsg2; nmsg2 = osmo_ipa_msg_alloc(0); if (nmsg2 == NULL) return NULL; *msgb_put(nmsg2, 1) = IPAC_MSGT_ID_ACK; osmo_ipa_msg_push_header(nmsg2, IPAC_PROTO_IPACCESS); return nmsg2; } int osmo_ipa_parse_msg_id_resp(struct msgb *msg, struct ipaccess_unit *unit_data) { struct tlv_parsed tlvp; char *unitid; int len, ret; DEBUGP(DLINP, "ID_RESP\n"); /* parse tags, search for Unit ID */ ret = osmo_ipa_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2, msgb_l2len(msg)-2); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "IPA response message " "with malformed TLVs\n"); return -EINVAL; } if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) { LOGP(DLINP, LOGL_ERROR, "IPA response message " "without unit ID\n"); return -EINVAL; } len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT); if (len < 1) { LOGP(DLINP, LOGL_ERROR, "IPA response message " "with too small unit ID\n"); return -EINVAL; } unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT); unitid[len - 1] = '\0'; if (osmo_ipa_parse_unitid(unitid, unit_data) < 0) { LOGP(DLINP, LOGL_ERROR, "failed to parse IPA IDTAG\n"); return -EINVAL; } return 0; } libosmo-netif-0.0.6/src/ipa_unit.c000066400000000000000000000126051261607103500170340ustar00rootroot00000000000000#include #include #include #include struct osmo_ipa_unit { struct llist_head head; uint16_t site_id; uint16_t bts_id; uint16_t trx_id; char *name; char *hwvers; char *swvers; uint8_t mac_addr[6]; char *location1; char *location2; char *serno; uint8_t data[0]; }; struct osmo_ipa_unit *osmo_ipa_unit_alloc(size_t datalen) { struct osmo_ipa_unit *unit; unit = talloc_zero_size(NULL, sizeof(struct osmo_ipa_unit) + datalen); if (unit == NULL) return NULL; unit->name = talloc_strdup(unit, ""); unit->hwvers = talloc_strdup(unit, ""); unit->swvers = talloc_strdup(unit, ""); unit->location1 = talloc_strdup(unit, ""); unit->location2 = talloc_strdup(unit, ""); unit->serno = talloc_strdup(unit, ""); return unit; } void osmo_ipa_unit_free(struct osmo_ipa_unit *unit) { if (unit->name) free(unit->name); if (unit->hwvers) free(unit->hwvers); if (unit->swvers) free(unit->swvers); if (unit->location1) free(unit->location1); if (unit->location2) free(unit->location2); if (unit->serno) free(unit->serno); talloc_free(unit); } void *osmo_ipa_unit_get_data(struct osmo_ipa_unit *unit) { return unit->data; } void osmo_ipa_unit_set_site_id(struct osmo_ipa_unit *unit, uint16_t site_id) { unit->site_id = site_id; } void osmo_ipa_unit_set_bts_id(struct osmo_ipa_unit *unit, uint16_t bts_id) { unit->bts_id = bts_id; } void osmo_ipa_unit_set_trx_id(struct osmo_ipa_unit *unit, uint16_t trx_id) { unit->trx_id = trx_id; } void osmo_ipa_unit_set_unit_name(struct osmo_ipa_unit *unit, const char *name) { if (unit->name) free(unit->name); unit->name = talloc_strdup(unit, name); } void osmo_ipa_unit_set_unit_hwvers(struct osmo_ipa_unit *unit, const char *vers) { if (unit->hwvers) free(unit->hwvers); unit->hwvers = talloc_strdup(unit, vers); } void osmo_ipa_unit_set_unit_swvers(struct osmo_ipa_unit *unit, const char *vers) { if (unit->swvers) free(unit->swvers); unit->swvers = talloc_strdup(unit, vers); } void osmo_ipa_unit_set_unit_mac_addr(struct osmo_ipa_unit *unit, uint8_t *addr) { memcpy(unit->mac_addr, addr, sizeof(unit->mac_addr)); } void osmo_ipa_unit_set_unit_location1(struct osmo_ipa_unit *unit, const char *loc) { if (unit->location1) free(unit->location1); unit->location1 = talloc_strdup(unit, loc); } void osmo_ipa_unit_set_unit_location2(struct osmo_ipa_unit *unit, const char *loc) { if (unit->location2) free(unit->location2); unit->location2 = talloc_strdup(unit, loc); } void osmo_ipa_unit_set_unit_serno(struct osmo_ipa_unit *unit, const char *serno) { unit->serno = talloc_strdup(unit, serno); } uint16_t osmo_ipa_unit_get_site_id(struct osmo_ipa_unit *unit) { return unit->site_id; } uint16_t osmo_ipa_unit_get_bts_id(struct osmo_ipa_unit *unit) { return unit->bts_id; } uint16_t osmo_ipa_unit_get_trx_id(struct osmo_ipa_unit *unit) { return unit->trx_id; } const char *osmo_ipa_unit_get_unit_name(struct osmo_ipa_unit *unit) { return unit->name; } const char *osmo_ipa_unit_get_unit_hwvers(struct osmo_ipa_unit *unit) { return unit->hwvers; } const char *osmo_ipa_unit_get_unit_swvers(struct osmo_ipa_unit *unit) { return unit->swvers; } uint8_t *osmo_ipa_unit_get_unit_mac_addr(struct osmo_ipa_unit *unit) { return unit->mac_addr; } const char *osmo_ipa_unit_get_unit_location1(struct osmo_ipa_unit *unit) { return unit->location1; } const char *osmo_ipa_unit_get_unit_location2(struct osmo_ipa_unit *unit) { return unit->location2; } const char *osmo_ipa_unit_get_unit_serno(struct osmo_ipa_unit *unit) { return unit->serno; } struct osmo_ipa_unit * osmo_ipa_unit_find(struct llist_head *list, uint16_t site_id, uint16_t bts_id) { struct osmo_ipa_unit *unit; llist_for_each_entry(unit, list, head) { if (unit->site_id == site_id && unit->bts_id == bts_id) return unit; } return NULL; } void osmo_ipa_unit_add(struct llist_head *list, struct osmo_ipa_unit *unit) { llist_add(&unit->head, list); } int osmo_ipa_unit_snprintf(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%u/%u/%u", unit->site_id, unit->bts_id, unit->trx_id); } int osmo_ipa_unit_snprintf_mac_addr(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%02x:%02x:%02x:%02x:%02x:%02x", unit->mac_addr[0], unit->mac_addr[1], unit->mac_addr[2], unit->mac_addr[3], unit->mac_addr[4], unit->mac_addr[5]); } int osmo_ipa_unit_snprintf_name(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%s-%02x-%02x-%02x-%02x-%02x-%02x", unit->name, unit->mac_addr[0], unit->mac_addr[1], unit->mac_addr[2], unit->mac_addr[3], unit->mac_addr[4], unit->mac_addr[5]); } int osmo_ipa_unit_snprintf_loc1(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%s", unit->location1); } int osmo_ipa_unit_snprintf_loc2(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%s", unit->location2); } int osmo_ipa_unit_snprintf_hwvers(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%s", unit->hwvers); } int osmo_ipa_unit_snprintf_swvers(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%s", unit->hwvers); } int osmo_ipa_unit_snprintf_serno(char *buf, size_t size, struct osmo_ipa_unit *unit) { return snprintf(buf, size, "%s", unit->serno); } libosmo-netif-0.0.6/src/osmux.c000066400000000000000000000531311261607103500163760ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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. */ #include #include #include #include #include #include #include #include #include #include #include /* This allows you to debug timing reconstruction in the output path */ #if 0 #define DEBUG_TIMING 0 #endif /* This allows you to debug osmux message transformations (spamming) */ #if 0 #define DEBUG_MSG 0 #endif /* delta time between two RTP messages */ #define DELTA_RTP_MSG 16000 #define DELTA_RTP_TIMESTAMP 160 static void *osmux_ctx; static uint32_t osmux_get_payload_len(struct osmux_hdr *osmuxh) { return osmo_amr_bytes(osmuxh->amr_ft) * (osmuxh->ctr+1); } static uint32_t osmux_ft_dummy_size(uint8_t amr_ft, uint32_t batch_factor) { return sizeof(struct osmux_hdr) + (osmo_amr_bytes(amr_ft) * batch_factor); } struct osmux_hdr *osmux_xfrm_output_pull(struct msgb *msg) { struct osmux_hdr *osmuxh; next: osmuxh = NULL; if (msg->len > sizeof(struct osmux_hdr)) { size_t len; osmuxh = (struct osmux_hdr *)msg->data; switch (osmuxh->ft) { case OSMUX_FT_VOICE_AMR: break; case OSMUX_FT_DUMMY: msgb_pull(msg, osmux_ft_dummy_size(osmuxh->amr_ft, osmuxh->ctr + 1)); goto next; default: LOGP(DLMIB, LOGL_ERROR, "Discarding unsupported Osmux FT %d\n", osmuxh->ft); return NULL; } if (!osmo_amr_ft_valid(osmuxh->amr_ft)) { LOGP(DLMIB, LOGL_ERROR, "Discarding bad AMR FT %d\n", osmuxh->amr_ft); return NULL; } len = osmo_amr_bytes(osmuxh->amr_ft) * (osmuxh->ctr+1) + sizeof(struct osmux_hdr); if (len > msg->len) { LOGP(DLMIB, LOGL_ERROR, "Discarding malformed " "OSMUX message\n"); return NULL; } msgb_pull(msg, len); } else if (msg->len > 0) { LOGP(DLMIB, LOGL_ERROR, "remaining %d bytes, broken osmuxhdr?\n", msg->len); } return osmuxh; } static struct msgb * osmux_rebuild_rtp(struct osmux_out_handle *h, struct osmux_hdr *osmuxh, void *payload, int payload_len) { struct msgb *out_msg; struct rtp_hdr *rtph; struct amr_hdr *amrh; out_msg = msgb_alloc(sizeof(struct rtp_hdr) + sizeof(struct amr_hdr) + osmo_amr_bytes(osmuxh->amr_ft), "OSMUX test"); if (out_msg == NULL) return NULL; /* Reconstruct RTP header */ rtph = (struct rtp_hdr *)out_msg->data; rtph->csrc_count = 0; rtph->extension = 0; rtph->version = RTP_VERSION; rtph->payload_type = 98; /* ... emulate timestamp and ssrc */ rtph->timestamp = htonl(h->rtp_timestamp); rtph->sequence = htons(h->rtp_seq); rtph->ssrc = htonl(h->rtp_ssrc); msgb_put(out_msg, sizeof(struct rtp_hdr)); /* Reconstruct AMR header */ amrh = (struct amr_hdr *)out_msg->tail; amrh->cmr = osmuxh->amr_cmr; amrh->f = osmuxh->amr_f; amrh->ft = osmuxh->amr_ft; amrh->q = osmuxh->amr_q; msgb_put(out_msg, sizeof(struct amr_hdr)); /* add AMR speech data */ memcpy(out_msg->tail, payload, payload_len); msgb_put(out_msg, payload_len); /* bump last RTP sequence number and timestamp that has been used */ h->rtp_seq++; h->rtp_timestamp += DELTA_RTP_TIMESTAMP; return out_msg; } int osmux_xfrm_output(struct osmux_hdr *osmuxh, struct osmux_out_handle *h, struct llist_head *list) { struct msgb *msg; int i; INIT_LLIST_HEAD(list); for (i=0; ictr+1; i++) { struct rtp_hdr *rtph; msg = osmux_rebuild_rtp(h, osmuxh, osmux_get_payload(osmuxh) + i * osmo_amr_bytes(osmuxh->amr_ft), osmo_amr_bytes(osmuxh->amr_ft)); if (msg == NULL) continue; rtph = osmo_rtp_get_hdr(msg); if (rtph == NULL) continue; #ifdef DEBUG_MSG { char buf[4096]; osmo_rtp_snprintf(buf, sizeof(buf), msg); buf[sizeof(buf)-1] = '\0'; LOGP(DLMIB, LOGL_DEBUG, "to BTS: %s\n", buf); } #endif llist_add_tail(&msg->list, list); } return i; } struct osmux_batch { struct osmo_timer_list timer; struct osmux_hdr *osmuxh; struct llist_head circuit_list; unsigned int remaining_bytes; uint8_t seq; uint32_t nmsgs; int ndummy; }; struct osmux_circuit { struct llist_head head; int ccid; struct llist_head msg_list; int nmsgs; int dummy; }; static int osmux_batch_enqueue(struct msgb *msg, struct osmux_circuit *circuit) { /* Too many messages per batch, discard it. The counter field of the * osmux header is just 3 bits long, so make sure it doesn't overflow. */ if (circuit->nmsgs >= 8) { struct rtp_hdr *rtph; rtph = osmo_rtp_get_hdr(msg); if (rtph == NULL) return -1; LOGP(DLMIB, LOGL_ERROR, "too many messages for this RTP " "ssrc=%u\n", rtph->ssrc); return -1; } llist_add_tail(&msg->list, &circuit->msg_list); circuit->nmsgs++; return 0; } static void osmux_batch_dequeue(struct msgb *msg, struct osmux_circuit *circuit) { llist_del(&msg->list); circuit->nmsgs--; } struct osmux_input_state { struct msgb *out_msg; struct msgb *msg; struct rtp_hdr *rtph; struct amr_hdr *amrh; uint32_t amr_payload_len; int ccid; int add_osmux_hdr; }; static int osmux_batch_put(struct osmux_batch *batch, struct osmux_input_state *state) { struct osmux_hdr *osmuxh; if (state->add_osmux_hdr) { osmuxh = (struct osmux_hdr *)state->out_msg->tail; osmuxh->ft = OSMUX_FT_VOICE_AMR; osmuxh->ctr = 0; osmuxh->amr_f = state->amrh->f; osmuxh->amr_q= state->amrh->q; osmuxh->seq = batch->seq++; osmuxh->circuit_id = state->ccid; osmuxh->amr_cmr = state->amrh->cmr; osmuxh->amr_ft = state->amrh->ft; msgb_put(state->out_msg, sizeof(struct osmux_hdr)); /* annotate current osmux header */ batch->osmuxh = osmuxh; } else { if (batch->osmuxh->ctr == 0x7) { LOGP(DLMIB, LOGL_ERROR, "cannot add msg=%p, " "too many messages for this RTP ssrc=%u\n", state->msg, state->rtph->ssrc); return 0; } batch->osmuxh->ctr++; } memcpy(state->out_msg->tail, osmo_amr_get_payload(state->amrh), state->amr_payload_len); msgb_put(state->out_msg, state->amr_payload_len); return 0; } static int osmux_xfrm_encode_amr(struct osmux_batch *batch, struct osmux_input_state *state) { uint32_t amr_len; state->amrh = osmo_rtp_get_payload(state->rtph, state->msg, &amr_len); if (state->amrh == NULL) return -1; state->amr_payload_len = amr_len - sizeof(struct amr_hdr); if (osmux_batch_put(batch, state) < 0) return -1; return 0; } static void osmux_encode_dummy(struct osmux_batch *batch, uint32_t batch_factor, struct osmux_input_state *state) { struct osmux_hdr *osmuxh; /* TODO: This should be configurable at some point. */ uint32_t payload_size = osmux_ft_dummy_size(AMR_FT_3, batch_factor) - sizeof(struct osmux_hdr); osmuxh = (struct osmux_hdr *)state->out_msg->tail; osmuxh->ft = OSMUX_FT_DUMMY; osmuxh->ctr = batch_factor - 1; osmuxh->amr_f = 0; osmuxh->amr_q= 0; osmuxh->seq = 0; osmuxh->circuit_id = state->ccid; osmuxh->amr_cmr = 0; osmuxh->amr_ft = AMR_FT_3; msgb_put(state->out_msg, sizeof(struct osmux_hdr)); memset(state->out_msg->tail, 0xff, payload_size); msgb_put(state->out_msg, payload_size); } static struct msgb *osmux_build_batch(struct osmux_batch *batch, uint32_t batch_size, uint32_t batch_factor) { struct msgb *batch_msg; struct osmux_circuit *circuit; #ifdef DEBUG_MSG LOGP(DLMIB, LOGL_DEBUG, "Now building batch\n"); #endif batch_msg = msgb_alloc(batch_size, "osmux"); if (batch_msg == NULL) { LOGP(DLMIB, LOGL_ERROR, "Not enough memory\n"); return NULL; } llist_for_each_entry(circuit, &batch->circuit_list, head) { struct msgb *cur, *tmp; int ctr = 0; if (circuit->dummy) { struct osmux_input_state state = { .out_msg = batch_msg, .ccid = circuit->ccid, }; osmux_encode_dummy(batch, batch_factor, &state); continue; } llist_for_each_entry_safe(cur, tmp, &circuit->msg_list, list) { struct osmux_input_state state = { .msg = cur, .out_msg = batch_msg, .ccid = circuit->ccid, }; #ifdef DEBUG_MSG char buf[4096]; osmo_rtp_snprintf(buf, sizeof(buf), cur); buf[sizeof(buf)-1] = '\0'; LOGP(DLMIB, LOGL_DEBUG, "to BSC-NAT: %s\n", buf); #endif state.rtph = osmo_rtp_get_hdr(cur); if (state.rtph == NULL) return NULL; if (ctr == 0) { #ifdef DEBUG_MSG LOGP(DLMIB, LOGL_DEBUG, "add osmux header\n"); #endif state.add_osmux_hdr = 1; } osmux_xfrm_encode_amr(batch, &state); osmux_batch_dequeue(cur, circuit); msgb_free(cur); ctr++; batch->nmsgs--; } } return batch_msg; } void osmux_xfrm_input_deliver(struct osmux_in_handle *h) { struct msgb *batch_msg; struct osmux_batch *batch = (struct osmux_batch *)h->internal_data; #ifdef DEBUG_MSG LOGP(DLMIB, LOGL_DEBUG, "invoking delivery function\n"); #endif batch_msg = osmux_build_batch(batch, h->batch_size, h->batch_factor); h->stats.output_osmux_msgs++; h->stats.output_osmux_bytes += batch_msg->len; h->deliver(batch_msg, h->data); osmo_timer_del(&batch->timer); batch->remaining_bytes = h->batch_size; if (batch->ndummy) { osmo_timer_schedule(&batch->timer, 0, h->batch_factor * DELTA_RTP_MSG); } } static void osmux_batch_timer_expired(void *data) { struct osmux_in_handle *h = data; #ifdef DEBUG_MSG LOGP(DLMIB, LOGL_DEBUG, "osmux_batch_timer_expired\n"); #endif osmux_xfrm_input_deliver(h); } static int osmux_rtp_amr_payload_len(struct msgb *msg, struct rtp_hdr *rtph) { struct amr_hdr *amrh; unsigned int amr_len; int amr_payload_len; amrh = osmo_rtp_get_payload(rtph, msg, &amr_len); if (amrh == NULL) return -1; if (!osmo_amr_ft_valid(amrh->ft)) return -1; amr_payload_len = amr_len - sizeof(struct amr_hdr); /* The AMR payload does not fit with what we expect */ if (osmo_amr_bytes(amrh->ft) != amr_payload_len) { LOGP(DLMIB, LOGL_ERROR, "Bad AMR frame, expected %zd bytes, got %d bytes\n", osmo_amr_bytes(amrh->ft), amr_len); return -1; } return amr_payload_len; } static void osmux_replay_lost_packets(struct osmux_circuit *circuit, struct rtp_hdr *cur_rtph) { int16_t diff; struct msgb *last; struct rtp_hdr *rtph; int i; /* Have we see any RTP packet in this batch before? */ if (llist_empty(&circuit->msg_list)) return; /* Get last RTP packet seen in this batch */ last = llist_entry(circuit->msg_list.prev, struct msgb, list); rtph = osmo_rtp_get_hdr(last); if (rtph == NULL) return; diff = ntohs(cur_rtph->sequence) - ntohs(rtph->sequence); /* Lifesaver: make sure bugs don't spawn lots of clones */ if (diff > 16) diff = 16; /* If diff between last RTP packet seen and this one is > 1, * then we lost several RTP packets, let's replay them. */ for (i=1; idata_len, "RTP clone"); if (!clone) continue; memcpy(clone->data, last->data, last->len); msgb_put(clone, last->len); /* The original RTP message has been already sanity check. */ rtph = osmo_rtp_get_hdr(clone); /* Adjust sequence number and timestamp */ rtph->sequence = htons(ntohs(rtph->sequence) + i); rtph->timestamp = htonl(ntohl(rtph->timestamp) + DELTA_RTP_TIMESTAMP); /* No more room in this batch, skip padding with more clones */ if (osmux_batch_enqueue(clone, circuit) < 0) { msgb_free(clone); break; } LOGP(DLMIB, LOGL_ERROR, "adding cloned RTP\n"); } } static struct osmux_circuit * osmux_batch_find_circuit(struct osmux_batch *batch, int ccid) { struct osmux_circuit *circuit; llist_for_each_entry(circuit, &batch->circuit_list, head) { if (circuit->ccid == ccid) return circuit; } return NULL; } static struct osmux_circuit * osmux_batch_add_circuit(struct osmux_batch *batch, int ccid, int dummy, int batch_factor) { struct osmux_circuit *circuit; circuit = osmux_batch_find_circuit(batch, ccid); if (circuit != NULL) { LOGP(DLMIB, LOGL_ERROR, "circuit %u already exists!\n", ccid); return NULL; } circuit = talloc_zero(osmux_ctx, struct osmux_circuit); if (circuit == NULL) { LOGP(DLMIB, LOGL_ERROR, "OOM on circuit %u\n", ccid); return NULL; } circuit->ccid = ccid; INIT_LLIST_HEAD(&circuit->msg_list); llist_add_tail(&circuit->head, &batch->circuit_list); if (dummy) { circuit->dummy = dummy; batch->ndummy++; if (!osmo_timer_pending(&batch->timer)) osmo_timer_schedule(&batch->timer, 0, batch_factor * DELTA_RTP_MSG); } return circuit; } static void osmux_batch_del_circuit(struct osmux_batch *batch, int ccid) { struct osmux_circuit *circuit; circuit = osmux_batch_find_circuit(batch, ccid); if (circuit == NULL) return; if (circuit->dummy) batch->ndummy--; llist_del(&circuit->head); talloc_free(circuit); } static int osmux_batch_add(struct osmux_batch *batch, int batch_factor, struct msgb *msg, struct rtp_hdr *rtph, int ccid) { int bytes = 0, amr_payload_len; struct osmux_circuit *circuit; struct msgb *cur; circuit = osmux_batch_find_circuit(batch, ccid); if (!circuit) return -1; /* We've seen the first RTP message, disable dummy padding */ if (circuit->dummy) { circuit->dummy = 0; batch->ndummy--; } amr_payload_len = osmux_rtp_amr_payload_len(msg, rtph); if (amr_payload_len < 0) return -1; /* First check if there is room for this message in the batch */ bytes += amr_payload_len; if (circuit->nmsgs == 0) bytes += sizeof(struct osmux_hdr); /* No room, sorry. You'll have to retry */ if (bytes > batch->remaining_bytes) return 1; /* Extra validation: check if this message already exists, should not * happen but make sure we don't propagate duplicated messages. */ llist_for_each_entry(cur, &circuit->msg_list, list) { struct rtp_hdr *rtph2 = osmo_rtp_get_hdr(cur); if (rtph2 == NULL) return -1; /* Already exists message with this sequence, skip */ if (rtph2->sequence == rtph->sequence) { LOGP(DLMIB, LOGL_ERROR, "already exists " "message with seq=%u, skip it\n", rtph->sequence); return -1; } } /* Handle RTP packet loss scenario */ osmux_replay_lost_packets(circuit, rtph); /* This batch is full, force batch delivery */ if (osmux_batch_enqueue(msg, circuit) < 0) return 1; #ifdef DEBUG_MSG LOGP(DLMIB, LOGL_DEBUG, "adding msg with ssrc=%u to batch\n", rtph->ssrc); #endif /* Update remaining room in this batch */ batch->remaining_bytes -= bytes; if (batch->nmsgs == 0) { #ifdef DEBUG_MSG LOGP(DLMIB, LOGL_DEBUG, "osmux start timer batch\n"); #endif osmo_timer_schedule(&batch->timer, 0, batch_factor * DELTA_RTP_MSG); } batch->nmsgs++; return 0; } /** * osmux_xfrm_input - add RTP message to OSmux batch * \param msg: RTP message that you want to batch into one OSmux message * * If 0 is returned, this indicates that the message has been batched or that * an error occured and we have skipped the message. If 1 is returned, you * have to invoke osmux_xfrm_input_deliver and try again. * * The function takes care of releasing the messages in case of error and * when building the batch. */ int osmux_xfrm_input(struct osmux_in_handle *h, struct msgb *msg, int ccid) { int ret; struct rtp_hdr *rtph; struct osmux_batch *batch = (struct osmux_batch *)h->internal_data; /* Ignore too big RTP/RTCP messages, most likely forged. Sanity check * to avoid a possible forever loop in the caller. */ if (msg->len > h->batch_size - sizeof(struct osmux_hdr)) { msgb_free(msg); return 0; } rtph = osmo_rtp_get_hdr(msg); if (rtph == NULL) { msgb_free(msg); return 0; } switch(rtph->payload_type) { case RTP_PT_RTCP: msgb_free(msg); return 0; default: /* The RTP payload type is dynamically allocated, * although we use static ones. Assume that we always * receive AMR traffic. */ /* Add this RTP to the OSMUX batch */ ret = osmux_batch_add(batch, h->batch_factor, msg, rtph, ccid); if (ret < 0) { /* Cannot put this message into the batch. * Malformed, duplicated, OOM. Drop it and tell * the upper layer that we have digest it. */ msgb_free(msg); return 0; } h->stats.input_rtp_msgs++; h->stats.input_rtp_bytes += msg->len; break; } return ret; } void osmux_xfrm_input_init(struct osmux_in_handle *h) { struct osmux_batch *batch; /* Default to osmux packet size if not specified */ if (h->batch_size == 0) h->batch_size = OSMUX_BATCH_DEFAULT_MAX; batch = talloc_zero(osmux_ctx, struct osmux_batch); if (batch == NULL) return; INIT_LLIST_HEAD(&batch->circuit_list); batch->remaining_bytes = h->batch_size; batch->timer.cb = osmux_batch_timer_expired; batch->timer.data = h; h->internal_data = (void *)batch; LOGP(DLMIB, LOGL_DEBUG, "initialized osmux input converter\n"); } int osmux_xfrm_input_open_circuit(struct osmux_in_handle *h, int ccid, int dummy) { struct osmux_batch *batch = (struct osmux_batch *)h->internal_data; return osmux_batch_add_circuit(batch, ccid, dummy, h->batch_factor) ? 0 : -1; } void osmux_xfrm_input_close_circuit(struct osmux_in_handle *h, int ccid) { struct osmux_batch *batch = (struct osmux_batch *)h->internal_data; osmux_batch_del_circuit(batch, ccid); } void osmux_xfrm_input_fini(struct osmux_in_handle *h) { struct osmux_batch *batch = (struct osmux_batch *)h->internal_data; struct osmux_circuit *circuit, *next; llist_for_each_entry_safe(circuit, next, &batch->circuit_list, head) { llist_del(&circuit->head); talloc_free(circuit); } osmo_timer_del(&batch->timer); talloc_free(batch); } struct osmux_tx_handle { struct osmo_timer_list timer; struct msgb *msg; void (*tx_cb)(struct msgb *msg, void *data); void *data; #ifdef DEBUG_TIMING struct timeval start; struct timeval when; #endif }; static void osmux_tx_cb(void *data) { struct osmux_tx_handle *h = data; #ifdef DEBUG_TIMING struct timeval now, diff; gettimeofday(&now, NULL); timersub(&now, &h->start, &diff); timersub(&diff,&h->when, &diff); LOGP(DLMIB, LOGL_DEBUG, "we are lagging %lu.%.6lu in scheduled " "transmissions\n", diff.tv_sec, diff.tv_usec); #endif h->tx_cb(h->msg, h->data); talloc_free(h); } static void osmux_tx(struct msgb *msg, struct timeval *when, void (*tx_cb)(struct msgb *msg, void *data), void *data) { struct osmux_tx_handle *h; h = talloc_zero(osmux_ctx, struct osmux_tx_handle); if (h == NULL) return; h->msg = msg; h->tx_cb = tx_cb; h->data = data; h->timer.cb = osmux_tx_cb; h->timer.data = h; #ifdef DEBUG_TIMING gettimeofday(&h->start, NULL); h->when.tv_sec = when->tv_sec; h->when.tv_usec = when->tv_usec; #endif /* send it now */ if (when->tv_sec == 0 && when->tv_usec == 0) { osmux_tx_cb(h); return; } osmo_timer_schedule(&h->timer, when->tv_sec, when->tv_usec); } void osmux_tx_sched(struct llist_head *list, void (*tx_cb)(struct msgb *msg, void *data), void *data) { struct msgb *cur, *tmp; struct timeval delta = { .tv_sec = 0, .tv_usec = DELTA_RTP_MSG }; struct timeval when; timerclear(&when); llist_for_each_entry_safe(cur, tmp, list, list) { #ifdef DEBUG_MSG LOGP(DLMIB, LOGL_DEBUG, "scheduled transmision in %lu.%6lu " "seconds, msg=%p\n", when.tv_sec, when.tv_usec, cur); #endif llist_del(&cur->list); osmux_tx(cur, &when, tx_cb, data); timeradd(&when, &delta, &when); } } void osmux_xfrm_output_init(struct osmux_out_handle *h, uint32_t rtp_ssrc) { h->rtp_seq = (uint16_t)random(); h->rtp_timestamp = (uint32_t)random(); h->rtp_ssrc = rtp_ssrc; } #define SNPRINTF_BUFFER_SIZE(ret, size, len, offset) \ size += ret; \ if (ret > len) \ ret = len; \ offset += ret; \ len -= ret; static int osmux_snprintf_header(char *buf, size_t size, struct osmux_hdr *osmuxh) { int ret; int len = size, offset = 0; ret = snprintf(buf, len, "OSMUX seq=%03u ccid=%03u " "ft=%01u ctr=%01u " "amr_f=%01u amr_q=%01u " "amr_ft=%02u amr_cmr=%02u ", osmuxh->seq, osmuxh->circuit_id, osmuxh->ft, osmuxh->ctr, osmuxh->amr_f, osmuxh->amr_q, osmuxh->amr_ft, osmuxh->amr_cmr); SNPRINTF_BUFFER_SIZE(ret, size, len, offset); return offset; } static int osmux_snprintf_payload(char *buf, size_t size, const uint8_t *payload, int payload_len) { int ret, i; int len = size, offset = 0; for (i=0; ilen, len = size; struct osmux_hdr *osmuxh; int this_len, msg_off = 0; while (msg_len > 0) { if (msg_len < sizeof(struct osmux_hdr)) { LOGP(DLMIB, LOGL_ERROR, "No room for OSMUX header: only %d bytes\n", msg_len); return -1; } osmuxh = (struct osmux_hdr *)((uint8_t *)msg->data + msg_off); if (!osmo_amr_ft_valid(osmuxh->amr_ft)) { LOGP(DLMIB, LOGL_ERROR, "Bad AMR FT %d, skipping\n", osmuxh->amr_ft); return -1; } ret = osmux_snprintf_header(buf+offset, size, osmuxh); if (ret < 0) break; SNPRINTF_BUFFER_SIZE(ret, size, len, offset); this_len = sizeof(struct osmux_hdr) + osmux_get_payload_len(osmuxh); msg_off += this_len; if (msg_len < this_len) { LOGP(DLMIB, LOGL_ERROR, "No room for OSMUX payload: only %d bytes\n", msg_len); return -1; } ret = osmux_snprintf_payload(buf+offset, size, osmux_get_payload(osmuxh), osmux_get_payload_len(osmuxh)); if (ret < 0) break; SNPRINTF_BUFFER_SIZE(ret, size, len, offset); msg_len -= this_len; } return offset; } libosmo-netif-0.0.6/src/rs232.c000066400000000000000000000135311261607103500160760ustar00rootroot00000000000000/* T-Link interface using POSIX serial port */ /* (C) 2008-2011 by Harald Welte * * All Rights Reserved * * Authors: Harald Welte * Pablo Neira Ayuso * * 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 struct osmo_rs232 { struct osmo_fd ofd; struct llist_head tx_queue; struct { int (*read)(struct osmo_rs232 *); } cb; /* sometimes we want to delay the transmission. */ struct osmo_timer_list tx_timer; struct { char serial_port[PATH_MAX]; int baudrate; unsigned int delay_us; } cfg; }; void rs232_tx_timer_cb(void *ptr) { struct osmo_rs232 *r = ptr; /* we're again ready to transmit. */ r->ofd.when |= BSC_FD_WRITE; } static int handle_ser_write(struct osmo_fd *bfd) { struct osmo_rs232 *r = bfd->data; struct llist_head *lh; struct msgb *msg; int written; LOGP(DLINP, LOGL_DEBUG, "writing data to rs232\n"); if (llist_empty(&r->tx_queue)) { r->ofd.when &= ~BSC_FD_WRITE; return 0; } lh = r->tx_queue.next; llist_del(lh); msg = llist_entry(lh, struct msgb, list); written = write(bfd->fd, msg->data, msg->len); if (written < msg->len) { LOGP(DLINP, LOGL_ERROR, "rs232: short write\n"); msgb_free(msg); return -1; } msgb_free(msg); /* We've got more data to write, but we have to wait to make it. */ if (!llist_empty(&r->tx_queue) && r->cfg.delay_us) { r->ofd.when &= ~BSC_FD_WRITE; osmo_timer_schedule(&r->tx_timer, 0, r->cfg.delay_us); } return 0; } static int handle_ser_read(struct osmo_fd *bfd) { struct osmo_rs232 *r = bfd->data; LOGP(DLINP, LOGL_DEBUG, "data to be read in rs232\n"); if (r->cb.read) r->cb.read(r); return 0; } static int serial_fd_cb(struct osmo_fd *bfd, unsigned int what) { int rc = 0; if (what & BSC_FD_READ) rc = handle_ser_read(bfd); if (rc < 0) return rc; if (what & BSC_FD_WRITE) rc = handle_ser_write(bfd); return rc; } struct osmo_rs232 *osmo_rs232_create(void *ctx) { struct osmo_rs232 *r; r = talloc_zero(ctx, struct osmo_rs232); if (r == NULL) return NULL; INIT_LLIST_HEAD(&r->tx_queue); return r; } void osmo_rs232_set_serial_port(struct osmo_rs232 *r, char *serial_port) { strncpy(r->cfg.serial_port, serial_port, PATH_MAX); r->cfg.serial_port[PATH_MAX-1] = '\0'; } void osmo_rs232_set_baudrate(struct osmo_rs232 *r, int baudrate) { r->cfg.baudrate = baudrate; } void osmo_rs232_set_delay_us(struct osmo_rs232 *r, int delay_us) { r->cfg.delay_us = delay_us; } void osmo_rs232_set_read_cb(struct osmo_rs232 *r, int (*read_cb)(struct osmo_rs232 *r)) { r->cb.read = read_cb; } /* XXX: Better use TIOCGSERIAL / TIOCSSERIAL to allow setting non-standard. */ static struct baudrate2termbits { int rate; int def; } baudrate2termbits[] = { { 9600, B9600 }, { 19200, B19200 }, { 38400, B38400 }, { 115200, B115200 }, { -1, -1 }, }; int osmo_rs232_open(struct osmo_rs232 *r) { int rc, i, speed = 0; struct osmo_fd *bfd = &r->ofd; struct termios tio; rc = open(r->cfg.serial_port, O_RDWR); if (rc < 0) { LOGP(DLINP, LOGL_ERROR, "rs232: cannot open serial port: %s", strerror(errno)); return rc; } bfd->fd = rc; /* set baudrate */ rc = tcgetattr(bfd->fd, &tio); if (rc < 0) { LOGP(DLINP, LOGL_ERROR, "rs232: tcgetattr says: %s", strerror(errno)); return rc; } for (i=0; icfg.baudrate) { speed = baudrate2termbits[i].def; break; } } if (speed == 0) { close(rc); bfd->fd = -1; return -1; } cfsetispeed(&tio, speed); cfsetospeed(&tio, speed); tio.c_cflag |= (CREAD | CLOCAL | CS8); tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); tio.c_iflag |= (INPCK | ISTRIP); tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR); tio.c_oflag &= ~(OPOST); rc = tcsetattr(bfd->fd, TCSADRAIN, &tio); if (rc < 0) { LOGP(DLINP, LOGL_ERROR, "rs232: tcsetattr says: %s", strerror(errno)); return rc; } bfd->when = BSC_FD_READ; bfd->cb = serial_fd_cb; bfd->data = r; rc = osmo_fd_register(bfd); if (rc < 0) { close(bfd->fd); LOGP(DLINP, LOGL_ERROR, "rs232: could not register FD: %s\n", strerror(rc)); return rc; } if (r->cfg.delay_us) { r->tx_timer.cb = rs232_tx_timer_cb; r->tx_timer.data = r; } return 0; } int osmo_rs232_read(struct osmo_rs232 *r, struct msgb *msg) { int ret; ret = read(r->ofd.fd, msg->data, msg->data_len); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "read error: %s\n", strerror(errno)); return -EIO; } msgb_put(msg, ret); return ret; } void osmo_rs232_write(struct osmo_rs232 *r, struct msgb *msg) { msgb_enqueue(&r->tx_queue, msg); r->ofd.when |= BSC_FD_WRITE; } void osmo_rs232_close(struct osmo_rs232 *r) { close(r->ofd.fd); r->ofd.fd = -1; } void osmo_rs232_destroy(struct osmo_rs232 *r) { talloc_free(r); } libosmo-netif-0.0.6/src/rtp.c000066400000000000000000000125511261607103500160310ustar00rootroot00000000000000#include #include #include #include /* for memcpy. */ #include /* for ntohs. */ #include #include #include #include /* * Internal definitions for this implementation. */ struct osmo_rtp_handle { struct { uint16_t sequence; uint32_t timestamp; uint32_t ssrc; struct timeval last_tv; } tx; }; struct osmo_rtp_handle *osmo_rtp_handle_create(void *ctx) { struct osmo_rtp_handle *h; h = talloc_zero(ctx, struct osmo_rtp_handle); if (h == NULL) { LOGP(DLMUX, LOGL_ERROR, "OOM\n"); return NULL; } return h; } void osmo_rtp_handle_free(struct osmo_rtp_handle *h) { DEBUGP(DLMUX, "%s (h=%p)\n", __FUNCTION__, h); talloc_free(h); } int osmo_rtp_handle_tx_set_sequence(struct osmo_rtp_handle *h, uint16_t seq) { DEBUGP(DLMUX, "%s (handle=%p, seq=%hu)\n", __FUNCTION__, h, seq); h->tx.sequence = seq; return 0; } int osmo_rtp_handle_tx_set_ssrc(struct osmo_rtp_handle *h, uint32_t ssrc) { DEBUGP(DLMUX, "%s (handle=%p, seq=%hu)\n", __FUNCTION__, h, ssrc); h->tx.ssrc = ssrc; return 0; } int osmo_rtp_handle_tx_set_timestamp(struct osmo_rtp_handle *h, uint32_t timestamp) { DEBUGP(DLMUX, "%s (handle=%p, ts=%hu)\n", __FUNCTION__, h, timestamp); h->tx.timestamp = timestamp; return 0; } struct rtp_hdr *osmo_rtp_get_hdr(struct msgb *msg) { struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data; if (msg->len < sizeof(struct rtp_hdr)) { DEBUGPC(DLMUX, "received RTP frame too short (len = %d)\n", msg->len); return NULL; } if (rtph->version != RTP_VERSION) { DEBUGPC(DLMUX, "received RTP version %d not supported.\n", rtph->version); return NULL; } return rtph; } void *osmo_rtp_get_payload(struct rtp_hdr *rtph, struct msgb *msg, uint32_t *plen) { struct rtp_x_hdr *rtpxh; uint8_t *payload; int payload_len; int x_len; int csrc_len; csrc_len = rtph->csrc_count << 2; payload = msg->data + sizeof(struct rtp_hdr) + csrc_len; payload_len = msg->len - sizeof(struct rtp_hdr) - csrc_len; if (payload_len < 0) { DEBUGPC(DLMUX, "received RTP frame too short (len = %d, " "csrc count = %d)\n", msg->len, rtph->csrc_count); return NULL; } if (rtph->extension) { if (payload_len < sizeof(struct rtp_x_hdr)) { DEBUGPC(DLMUX, "received RTP frame too short for " "extension header\n"); return NULL; } rtpxh = (struct rtp_x_hdr *)payload; x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr); payload += x_len; payload_len -= x_len; if (payload_len < 0) { DEBUGPC(DLMUX, "received RTP frame too short, " "extension header exceeds frame length\n"); return NULL; } } if (rtph->padding) { if (payload_len < 0) { DEBUGPC(DLMUX, "received RTP frame too short for " "padding length\n"); return NULL; } payload_len -= payload[payload_len - 1]; if (payload_len < 0) { DEBUGPC(DLMUX, "received RTP frame with padding " "greater than payload\n"); return NULL; } } *plen = payload_len; return (uint8_t *)msg->data + msg->len - payload_len; } struct msgb * osmo_rtp_build(struct osmo_rtp_handle *h, uint8_t payload_type, uint32_t payload_len, const void *data, uint32_t duration) { struct msgb *msg; struct rtp_hdr *rtph; struct timeval tv, tv_diff; long int usec_diff, frame_diff; gettimeofday(&tv, NULL); timersub(&tv, &h->tx.last_tv, &tv_diff); h->tx.last_tv = tv; usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec; frame_diff = (usec_diff / 20000); if (abs(frame_diff) > 1) { long int frame_diff_excess = frame_diff - 1; LOGP(DLMUX, LOGL_NOTICE, "Correcting frame difference of %ld frames\n", frame_diff_excess); h->tx.sequence += frame_diff_excess; h->tx.timestamp += frame_diff_excess * duration; } msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP"); if (!msg) { LOGP(DLMUX, LOGL_ERROR, "OOM\n"); return NULL; } rtph = (struct rtp_hdr *)msg->data; rtph->version = RTP_VERSION; rtph->padding = 0; rtph->extension = 0; rtph->csrc_count = 0; rtph->marker = 0; rtph->payload_type = payload_type; rtph->sequence = htons(h->tx.sequence++); rtph->timestamp = htonl(h->tx.timestamp); h->tx.timestamp += duration; rtph->ssrc = htonl(h->tx.ssrc); memcpy(msg->data + sizeof(struct rtp_hdr), data, payload_len); msgb_put(msg, sizeof(struct rtp_hdr) + payload_len); return msg; } #define SNPRINTF_BUFFER_SIZE(ret, size, len, offset) \ size += ret; \ if (ret > len) \ ret = len; \ offset += ret; \ len -= ret; int osmo_rtp_snprintf(char *buf, size_t size, struct msgb *msg) { struct rtp_hdr *rtph; int ret, i; uint8_t *payload; unsigned int len = size, offset = 0; rtph = osmo_rtp_get_hdr(msg); if (rtph == NULL) return -1; payload = (uint8_t *)rtph + sizeof(struct rtp_hdr); ret = snprintf(buf, len, "RTP ver=%01u ssrc=%u type=%02u " "marker=%01u ext=%01u csrc_count=%01u " "sequence=%u timestamp=%u [", rtph->version, ntohl(rtph->ssrc), rtph->payload_type, rtph->marker, rtph->extension, rtph->csrc_count, ntohs(rtph->sequence), ntohl(rtph->timestamp)); SNPRINTF_BUFFER_SIZE(ret, size, len, offset); for (i=0; ilen - sizeof(struct rtp_hdr); i++) { ret = snprintf(buf+offset, len, "%02x ", payload[i]); SNPRINTF_BUFFER_SIZE(ret, size, len, offset); } ret = snprintf(buf+offset, len, "]"); SNPRINTF_BUFFER_SIZE(ret, size, len, offset); return ret; } libosmo-netif-0.0.6/src/stream.c000066400000000000000000000307301261607103500165160ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Client side. */ enum osmo_stream_cli_state { STREAM_CLI_STATE_NONE = 0, STREAM_CLI_STATE_CONNECTING = 1, STREAM_CLI_STATE_CONNECTED = 2, STREAM_CLI_STATE_MAX }; #define OSMO_STREAM_CLI_F_RECONF (1 << 0) struct osmo_stream_cli { struct osmo_fd ofd; struct llist_head tx_queue; struct osmo_timer_list timer; enum osmo_stream_cli_state state; const char *addr; uint16_t port; int (*connect_cb)(struct osmo_stream_cli *srv); int (*read_cb)(struct osmo_stream_cli *srv); int (*write_cb)(struct osmo_stream_cli *srv); void *data; int flags; int reconnect_timeout; }; void osmo_stream_cli_close(struct osmo_stream_cli *cli); static void osmo_stream_cli_reconnect(struct osmo_stream_cli *cli) { if (cli->reconnect_timeout < 0) { LOGP(DLINP, LOGL_DEBUG, "not reconnecting, disabled.\n"); return; } LOGP(DLINP, LOGL_DEBUG, "connection closed\n"); osmo_stream_cli_close(cli); LOGP(DLINP, LOGL_DEBUG, "retrying in %d seconds...\n", cli->reconnect_timeout); osmo_timer_schedule(&cli->timer, cli->reconnect_timeout, 0); cli->state = STREAM_CLI_STATE_CONNECTING; } void osmo_stream_cli_close(struct osmo_stream_cli *cli) { osmo_fd_unregister(&cli->ofd); close(cli->ofd.fd); } static void osmo_stream_cli_read(struct osmo_stream_cli *cli) { LOGP(DLINP, LOGL_DEBUG, "message received\n"); if (cli->read_cb) cli->read_cb(cli); } static int osmo_stream_cli_write(struct osmo_stream_cli *cli) { struct msgb *msg; struct llist_head *lh; int ret; LOGP(DLINP, LOGL_DEBUG, "sending data\n"); if (llist_empty(&cli->tx_queue)) { cli->ofd.when &= ~BSC_FD_WRITE; return 0; } lh = cli->tx_queue.next; llist_del(lh); msg = llist_entry(lh, struct msgb, list); if (cli->state == STREAM_CLI_STATE_CONNECTING) { LOGP(DLINP, LOGL_ERROR, "not connected, dropping data!\n"); return 0; } ret = send(cli->ofd.fd, msg->data, msg->len, 0); if (ret < 0) { if (errno == EPIPE || errno == ENOTCONN) { osmo_stream_cli_reconnect(cli); } LOGP(DLINP, LOGL_ERROR, "error to send\n"); } msgb_free(msg); return 0; } static int osmo_stream_cli_fd_cb(struct osmo_fd *ofd, unsigned int what) { struct osmo_stream_cli *cli = ofd->data; int error, ret; socklen_t len = sizeof(error); switch(cli->state) { case STREAM_CLI_STATE_CONNECTING: ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len); if (ret >= 0 && error > 0) { osmo_stream_cli_reconnect(cli); return 0; } ofd->when &= ~BSC_FD_WRITE; LOGP(DLINP, LOGL_DEBUG, "connection done.\n"); cli->state = STREAM_CLI_STATE_CONNECTED; if (cli->connect_cb) cli->connect_cb(cli); break; case STREAM_CLI_STATE_CONNECTED: if (what & BSC_FD_READ) { LOGP(DLINP, LOGL_DEBUG, "connected read\n"); osmo_stream_cli_read(cli); } if (what & BSC_FD_WRITE) { LOGP(DLINP, LOGL_DEBUG, "connected write\n"); osmo_stream_cli_write(cli); } break; default: break; } return 0; } static void cli_timer_cb(void *data); struct osmo_stream_cli *osmo_stream_cli_create(void *ctx) { struct osmo_stream_cli *cli; cli = talloc_zero(ctx, struct osmo_stream_cli); if (!cli) return NULL; cli->ofd.fd = -1; cli->ofd.when |= BSC_FD_READ | BSC_FD_WRITE; cli->ofd.priv_nr = 0; /* XXX */ cli->ofd.cb = osmo_stream_cli_fd_cb; cli->ofd.data = cli; cli->state = STREAM_CLI_STATE_CONNECTING; cli->timer.cb = cli_timer_cb; cli->timer.data = link; cli->reconnect_timeout = 5; /* default is 5 seconds. */ INIT_LLIST_HEAD(&cli->tx_queue); return cli; } void osmo_stream_cli_set_addr(struct osmo_stream_cli *cli, const char *addr) { cli->addr = talloc_strdup(cli, addr); cli->flags |= OSMO_STREAM_CLI_F_RECONF; } void osmo_stream_cli_set_port(struct osmo_stream_cli *cli, uint16_t port) { cli->port = port; cli->flags |= OSMO_STREAM_CLI_F_RECONF; } void osmo_stream_cli_set_reconnect_timeout(struct osmo_stream_cli *cli, int timeout) { cli->reconnect_timeout = timeout; } void osmo_stream_cli_set_data(struct osmo_stream_cli *cli, void *data) { cli->data = data; } void *osmo_stream_cli_get_data(struct osmo_stream_cli *cli) { return cli->data; } struct osmo_fd * osmo_stream_cli_get_ofd(struct osmo_stream_cli *cli) { return &cli->ofd; } void osmo_stream_cli_set_connect_cb(struct osmo_stream_cli *cli, int (*connect_cb)(struct osmo_stream_cli *cli)) { cli->connect_cb = connect_cb; } void osmo_stream_cli_set_read_cb(struct osmo_stream_cli *cli, int (*read_cb)(struct osmo_stream_cli *cli)) { cli->read_cb = read_cb; } void osmo_stream_cli_destroy(struct osmo_stream_cli *cli) { talloc_free(link); } int osmo_stream_cli_open(struct osmo_stream_cli *cli) { int ret; /* we are reconfiguring this socket, close existing first. */ if ((cli->flags & OSMO_STREAM_CLI_F_RECONF) && cli->ofd.fd >= 0) osmo_stream_cli_close(cli); cli->flags &= ~OSMO_STREAM_CLI_F_RECONF; ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP, cli->addr, cli->port, OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK); if (ret < 0) { if (errno != EINPROGRESS) return ret; } cli->ofd.fd = ret; if (osmo_fd_register(&cli->ofd) < 0) { close(ret); return -EIO; } return 0; } static void cli_timer_cb(void *data) { struct osmo_stream_cli *cli = data; LOGP(DLINP, LOGL_DEBUG, "reconnecting.\n"); switch(cli->state) { case STREAM_CLI_STATE_CONNECTING: osmo_stream_cli_open(cli); break; default: break; } } void osmo_stream_cli_send(struct osmo_stream_cli *cli, struct msgb *msg) { msgb_enqueue(&cli->tx_queue, msg); cli->ofd.when |= BSC_FD_WRITE; } int osmo_stream_cli_recv(struct osmo_stream_cli *cli, struct msgb *msg) { int ret; ret = recv(cli->ofd.fd, msg->data, msg->data_len, 0); if (ret < 0) { if (errno == EPIPE || errno == ECONNRESET) { LOGP(DLINP, LOGL_ERROR, "lost connection with srv\n"); } osmo_stream_cli_reconnect(cli); return ret; } else if (ret == 0) { LOGP(DLINP, LOGL_ERROR, "connection closed with srv\n"); osmo_stream_cli_reconnect(cli); return ret; } msgb_put(msg, ret); LOGP(DLINP, LOGL_DEBUG, "received %d bytes from srv\n", ret); return ret; } /* * Server side. */ #define OSMO_STREAM_SRV_F_RECONF (1 << 0) struct osmo_stream_srv_link { struct osmo_fd ofd; const char *addr; uint16_t port; int (*accept_cb)(struct osmo_stream_srv_link *srv, int fd); void *data; int flags; }; static int osmo_stream_srv_fd_cb(struct osmo_fd *ofd, unsigned int what) { int ret; struct sockaddr_in sa; socklen_t sa_len = sizeof(sa); struct osmo_stream_srv_link *link = ofd->data; ret = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "failed to accept from origin " "peer, reason=`%s'\n", strerror(errno)); return ret; } LOGP(DLINP, LOGL_DEBUG, "accept()ed new link from %s to port %u\n", inet_ntoa(sa.sin_addr), link->port); if (link->accept_cb) link->accept_cb(link, ret); return 0; } struct osmo_stream_srv_link *osmo_stream_srv_link_create(void *ctx) { struct osmo_stream_srv_link *link; link = talloc_zero(ctx, struct osmo_stream_srv_link); if (!link) return NULL; link->ofd.fd = -1; link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE; link->ofd.cb = osmo_stream_srv_fd_cb; link->ofd.data = link; return link; } void osmo_stream_srv_link_set_addr(struct osmo_stream_srv_link *link, const char *addr) { link->addr = talloc_strdup(link, addr); link->flags |= OSMO_STREAM_SRV_F_RECONF; } void osmo_stream_srv_link_set_port(struct osmo_stream_srv_link *link, uint16_t port) { link->port = port; link->flags |= OSMO_STREAM_SRV_F_RECONF; } void osmo_stream_srv_link_set_data(struct osmo_stream_srv_link *link, void *data) { link->data = data; } void *osmo_stream_srv_link_get_data(struct osmo_stream_srv_link *link) { return link->data; } struct osmo_fd * osmo_stream_srv_link_get_ofd(struct osmo_stream_srv_link *link) { return &link->ofd; } void osmo_stream_srv_link_set_accept_cb(struct osmo_stream_srv_link *link, int (*accept_cb)(struct osmo_stream_srv_link *link, int fd)) { link->accept_cb = accept_cb; } void osmo_stream_srv_link_destroy(struct osmo_stream_srv_link *link) { talloc_free(link); } int osmo_stream_srv_link_open(struct osmo_stream_srv_link *link) { int ret; /* we are reconfiguring this socket, close existing first. */ if ((link->flags & OSMO_STREAM_SRV_F_RECONF) && link->ofd.fd >= 0) osmo_stream_srv_link_close(link); link->flags &= ~OSMO_STREAM_SRV_F_RECONF; ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP, link->addr, link->port, OSMO_SOCK_F_BIND); if (ret < 0) return ret; link->ofd.fd = ret; if (osmo_fd_register(&link->ofd) < 0) { close(ret); return -EIO; } return 0; } void osmo_stream_srv_link_close(struct osmo_stream_srv_link *link) { osmo_fd_unregister(&link->ofd); close(link->ofd.fd); } struct osmo_stream_srv { struct osmo_stream_srv_link *srv; struct osmo_fd ofd; struct llist_head tx_queue; int (*closed_cb)(struct osmo_stream_srv *peer); int (*cb)(struct osmo_stream_srv *peer); void *data; }; static void osmo_stream_srv_read(struct osmo_stream_srv *conn) { LOGP(DLINP, LOGL_DEBUG, "message received\n"); if (conn->cb) conn->cb(conn); return; } static void osmo_stream_srv_write(struct osmo_stream_srv *conn) { struct msgb *msg; struct llist_head *lh; int ret; LOGP(DLINP, LOGL_DEBUG, "sending data\n"); if (llist_empty(&conn->tx_queue)) { conn->ofd.when &= ~BSC_FD_WRITE; return; } lh = conn->tx_queue.next; llist_del(lh); msg = llist_entry(lh, struct msgb, list); ret = send(conn->ofd.fd, msg->data, msg->len, 0); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "error to send\n"); } msgb_free(msg); } static int osmo_stream_srv_cb(struct osmo_fd *ofd, unsigned int what) { struct osmo_stream_srv *conn = ofd->data; LOGP(DLINP, LOGL_DEBUG, "connected read/write\n"); if (what & BSC_FD_READ) osmo_stream_srv_read(conn); if (what & BSC_FD_WRITE) osmo_stream_srv_write(conn); return 0; } struct osmo_stream_srv * osmo_stream_srv_create(void *ctx, struct osmo_stream_srv_link *link, int fd, int (*cb)(struct osmo_stream_srv *conn), int (*closed_cb)(struct osmo_stream_srv *conn), void *data) { struct osmo_stream_srv *conn; conn = talloc_zero(ctx, struct osmo_stream_srv); if (conn == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in srv, " "reason=`%s'\n", strerror(errno)); return NULL; } conn->srv = link; conn->ofd.fd = fd; conn->ofd.data = conn; conn->ofd.cb = osmo_stream_srv_cb; conn->ofd.when = BSC_FD_READ; conn->cb = cb; conn->closed_cb = closed_cb; conn->data = data; INIT_LLIST_HEAD(&conn->tx_queue); if (osmo_fd_register(&conn->ofd) < 0) { LOGP(DLINP, LOGL_ERROR, "could not register FD\n"); talloc_free(conn); return NULL; } return conn; } void osmo_stream_srv_set_data(struct osmo_stream_srv *conn, void *data) { conn->data = data; } void *osmo_stream_srv_get_data(struct osmo_stream_srv *link) { return link->data; } struct osmo_fd * osmo_stream_srv_get_ofd(struct osmo_stream_srv *link) { return &link->ofd; } struct osmo_stream_srv_link *osmo_stream_srv_get_master(struct osmo_stream_srv *conn) { return conn->srv; } void osmo_stream_srv_destroy(struct osmo_stream_srv *conn) { close(conn->ofd.fd); osmo_fd_unregister(&conn->ofd); if (conn->closed_cb) conn->closed_cb(conn); talloc_free(conn); } void osmo_stream_srv_send(struct osmo_stream_srv *conn, struct msgb *msg) { msgb_enqueue(&conn->tx_queue, msg); conn->ofd.when |= BSC_FD_WRITE; } int osmo_stream_srv_recv(struct osmo_stream_srv *conn, struct msgb *msg) { int ret; ret = recv(conn->ofd.fd, msg->data, msg->data_len, 0); if (ret < 0) { if (errno == EPIPE || errno == ECONNRESET) { LOGP(DLINP, LOGL_ERROR, "lost connection with srv\n"); } return ret; } else if (ret == 0) { LOGP(DLINP, LOGL_ERROR, "connection closed with srv\n"); return ret; } msgb_put(msg, ret); LOGP(DLINP, LOGL_DEBUG, "received %d bytes from client\n", ret); return ret; } libosmo-netif-0.0.6/tests/000077500000000000000000000000001261607103500154275ustar00rootroot00000000000000libosmo-netif-0.0.6/tests/Makefile.am000066400000000000000000000032251261607103500174650ustar00rootroot00000000000000AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g AM_LDFLAGS = $(LIBOSMOCORE_LDFLAGS) check_PROGRAMS = osmux/osmux_test osmux_osmux_test_SOURCES = osmux/osmux_test.c osmux_osmux_test_LDADD = $(LIBOSMOCORE_LIBS) $(top_builddir)/src/libosmonetif.la # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac :;{ \ echo '# Signature of the current package.' && \ echo 'm4_define([AT_PACKAGE_NAME],' && \ echo ' [$(PACKAGE_NAME)])' && \ echo 'm4_define([AT_PACKAGE_TARNAME],' && \ echo ' [$(PACKAGE_TARNAME)])' && \ echo 'm4_define([AT_PACKAGE_VERSION],' && \ echo ' [$(PACKAGE_VERSION)])' && \ echo 'm4_define([AT_PACKAGE_STRING],' && \ echo ' [$(PACKAGE_STRING)])' && \ echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \ echo ' [$(PACKAGE_BUGREPORT)])'; \ echo 'm4_define([AT_PACKAGE_URL],' && \ echo ' [$(PACKAGE_URL)])'; \ } >'$(srcdir)/package.m4' EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ osmux/osmux_test.ok DISTCLEANFILES = atconfig TESTSUITE = $(srcdir)/testsuite check-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) installcheck-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \ $(TESTSUITEFLAGS) clean-local: test ! -f '$(TESTSUITE)' || \ $(SHELL) '$(TESTSUITE)' --clean AUTOM4TE = $(SHELL) $(top_srcdir)/missing --run autom4te AUTOTEST = $(AUTOM4TE) --language=autotest $(TESTSUITE): $(srcdir)/testsuite.at $(srcdir)/package.m4 $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at mv $@.tmp $@ libosmo-netif-0.0.6/tests/osmo-pcap-test/000077500000000000000000000000001261607103500203025ustar00rootroot00000000000000libosmo-netif-0.0.6/tests/osmo-pcap-test/.gitignore000066400000000000000000000003461261607103500222750ustar00rootroot00000000000000Makefile Makefile.in .deps .libs *.o *.lo *.la aclocal.m4 acinclude.m4 aminclude.am m4/*.m4 autom4te.cache config.h* config.sub config.log config.status config.guess configure depcomp missing ltmain.sh install-sh stamp-h1 libtool libosmo-netif-0.0.6/tests/osmo-pcap-test/Make_global.am000066400000000000000000000005771261607103500230270ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include -I../../../include AM_CFLAGS = -std=gnu99 -W -Wall \ -Wmissing-prototypes -Wwrite-strings -Wcast-qual -Wfloat-equal -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wstrict-prototypes -Wundef \ -Wno-unused-parameter -g \ ${LIBOSMOCORE_CFLAGS} libosmo-netif-0.0.6/tests/osmo-pcap-test/Makefile.am000066400000000000000000000004021261607103500223320ustar00rootroot00000000000000include $(top_srcdir)/Make_global.am check_PROGRAMS = osmo-pcap-test osmo_pcap_test_SOURCES = proto.c \ l3_ipv4.c \ l4_tcp.c \ l4_udp.c \ osmux_test.c \ pcap.c osmo_pcap_test_LDADD = -lpcap \ -losmocore \ -losmonetif libosmo-netif-0.0.6/tests/osmo-pcap-test/configure.ac000066400000000000000000000010731261607103500225710ustar00rootroot00000000000000AC_INIT(osmo-pcap-test, 0.0.1, pablo@gnumonks.org) AC_CONFIG_AUX_DIR([build-aux]) AC_CANONICAL_HOST AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects tar-pax no-dist-gzip dist-bzip2 1.6]) dnl kernel style compile messages m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0) AC_PROG_CC AC_DISABLE_STATIC AM_PROG_LIBTOOL AC_PROG_INSTALL AC_PROG_LN_S AM_PROG_LEX AC_PROG_YACC case "$host" in *-*-linux*) ;; *) AC_MSG_ERROR([Linux only, dude!]);; esac AC_CONFIG_FILES([Makefile]) AC_OUTPUT libosmo-netif-0.0.6/tests/osmo-pcap-test/l3_ipv4.c000066400000000000000000000020061261607103500217240ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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 vers */ #include #include #include #include "proto.h" #define PRINT_CMP(...) static int l3_ipv4_pkt_l4proto_num(const uint8_t *pkt) { const struct iphdr *iph = (const struct iphdr *)pkt; return iph->protocol; } static int l3_ipv4_pkt_l3hdr_len(const uint8_t *pkt) { const struct iphdr *iph = (const struct iphdr *)pkt; return iph->ihl << 2; } static struct osmo_pcap_proto_l2l3 ipv4 = { .l2protonum = ETH_P_IP, .l3protonum = AF_INET, .l2hdr_len = ETH_HLEN, .l3pkt_hdr_len = l3_ipv4_pkt_l3hdr_len, .l4pkt_proto = l3_ipv4_pkt_l4proto_num, }; void l2l3_ipv4_init(void) { osmo_pcap_proto_l2l3_register(&ipv4); } libosmo-netif-0.0.6/tests/osmo-pcap-test/l4_tcp.c000066400000000000000000000016761261607103500216450ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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 vers */ #include #include #include "proto.h" static int l4_tcp_pkt_hdr_len(const uint8_t *pkt) { const struct tcphdr *tcph = (const struct tcphdr *)pkt; return tcph->doff << 2; } static int l4_tcp_pkt_no_data(const uint8_t *pkt) { const struct tcphdr *tcph = (const struct tcphdr *)pkt; return tcph->syn || tcph->fin || tcph->rst || !tcph->psh; } static struct osmo_pcap_proto_l4 tcp = { .l4protonum = IPPROTO_TCP, .l4pkt_hdr_len = l4_tcp_pkt_hdr_len, .l4pkt_no_data = l4_tcp_pkt_no_data, }; void l4_tcp_init(void) { osmo_pcap_proto_l4_register(&tcp); } libosmo-netif-0.0.6/tests/osmo-pcap-test/l4_udp.c000066400000000000000000000015041261607103500216350ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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 vers */ #include #include #include "proto.h" static int l4_udp_pkt_hdr_len(const uint8_t *pkt) { return sizeof(struct udphdr); } static int l4_udp_pkt_no_data(const uint8_t *pkt) { /* UDP has no control packets. */ return 0; } static struct osmo_pcap_proto_l4 udp = { .l4protonum = IPPROTO_UDP, .l4pkt_hdr_len = l4_udp_pkt_hdr_len, .l4pkt_no_data = l4_udp_pkt_no_data, }; void l4_udp_init(void) { osmo_pcap_proto_l4_register(&udp); } libosmo-netif-0.0.6/tests/osmo-pcap-test/osmo_pcap.h000066400000000000000000000007231261607103500224350ustar00rootroot00000000000000#ifndef _OSMO_PCAP_TEST_H_ #define _OSMO_PCAP_TEST_H_ #include #include struct msgb; void osmo_pcap_init(void); struct osmo_pcap { pcap_t *h; struct osmo_timer_list timer; struct timeval last; }; pcap_t *osmo_pcap_test_open(const char *pcapfile); void osmo_pcap_test_close(pcap_t *handle); int osmo_pcap_test_run(struct osmo_pcap *p, uint8_t pnum, int (*cb)(struct msgb *msgb)); void osmo_pcap_stats_printf(void); #endif libosmo-netif-0.0.6/tests/osmo-pcap-test/osmux_test.c000066400000000000000000000113241261607103500226610ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "osmo_pcap.h" #define DOSMUXTEST 0 /* * This is the output handle for osmux, it stores last RTP sequence and * timestamp that has been used. There should be one per circuit ID. */ static struct osmux_out_handle h_output; static void tx_cb(struct msgb *msg, void *data) { printf("now sending message scheduled [emulated], msg=%p\n", msg); /* * Here we should call the real function that sends the message * instead of releasing it. */ msgb_free(msg); } static void deliver(struct msgb *batch_msg) { struct osmux_hdr *osmuxh; struct llist_head list; printf("sending batch (len=%d) [emulated]\n", batch_msg->len); /* This code below belongs to the osmux receiver */ while((osmuxh = osmux_xfrm_output_pull(batch_msg)) != NULL) { osmux_xfrm_output(osmuxh, &h_output, &list); osmux_tx_sched(&list, tx_cb, NULL); } msgb_free(batch_msg); } /* * This is the input handle for osmux. It stores the last osmux sequence that * has been used and the deliver function that sends the osmux batch. */ struct osmux_in_handle h_input = { .osmux_seq = 0, /* sequence number to start OSmux message from */ .batch_factor = 4, /* batch up to 4 RTP messages */ .deliver = deliver, }; #define MAX_CONCURRENT_CALLS 8 static int ccid[MAX_CONCURRENT_CALLS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; static void register_ccid(uint32_t ssrc) { int i, found = 0; for (i=0; issrc); if (ccid < 0) register_ccid(rtph->ssrc); while ((ret = osmux_xfrm_input(&h_input, msg, ccid)) > 1) { /* batch full, deliver it */ osmux_xfrm_input_deliver(&h_input); } if (ret == -1) printf("something is wrong\n"); return 0; } static struct osmo_pcap osmo_pcap; static void osmo_pcap_pkt_timer_cb(void *data) { if (osmo_pcap_test_run(&osmo_pcap, IPPROTO_UDP, pcap_test_run) < 0) { osmo_pcap_stats_printf(); printf("\e[1;34mDone.\e[0m\n"); osmo_pcap_test_close(osmo_pcap.h); exit(EXIT_SUCCESS); } } struct log_info_cat osmux_test_cat[] = { [DOSMUXTEST] = { .name = "DOSMUXTEST", .description = "osmux test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_NOTICE, }, }; const struct log_info osmux_log_info = { .filter_fn = NULL, .cat = osmux_test_cat, .num_cat = ARRAY_SIZE(osmux_test_cat), }; static void *tall_test; int main(int argc, char *argv[]) { int ret; if (argc != 2) { fprintf(stderr, "Wrong usage:\n"); fprintf(stderr, "%s \n", argv[0]); fprintf(stderr, "example: %s file.pcap\n", argv[0]); exit(EXIT_FAILURE); } tall_test = talloc_named_const(NULL, 1, "osmux_pcap_test"); osmo_init_logging(&osmux_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); osmo_pcap_init(); printf("\e[1;34mStarting test...\e[0m\n"); osmo_pcap.h = osmo_pcap_test_open(argv[1]); if (osmo_pcap.h == NULL) exit(EXIT_FAILURE); osmo_pcap.timer.cb = osmo_pcap_pkt_timer_cb; osmux_xfrm_input_init(&h_input); osmux_xfrm_output_init(&h_output); /* first run */ osmo_pcap_pkt_timer_cb(NULL); while(1) { osmo_select_main(0); } return ret; } libosmo-netif-0.0.6/tests/osmo-pcap-test/pcap.c000066400000000000000000000076751261607103500214100ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include "proto.h" #include "osmo_pcap.h" #include #include #include #include struct osmo_pcap_test_stats { uint32_t pkts; uint32_t skip; uint32_t processed; uint32_t unsupported_l3; uint32_t unsupported_l4; } osmo_pcap_test_stats; static int osmo_pcap_process_packet(const uint8_t *pkt, uint32_t pktlen, struct osmo_pcap_proto_l2l3 *l3h, struct osmo_pcap_proto_l4 *l4h, int (*cb)(struct msgb *msgb)) { unsigned int l3hdr_len, skip_hdr_len; struct msgb *msgb; int ret; /* skip layer 2, 3 and 4 headers */ l3hdr_len = l3h->l3pkt_hdr_len(pkt + ETH_HLEN); skip_hdr_len = l3h->l2hdr_len + l3hdr_len + l4h->l4pkt_hdr_len(pkt + ETH_HLEN + l3hdr_len); /* This packet contains no data, skip it. */ if (l4h->l4pkt_no_data(pkt + l3hdr_len + ETH_HLEN)) { osmo_pcap_test_stats.skip++; return 0; } /* get application layer data. */ pkt += skip_hdr_len; pktlen -= skip_hdr_len; /* Create the fake network buffer. */ msgb = msgb_alloc(pktlen, "OSMO/PCAP test"); if (msgb == NULL) { fprintf(stderr, "Not enough memory\n"); return -1; } memcpy(msgb->data, pkt, pktlen); msgb_put(msgb, pktlen); ret = cb(msgb); osmo_pcap_test_stats.processed++; return ret; } pcap_t *osmo_pcap_test_open(const char *pcapfile) { pcap_t *handle; char errbuf[PCAP_ERRBUF_SIZE]; handle = pcap_open_offline(pcapfile, errbuf); if (handle == NULL) { fprintf(stderr, "couldn't open pcap file %s: %s\n", pcapfile, errbuf); return NULL; } return handle; } void osmo_pcap_test_close(pcap_t *handle) { pcap_close(handle); } int osmo_pcap_test_run(struct osmo_pcap *p, uint8_t pnum, int (*cb)(struct msgb *msgb)) { struct osmo_pcap_proto_l2l3 *l3h; struct osmo_pcap_proto_l4 *l4h; struct pcap_pkthdr pcaph; const u_char *pkt; struct timeval res; uint8_t l4protonum; retry: pkt = pcap_next(p->h, &pcaph); if (pkt == NULL) return -1; osmo_pcap_test_stats.pkts++; l3h = osmo_pcap_proto_l2l3_find(pkt); if (l3h == NULL) { osmo_pcap_test_stats.unsupported_l3++; goto retry; } l4protonum = l3h->l4pkt_proto(pkt + ETH_HLEN); /* filter l4 protocols we are not interested in */ if (l4protonum != pnum) { osmo_pcap_test_stats.skip++; goto retry; } l4h = osmo_pcap_proto_l4_find(pkt, l4protonum); if (l4h == NULL) { osmo_pcap_test_stats.unsupported_l4++; goto retry; } /* first packet that is going to be processed */ if (osmo_pcap_test_stats.processed == 0) memcpy(&p->last, &pcaph.ts, sizeof(struct timeval)); /* retry with next packet if this has been skipped. */ if (osmo_pcap_process_packet(pkt, pcaph.caplen, l3h, l4h, cb) < 0) goto retry; /* calculate waiting time */ timersub(&pcaph.ts, &p->last, &res); printf("next packet comes in %lu.%.6lu seconds\n", res.tv_sec, res.tv_usec); osmo_timer_schedule(&p->timer, res.tv_sec, res.tv_usec); memcpy(&p->last, &pcaph.ts, sizeof(struct timeval)); return 0; } void osmo_pcap_stats_printf(void) { printf("pkts=%d processed=%d skip=%d " "unsupported_l3=%d unsupported_l4=%d\n", osmo_pcap_test_stats.pkts, osmo_pcap_test_stats.processed, osmo_pcap_test_stats.skip, osmo_pcap_test_stats.unsupported_l3, osmo_pcap_test_stats.unsupported_l4); } void osmo_pcap_init(void) { /* Initialization of supported layer 3 and 4 protocols here. */ l2l3_ipv4_init(); l4_tcp_init(); l4_udp_init(); } libosmo-netif-0.0.6/tests/osmo-pcap-test/pcaps/000077500000000000000000000000001261607103500214105ustar00rootroot00000000000000libosmo-netif-0.0.6/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap000066400000000000000000004431441261607103500275410ustar00rootroot00000000000000 hM<+Linux 3.5.0-rc1+*Dumpcap 1.7.1 (SVN Rev 41546 from /trunk)hDeth0  Linux 3.5.0-rc1+D1{aa!JSES>u r.6 ߠP>($ (08AIQYaiqy X1$|66S!JE(y@@?3 >u ߠr.6P<Xd13CC!JSE5,>u r.6 ߠP>$ HBdX1366S!JE(y@@?2 >u ߠr.6P<Xt14SSS!JEEy@@? >u ߠr.6P<7! d r t`1@@!JSE2.>u r.6 ߽P>6" B`x1rVVS!JEHy@@? >u ߽r.6P<: +-? HB+++++++++++x\1핸<<!JSE(7>u r.6 P>\p1!OO!JSEA>u r.6 P>t  $q0M#qpd1$DDS!JE6y@@?! >u r.7P<(   !dh1HH!JSE:#>u r.7 P>p( ?0%?hX166S!JE(y@@?. >u r.7*P<Xp1NN!JSE@>u r.7* P>@~  0 ` pX1Ԯ66S!JE(y@@?- >u r.7BP<Xx1vUU!JSEG>u r.7B P>  E`^xX1v66S!JE(y@@?, >u r.7aP<Xl1xLLS!JE>y@@? >u r.7aP<0   A(lh1HH!JSE: >u r.7a P>   Ahx1蓿VVS!JEHy@@?  >u r.7sP<:     -xh1dHH!JSE:>u r.7s !P>r9( ?<.%?ht11dRRS!JEDy@@?  >u !r.7P<6) !6(~p bt`1n==!JSE/)>u r.7 =P>* `X166S!JE(y@@?( >u =r.7P<Xx1VV!JSEH>u r.7 =P>~q    *xX166S!JE(y@@?' >u =r.7P<Xh1.EES!JE7y@@? >u =r.7P<)    h13!aa!JSES>u r.7 LP>l(~v `1c!==S!JE/y@@? >u Lr.7Pu r.7 LP>  `X166S!JE(y@@?$ >u Sr.7P<X12m__!JSEQ>u r.7 SP>.M&" (08AIQYaiqy `1bm==S!JE/y@@? >u Sr.8 Pu r.8 ZP>G ABdt1SSS!JEEy@@? >u Zr.8P<7! d r t`1`==!JSE/#>u r.8 wP>63 `X1!N66S!JE(y@@?! >u wr.8P<X`1P@@!JSE2>u r.8 wP>" Cm`X1P66S!JE(y@@?  >u wr.8'P<Xx1QVVS!JEHy@@> >u wr.8'P<: +-? AB+++++++++++xh1HH!JSE:>u r.8' P>pL( =0%?hX1T<66S!JE(y@@? >u r.89P<Xp1OO!JSEA>u r.89 P>r  $q0M#qpX166S!JE(y@@? >u r.8RP<Xd1lDDS!JE6y@@? >u r.8RP<(   !dp1NN!JSE@>u r.8R P>=  0 ` pX1966S!JE(y@@? >u r.8jP<Xx1UU!JSEG>u r.8j P>  E`^xX166S!JE(y@@? >u r.8P<Xl1eLLS!JE>y@@? >u r.8P<0   A(lh1HH!JSE:>u r.8 P>"   Ahx1HVVS!JEHy@@> >u r.8P<:     -xl1KK!JSE=>u r.8 P>H( >>% p%@lt1RRS!JEDy@@> >u r.8P<6) !6(~p bt`1==!JSE/>u r.8 P>* `X1M66S!JE(y@@? >u r.8P<Xh1HH!JSE:>u r.8 P>)%~q hX1\66S!JE(y@@? >u r.8P<Xd1xGDD!JSE6>u r.8 P>   *dX1$H66S!JE(y@@? >u r.8P<Xh1HEES!JE7y@@? >u r.8P<)    h1Aqaa!JSES>u r.8 P>j (~v `1rq==S!JE/y@@?  >u r.9Pu r.9 P>  `X1 66S!JE(y@@? >u  r.9 P<X1I``!JSER>u r.9  P>'( 4.( p 998%@`1I==S!JE/y@@?  >u  r.95Pu r.95 P> GB`dt1USSS!JEEy@@> >u r.9BP<7! d r t`1,@@!JSE2>u r.9B 1P>^" B`x1VVS!JEHy@@> >u 1r.9LP<: +-? GB`+++++++++++x`1==!JSE/>u r.9L QP>`F3 `X1 66S!JE(y@@?  >u Qr.9SP<Xp1OO!JSEA>u r.9S QP>q0  $q0M#qpX166S!JE(y@@?  >u Qr.9lP<Xd1NDDS!JE6y@@> >u Qr.9lP<(   !dp1VNN!JSE@>u r.9l _P><  0 ` pX1166S!JE(y@@?  >u _r.9P<Xh1HH!JSE:>u r.9 _P>( 7%?hX1f66S!JE(y@@?  >u _r.9P<Xx1!+UU!JSEG>u r.9 _P>   E`^xX1+66S!JE(y@@? >u _r.9P<Xl1.LLS!JE>y@@> >u _r.9P<0   A(lh1GHH!JSE:>u r.9 uP><   Ahx1HVVS!JEHy@@> >u ur.9P<:     -x\1b8<<!JSE(>u r.9 P> |\t18RRS!JEDy@@> >u r.9P<6) !6(~p bt`1Q@==!JSE/ >u r.9 P>K* `X166S!JE(y@@? >u r.9P<Xx1VV!JSEH>u r.9 P>~q    *xX166S!JE(y@@? >u r.9P<Xh10EES!JE7y@@> >u r.9P<)    hh1HH!JSE:>u r.9 P>u!( >5-%?h`1K==S!JE/y@@> >u r.:Pu r.: P>i(~v X1 c66S!JE(y@@? >u r.:+P<X`1e??!JSE1>u r.:+ P>  `X1Bf66S!JE(y@@> >u r.:4P<X`1f==S!JE/y@@> >u r.:4Pu r.:4 P>3 `X1=66S!JE(y@@> >u r.:;P<X1:^]]!JSEO>u r.:; P>̆$ (08AIQYaiqy X1^66S!JE(y@@> >u r.:bP<X1Oaa!JSES>u r.:b P>A($ (08AIQYaiqy X15P66S!JE(y@@> >u r.:P<X\1~"<<!JSE, Xk=pP>\\1a"::S!JE,/@@  Xk=pP\Ƃ\\1 %<<!JSE(  Xk=tP>\d1-CC!JSE5>u r.: P> AMdX1-66S!JE(y@@> >u r.:P<Xt1-SSS!JEEy@@> >u r.:P<7! d r t`1" .@@!JSE2>u r.: P>" NH`x1/ .VVS!JEHy@@> >u r.:P<: +-? AM+++++++++++xp1/;0OO!JSEA>u r.:  P>o%  $q0M#qpd1kD0DDS!JE6y@@> >u  r.:P<(   !dh1F0HH!JSE:>u r.:  P>k"(  ?(%?hX1066S!JE(y@@> >u r.:P<Xp1ӻ1NN!JSE@>u r.: P>:  0 ` pX1166S!JE(y@@> >u r.:P<Xx1]3UU!JSEG>u r.: P>  E`^xX1366S!JE(y@@> >u r.;P<Xl1Ƙ3LLS!JE>y@@> >u r.;P<0   A(lh1c5HH!JSE:>u r.; /P>1   Ahd15DDS!JE6y@@> >u /r.;P<(   dl1Փ7KK!JSE=>u r.; =P>I( ?;. p%?lt17RRS!JEDy@@> >u =r.;-P<6) !6(~p bt`17==!JSE/>u r.;- YP>=* `X1.866S!JE(y@@> >u Yr.;4P<Xh118HH!JSE:>u r.;4 YP>"D~q hX11866S!JE(y@@> >u Yr.;FP<Xh1;;HHS!JE:y@@> >u Yr.;FP<,  5X:(h\1H><<!JSE(>u r.;F kP>'\1>``!JSER>u r.;F kP>}'( ?? p ::K%?X1>66S!JE(y@@> >u kr.;pP<Xh1xBHHS!JE:y@@> >u kr.;pP<,  5X:(h\1E<<!JSE(>u r.;p }P>\d14FCC!JSE5>u r.;p }P>U %LldX14F66S!JE(y@@> >u }r.;}P<Xt14FSSS!JEEy@@> >u }r.;}P<7! d r t1[:F``!JSER>u r.;} P>c'( ?? p ::%?X1F66S!JE(y@@> >u r.;P<X`1F@@!JSE2>u r.; P>[" M`X1F66S!JE(y@@> >u r.;P<Xx1FVVS!JEHy@@> >u r.;P<: +-? %Ll+++++++++++xh1B&GHH!JSE:>u r.; P>(  %?hX1LG66S!JE(y@@> >u r.;P<Xp1ւIOO!JSEA>u r.; P>R7  '05X:pX1I66S!JE(y@@> >u r.;P<Xx1PIVVS!JEHy@@> >u r.;P<:  `\^xp1KNN!JSE@>u r.; P>6  0 ` pX1NK66S!JE(y@@> >u r.;P<X1K]]!JSEO>u r.; P>ɹ$ (08AIQYaiqy X1@K66S!JE(y@@> >u r.<P<Xd1LDD!JSE6>u r.< P>v   dX1%L66S!JE(y@@> >u r.<)P<Xl1LLLS!JE>y@@> >u r.<)P<0   A(l1M``!JSER>u r.<) P>'( >> p ::%?X1'N66S!JE(y@@> >u r.u r.( 47%AhX1>yN66S!JE(y@@> >u r.u r.   AhX1p O66S!JE(y@@> >u r. >u r.u r.K* `d1oOAAS!JE3y@@> >u r.<~P<%~p bdh1 OHH!JSE:>u r.<~  P>N~q hX1,O66S!JE(y@@> >u  r.u r.<  P>u   AdX1P66S!JE(y@@> >u  r. >u  r.u r.< P> \1T``!JSER>u r.< P>8'( >> p ::%?X1zU66S!JE(y@@> >u r.u r.< P>S'( ?? p @%AX1U66S!JE(y@@> >u r.u r.< P>'( >> p 9:%?X1x2\66S!JE(y@@> >u r.=P<X1!]``!JSER>u r.= P>'( ?? p >>0%AX1M]66S!JE(y@@> >u r.=FP<X1(c``!JSER>u r.=F P>'( >> p 9:%?X1fc66S!JE(y@@> >u r.=pP<X1 rd``!JSER>u r.=p P>_'( ?? p >>%AX17rd66S!JE(y@@> >u r.=P<X1)j``!JSER>u r.= P><'( >> p ::%?X1ij66S!JE(y@@> >u r.=P<X1Ok``!JSER>u r.= P> '( ?? p >>%AX1k66S!JE(z@@> >u r.=P<X1*r``!JSER>u r.= P>'(  >? p ::%?X1*r66S!JE(z@@> >u r.>P<X1Gs``!JSER>u r.> P>'( ?? p >>%AX1s66S!JE(z@@> >u r.>BP<X13w]]!JSEO>u r.>B P>3$ (08AIQYaiqy X1@3w66S!JE(z@@> >u r.>iP<X1H~y``!JSER>u r.>i P>m'(  >? p ::%?X1r~y66S!JE(z@@> >u r.>P<X1Dkz``!JSER>u r.> P><'( ?? p >>%AX1okz66S!JE(z@@> >u r.>P<Xd1D{DD!JSE6>u r.> P>s   dX1D{66S!JE(z@@> >u r.>P<Xd1E{DDS!JE6z@@> >u r.>P<(   d\1;~<<!JSE(>u r.> (P>\1;~uuS!JEgz@@> >u (r.>Pu r.> gP>~t `h1YZ~GG!JSE9u4%Tрb A ?hh1 [~GGS!JE9<@@|u6%6b A ?hh14]~GG!JSE9u6%Lb2< ` @ |<@M˼0hh1]~GGS!JE9;8@@}|u4%6b2< ` @ |<@M˼0hh1_~GG!JSE9u4%GJb A y~hh1~GGS!JE9<@@|u6%6b A y~hh1O~GG!JSE9u6%A b2 ` Z''o4@ hh1~GGS!JE9;9@@}{u4%6b2 ` Z''o4@ hX1~66S!JE(z @@> >u gr.>P<X`1.~@@!JSE2>u r.> gP>~t `X1b~66S!JE(z @@> >u gr.>P<Xh1p~GG!JSE9u4%Pb6 A ~hh1~GGS!JE9<@@|u6%6b6 A ~hh1n~GG!JSE9u6%otb2| ` 7kϝ/(njthh1~GGS!JE9;:@@}zu4%6b2| ` 7kϝ/(njthh1DGG!JSE9u4% b A y{hh1IEGGS!JE9<@@|u6%6b A y{hh1GGG!JSE9u6%b2 ` 8 /G}Tg5hh1HGGS!JE9;;@@}yu4%6b2 ` 8 /G}Tg5hh1GG!JSE9u4%RMbv A ?hh1IGGS!JE9<@@|u6%6bv A ?hh1GG!JSE9u6%lSb2 ` m-d|TMhh1DGGS!JE9;<@@}xu4%6b2 ` m-d|TMhh1;GG!JSE9u6%] b2\ ` uh`Ǒ"4hh1GGS!JE9;=@@}wu4%6b2\ ` uh`Ǒ"4hd1DD!JSE6>u r.> gP>W   dX166S!JE(z @@> >u gr.>P<Xh1(/GG!JSE9u4%}b A 8QNOI3hh1/GGS!JE9<@@{u6%6b A 8QNOI3hh11GG!JSE9u6%#b2 ` #7̐DEOThh12GGS!JE9;>@@}vu4%6b2 ` #7̐DEOThh1*wGG!JSE9u4%rҀb A #RmZ1Л7hh1wGGS!JE9<@@{u6%6b A #RmZ1Л7hh1zGG!JSE9u6%Wvb2  ` * Gu r.> gP>'(  >? p :;%?X1р66S!JE(z @@> >u gr.?P<Xh1yGG!JSE9u4%@b A u y-~$hh1 GGS!JE9<@@{u6%6b A u y-~$hh1NGG!JSE9u6%ib2  ` uQY4*hh1GGS!JE9;A@@}su4%6b2  ` uQY4*hh1aGG!JSE9 u4%K$b A #85X.Je(hh1!bGGS!JE9<@@{u6%6b A #85X.Je(hh1sdGG!JSE9 u6%b2 | `  z'K-2hh1eGGS!JE9;B@@}ru4%6b2 | `  z'K-2hh1GG!JSE9 u4%Ѳb6 A 8=(IϿRThh1CGGS!JE9<@@{u6%6b6 A 8=(IϿRThh1rGG!JSE9 u6%vb2  ` 8]T%<hh1GGS!JE9;C@@}qu4%6b2  ` 8]T%<h1``!JSER >u r.? gP> l'( ?? p >>%@X1+66S!JE(z @@> >u gr.?AP<Xh1GG!JSE9u4%B@b A *z.srbhh1iGGS!JE9<@@{u6%6b A *z.srbhh1GG!JSE9u6%Ͷb2¼ ` *<Ě hh19GGS!JE9;D@@}pu4%6b2¼ ` *<Ě hh1KGG!JSE9u4%b v A gW{:/Őhh1}LGGS!JE9<@@{u6%6b v A gW{:/Őhh1NGG!JSE9u6%hb2\ ` L_լq[`hh17OGGS!JE9;E@@}ou4%6b2\ ` L_լq[`hh1GG!JSE9u4%b  A _V햃hh1}GGS!JE9<@@{u6%6b  A _V햃hh1ӖGG!JSE9u6% kb2 ` * Wj6z{e`hh1GGS!JE9;F@@}nu4%6b2 ` * Wj6z{e`hh1TGG!JSE9u4%ߺb  A L*J^UWZȐhh1WGGS!JE9<@@{u6%6b  A L*J^UWZȐhh1GG!JSE9u6%'b2Ĝ ` & Yhh1GGS!JE9;G@@}mu4%6b2Ĝ ` & Yhh1g6GG!JSE9u4%b V A * X=hh1<7GGS!JE9<@@{u6%6b V A * X=hh17GG!JSE9u6%yb2< ` U71_rhh18GGS!JE9;H@@}lu4%6b2< ` U71_rhh1q~GG!JSE9u4%$b  A 8גhnhh1EGGS!JE9<@@{u6%6b  A 8גhnhh1!GG!JSE9u6%b2 `  S?U?͕hh1ɀGGS!JE9;I@@}ku4%6b2 `  S?U?͕hh1؃GG!JSE9u4%]b  A  /Q4hh1كGGS!JE9<@@{u6%6b  A  /Q4hh1mۃGG!JSE9u6%Fvb2| ` 80zhh1ۃGGS!JE9;J@@}ju4%6b2| ` 80zhh1 GG!JSE9u4%Bb 6 A WLE7iMCL(hh1/!GGS!JE9<@@{u6%6b 6 A WLE7iMCL(hh1#GG!JSE9u6%=tb2 ` gex1hh1$GGS!JE9;K@@}iu4%6b2 ` gex1hh1hGG!JSE9u4%yb  A u# xhh19iGGS!JE9<@@{u6%6b  A u# xhh1kGG!JSE9u6%G;b2Ǽ ` # ' J>(fhh1*lGGS!JE9;L@@}hu4%6b2Ǽ ` # ' J>(fhh1„GG!JSE9 u4%Zbv A .D(dhh1sÄGGS!JE9<@@{u6%6bv A .D(dhh1ńGG!JSE9!u6%ۀb2\ ` Jˈ@hh1YƄGGS!JE9;M@@}gu4%6b2\ ` Jˈ@hh1 GG!JSE9"u4%nb A P'_̱bl0hh1 GGS!JE9<@@{u6%6b A P'_̱bl0hh1 GG!JSE9#u6%oЀb2 ` &mX50+bhh1GGS!JE9;N@@}fu4%6b2 ` &mX50+bhh1%SGG!JSE9$u4%0b A *VJ hh1SGGS!JE9<@@{u6%6b A *VJ hh1UGG!JSE9%u6%晀b2ɜ ` 8 eJ;]}hh1VGGS!JE9;O@@}eu4%6b2ɜ ` 8 eJ;]}hh1PGG!JSE9&u4%bV A .(;ΗdˈDhh1䭅GGS!JE9<@@{u6%6bV A .(;ΗdˈDhh1-GG!JSE9'u6%X b2< ` *=,hh1GGS!JE9;P@@}du4%6b2< ` *=,hh1kGG!JSE9(u4%ƀb A QV̙2Vhh1GGS!JE9<@@{u6%6b A QV̙2Vhh1QGG!JSE9)u6%cրb2 ` G;GGS!JE9<@@{u6%6b A I?Զ #dhh1GG!JSE93u6%eb2  ` *ﶚW沀Bldhh1GGS!JE9;V@@}^u4%6b2  ` *ﶚW沀Bldhh1ɇGG!JSE94u4%)b A .~hh1?ʇGGS!JE9<@@{u6%6b A .~hh16͇GG!JSE95u6%b2!Μ ` .zEsۜ1Khh1͇GGS!JE9;W@@}]u4%6b2!Μ ` .zEsۜ1Khh1,GG!JSE96~u4%?0bV A ޑ>gWBhh1GGS!JE9<@@{u6%6bV A ޑ>gWBhh1#GG!JSE97}u6%^b2"< ` .z/1sLjhh1GGS!JE9;X@@}\u4%6b2"< ` .z/1sLjh1t$``!JSER8n>u r.?A gP>G'(  >> p ;;%?X1$66S!JE(z@@> >u gr.?kP<Xh10lGG!JSE99{u4%6b A .Oq 0hh1lGGS!JE9<@@{u6%6b A .Oq 0hh1oGG!JSE9:zu6%}b2# ` ҄vu6%ڎb2% ` #מ8}g(hh1GGS!JE9;[@@}Yu4%6b2% ` #מ8}g(h1``!JSER?g>u r.?k gP>'(  ?? p >>0%@X1f66S!JE(z@@> >u gr.?P<Xh1VGG!JSE9@tu4%b A W"}߳fJhh1aWGGS!JE9<@@{u6%6b A W"}߳fJhh1YGG!JSE9Asu6%EĀb2&Ѽ `  uޱdHjhh1=ZGGS!JE9;\@@}Xu4%6b2&Ѽ `  uޱdHjhh1ϞGG!JSE9Bru4%Vbv A #HWބ: dHhh1bGGS!JE9<@@{u6%6bv A #HWބ: dHhh1GG!JSE9Cqu6%>9b2'\ ` )nBEThh1GGS!JE9;]@@}Wu4%6b2'\ ` )nBEThh1GG!JSE9Dpu4%Wb A 3o|e hh1}GGS!JE9<@@{u6%6b A 3o|e hh1GG!JSE9Eou6%9b2( ` uwׂԟ@&hh1GGS!JE9;^@@}Vu4%6b2( ` uwׂԟ@&hh1HAGG!JSE9Fnu4%t@b A *-社hh1AGGS!JE9<@@{u6%6b A *-社hh1CGG!JSE9Gmu6%'b2)Ӝ ` QMV{hh1DGGS!JE9;_@@}Uu4%6b2)Ӝ ` QMV{hh12GG!JSE9Hlu4%bV A ,:Y^hh1oGGS!JE9<@@{u6%6bV A ,:Y^hh1GG!JSE9Iku6%ǀb2*< ` $5͞h>T{ahh1ŒGGS!JE9;`@@}Tu4%6b2*< ` $5͞h>T{ahh1ъGG!JSE9Jju4%Ab A 2-'V @hh1ҊGGS!JE9<@@{u6%6b A 2-'V @hh1]ӊGG!JSE9Kiu6%izb2+ ` 8sGxJhh1ӊGGS!JE9;a@@}Su4%6b2+ ` 8sGxJhh1+GG!JSE9Lhu4%b A `{ʖ)r hh1t,GGS!JE9<@@{u6%6b A `{ʖ)r hh10-GG!JSE9Mgu6%%Ib2,| ` V_ \0<hh1-GGS!JE9;b@@}Ru4%6b2,| ` V_ \0<hh1sGG!JSE9Nfu4%b6 A uQQ`[8hh1tGGS!JE9<@@{u6%6b6 A uQQ`[8hh1huGG!JSE9Oeu6%G;b2- ` P$}@-hh1vGGS!JE9;c@@}Qu4%6b2- ` P$}@-hh1ɻGG!JSE9Pdu4%ڀb A ytQѰhh1GGS!JE9<@@{u6%6b A ytQѰhh1wGG!JSE9Qcu6%(b2.ּ ` .vLVʋbLhh1&GGS!JE9;d@@}Pu4%6b2.ּ ` .vLVʋbLhh1GG!JSE9Rbu4%ʀbv A  ڗޠ{|̪dhh1rGGS!JE9<@@{u6%6bv A  ڗޠ{|̪dhh1GG!JSE9Sau6%,b2/\ ` -ެ 10\hh1TGGS!JE9;e@@}Ou4%6b2/\ ` -ެ 10\hh1 ^GG!JSE9T`u4%b A 5Ӯߤ\phh1^GGS!JE9<@@{u6%6b A 5Ӯߤ\phh1`GG!JSE9U_u6%b20 ` Lǖ@(hh1{aGGS!JE9;f@@}Nu4%6b20 ` Lǖ@(hh1GG!JSE9V^u4%qb A u FzD"`hh1GGS!JE9<@@{u6%6b A u FzD"`hh1GG!JSE9W]u6%b21؜ ` uQ'q!zhh1GGS!JE9;g@@}Mu4%6b21؜ ` uQ'q!zhh1!GG!JSE9X\u4%wbV A Dg:qܶS(Lxhh1GGS!JE9<@@{u6%6bV A Dg:qܶS(Lxhh1GG!JSE9Y[u6%Àb22< ` WP//Lhh1GGS!JE9;h@@}Lu4%6b22< ` WP//Lhh1fHGG!JSE9ZZu4%b A {'4xhh1HGGS!JE9<@@{u6%6b A {'4xhh1?KGG!JSE9[Yu6%K23 ` u OX[ hh1KGGS!JE9;i@@}Ku4%623 ` u OX[ hh1GG!JSE9\Xu4%9b  A NnCH hh1GGS!JE9<@@{u6%6b  A NnCH hh1mGG!JSE9]Wu6%E[b24| ` Izlhh1GGS!JE9;j@@}Ju4%6b24| ` Izlhh1GG!JSE9^Vu4%%b!6 A 8>uf+hh1uf+hh1GG!JSE9_Uu6%4l25 ` ڗ( hh1GGS!JE9;k@@}Iu4%625 ` ڗ( hh12GG!JSE9`Tu4%Āb! A wwdDDhh1K3GGS!JE9<@@{u6%6b! A wwdDDhh1n5GG!JSE9aSu6%:b26ۼ ` # oɬ5m[$hh15GGS!JE9;l@@}Hu4%6b26ۼ ` # oɬ5m[$hh1zGG!JSE9bRu4%ۀb"v A Q *7Lhh1X{GGS!JE9<@@{u6%6b"v A Q *7Lhh1}GG!JSE9cQu6%b27\ ` Qtۈ΃b(hh1H~GGS!JE9;m@@}Gu4%6b27\ ` Qtۈ΃b(hh1ԎGG!JSE9dPu4%ab# A #؞x>_hh1nՎGGS!JE9<@@{u6%6b# A #؞x>_hh1׎GG!JSE9eOu6%8b28 ` *<߸s9sRhh1{؎GGS!JE9;n@@}Fu4%6b28 ` *<߸s9sRhh1#GG!JSE9fNu4%b# A Sڟl0,hh1GGS!JE9<@@{u6%6b# A Sڟl0,hh1 GG!JSE9gMu6%?q29ݜ ` u~ۦJ hh1 GGS!JE9;o@@}Eu4%629ݜ ` u~ۦJ hh19eGG!JSE9hLu4%Lb$V A P 4qҷ.` hh1eGGS!JE9<@@{u6%6b$V A P 4qҷ.` hh1hGG!JSE9iKu6%$b2:< ` Q.ܟhh1hGGS!JE9;p@@}Du4%6b2:< ` Q.ܟh1.w``!JSERj<>u r.? gP> '(  => p ;;%?X1w66S!JE(z@@> >u gr.?P<Xh1[GG!JSE9kIu4%b$ A Q>њ’38hh1迏GGS!JE9<@@{u6%6b$ A Q>њ’38hh1:GG!JSE9lHu6%2; ` 8GR SS\hh1GGS!JE9;q@@}Cu4%62; ` 8GR SS\hh1GG!JSE9mGu4%]b% A M,凁hh1GGS!JE9<@@{u6%6b% A M,凁hh1y GG!JSE9nFu6%2b2<| ` Pష|)B,Mhh1 GGS!JE9;r@@}Bu4%6b2<| ` Pష|)B,Mhh1OGG!JSE9oEu4%7=b&6 A c՟RL`$hh1*PGGS!JE9<@@{u6%6b&6 A c՟RL`$hh1RGG!JSE9pDu6%:b2= ` #Arhh1SGGS!JE9;s@@}Au4%6b2= ` #Arh1c``!JSERq5>u r.? gP> '(  ?? p =>%@X13d66S!JE(z@@> >u gr.?P<Xh1ʩGG!JSE9rBu4%&Xb& A 3a\Lhh1VGGS!JE9<@@{u6%6b& A 3a\Lhh1GG!JSE9sAu6%{b2> ` d13#xhh12GGS!JE9;t@@}@u4%6b2> ` d13#xhh1GG!JSE9t@u4%W/b'v A /|\$,lhh1hGGS!JE9<@@{u6%6b'v A /|\$,lhh1GG!JSE9u?u6% b2?\ ` uwܛ 8hh1GGS!JE9;u@@}?u4%6b2?\ ` uwܛ 8hh19GG!JSE9v>u4%b( A 877dzF/$hh1:GGS!JE9<@@{u6%6b( A 877dzF/$hh1u4%6b2@ ` L/,ғd`,Thh1GG!JSE9x<u4%Db( A PLDG6^1cOthh1GGS!JE9<@@{u6%6b( A PLDG6^1cOthh1GG!JSE9y;u6% b2A ` 37ב3xdhh1GGS!JE9;w@@}=u4%6b2A ` 37ב3xdhh1)ܑGG!JSE9z:u4%Yb)V A q?s⸠hh1ܑGGS!JE9<@@{u6%6b)V A q?s⸠hh1ޑGG!JSE9{9u6%=b2B< ` GC2p\hh1|ߑGGS!JE9;x@@}<u4%6b2B< ` GC2p\hh1D$GG!JSE9|8u4%NՀb) A P [8<hh1$GGS!JE9<@@{u6%6b) A P [8<hh1#'GG!JSE9}7u6%b2C ` 'Bs$Bhh1'GGS!JE9;y@@};u4%6b2C ` 'Bs$Bhh1_~GG!JSE9~6u4%b* A  a߹-~k Lhh1~GGS!JE9<@@{u6%6b* A  a߹-~k Lhh1GG!JSE95u6%b2D| ` .\ڎ%,hh1ˁGGS!JE9;z@@}:u4%6b2D| ` .\ڎ%,hh1ƒGG!JSE94u4%db+6 A G/QeÒDhh1ǒGGS!JE9<@@{u6%6b+6 A G/QeÒDhh1oȒGG!JSE93u6%'"b2E ` bǫޑL dhhh1ɒGGS!JE9;{@@}9u4%6b2E ` bǫޑL dhhh1GG!JSE92u4%Cqb+ A -ϕ3\hh1;GGS!JE9<@@{u6%6b+ A -ϕ3\hh1GG!JSE91u6%b2F ` X *l hh1.GGS!JE9;|@@}8u4%6b2F ` X *l hh1hGG!JSE90u4% b,v A 8Q'h5Ŝhh1eiGGS!JE9<@@{u6%6b,v A 8Q'h5Ŝhh1kGG!JSE9/u6%xb2G\ ` LzOBi(hh1IlGGS!JE9;}@@}7u4%6b2G\ ` LzOBi(hh1GG!JSE9.u4%2b- A IG_`$H(hh1GGS!JE9<@@{u6%6b- A IG_`$H(hh1GG!JSE9-u6%)̀b2H `  dcޞhh19GGS!JE9;~@@}6u4%6b2H `  dcޞhh1GG!JSE9,u4%b- A ٙ_ߢ~Ƣhh1GGS!JE9<@@{u6%6b- A ٙ_ߢ~Ƣhh1GG!JSE9+u6%b2I ` uWR: hh1xGGS!JE9;@@}5u4%6b2I ` uWR: hh1SGG!JSE9*u4%b.V A ߀F$hh1SGGS!JE9<@@{u6%6b.V A ߀F$hh1VGG!JSE9)u6%"b2J< ` LtyN>\ hh1VGGS!JE9;@@}4u4%6b2J< ` LtyN>\ hh1RGG!JSE9(u4%̂b. A Q ;zthh1GGS!JE9<@@{u6%6b. A Q ;zthh1 GG!JSE9'u6%(b2K ` nlbp<hh1GGS!JE9;@@}3u4%6b2K ` nlbp<hh1]GG!JSE9&u4%%|b/ A TOͦ_u (&0hh1GGS!JE9<@@{u6%6b/ A TOͦ_u (&0hh1XGG!JSE9%u6%b2L| ` -ߐվ"UΊ hh1GGS!JE9;@@}2u4%6b2L| ` -ߐվ"UΊ hh1=GG!JSE9$u4%b06 A 8 ϱfTȤhh18>GGS!JE9<@@{u6%6b06 A 8 ϱfTȤhh1w@GG!JSE9#u6%b2M ` #La ,hh1AGGS!JE9;@@}1u4%6b2M ` #La ,hh1GG!JSE9"u4%b0 A l{au (hh1JGGS!JE9<@@{u6%6b0 A l{au (hh1GG!JSE9!u6%,bb2N ` WQ/"N j0hh1GGS!JE9;@@}0u4%6b2N ` WQ/"N j0hh1͕GG!JSE9 u4%tb1v A -tzĄH@hh11ΕGGS!JE9<@@{u6%6b1v A -tzĄH@hh1ЕGG!JSE9u6%*b2O\ ` 狠)hh1ѕGGS!JE9;@@}/u4%6b2O\ ` 狠)hh1'GG!JSE9u4% b2 A RwkX@hh1(GGS!JE9<@@{u6%6b2 A RwkX@hh1*GG!JSE9u6%ob2P ` *;ﮟR4hh1k+GGS!JE9;@@}.u4%6b2P ` *;ﮟR4hh1pGG!JSE9u4%b2 A 7N^=(|hh1pGGS!JE9<@@{u6%6b2 A 7N^=(|hh1rGG!JSE9u6%xb2Q ` ڰ?.jpnhh1psGGS!JE9;@@}-u4%6b2Q ` ڰ?.jpnhh17GG!JSE9u4%Rـb3V A *" hh1ĸGGS!JE9<@@{u6%6b3V A *" hh1GG!JSE9u6%o4b2R< ` #"ף#64hh1GGS!JE9;@@},u4%6b2R< ` #"ף#64h1>ʖ``!JSER >u r.? gP> '( => p :;%?X1ʖ66S!JE(z@@> >u gr.@P<Xh1aGG!JSE9u4%b3 A S~ܜ'hh1GGS!JE9=@@{u6%6b3 A S~ܜ'hh1GGG!JSE9u6%ӣb2S ` c_,J,hh1GGS!JE9;@@}+u4%6b2S ` c_,J,hh1ZGG!JSE9u4%wb4 A *bzDdhh13[GGS!JE9=@@{u6%6b4 A *bzDdh1h]vv!JSEhu5T'1  A ,4Rr `2S5( A 192.168.0.1741^vvS!JEh<@@{u7Te  A ,4Rr `2S5( A 192.168.0.174h1p^GG!JSE9u6%b2T| ` 8Lg?˓ڷ,hh1^GGS!JE9;@@}*u4%6b2T| ` 8Lg?˓ڷ,hh1GG!JSE9u4%#b56 A uQbU{hh1"GGS!JE9=@@{u6%6b56 A uQbU{hh1yGG!JSE9u6%/b2U ` u_-Wʦthh1 GGS!JE9;@@})u4%6b2U ` u_-Wʦth1۶``!JSER>u r.@ gP> p'(  ?? p >>%@X1h66S!JE(z@@> >u gr.@=P<Xh1GG!JSE9u4%b5 A RPM?v--Hhh1{k,5dhh13GGS!JE9;@@}(u4%6b2V ` >{k,5dhh1DGG!JSE9 u4%b6v A XE'ƥ.hh1kEGGS!JE9=@@{u6%6b6v A XE'ƥ.hh1GGG!JSE9 u6%Rb2W\ ` 8QЧjȺj0hh1HGGS!JE9;@@}'u4%6b2W\ ` 8QЧjȺj0hh1팘GG!JSE9 u4%̀b7 A ǹhhh1GGS!JE9=@@{u6%6b7 A ǹhhh1ڏGG!JSE9 u6%^b2X ` [5xhh1kGGS!JE9;@@}&u4%6b2X ` [5xhh1GG!JSE9 u4%~b7 A .>>1ܺo4hh1GGS!JE9=@@{u6%6b7 A .>>1ܺo4hh1GG!JSE9u6%7b2Y ` . m=N&ihh1GGS!JE9;@@}%u4%6b2Y ` . m=N&ih1Qvv!JSEhu7TD  ` X A6 ,X ` 192.168.0.1741vvS!JEh;8@@}Mu5Te  ` X A6 ,X ` 192.168.0.174h1/GG!JSE9u4%b8V A  Iʑ3%hh1/GGS!JE9=@@{u6%6b8V A  Iʑ3%hh1J2GG!JSE9u6%eb2Z< ` QH hh12GGS!JE9;@@}$u4%6b2Z< ` QH hh12wGG!JSE9u4%܀b8 A hh1wGGS!JE9=@@{u6%6b8 A hh1#zGG!JSE9u6%kb2[ ` uL Ǐ8H hh1zGGS!JE9;@@}#u4%6b2[ ` uL Ǐ8H hh1jљGG!JSE9u4%T;b9 A Q}{H  hh1љGGS!JE9= @@{u6%6b9 A Q}{H  hh1<ԙGG!JSE9u6%ZԀb2\| ` 2ƆX> @ihh1ԙGGS!JE9;@@}"u4%6b2\| ` 2ƆX> @ihh1fGG!JSE9u4%b:6 A .Gxg$hh1GGS!JE9= @@{u6%6b:6 A .Gxg$hh1GG!JSE9u6%ǀb2] ` 8Sw.x1-hh1GGS!JE9;@@}!u4%6b2] ` 8Sw.x1-hh1aGG!JSE9u4%Kb: A Mt"$hh1bGGS!JE9= @@{u6%6b: A Mt"$hh1cGG!JSE9u6%b2^ ` .55 Flhh1!dGGS!JE9;@@} u4%6b2^ ` .55 Flhh1»GG!JSE9u4%Vހb;v A 2ҠfDhh1PGGS!JE9= @@{u6%6b;v A 2ҠfDhh1GG!JSE9u6%Axb2_\ ` aŞ1Mlhh1IGGS!JE9;@@}u4%6b2_\ ` aŞ1Mlhh1GG!JSE9u4%Àb< A *Lq?x? bhh1rGGS!JE9= @@{u6%6b< A *Lq?x? bhh1GG!JSE9u6%wb2` ` ПsԞ\~w$hh1'GGS!JE9;@@}u4%6b2` ` ПsԞ\~w$hh1 LGG!JSE9u4%b< A uϟ^йH<hh1LGGS!JE9=@@{u6%6b< A uϟ^йH<hh1NGG!JSE9u6%1gb2a ` uIIshh1oOGGS!JE9;@@}u4%6b2a ` uIIshh1GG!JSE9u4%\b=V A TLPOvdLnhh1GGS!JE9=@@{u6%6b=V A TLPOvdLnhh1GG!JSE9u6% A 7zϿjndhh16GGS!JE9=@@{u6%6b> A 7zϿjndhh149GG!JSE9u6%xb2d| ` eǦPhh19GGS!JE9;@@}u4%6b2d| ` eǦPhh1rGG!JSE9u4%b?6 A Zmڱձ쌚Thh1GGS!JE9=@@{u6%6b?6 A Zmڱձ쌚Thh1zGG!JSE9u6%b2e ` 8LqW=<8hh1 GGS!JE9;@@}u4%6b2e ` 8LqW=<8hh1؜GG!JSE9u4%b? A u 8wǏ6l hh1CٜGGS!JE9=@@{u6%6b? A u 8wǏ6l hh1ۜGG!JSE9u6%\b2f ` 2g7\ɢLhh1ܜGGS!JE9;@@}u4%6b2f ` 2g7\ɢLhh1 GG!JSE9u4%èb@v A f|6ڠdBhh1P!GGS!JE9=@@{u6%6b@v A f|6ڠdBhh1#GG!JSE9u6%`-b2g\ ` 8QׯN~?hh1@$GGS!JE9;@@}u4%6b2g\ ` 8QׯN~?hh1zGG!JSE9u4%GbA A 2,w^~NJ$hh1w{GGS!JE9=@@{u6%6bA A 2,w^~NJ$hh1}GG!JSE9u6%ރb2h ` #_՜0ihh1O~GGS!JE9;@@}u4%6b2h ` #_՜0ihh1GG!JSE9u4%mۀbA A \Z9O~bJH hh1fÝGGS!JE9=@@{u6%6bA A \Z9O~bJH hh1)ƝGG!JSE9u6%Ҍb2i ` XTeǶI$fjhh1ƝGGS!JE9;@@}u4%6b2i ` XTeǶI$fjhh1 GG!JSE9u4%:bBV A ={)(hh1 GGS!JE9=@@{u6%6bBV A ={)(hh1 GG!JSE9u6%b2j< ` upOюhh1GGS!JE9;@@}u4%6b2j< ` upOюh1``!JSER>u r.@= gP> L'( >> p ::%?X166S!JE(z@@> >u gr.@gP<Xh1VeGG!JSE9u4%bB A uG\tlhh1eGGS!JE9=@@{u6%6bB A uG\tlhh10hGG!JSE9u6%Nb2k ` 8QrGҁ Xhh1hGGS!JE9;@@}u4%6b2k ` 8QrGҁ Xhh1GG!JSE9u4%'bC A Q{v|hh1GGS!JE9=@@{u6%6bC A Q{v|hh1ʰGG!JSE9u6%t:b2l| ` uluڴhh1UGGS!JE9;@@}u4%6b2l| ` uluڴhh1uGG!JSE9u4%bD6 A *Rg^1hh1GGS!JE9=@@{u6%6bD6 A *Rg^1hh1zGG!JSE9u6%)b2m ` *7qԹ#=hh1 GGS!JE9;@@}u4%6b2m ` *7qԹ#=h1 ``!JSER>u r.@g gP>'(  ?? p >>%@X1g 66S!JE(z@@> >u gr.@P<Xh1OGG!JSE9u4%ّ,#@hh1#GGS!JE9=@@{u6%6bEv A *Qw>ّ,#@hh1䚟GG!JSE9u6%b2o\ ` u-wN[!0Phh1tGGS!JE9;@@}u4%6b2o\ ` u-wN[!0Phh1ߟGG!JSE9u4%bF A 8Agה=IrThh1cGGS!JE9=@@{u6%6bF A 8Agה=IrThh1GG!JSE9u6%b2p ` 86\59h|hh1GGS!JE9;@@}u4%6b2p ` 86\59h|hh19GG!JSE9u4%UbF A -0(hh1:GGS!JE9=@@{u6%6bF A -0(hh1b2 \ ` '>6hh1&wGGS!JE9;@@|u4%6b2 \ ` '>6hh1ͤGG!JSE9u4%*bP A #7qFc*hh1sΤGGS!JE9=-@@{u6%6bP A #7qFc*hh1ФGG!JSE9u6%Eb2  ` 8W[M"1thh1VѤGGS!JE9;@@|u4%6b2  ` 8W[M"1thh1GG!JSE9u4%.bP A eft[R(hh1GGS!JE9=.@@{u6%6bP A eft[R(hh1GG!JSE9u6%b2  ` ]8~K ! hh1XGGS!JE9;@@|u4%6b2  ` ]8~K ! hh1^GG!JSE9u4%9bQV A #fL/ҷQL>hh1^GGS!JE9=/@@{u6%6bQV A #fL/ҷQL>hh1aGG!JSE9u6%΀b2 < ` 8Rڐ+}U(hh1aGGS!JE9;@@|u4%6b2 < ` 8Rڐ+}U(h1*p``!JSER>u r.@ gP> '( >> p ::%?X1p66S!JE(z@@> >u gr.@P<Xh1=GG!JSE9u4%bQ A I FIhh1ʸGGS!JE9=0@@{u6%6bQ A I FIhh19GG!JSE9u6%"b2  ` ȆIQؒyhh1ƻGGS!JE9;@@|u4%6b2  ` ȆIQؒyhh1tGG!JSE9u4%؀bR A H]@Bhh1GGS!JE9=1@@{u6%6bR A H]@Bhh1VGG!JSE9u6%b2 | ` l]ehh1GGS!JE9;@@|u4%6b2 | ` l]ehh1nHGG!JSE9u4%HbS6 A uV߀*hh1IGGS!JE9=2@@{u6%6bS6 A uV߀*hh1YKGG!JSE9 u6%C[b2  ` 8Zas`FH* hh1KGGS!JE9;@@|u4%6b2  ` 8Zas`FH* h1\``!JSER >u r.@ gP>'(  ?? p >>%@X1=]66S!JE(z@@> >u gr.A P<Xh1GG!JSE9 u4%xbS A Gf{6lhh1AGGS!JE9=3@@{u6%6bS A Gf{6lhh1GG!JSE9 u6%{Qb2  ` zQwFDF*Ȁhh1 GGS!JE9;@@|u4%6b2  ` zQwFDF*Ȁhh1GG!JSE9 u4%b Tv A VƷ$((hh1WGGS!JE9=4@@{u6%6b Tv A VƷ$((hh1oGG!JSE9u6%#]b2\ ` #ڑ71w#Nhh1GGS!JE9;@@|u4%6b2\ ` #ڑ71w#Nhh1_2GG!JSE9u4% b U A #Rw ߋ4hh163GGS!JE9=5@@{u6%6b U A #Rw ߋ4hh15GG!JSE9u6%@@{vu6%6bZ A 8-}rhh1GG!JSE9"u6%~2 ` u0%̰$(Xhh1cGGS!JE9;@@|u4%62 ` u0%̰$(Xhh1KGG!JSE9#u4%րb[V A ZpJhh1LGGS!JE9=?@@{uu6%6b[V A ZpJhh1OGG!JSE9$u6%fb2< ` dm ʠDhh1PGGS!JE9;@@|u4%6b2< ` dm ʠDhh13GG!JSE9%u4%{b[ A 5{~֦ hh1ŔGGS!JE9=@@@{tu6%6b[ A 5{~֦ hh1GG!JSE9&u6%Xb2 ` S_Zԟ p(hh1GGS!JE9;@@|u4%6b2 ` S_Zԟ p(hh1OܪGG!JSE9'u4%Vрb\ A  _hh1ܪGGS!JE9=A@@{su6%6b\ A  _hh12ߪGG!JSE9(u6%b2| ` 8RcF hh1ߪGGS!JE9;@@|u4%6b2| ` 8RcF hh1m6GG!JSE9)u4%(b]6 A Z6ϟJN(dhh16GGS!JE9=B@@{ru6%6b]6 A Z6ϟJN(dhh1]9GG!JSE9*u6%,b2 ` *u֖`lhh19GGS!JE9;@@|u4%6b2 ` *u֖`lhh1~GG!JSE9+u4%Mb] A S`PϟDBN@hh1,GGS!JE9=C@@{qu6%6b] A S`PϟDBN@hh1BGG!JSE9,u6%Wb2 `  ZX߾Is$hh1΁GGS!JE9;@@|u4%6b2 `  ZX߾Is$hh1ƫGG!JSE9-u4%b^v A 8)Mަl.가hh14ǫGGS!JE9=D@@{pu6%6b^v A 8)Mަl.가hh1ɫGG!JSE9.u6%b2\ `  5޾s |hh1%ʫGGS!JE9;@@|u4%6b2\ `  5޾s |hh1 GG!JSE9/u4%b_ A vl@hh1w!GGS!JE9=E@@{ou6%6b_ A vl@hh1#GG!JSE90u6%b2 ` S*gZhh1V$GGS!JE9;@@|u4%6b2 ` S*gZhh1iGG!JSE91u4%b_ A R /q6q$J hh1iGGS!JE9=F@@{nu6%6b_ A R /q6q$J hh1kGG!JSE92u6%ub2 ` .QSԵIdhh1JlGGS!JE9;@@|u4%6b2 ` .QSԵIdhh1GG!JSE93u4%F.b`V A  RJH(hh1GGS!JE9=G@@{mu6%6b`V A  RJH(hh1쳬GG!JSE94u6%3b2< ` DGI*b0hh1}GGS!JE9;@@|u4%6b2< ` DGI*b0h1\ì``!JSER5q>u r.A gP>}'( >> p ::%?X1ì66S!JE(z@@> >u gr.A6P<Xh1H GG!JSE96~u4%€b` A #uн*hh1 GGS!JE9=H@@{lu6%6b` A #uн*hh1GG!JSE97}u6%ˀb2 ` 8LOGIhh1GGS!JE9;@@|u4%6b2 ` 8LOGIhh1RGG!JSE98|u4%Iˀba A j* ,hh1SGGS!JE9=I@@{ku6%6ba A j* ,hh1vVGG!JSE99{u6%1b2| ` *dOcphh1 WGGS!JE9;@@|u4%6b2| ` *dOcphh1zGG!JSE9:zu4%Lbb6 A *ew hh1 GGS!JE9=J@@{ju6%6bb6 A *ew hh1ZGG!JSE9;yu6%€b2 `  =}hh1잭GGS!JE9;@@|u4%6b2 `  =}h1į``!JSER<j>u r.A6 gP>M'( ?? p >>%@X1J66S!JE(z@@> >u gr.A`P<Xh1GG!JSE9=wu4%Ub b A H`4}qrmChh1-GGS!JE9=K@@{iu6%6b b A H`4}qrmChh1pGG!JSE9>vu6%]b2 ` 8W. hh1GGS!JE9;@@|u4%6b2 ` 8W. hh1=GG!JSE9?uu4%Tb!cv A * O6IN?bBhh1;>GGS!JE9=L@@{hu6%6b!cv A * O6IN?bBhh1@GG!JSE9@tu6%€b2\ ` k/zVthh1AGGS!JE9;@@|u4%6b2\ ` k/zVthh1ʅGG!JSE9Asu4%Xb"d A 1 INzhh1]GGS!JE9=M@@{gu6%6b"d A 1 INzhh1GG!JSE9Bru6%ɀb2 ` *f}#ږNhh1RGGS!JE9;@@|u4%6b2 ` *f}#ږNhh1߮GG!JSE9Cqu4%b#d A XQ&|Lf"hh1GGS!JE9=N@@{fu6%6b#d A XQ&|Lf"hh1GG!JSE9Dpu6%ORb2 ` #Lb?,ܬ5mhh1wGGS!JE9;@@|u4%6b2 ` #Lb?,ܬ5mhh1C(GG!JSE9Eou4%$eV A ퟆ~*ĤN hh1(GGS!JE9=O@@{eu6%6$eV A ퟆ~*ĤN hh1*GG!JSE9Fnu6%\b2< ` uL7גhh1w+GGS!JE9;@@|u4%6b2< ` uL7גhh1pGG!JSE9Gmu4%$b%e A 8f7מ}{*|phh1pGGS!JE9=P@@{du6%6b%e A 8f7מ}{*|phh1sGG!JSE9Hlu6%Y9b2 ` 7t1דQhh1sGGS!JE9;@@|u4%6b2 ` 7t1דQhh1fʯGG!JSE9Iku4%yb&f A 8LIݴv'(hh1ʯGGS!JE9=Q@@{cu6%6b&f A 8LIݴv'(hh1KͯGG!JSE9Jju6%9b2 | ` .\1 hh1ͯGGS!JE9;@@|u4%6b2 | ` .\1 hh1oGG!JSE9Kiu4%b'g6 A 2&hB(hh1GGS!JE9=R@@{bu6%6b'g6 A 2&hB(hh1'GG!JSE9Lhu6%Cb2! `  d_p|9tPhh1GGS!JE9;@@|u4%6b2! `  d_p|9tPhh1ZGG!JSE9Mgu4%b(g A >֪lhFhh1[GGS!JE9=S@@{au6%6b(g A >֪lhFhh1|]GG!JSE9Nfu6%b2! ` 75Orhh1^GGS!JE9;@@|u4%6b2! ` 75Orhh1GG!JSE9Oeu4%pb)hv A 2``z}׺,l'hh1HGGS!JE9=T@@{`u6%6b)hv A 2``z}׺,l'hh1GG!JSE9Pdu6%ϭb2"\ ` Qgǡ7,hh1"GGS!JE9;@@|u4%6b2"\ ` Qgǡ7,hh1GG!JSE9Qcu4%ab*i A  1<]ִ{ `hh1uGGS!JE9=U@@{_u6%6b*i A  1<]ִ{ `hh1GG!JSE9Rbu6%=πb2" `  aضXj@hh1IGGS!JE9;@@|u4%6b2" `  aضXj@hh1DGG!JSE9Sau4%Tb+i A 8k޵Dhh1rEGGS!JE9=V@@{^u6%6b+i A 8k޵Dhh1GGG!JSE9T`u6%؝b2# ` ;m4f~2 hh1IHGGS!JE9;@@|u4%6b2# ` ;m4f~2 hh1GG!JSE9U_u4%͝b,jV A Z 6@@(hh1+GGS!JE9=W@@{]u6%6b,jV A Z 6@@(hh10GG!JSE9V^u6%P_b2$< ` nXxA,Chh1TGGS!JE9;@@|u4%6b2$< ` nXxA,Chh1]GG!JSE9W]u4%:b-j A 8Q| I<hh1GGS!JE9=X@@{\u6%6b-j A 8Q| I<hh1GG!JSE9X\u6%b2$ ` .eGŁV#h5chh1GGS!JE9;@@|u4%6b2$ ` .eGŁV#h5chh1V/GG!JSE9Y[u4%݀b.k A [( hh1/GGS!JE9=Y@@{[u6%6b.k A [( hh1#2GG!JSE9ZZu6%b2%| ` *_Ń߷6ahh12GGS!JE9;@@|u4%6b2%| ` *_Ń߷6ahh1cGG!JSE9[Yu4%\Tb/l6 A *\7-Y6wthh1GGS!JE9=Z@@{Zu6%6b/l6 A *\7-Y6wthh1?GG!JSE9\Xu6%Ab2& ` [Ǽ,`hh1ˌGGS!JE9;@@|u4%6b2& ` [Ǽ,`hh1}ѲGG!JSE9]Wu4%5ib0l A  Zk/g~1Zhh1 ҲGGS!JE9=[@@{Yu6%6b0l A  Zk/g~1Zhh1TԲGG!JSE9^Vu6%b2& `  R%Qu0hh1ԲGGS!JE9;@@|u4%6b2& `  R%Qu0hh1GG!JSE9_Uu4%Jb1mv A Ȣ瑖O?Pq4hh17GGS!JE9=\@@{Xu6%6b1mv A Ȣ瑖O?Pq4hh1GG!JSE9`Tu6%bb2'\ ` QNJl@hh10GGS!JE9;@@|u4%6b2'\ ` QNJl@hh1sGG!JSE9aSu4%kb2n A  !ex Dhh1NtGGS!JE9=]@@{Wu6%6b2n A  !ex Dhh1vGG!JSE9bRu6%b2' ` Zb_x2'@k@hh1&wGGS!JE9;@@|u4%6b2' ` Zb_x2'@k@hh1޻GG!JSE9cQu4%굀b3n A *g~\r@thh1kGGS!JE9=^@@{Vu6%6b3n A *g~\r@thh1GG!JSE9dPu6%Qb2( `  @ǧ\hh1FGGS!JE9;@@|u4%6b2( `  @ǧ\hh1GG!JSE9eOu4%[b4oV A  Ziߑҗnfhh1GGS!JE9=_@@{Uu6%6b4oV A  Ziߑҗnfhh1GG!JSE9fNu6%RÀb2)< ` ٬Qʻ HThh1tGGS!JE9;@@|u4%6b2)< ` ٬Qʻ HTh1``!JSERg?>u r.A` gP>)'( >> p 9:%?X166S!JE(z@@> >u gr.AP<Xh17^GG!JSE9hLu4%b5o A RV |rx`ohh1^GGS!JE9=`@@{Tu6%6b5o A RV |rx`ohh1#aGG!JSE9iKu6%b2) ` LWf] (hh1aGGS!JE9;@@|u4%6b2) ` LWf] (hh1]GG!JSE9jJu4%Gb6p A #GG~N"($hh1ꦴGGS!JE9=a@@{Su6%6b6p A #GG~N"($hh1GG!JSE9kIu6%wb2*| `  ,tբ hh1GGS!JE9;@@|u4%6b2*| `  ,tբ hh1GG!JSE9lHu4%u r.A gP>'( ?? p >>%@X1K66S!JE(z@@> >u gr.AP<Xh1HGG!JSE9oEu4%b8q A f'ϯ^ߺ$|hh1)IGGS!JE9=c@@{Qu6%6b8q A f'ϯ^ߺ$|hh1yKGG!JSE9pDu6%j+b2+ ` Q~@hh1LGGS!JE9;@@|u4%6b2+ ` Q~@hh1GG!JSE9qCu4%KҀb9rv A RV票ԾFkThh17GGS!JE9=d@@{Pu6%6b9rv A RV票ԾFkThh1{GG!JSE9rBu6%kb2,\ ` uQ_̕l)`hh1 GGS!JE9;@@|u4%6b2,\ ` uQ_̕l)`hh1صGG!JSE9sAu4%cb:s A Zg1ԿHhh1JٵGGS!JE9=e@@{Ou6%6b:s A Zg1ԿHhh1۵GG!JSE9t@u6%b2, ` *R`W|Y&hh1@ܵGGS!JE9;@@|u4%6b2, ` *R`W|Y&hh12GG!JSE9u?u4%Ѐb;s A fzu6%b2- `  }{{ADhVdhh1O6GGS!JE9;@@|u4%6b2- `  }{{ADhVdhh1zGG!JSE9w=u4%3b<tV A .O6Ih(hh1{GGS!JE9=g@@{Mu6%6b<tV A .O6Ih(hh1}GG!JSE9x<u6%R b2.< ` R|'ë>Ð'=tϼhh1n~GGS!JE9;@@|u4%6b2.< ` R|'ë>Ð'=tϼhh1öGG!JSE9y;u4%flb=t A 8m_}ճϲhh1öGGS!JE9=h@@{Lu6%6b=t A 8m_}ճϲhh1ƶGG!JSE9z:u6%Wb2. ` ܾΞ`Hhh1ƶGGS!JE9;@@|u4%6b2. ` ܾΞ`Hhh1GG!JSE9{9u4%b>u A Z}fZB6hh1GGS!JE9=i@@{Ku6%6b>u A Z}fZB6hh1? GG!JSE9|8u6%Űb2/| ` .u<hh1 GGS!JE9;@@|u4%6b2/| ` .u<hh1peGG!JSE9}7u4%b?v6 A ϗe^˻, hh1fGGS!JE9=j@@{Ju6%6b?v6 A ϗe^˻, hh1?hGG!JSE9~6u6%4b20 `  6ٸvKhh1hGGS!JE9;@@|u4%6b20 `  6ٸvKhh1#GG!JSE95u4%?b@v A 8ZO~ُahh1GGS!JE9=k@@{Iu6%6b@v A 8ZO~ُahh1GG!JSE94u6%=b20 ` 8oמڱȬ`hh1GGS!JE9;@@|u4%6b20 ` 8oמڱȬ`hh1GG!JSE93u4%߀bAwv A inۧA$hh1!GGS!JE9=l@@{Hu6%6bAwv A inۧA$hh1 GG!JSE92u6%\b21\ ` *`G&ڟj $hh1 GGS!JE9;@@|u4%6b21\ ` *`G&ڟj $hh1OGG!JSE91u4%UbBx A b(&Ďhh1VPGGS!JE9=m@@{Gu6%6bBx A b(&Ďhh1RGG!JSE90u6%Xb21 `  g~ DiThh1&SGGS!JE9;@@|u4%6b21 `  g~ DiThh1ԗGG!JSE9/u4%vbCx A Q/tt n(hh1hGGS!JE9=n@@{Fu6%6bCx A Q/tt n(hh1ŚGG!JSE9.u6%Wb22 ` &A8Ǟhh1XGGS!JE9;@@|u4%6b22 ` &A8Ǟhh1GG!JSE9-u4%AbDyV A #˗Ǹ6ܾNLhhh1GGS!JE9=o@@{Eu6%6bDyV A #˗Ǹ6ܾNLhhh1GG!JSE9,u6%plb23< ` 8f@o7{qYs4hh1fGGS!JE9;@@|u4%6b23< ` 8f@o7{qYs4hh1:GG!JSE9+u4%bEy A uvƊ@$hh1L:GGS!JE9=p@@{Du6%6bEy A uvƊ@$hh1K=GG!JSE9*u6%b23 ` OSk4hh1=GGS!JE9;@@|u4%6b23 ` OSk4hh1qGG!JSE9)u4%ćbFz A #`ntܻ`@ hh1tGGS!JE9=q@@{Cu6%6bFz A #`ntܻ`@ hh11GG!JSE9(u6%zb24| ` SXi_1Փdhh1݄GGS!JE9;@@|u4%6b24| ` SXi_1Փdhh1ܹGG!JSE9'u4%i]bG{6 A 27Rؠ$D8hh1 ݹGGS!JE9=r@@{Bu6%6bG{6 A 27Rؠ$D8hh1l߹GG!JSE9&u6%n]b25 ` Pdտؾ̚n/TKhh1߹GGS!JE9;@@|u4%6b25 ` Pdտؾ̚n/TKhh1M$GG!JSE9%u4%{pbH{ A  O_Qʹhh1$GGS!JE9=s@@{Au6%6bH{ A  O_Qʹhh1'GG!JSE9$u6%@b25 ` a?->Q"J2+hh19(GGS!JE9;@@|u4%6b25 ` a?->Q"J2+hh1lGG!JSE9#u4%bI|v A *(|ʿH0hh16mGGS!JE9=t@@{@u6%6bI|v A *(|ʿH0hh1voGG!JSE9"u6%nb26\ ` p}̊"hh1pGGS!JE9;@@|u4%6b26\ ` p}̊"hh1ƺGG!JSE9!u4%@bJ} A 871 "dhh1eǺGGS!JE9=u@@{?u6%6bJ} A 871 "dhh1ɺGG!JSE9 u6%b26 ` # d  $hh1IʺGGS!JE9;@@|u4%6b26 ` # d  $hh1GG!JSE9u4%bbK} A G^fh9ٌ hh1mGGS!JE9=v@@{>u6%6bK} A G^fh9ٌ hh1GG!JSE9u6%׀b27 `  R_h$hh1,GGS!JE9;@@|u4%6b27 `  R_h$hh1VGG!JSE9u4%xbL~V A 8ݏ|jH`hh1}WGGS!JE9=w@@{=u6%6bL~V A 8ݏ|jH`hh1YGG!JSE9u6% b28< ` #-_1_8Lhh1~ZGGS!JE9<@@|u4%6b28< ` #-_1_8Lh1h``!JSER >u r.A gP>'( >> p ::%?X1i66S!JE(z@@> >u gr.AP<Xh1.GG!JSE9u4%ybM~ A 8fIG1Зjhh1GGS!JE9=x@@{<u6%6bM~ A 8fIG1Зjhh1GG!JSE9u6%Bb28 ` 8k'I(Fhh1GGS!JE9<@@|u4%6b28 ` 8k'I(Fhh17GG!JSE9u4%cbN A H'x^HȀhh1GGS!JE9=y@@{;u6%6bN A H'x^HȀhh1GG!JSE9u6%b29| ` #oq $hh1GGS!JE9<@@|u4%6b29| ` #oq $hh1kAGG!JSE9u4%ێbO6 A * zP-(hh1AGGS!JE9=z@@{:u6%6bO6 A * zP-(hh1>DGG!JSE9u6%b2: `  A/ hh1DGGS!JE9<@@|u4%6b2: `  A/ h1U``!JSER>u r.A gP>'( ?? p >>%@X19V66S!JE(z@@> >u gr.BP<Xh1GG!JSE9u4%ŝbP A #͎WLhh1GGS!JE9={@@{9u6%6bP A #͎WLhh1mGG!JSE9u6%b2: ` uL*G?Qs>Vhh1GGS!JE9<@@|u4%6b2: ` uL*G?Qs>Vhh1GG!JSE9u4%8IbQv A 2R=MƄhh1GGS!JE9=|@@{8u6%6bQv A 2R=MƄhh1\GG!JSE9u6%⽀b2;\ ` u@j%db\hh1GGS!JE9<@@|u4%6b2;\ ` u@j%db\hh1+GG!JSE9u4%3bR A iG>HLhh10,GGS!JE9=}@@{7u6%6bR A iG>HLhh1.GG!JSE9u6%b2; ` 8Qg.Cʪ`(bhh15/GGS!JE9<@@|u4%6b2; ` 8Qg.Cʪ`(bhh1셽GG!JSE9 u4%ZibS A Rpozܸ Zhhh1xGGS!JE9=~@@{6u6%6bS A Rpozܸ Zhhh1GG!JSE9 u6%GBb2< ` @g @dhh1JGGS!JE9<@@|u4%6b2< ` @g @dhh1ͽGG!JSE9 u4%XBbTV A *ߕp6]$a hh1νGGS!JE9=@@{5u6%6bTV A *ߕp6]$a hh1нGG!JSE9 u6%b2=< ` 2`~7|cP/hh1KѽGGS!JE9<@@|u4%6b2=< ` 2`~7|cP/hh1GG!JSE9 u4%=bU A .QVß.tɠhh1~GGS!JE9=@@{4u6%6bU A .QVß.tɠhh1KGG!JSE9u6%Vb2= ` 8t,|NƟShh1GGS!JE9< @@|u4%6b2= ` 8t,|NƟShh11pGG!JSE9u4%bV A f/~Vlhh1pGGS!JE9=@@{3u6%6bV A f/~Vlhh1+sGG!JSE9u6%ub2>| ` S ozX, Hhh1sGGS!JE9< @@|u4%6b2>| ` S ozX, Hhh1KGG!JSE9u4%mbW6 A 2ϯAhh1ٸGGS!JE9=@@{2u6%6bW6 A 2ϯAhh1GG!JSE9u6%IAb2? ` *X5Fڑݢ蠀hh1GGS!JE9< @@|u4%6b2? ` *X5Fڑݢ蠀hh1GG!JSE9u4%bX A *7rxe8vaT0hh1GGS!JE9=@@{1u6%6bX A *7rxe8vaT0hh1GG!JSE9u6%b2? `  XEw1RP\hh1ZGGS!JE9< @@|u4%6b2? `  XEw1RP\hh1ZGG!JSE9u4%bYv A ,7Z㐠Nuhh1D[GGS!JE9=@@{0u6%6bYv A ,7Z㐠Nuhh1]GG!JSE9u6%z΀b2@\ ` Z1@:Ahh1^GGS!JE9< @@|u4%6b2@\ ` Z1@:Ahh1GG!JSE9u4%:bZ A ȿs:ծhh1u r.B gP>'( == p ::%?X166S!JE(z@@> >u gr.B2P<Xh15GG!JSE9u4%>be A 'VZތ,lhh1GGS!JE9=@@{$u6%6be A 'VZތ,lhh1CGG!JSE9u6%/ib2G ` #R-i2Gi1hh1GGS!JE9<@@|u4%6b2G ` #R-i2Gi1hh1,LGG!JSE9u4%€bf A WG^FLhh1LGGS!JE9=@@{#u6%6bf A WG^FLhh1NGG!JSE9u6%偀b2H| ` :{R@ߨ"hh1OGGS!JE9<@@|u4%6b2H| ` :{R@ߨ"hh1GG!JSE9u4%܀bg6 A ,5ىf+˸hh1&GGS!JE9=@@{"u6%6bg6 A ,5ىf+˸hh1@GG!JSE9u6%tzb2I ` #Ow]&Ndhh1їGGS!JE9<@@|u4%6b2I ` #Ow]&Ndh1``!JSER>u r.B2 gP>R'( ?? p >>%?X1&66S!JE(z @@> >u gr.B\P<Xh1GG!JSE9u4%-ŀbh A .-6hHjhh1GGS!JE9=@@{!u6%6bh A .-6hHjhh1[GG!JSE9u6%Hb2I `  A#EThh1GGS!JE9<@@|u4%6b2I `  A#EThh1y6GG!JSE9u4%biv A şa (hh1 7GGS!JE9=@@{ u6%6biv A şa (hh1\9GG!JSE9u6%1qb2J\ ` Eܿ"hhh19GGS!JE9<@@|u4%6b2J\ ` Eܿ"hhh1~GG!JSE9u4%wbj A 8'VfnJ. hh1AGGS!JE9=@@{u6%6bj A 8'VfnJ. hh1GG!JSE9u6%b2J ` 8 2~\Hlhh1AGGS!JE9<@@|u4%6b2J ` 8 2~\Hlhh1GG!JSE9u4%Ѐbk A *ZVV@bhh1vGGS!JE9=@@{u6%6bk A *ZVV@bhh1GG!JSE9u6%b2K ` T74״y4fJhh1KGGS!JE9<@@|u4%6b2K ` T74״y4fJhh1 GG!JSE9u4%blV A  *GVvHB$ hh1|!GGS!JE9=@@{u6%6blV A  *GVvHB$ hh1#GG!JSE9u6%cb2L< ` SLEyו_Lhh1O$GGS!JE9< @@|u4%6b2L< ` SLEyו_Lhh1iGG!JSE9u4%sbm A Z6fu:hh1iGGS!JE9=@@{u6%6bm A Z6fu:hh1kGG!JSE9u6%>lb2L ` .#n'Khh1lGGS!JE9/hh1 GGS!JE9<&@@|u4%6b2O ` 8?7q>/hh1=GG!JSE9u4%jbs A 9N`l@hh1K>GGS!JE9=@@{u6%6bs A 9N`l@hh1@GG!JSE9u6%J=b2P ` \m=WMNF)j`hh1TAGGS!JE9<'@@|u4%6b2P ` \m=WMNF)j`hh1GG!JSE9u4%VbtV A Tԗ$b,(hh1GGS!JE9=@@{u6%6btV A Tԗ$b,(hh1GG!JSE9u6%`Āb2Q< ` 7ؾdhh1rGGS!JE9<(@@|u4%6b2Q< ` 7ؾdhh1GG!JSE9u4%{bu A  Z[f,Bhh1nGGS!JE9=@@{u6%6bu A  Z[f,Bhh1SGG!JSE9u6%Y:b2Q ` OxJ{Aphh1GGS!JE9<)@@|u4%6b2Q ` OxJ{Aphh1(GG!JSE9u4%Ebv A 8y{fB hh1(GGS!JE9=@@{u6%6bv A 8y{fB hh1 +GG!JSE9u6%b2R| ` 8(,QݓfD0hh1+GGS!JE9<*@@|u4%6b2R| ` 8(,QݓfD0hh1cGG!JSE9u4%a+bw6 A *78~ٔNAR hh1GGS!JE9=@@{u6%6bw6 A *78~ٔNAR hh1GG!JSE9u6%wb2S ` *һHrhh1RGGS!JE9<+@@|u4%6b2S ` *һHrhh1=GG!JSE9u4%㾀bx A {՗α"hh1yGGS!JE9=@@{u6%6bx A {՗α"hh1GG!JSE9u6%,b2S ` \Ze.lQa<hh1GGS!JE9<,@@|u4%6b2S ` \Ze.lQa<hh1GG!JSE9u4%=byv A  Z5}ـ⢊hh1GGS!JE9=@@{u6%6byv A  Z5}ـ⢊hh1wGG!JSE9u6%ab2T\ ` Zp3zhh1GGS!JE9<-@@|u4%6b2T\ ` Zp3zhh1lGG!JSE9u4%bz A uQrϸD&hh1 mGGS!JE9=@@{u6%6bz A uQrϸD&hh1woGG!JSE9u6%b2T ` /m6Q>8hh1pGGS!JE9<.@@|u4%6b2T ` /m6Q>8hh1GG!JSE9u4%ʀb{ A  3^v\ Dhh1uGGS!JE9=@@{u6%6b{ A  3^v\ Dhh1GG!JSE9u6%_Pb2U `  篮.תt˸hh18GGS!JE9u r.B\ gP>/'( << p ::%?X1}66S!JE(z!@@> >u gr.BP<Xh1WGG!JSE9u4%b} A ƙ@"Lhh1WGGS!JE9=@@{ u6%6b} A ƙ@"Lhh1YGG!JSE9u6%m b2V ` dO1+: hh1ZGGS!JE9<1@@|u4%6b2V ` dO1+: hh10GG!JSE9u4%w;b~ A w`Hb(hh1GGS!JE9=@@{ u6%6b~ A w`Hb(hh1GG!JSE9u6%ހb2W| ` # bçz!hh1;GGS!JE9<2@@|u4%6b2W| ` # bçz!hh1GG!JSE9u4% b6 A #+~y(hh1!GGS!JE9=@@{ u6%6b6 A #+~y(hh1:GG!JSE9u6%vb2X `  ]6hh1GGS!JE9<3@@|u4%6b2X `  ]6h1``!JSER>u r.B gP>'( ?? p >>%?X1066S!JE(z"@@> >u gr.BP<Xh1AGG!JSE9u4%Ab A Iw}WXhh1!BGGS!JE9=@@{ u6%6b A Iw}WXhh1\DGG!JSE9u6%b2X ` T'(M;|hh1DGGS!JE9<4@@|u4%6b2X ` T'(M;|hh1GG!JSE9u4%bv A 8A˿>x hh1!GGS!JE9=@@{u6%6bv A 8A˿>x hh1HGG!JSE9 u6%b2Y\ ` ߿~O|If۰hh1ӌGGS!JE9<5@@|u4%6b2Y\ ` ߿~O|If۰hh1GG!JSE9 u4%܀b A W&yzu6chh1GGS!JE9=@@{u6%6b A W&yzu6chh1GG!JSE9 u6%b3Y ` Z FOS9hh1GGS!JE9<6@@|~u4%6b3Y ` Z FOS9hh1+GG!JSE9 u4%2b A  ;Wr dhh1_,GGS!JE9=@@{u6%6b A  ;Wr dhh1.GG!JSE9 u6%b3Z ` *qƘ# hh1J/GGS!JE9<7@@|}u4%6b3Z ` *qƘ# hh1tGG!JSE9u4%i$bV A #%}$hh1tGGS!JE9=@@{u6%6bV A #%}$hh1vGG!JSE9u6%b3[< ` W',hh1YwGGS!JE9<8@@||u4%6b3[< ` W',hh1GG!JSE9u4%yb A TR&n&$fdhh1GGS!JE9=@@{u6%6b A TR&n&$fdhh1GG!JSE9u6%g݀b3[ ` T'j"-hh1GGS!JE9<9@@|{u4%6b3[ ` T'j"-hh1BGG!JSE9u4%Ͳb A SA[N(ʄhh1GGS!JE9=@@{u6%6b A SA[N(ʄhh1&GG!JSE9u6%Gb3\| `  Z@'Wz΂EThh1GGS!JE9<:@@|zu4%6b3\| `  Z@'Wz΂EThh1(^GG!JSE9u4%b6 A ™ߗFl. hh1^GGS!JE9=@@{u6%6b6 A ™ߗFl. hh1aGG!JSE9u6%mb3] `  `gŒ>~,Jʀhh1aGGS!JE9<;@@|yu4%6b3] `  `gŒ>~,Jʀhh1]GG!JSE9u4%Sb A  Q>cMfhh1GGS!JE9=@@{u6%6b A  Q>cMfhh1GG!JSE9u6% b3] ` ȢWhh1GGS!JE9<<@@|xu4%6b3] ` ȢWhh1GG!JSE9u4%bv A *ªwӤnxhh1FGGS!JE9=@@{u6%6bv A *ªwӤnxhh1GG!JSE9u6%b3^\ ` f χz0hh1GGS!JE9<=@@|wu4%6b3^\ ` f χz0hh1HGG!JSE9u4%Yb A FgVapH*Hhh1nIGGS!JE9=@@zu6%6b A FgVapH*Hhh1sKGG!JSE9u6%Lb3^ ` /n" |hh1KGGS!JE9<>@@|vu4%6b3^ ` /n" |hh1ڐGG!JSE9u4%b A *:ߟ룰&Μhh1lGGS!JE9=@@zu6%6b A *:ߟ룰&Μhh1GG!JSE9u6%Rb3 _ ` i7W5vF~@\hh1GGGS!JE9u r.B gP>x$ (08AIQYaiqy X1}66S!JE(z#@@> >u gr.BP<Xh1"3GG!JSE9!u4%b A .ܛ" hh13GGS!JE9=@@zu6%6b A .ܛ" hh15GG!JSE9"u6%Ѐb3 ` ` Y32!J(hh16GGS!JE9u r.B gP>]   ehX1N66S!JE(z$@@> >u gr.BP<Xh1HHS!JE:z%@@> >u gr.BP<,  -hh1GG!JSE9-u4%[b A y hh1oGGS!JE9=@@zu6%6b A y hh1 GG!JSE9.u6%b3d ` Z>Eֱhh13 GGS!JE9Eֱhh1OGG!JSE9/u4%b A vss hh1iPGGS!JE9=@@zu6%6b A vss hh1RGG!JSE90u6%Bb3e< ` gJUhh1gSGGS!JE9u r.B yP>'( => p ;;%?h1bGGS!JE9z&@@> >u yr.CP<+  %hh1%GG!JSE92u4%݀bV A ygٟލhh1GGS!JE9=@@zu6%6bV A ygٟލhh1GG!JSE93u6%b3e ` #ԡ&~׍Dɔhh1GGS!JE9u r.C P>N'( ?? p >>%?h1bGG!JSE99{u4%b6 A , hh1GGS!JE9=@@zu6%6b6 A , hh1TGG!JSE9:zu6%֏b3g ` 8ǿϾ}Έf(hh1GGS!JE9 >u r.Cu r.C< P>   *dX1n66S!JE(z(@@> >u r.CJP<Xh1EES!JE7z)@@> >u r.CJP<)    hh14'GG!JSE9=wu4%b A *hh1'GGS!JE9=@@zu6%6b A *hd1(DD!JSE6>>u r.CJ P>n\   md`1(==S!JE/z*@@> >u r.CXPGG!JSE9Gmu4%+Հb A y{hh1ѱGGS!JE9=@@zu6%6b A y{hh1GG!JSE9Hlu6%@b3k| ` yl"&hh1GGS!JE9u r.CX P>6(~v =|1A ZZS!JELz+@@> >u r.CP<>   *    % |`1 ??!JSE1K|>u r.C P>  `h1UGG!JSE9Lhu6%Ѐb3l ` yۋ1hh1ĝGG!JSE9Mgu6%Sb3m\ ` <hX1k66S!JE(z,@@> >u r.CP<Xh1GG!JSE9Nfu6%_9b3 m ` yXUhh1?GG!JSE9Oeu6%|b3!n ` ۹;hh1GG!JSE9Pdu6%b3"o< ` yk Lhh1a*GG!JSE9Qcu6%ήb3#o ` y빟꯮$hh1zrGG!JSE9Rbu6%hb3$p| ` L\Hhh1GG!JSE9Sau6%b3%q ` ydh\1<<!JSE(T|>u r.C P>\`1==S!JE/z-@@> >u r.CPu r.C P>l3 `X1,E66S!JE(z.@@> >u r.CP<Xh1 GG!JSE9W]u6%֌b3'r\ `  b`h1aa!JSESXM>u r.C P>3(~v &:X166S!JE(z/@@> >u r.CP<X`1P??!JSE1Yn>u r.C P>2  `X1Ѹ66S!JE(z0@@> >u r.CP<X`1(==S!JE/z1@@> >u r.CPu r.C P>*3 `X166S!JE(z2@@> >u r.CP<X1 ]]!JSEO[N>u r.C P>$ (08AIQYaiqy X1O 66S!JE(z3@@> >u r.CP<Xp1J<Counters provided by libpcapf1I<1plibosmo-netif-0.0.6/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap000066400000000000000000007234701261607103500267470ustar00rootroot00000000000000 dM<+Linux 3.5.0-rc1+)Dumpcap 1.7.1 (SVN Rev 41546 from /trunk)d<eth0  Linux 3.5.0-rc1+<1aa!JSES>u r.' ݘP>($ (08AIQYaiqy X166S!JE(y@@? >u ݘr.'P<Xd14żCC!JSE5>u r.' ݘP>1 FӇdX1sż66S!JE(y @@? >u ݘr.'P<Xt1BżSSS!JEEy!@@? >u ݘr.'P<7! d r t`1$Ƽ@@!JSE2>u r.' ݵP>" M`x1%ƼVVS!JEHy"@@? >u ݵr.( P<: +-? FӇ+++++++++++xh1GȼHH!JSE:>u r.( P>4( (%?hX1ȼ66S!JE(y#@@? >u r.(P<Xp1uɼOO!JSEA>u r.( P>  $q0M#qpX1ɼ66S!JE(y$@@? >u r.(4P<Xd1ɼDDS!JE6y%@@? >u r.(4P<(   !dp1P˼NN!JSE@ >u r.(4 P>Q  0 ` pX1˼66S!JE(y&@@? >u r.(LP<X1ͼ__!JSEQ >u r.(L P>@Q&" (08AIQYaiqy X15ͼ66S!JE(y'@@? >u r.(uP<Xx1Z%ͼUU!JSEG >u r.(u P>  E`^xX1%ͼ66S!JE(y(@@? >u r.(P<Xl1S.ͼLLS!JE>y)@@? >u r.(P<0   A(lh1)BϼHH!JSE: >u r.( P>   Ahd1YBϼDDS!JE6y*@@? >u r.(P<(   dh1TϼHH!JSE: >u r.( P>(( >2&%@ht1TϼRRS!JEDy+@@? >u r.(P<6) !6(~p bt`1\ϼ==!JSE/>u r.( #P>* `X1ϼ66S!JE(y,@@? >u #r.(P<Xh10ϼHH!JSE:>u r.( #P>B~q hX1cϼ66S!JE(y-@@? >u #r.(P<Xh1ԼHHS!JE:y.@@? >u #r.(P<,  5X:(h1ּ``!JSER>u r.( 5P>'( ?? p ??n%@X1ּ66S!JE(y/@@? >u 5r.(P<Xh1sܼHHS!JE:y0@@? >u 5r.(P<,  5X:(h1ݼ``!JSER>u r.( GP>'( ?? p <<@%@X1ݼ66S!JE(y1@@? >u Gr.)%P<Xd1߼CC!JSE5>u r.)% GP>F %܈dX1߼66S!JE(y2@@? >u Gr.)2P<Xt1߼SSS!JEEy3@@? >u Gr.)2P<7! d r t`1߼@@!JSE2>u r.)2 dP>" -`x1W߼VVS!JEHy4@@?| >u dr.)u r.)< ބP>h  '05X:px1gVVS!JEHy5@@?{ >u ބr.)UP<:  `\^xp1 NN!JSE@>u r.)U ޤP>M  0 ` pX166S!JE(y6@@? >u ޤr.)mP<X1L``!JSER>u r.)m ޤP>-'( ?? p ==%@X1L66S!JE(y7@@? >u ޤr.)P<Xd1{DD!JSE6>u r.) ޤP>i   dX166S!JE(y8@@? >u ޤr.)P<Xl1LLS!JE>y9@@? >u ޤr.)P<0   A(lh19HH!JSE:>u r.) ޺P>~( (?0%?hX1+66S!JE(y:@@? >u ޺r.)P<Xh19HH!JSE:>u r.) ޺P>   AhX1e66S!JE(y;@@? >u ޺r.)P<Xh11GGS!JE9y<@@? >u ޺r.)P<+) !6(h`1==!JSE/>u r.) P>/* `d1AAS!JE3y=@@? >u r.)P<%~p bdh1HH!JSE:>u r.) P>>7~q hX166S!JE(y>@@? >u r.)P<Xd1DD!JSE6>u r.) P>   AdX166S!JE(y?@@? >u r.)P<Xd1DDS!JE6y@@@? >u r.)P<(   d\1I<<!JSE(>u r.) P>\1@``!JSER>u r.) P>-'( ?? p <<%@X1366S!JE(yA@@? >u r.*P<Xh1HH!JSE:>u r.* P>( ?3%?hX1@66S!JE(yB@@? >u r.*,P<Xd1uDD!JSE6 >u r.*, P>   dX166S!JE(yC@@? >u r.*:P<Xd1DDS!JE6yD@@?~ >u r.*:P<(   d1f``!JSER!>u r.*: P>+'( ?? p <<%@1uuS!JEgyE@@?L >u r.*dPu r.*d 1P>~t `h1;GG!JSE9#u2%fIbK< B y{hh1ku 1r.*nP<X`1@@!JSE2'>u r.*n 1P>~t `X166S!JE(yG@@? >u 1r.*xP<Xh1TGG!JSE9(u2%bK| B y~hh1zGG!JSE9)u4%y9b=k b j#W|hh1bGGS!JE9@@u2%6b=k b j#W|hh1GGS!JE9.@@ԅu4%6bK| B y~h1``!JSER*}>u r.*x 1P>B'( ?? p ==H%?X166S!JE(yH@@? >u 1r.*P<Xh1%GG!JSE9+u2%z bK B ~hh1&GGS!JE9/@@Ԅu4%6bK B ~hh1'GG!JSE9,u4% b=lo b aȺQ! Uhh1'GGS!JE9@@u2%6b=lo b aȺQ! Uhh1MnGG!JSE9-u2%cŀbK B y{hh1rnGG!JSE9.u4%.րb=m b  6tP(\hh18oGGS!JE9@@u2%6b=m b  6tP(\hh1ZoGGS!JE90@@ԃu4%6bK B y{hd1DD!JSE6/>u r.* 1P>   dX1շ66S!JE(yI@@? >u 1r.*P<Xh1gGG!JSE90u2%bK\ B R;w7{7hh1:GGS!JE91@@Ԃu4%6bK\ B R;w7{7hh1GG!JSE91u4%b=m b  wʄB\hh1GGS!JE9@@ u2%6b=m b  wʄB\hh1XGG!JSE92u2%]ۀbK B |OɎV&dJhh1YGG!JSE93u4%b=nO b Hwm2lhh1YGGS!JE9@@ u2%6b=nO b Hwm2lhh1YGGS!JE92@@ԁu4%6bK B |OɎV&dJhh1CGG!JSE94u2%фbK B ҈ytF˞hh1 GGS!JE93@@Ԁu4%6bK B ҈ytF˞hh1GG!JSE95u4%$=n b ZGU1-Lhh1vGGS!JE9@@ u2%6=n b ZGU1-Lhh1GG!JSE96u2%9bK< B Q7gB}hh1GG!JSE97~u4%j؀b=o b ㇽkrhhh1TGGS!JE9@@ u2%6b=o b ㇽkrhhh1tGGS!JE94@@u4%6bK< B Q7gB}hh1zBGG!JSE98}u2%\bK B Z s1̐Dhh1GCGGS!JE95@@~u4%6bK B Z s1̐Dhh1CGG!JSE99|u4%b=p/ b >smJ(hh1DGGS!JE9@@ u2%6b=p/ b >smJ(hh1GG!JSE9:{u2%XbK| B 8An c܍ĸhh1GG!JSE9;zu4%~b=p b 1B j3hh1GGS!JE9@@u2%6b=p b 1B j3hh1GGS!JE96@@}u4%6bK| B 8An c܍ĸhh1AGG!JSE9<yu2%ZfbK B  xB*hh1GGS!JE97@@|u4%6bK B  xB*hh1GG!JSE9=xu4%b=qo b 85ͣumۨhh1GGS!JE9@@u2%6b=qo b 85ͣumۨhh13-GG!JSE9>wu2%!cbK B 8v^;r@hh1-GGS!JE98@@{u4%6bK B 8v^;r@hh1.GG!JSE9?vu4%wb=r b #A'҉ko'hh1.GGS!JE9@@u2%6b=r b #A'҉ko'hh1uGG!JSE9@uu2%bK\ B S B|h=YThh18vGGS!JE99@@zu4%6bK\ B S B|h=YThh1vGG!JSE9Atu4%f b=r b SFOem|d>|hh1wGGS!JE9@@u2%6b=r b SFOem|d>|hh1jGG!JSE9Bsu2%fbK B  `%j9hh1GGS!JE9:@@yu4%6bK B  `%j9hh1JGG!JSE9Cru4%4b=sO b ԪK/=lK/?Xhh1GGS!JE9@@u2%6b=sO b ԪK/=lK/?Xh1]]!JSEODf>u r.* 1P>ޮ$ (08AIQYaiqy X166S!JE(yJ@@? >u 1r.*P<Xh1wGG!JSE9Epu2% bK B /OhJ ghh1GG!JSE9Fou4%$b=s b f6ߡުa╻0hh1GGS!JE9@@u2%6b=s b f6ߡުa╻0hh1%GGS!JE9;@@xu4%6bK B /OhJ ghh1_GG!JSE9Gnu2%BbK< B :Ϲ3x/G)"hh1F`GGS!JE9<@@wu4%6bK< B :Ϲ3x/G)"hh1`GG!JSE9Hmu4%Sb=t b tw?º idLhh1aGGS!JE9@@u2%6b=t b tw?º idLhh1MGG!JSE9Ilu2%KbL B H[Zj8hh1غGGS!JE9=@@vu4%6bL B H[Zj8hh1.GG!JSE9Jku4%Chb=u/ b ķ3kȓ hh1GGS!JE9@@u2%6b=u/ b ķ3kȓ hh1GG!JSE9Kju2%kbL| B ZR4gVT Fb` hh1)GG!JSE9Liu4%b=u b AhT7 ~@hh1GGS!JE9@@u2%6b=u b AhT7 ~@hh1GGS!JE9>@@uu4%6bL| B ZR4gVT Fb` hh1%JGG!JSE9Mhu2%bL B  vۦ`hh1JJGG!JSE9Ngu4%#yb=vo b r>%hh1JGGS!JE9@@u2%6b=vo b r>%hh1JGGS!JE9?@@tu4%6bL B  vۦ`hh1 GG!JSE9Ofu2%VbL B lM"tRrV|hh1-GG!JSE9Peu4%֠b=w b 8?VN hh1GGS!JE9@@u2%6b=w b 8?VN hh1GGS!JE9@@@su4%6bL B lM"tRrV|hh1zGG!JSE9Qdu2%vbL\ B $ml4hh1GG!JSE9Rcu4%b=w b .s*{/`ǣhh1GGS!JE9@@u2%6b=w b .s*{/`ǣhh1-GGS!JE9A@@ru4%6bL\ B $ml4hh175GG!JSE9Sbu2%bL B !j6 hh1X5GG!JSE9Tau4%?b=xO b u]۹(44hh15GGS!JE9@@u2%6b=xO b u]۹(44hh15GGS!JE9B@@qu4%6bL B !j6 h1E``!JSERUR>u r.* 1P>('( ?? p ==%@X1OE66S!JE(yK@@? >u 1r.+P<Xh1AGG!JSE9V_u2%ibL B *ï`w\@hh1cGG!JSE9W^u4%jb=x b -؞R1hh1׏GGS!JE9@@u2%6b=x b -؞R1hh1GGS!JE9C@@pu4%6bL B *ï`w\@hh1xGG!JSE9X]u2%ЀbL< B OR8(_Dhh1 GGS!JE9D@@ou4%6bL< B OR8(_Dhh1QGG!JSE9Y\u4%tb=y b RAww4b%Uphh1GGS!JE9@@u2%6b=y b RAww4b%Uphh1lGG!JSE9Z[u2%nL B 4szMqhh1GGS!JE9E@@nu4%6L B 4szMqhh1WGG!JSE9[Zu4%QKb=z/ b 4Nv$Kj|hh1GGS!JE9@@u2%6b=z/ b 4Nv$Kj|h1i6``!JSER\K>u r.+ 1P>,'( ?? p <<%?X1666S!JE(yL@@? >u 1r.++P<Xh1"yGG!JSE9]Xu2%満bL | B n_c"6$hh1ayGGS!JE9F@@mu4%6bL | B n_c"6$hh1XzGG!JSE9^Wu4%b=z b n{Z 5$ xhh1xzGGS!JE9@@u2%6b=z b n{Z 5$ xhh1GG!JSE9_Vu2%ԀbL  B O 0hh1(GG!JSE9`Uu4%_b={o b @ffj dhh1GGS!JE9@@u2%6b={o b @ffj dhh1GGS!JE9G@@lu4%6bL  B O 0hh1R GG!JSE9aTu2%bL  B D{|SzSq`Lhh1s GG!JSE9bSu4%bb=| b ~zfxRp hh1 GGS!JE9@@u2%6b=| b ~zfxRp hh1 GGS!JE9H@@ku4%6bL  B D{|SzSq`Lhh1cGG!JSE9cRu2%pˀbL \ B Vx]jdhh1/cGG!JSE9dQu4%Xb=| b fxfKw֜Ahh1cGGS!JE9@@u2%6b=| b fxfKw֜Ahh1cGGS!JE9I@@ju4%6bL \ B Vx]jdhh11GG!JSE9ePu2%5bL  B f}`qҖF؈hh1VGG!JSE9fOu4%b=}O b :fpo}ǡ;`hh1ȬGGS!JE9@@u2%6b=}O b :fpo}ǡ;`hh1GGS!JE9J@@iu4%6bL  B f}`qҖF؈hh1GG!JSE9gNu2%eрbL B V@fir4lhh1GG!JSE9hMu4%Mb=} b fhv=$xc"Thh1AGGS!JE9@@u2%6b=} b fhv=$xc"Thh1^GGS!JE9K@@hu4%6bL B V@fir4lhh1&NGG!JSE9iLu2%bL< B ~`X<aw-dhh1GNGG!JSE9jKu4%Fb=~ b ,fYm<Ñ4<hh1NGGS!JE9@@u2%6b=~ b ,fYm<Ñ4<hh1NGGS!JE9L@@gu4%6bL< B ~`X<aw-dhh1:GG!JSE9kJu2%6 bL B ,RޙS'hh1[GG!JSE9lIu4%%xb=/ b ,j2o=khh1ЖGGS!JE9@@u2%6b=/ b ,j2o=khh1GGS!JE9M@@fu4%6bL B ,RޙS'hh1GG!JSE9mHu2%;bL| B ,W~A4>O|hh1GG!JSE9nGu4%b= b W~ڸi*hh1OGGS!JE9@@u2%6b= b W~ڸi*hh1lGGS!JE9N@@eu4%6bL| B ,W~A4>O|hh1r8GG!JSE9oFu2%bL B ,v:%ilhh18GG!JSE9pEu4%Eb=o b A~ ELhh19GGS!JE9@@u2%6b=o b A~ ELhh1 9GGS!JE9O@@du4%6bL B ,v:%ilhh1GG!JSE9qDu2%bL¼ B ,fz`׾sXՠhh10GG!JSE9rCu4%|b= b Av(3[dthh1GGS!JE9@@u2%6b= b Av(3[dthh1ÀGGS!JE9P@@cu4%6bL¼ B ,fz`׾sXՠhh1GG!JSE9sBu2%VрbL\ B ,TfhW΅UJ\hh1GG!JSE9tAu4%sb= b hQ7! hh1GGS!JE9@@u2%6b= b hQ7! hh1GGS!JE9Q@@bu4%6bL\ B ,TfhW΅UJ\hh1"GG!JSE9u@u2%.bL B ,fy24;"&(0hh1"GG!JSE9v?u4%b=O b fX)B<hh1a#GGS!JE9@@u2%6b=O b fX)B<hh1~#GGS!JE9R@@au4%6bL B ,fy24;"&(0hh1jGG!JSE9w>u2%ƀbLĜ B ,fЋX.hh1kkGGS!JE9S@@`u4%6bLĜ B ,fЋX.hh1kGG!JSE9x=u4%*b= b Ag('531U0hh1YlGGS!JE9@@u2%6b= b Ag('531U0hh1ԲGG!JSE9y<u2%SbL< B ~yf>o~N$hh1fGGS!JE9T@@_u4%6bL< B ~yf>o~N$hh1GG!JSE9z;u4%n(b= b .DN8'@,\hh1JGGS!JE9@@u2%6b= b .DN8'@,\hh1 GG!JSE9{:u2%&bL B ,uh}T*!hh1s GGS!JE9U@@^u4%6bL B ,uh}T*!hh1 GG!JSE9|9u4%t(b=/ b .D0/(ca7u\hh1EGGS!JE9@@u2%6b=/ b .D0/(ca7u\hh1 UGG!JSE9}8u2%ZbL| B T~D` 23hh1UGGS!JE9V@@]u4%6bL| B T~D` 23hh1VGG!JSE9~7u4%b= b ,i[1g"?Lhh1VGGS!JE9@@u2%6b= b ,i[1g"?Lhh1GG!JSE96u2%kbL B xEZ7hh1>GGS!JE9W@@\u4%6bL B xEZ7hh1GG!JSE95u4%b=o b Ϟq Oa0Dhh1!GGS!JE9@@u2%6b=o b Ϟq Oa0Dhh1GG!JSE94u2%c{bLǼ B ,̞z6^ thh1GGS!JE9X@@[u4%6bLǼ B ,̞z6^ thh1GG!JSE93u4%{b= b ~np[qS9Phh1GGS!JE9@@u2%6b= b ~np[qS9Phh1?GG!JSE92u2% tbL\ B ~%ag"n$d4hh17@GGS!JE9Y@@Zu4%6bL\ B ~%ag"n$d4hh1~@GG!JSE91u4%ـb= b n0_t+hIThh1AGGS!JE9@@u2%6b= b n0_t+hIThh1GG!JSE90u2%ąbL B \6ehh1'GGS!JE9Z@@Yu4%6bL B \6ehh1rGG!JSE9/u4%nb=O b ~P\.5Xt2hh1GGS!JE9@@u2%6b=O b ~P\.5Xt2h1՘``!JSER >u r.++ 1P>'( ?? p 670%@X166S!JE(yM@@? >u 1r.+UP<Xh1GG!JSE9-u2%hbLɜ B lqxH&e4hh1/GGS!JE9[@@Xu4%6bLɜ B lqxH&e4hh1wGG!JSE9,u4%b> b ~DoZUzhh1GGS!JE9@@u2%6b> b ~DoZUzhh1)GG!JSE9+u2%bL< B l^*7@EF hh1b*GGS!JE9\@@Wu4%6bL< B l^*7@EF hh1D+GG!JSE9*u4%}=b> b ~ɞ}>'hh1+GGS!JE9@@u2%6b> b ~ɞ}>'hh1qGG!JSE9)u2%bL  B :wZ]_3 Ÿhh1rGGS!JE9]@@Vu4%6bL  B :wZ]_3 Ÿhh1rGG!JSE9(u4%b>/ b ~\  qhh1psGGS!JE9@@u2%6b>/ b ~\  qh1``!JSER>u r.+U 1P>i'( ?? p 890%?X1Ƅ66S!JE(yN@@? >u 1r.+P<Xh1GG!JSE9&u2%bL!| B Ϟ};[Hhh1!GG!JSE9%u4%ʀb> b lɞb:i,FDhh1GGS!JE9@@u2%6b> b lɞb:i,FDhh1GGS!JE9^@@Uu4%6bL!| B Ϟ};[Hhh1GG!JSE9$u2%bL" B :Ϟoqqj[hh1YGGS!JE9_@@Tu4%6bL" B :Ϟoqqj[hh1SGG!JSE9#u4%a:b>o b 4%a>w`jŔ$hh1GGS!JE9@@u2%6b>o b 4%a>w`jŔ$hh1\GG!JSE9"u2%ɀbL#̼ B lXՙ&hh1\GG!JSE9!u4%Mmb> b lɞ{O賱hh1W]GGS!JE9@@u2%6b> b lɞ{O賱hh1u]GGS!JE9`@@Su4%6bL#̼ B lXՙ&hh1GG!JSE9 u2%\'bL$\ B  b qE(uxhh1bGGS!JE9@@u2%6b> b qE(uxhh1;GG!JSE9u2%X bL% B 4g.+lr,hh1GGS!JE9b@@Qu4%6bL% B 4g.+lr,hh1wGG!JSE9u4%*b>O b 4w]pߦ&)hh1GGS!JE9@@u2%6b>O b 4w]pߦ&)hh1FGG!JSE9u2%nbL&Μ B 4T#hh1FGG!JSE9u4%b> b .DzG_ b .DzG_  b Az_\ghh1 GGS!JE9@@u2%6b>  b Az_\ghh1*GGS!JE9d@@Ou4%6bL'< B +4s3x5hh1+GG!JSE9u2%PɀbL( B ~e漝C؃hhh1PGG!JSE9u4%~b> / b RTplBDhh1GGS!JE9@@u2%6b> / b RTplBDhh1GGS!JE9e@@Nu4%6bL( B ~e漝C؃hhh11GG!JSE9u2%UPbL)| B ͖]\HXhh11GG!JSE9u4%b>  b j;0YXF4hh172GGS!JE9@@u2%6b>  b j;0YXF4hh1T2GGS!JE9f@@Mu4%6bL)| B ͖]\HXhh1SGG!JSE9u2%bL* B 4ž羞{hh1tGG!JSE9u4%jb> o b @/G/61hh1GGS!JE9@@u2%6b> o b @/G/61hh1GGS!JE9g@@Lu4%6bL* B 4ž羞{hh1GG!JSE9u2%bL+Ѽ B ,p1EkSӐhh1GG!JSE9u4%GBb>  b ph?/p(zakܼhh1GGS!JE9@@u2%6b>  b ph?/p(zakܼhh1GGS!JE9h@@Ku4%6bL+Ѽ B ,p1EkSӐhh1.GG!JSE9u2%YbL,\ B ,@zj$Ghh1GGS!JE9i@@Ju4%6bL,\ B ,@zj$Ghh1GG!JSE9u4%b> b xzbphh1GGS!JE9@@u2%6b> b xzbphh1uGG!JSE9u2%~bL- B ,@|b`qFhh1hvGGS!JE9j@@Iu4%6bL- B ,@|b`qFhh1vGG!JSE9 u4%b>O b Ahwz5, chh1AwGGS!JE9@@u2%6b>O b Ahwz5, chh1?GG!JSE9 u2%bL.Ӝ B nγreA<hh1ѽGGS!JE9k@@Hu4%6bL.Ӝ B nγreA<hh1GG!JSE9 u4% b> b XCߓ5H$hh1GGS!JE9@@u2%6b> b XCߓ5H$hh1eGG!JSE9 u2%: b ,z6XqBk)پ$hh1GGS!JE9@@u2%6b> b ,z6XqBk)پ$hh1_GG!JSE9u2%tbL0 B f㣝rXhh1`GGS!JE9m@@Fu4%6bL0 B f㣝rXhh1e`GG!JSE9u4%[b>/ b ~U/ b ~U b fLg~nհhh1>GGS!JE9@@u2%6b> b fLg~nհhh1GG!JSE9u2%rtbL2 B %jxׅKFhh1'GGS!JE9o@@Du4%6bL2 B %jxׅKFhh1uGG!JSE9u4%b>o b %f8OǗ!3 chh1GGS!JE9@@u2%6b>o b %f8OǗ!3 chh1J GG!JSE9u2%}bL3ּ B l`xI[hh1K GGS!JE9p@@Cu4%6bL3ּ B l`xI[hh1oK GG!JSE9u4%CWb> b ~@x!YY<hh1K GGS!JE9@@u2%6b> b ~@x!YY<hh1 GG!JSE9u2%>bL4\ B  x7Q`JJhh1= GGS!JE9q@@Bu4%6bL4\ B  x7Q`JJhh1( GG!JSE9u4%կb> b pfx3 (-hh1 GGS!JE9@@u2%6b> b pfx3 (-hh1E GG!JSE9u2%рbL5 B xgWThh1f GG!JSE9u4%b>O b xJohR\hh1 GGS!JE9@@u2%6b>O b xJohR\hh1 GGS!JE9r@@Au4%6bL5 B xgWTh1 ``!JSER>u r.+ 1P>9N'(  ?? p **%@X1 66S!JE(yO@@? >u 1r.+P<Xh1Q5 GG!JSE9u2%bL6؜ B Afxf\yL^Thh1r5 GG!JSE9u4%4b> b APK}n.1hh15 GGS!JE9@@u2%6b> b APK}n.1hh16 GGS!JE9s@@@u4%6bL6؜ B Afxf\yL^Thh1y| GG!JSE9u2%xxbL7< B ,fxF 7馰hh1| GG!JSE9u4%Tb> b AfpnOoe|OHhh1 } GGS!JE9@@u2%6b> b AfpnOoe|OHhh1&} GGS!JE9t@@?u4%6bL7< B ,fxF 7馰hh1 GG!JSE9u2% bL8 B fxaϬtthh1 GG!JSE9u4%i-b>/ b .zCK+5*MThh1 GGS!JE9@@u2%6b>/ b .zCK+5*MThh1 GGS!JE9u@@>u4%6bL8 B fxaϬtth15 ``!JSER>u r.+ 1P>?('( ?? p ''%?X1` 66S!JE(yP@@? >u 1r.+P<Xh1 GG!JSE9u2%vebL9| B ,DfXN̓Z-Mhh1( GGS!JE9v@@=u4%6bL9| B ,DfXN̓Z-Mhh1o GG!JSE9u4%8b> b .fkҗr}J 0hh1 GGS!JE9@@u2%6b> b .fkҗr}J 0hh1eg GG!JSE9u2%&bL: B fH1ۿ Ohhhh1g GGS!JE9w@@<u4%6bL: B fH1ۿ Ohhhh1Lh GG!JSE9u4%b>o b .X' o|^hh1h GGS!JE9@@u2%6b>o b .X' o|^hh1 GG!JSE9u2%1bL;ۼ B nu6" hh1 GGS!JE9x@@;u4%6bL;ۼ B nu6" hh1y GG!JSE9u4%b> b .f5A}3dhh1̰ GGS!JE9@@u2%6b> b .f5A}3dhh1 GG!JSE9u2%bL<\ B 4fc}5,hh13 GGS!JE9y@@:u4%6bL<\ B 4fc}5,hh1# GG!JSE9u4%bb> b Dfc,=j" hh1L GGS!JE9@@u2%6b> b Dfc,=j" hh1Q GG!JSE9u2%|̀bL= B nnf?zV=tChh1R GG!JSE9u4%=b>O b A[flQnEkhh1iR GGS!JE9@@u2%6b>O b A[flQnEkhh1vR GGS!JE9z@@9u4%6bL= B nnf?zV=tChh1 GG!JSE9u2%-bL>ݜ B 3+ffeB9"Ghh1s GGS!JE9{@@8u4%6bL>ݜ B 3+ffeB9"Ghh1 GG!JSE9u4%Ѐb>  b 8DfcP+I!%hh1 GGS!JE9@@u2%6b>  b 8DfcP+I!%hh1 GG!JSE9u2%GBbL?< B ~+fWK,ڣ 4hh1 GG!JSE9u4%b>! b fG (f`nhh1 GGS!JE9@@u2%6b>! b fG (f`nhh1 GGS!JE9|@@7u4%6bL?< B ~+fWK,ڣ 4hh1: GG!JSE9u2%@bL@ B lrT$Whh1; GGS!JE9}@@6u4%6bL@ B lrT$Whh1t< GG!JSE9u4%+b>"/ b N8#>; B``hh1< GGS!JE9@@u2%6b>"/ b N8#>; B``hh1t GG!JSE9u2%πbLA| B :fSJP hh1 GG!JSE9u4%%Ub># b ~POVthh1Z GGS!JE9@@u2%6b># b ~POVthh1{ GGS!JE9~@@5u4%6bLA| B :fSJP hh1R GG!JSE9u2%dbLB B :BWrhh1t GG!JSE9u4%ۀb>$o b lɞxfR1U$hh17 GGS!JE9@@տu2%6b>$o b lɞxfR1U$hh1Z GGS!JE9@@4u4%6bLB B :BWrhh1&GG!JSE9u2%̀bLC B :cxsp8hh1{'GGS!JE9@@3u4%6bLC B :cxsp8hh1'GG!JSE9u4%w}b>% b lD`~Yɼ@hh1(GGS!JE9@@վu2%6b>% b lD`~Yɼ@hh1nGG!JSE9u2%ԀbLD\ B :|scrphh1nGG!JSE9u4%~b>& b ~jySw< '4phh1IoGGS!JE9@@սu2%6b>& b ~jySw< '4phh1foGGS!JE9@@2u4%6bLD\ B :|scrphh1GG!JSE9u2%'bLE B :mvؾ~NPhh1GG!JSE9u4%R1b>'O b ~nz%G؇}hh1GGS!JE9@@ռu2%6b>'O b ~nz%G؇}hh1<GGS!JE9@@1u4%6bLE B :mvؾ~NPhh1GG!JSE9u2%ÀbLF B V~udi"hh1GG!JSE9u4%fb>( b ~J|#JGUhh1tGGS!JE9@@ջu2%6b>( b ~J|#JGUhh1GGS!JE9@@0u4%6bLF B V~udi"hh1qXGG!JSE9u2%ubLG< B +lsƮN:hh1XGG!JSE9u4%Bրb>) b :%zeR#G¼hh1YGGS!JE9@@պu2%6b>) b :%zeR#G¼hh1%YGGS!JE9@@/u4%6bLG< B +lsƮN:hh1GG!JSE9u2%~bLH B w}xSԙ^mhh1$GG!JSE9u4%Nb>*/ b ~xŋů$َ1hh1GGS!JE9@@չu2%6b>*/ b ~xŋů$َ1hh1GGS!JE9@@.u4%6bLH B w}xSԙ^mhh1=GG!JSE9u2%+ b ~%b_jJsDthh1GGS!JE9@@ոu2%6b>+ b ~%b_jJsDthh1GGS!JE9@@-u4%6bLI| B :zKE,o b n-Zqe {hh1DGGS!JE9@@շu2%6b>,o b n-Zqe {hh1 GG!JSE9u2%bLK B ɞ}1whh1GGS!JE9@@+u4%6bLK B ɞ}1whh1GG!JSE9u4%b>- b fS.3dhh1rGGS!JE9@@նu2%6b>- b fS.3dhh1-GG!JSE9u2%RbLL\ B :~/fӫ2ehh1GGS!JE9@@*u4%6bLL\ B :~/fӫ2ehh1GG!JSE9u4% b>. b ~U_6#0hh1GGS!JE9@@յu2%6b>. b ~U_6#0hh1a-GG!JSE9u2%bLM B 4nlXhh1-GGS!JE9@@)u4%6bLM B 4nlXhh1Z.GG!JSE9u4%ab>/O b AV<9 ) hh1.GGS!JE9@@մu2%6b>/O b AV<9 ) h1=``!JSER>u r.+ 1P>4'(  ?? p --%@X1>66S!JE(yQ@@? >u 1r.+P<Xh1GG!JSE9u2%)ƀbLN B 4EnQ֒f*$hh1GG!JSE9u4%b>0 b A*(yQz:hh1&GGS!JE9@@ճu2%6b>0 b A*(yQz:hh1FGGS!JE9@@(u4%6bLN B 4EnQ֒f*$hh1GG!JSE9u2%bLO< B ~ ~Hq8hh1ZGGS!JE9@@'u4%6bLO< B ~ ~Hq8hh1GG!JSE9u4%_b>1 b THW9Pk'Jhh17GGS!JE9@@ղu2%6b>1 b THW9Pk'Jhh19GG!JSE9u2%ڀbLP B pN ݳx*Hhh1GGS!JE9@@&u4%6bLP B pN ݳx*Hhh1GG!JSE9u4%@b>2/ b .@(Ϟ׼όI-@hh1GGS!JE9@@ձu2%6b>2/ b .@(Ϟ׼όI-@h1/``!JSER>u r.+ 1P>B'( ?? p "$%?X1/66S!JE(yR@@?~ >u 1r.,'P<Xh1 sGG!JSE9u2%@bLQ| B ~psdhh1,sGG!JSE9u4%uab>3 b A`W Pָm4hh1sGGS!JE9@@հu2%6b>3 b A`W Pָm4hh1sGGS!JE9@@%u4%6bLQ| B ~psdhh1GG!JSE9u2%ʀbLR B 4@g5q#cI=chh1GGS!JE9@@$u4%6bLR B 4@g5q#cI=chh1պGG!JSE9u4%b>4o b T w~YFm hh1dGGS!JE9@@կu2%6b>4o b T w~YFm h1vv!JSEhu5TR  bpd BLQ/)YX b 192.168.0.1741hvvS!JEh@@u3Te  bpd BLQ/)YX b 192.168.0.174h1GG!JSE9u2%ϬbLS B Ds="+6sWvhh1GGS!JE9@@#u4%6bLS B Ds="+6sWvhh1GG!JSE9u4%7mb>5 b 4NlG64hh1cGGS!JE9@@ծu2%6b>5 b 4NlG64hh1[GG!JSE9u2%`рbLT\ B P~M`=Q#NHhh1\GGS!JE9@@"u4%6bLT\ B P~M`=Q#NHhh1\GG!JSE9u4%b>6 b 9x&@4spthh1]GGS!JE9@@խu2%6b>6 b 9x&@4spthh11GG!JSE9u2%NbLU B luh(0kM Cmhh1tGGS!JE9@@!u4%6bLU B luh(0kM Cmhh1lGG!JSE9u4% b>7O b l-|c4w@Uhh1GGS!JE9@@լu2%6b>7O b l-|c4w@Uhh1GG!JSE9u2%_bLV B :xgW hh1GG!JSE9u4%0Wb>8 b 96PKбhh1GGS!JE9@@իu2%6b>8 b 96PKбhh1GGS!JE9@@ u4%6bLV B :xgW hh1FGG!JSE9u2%DbLW< B ='_)@&hhh1@GGGS!JE9@@u4%6bLW< B ='_)@&hhh1GGG!JSE9u4%g(b>9 b l8hh1!HGGS!JE9 @@ժu2%6b>9 b l8hh1FGG!JSE9u2%5FbLX B =fishh1ӏGGS!JE9@@u4%6bLX B =fishh1GG!JSE9u4%8b>:/ b =`νA*C2{hh1GGS!JE9 @@թu2%6b>:/ b =`νA*C2{hh1GG!JSE9u2%ƀbLY| B %fs,+hh1LGGS!JE9@@u4%6bLY| B %fs,+hh1GG!JSE9u4%@7b>; b :`xbKjg18hh12GGS!JE9 @@ըu2%6b>; b :`xbKjg18hh1]1GG!JSE9u2%zۀbLZ B lf\ȠtGv@4hh11GGS!JE9@@u4%6bLZ B lf\ȠtGv@4hh1G2GG!JSE9u4%2€b><o b nWfxt^cNhh12GGS!JE9 @@էu2%6b><o b nWfxt^cNhh1xGG!JSE9u2%րbL[ B pf~aa@"T,hh1VyGGS!JE9@@u4%6bL[ B pf~aa@"T,hh1yGG!JSE9 u4%b>= b fxe/fԖyhh1'zGGS!JE9 @@զu2%6b>= b fxe/fԖyhh1GG!JSE9 u2%̀bL\\ B  Z@ҫ>(hh1GGS!JE9@@u4%6bL\\ B  Z@ҫ>(hh1GG!JSE9 u4%(b>> b nHPO26B hh1|GGS!JE9@@եu2%6b>> b nHPO26B hh12GG!JSE9 u2%hbL] B 4qE9بhh1GGS!JE9@@u4%6bL] B 4qE9بh1Cvv!JSEh yu3TȺ  Bco_ b>>-7 B 192.168.0.1741vvS!JEh,@@Xu5Te  Bco_ b>>-7 B 192.168.0.174h1,GG!JSE9u4%߀b>?O b ׃HT,<hh1GGS!JE9@@դu2%6b>?O b ׃HT,<hh1cGG!JSE9u2%ـbL^ B ~đs$)Dhh1>dGGS!JE9@@u4%6bL^ B ~đs$)Dhh1dGG!JSE9u4%$b>@ b {~=afhh1%eGGS!JE9@@գu2%6b>@ b {~=afhh1+GG!JSE9u2%XbL_< B 4nfyOT1{crhh1GGS!JE9@@u4%6bL_< B 4nfyOT1{crhh1GG!JSE9u4%90b>A b nfxgMt:K/hh1GGS!JE9@@բu2%6b>A b nfxgMt:K/hh1/GG!JSE9u2%9ЀbL` B t}t^thh1GGS!JE9@@u4%6bL` B t}t^thh1 GG!JSE9u4% >B/ b Apohp9hh1GGS!JE9@@աu2%6>B/ b Apohp9hh1ENGG!JSE9u2%bLa| B DzG3B,hh1NGGS!JE9@@u4%6bLa| B DzG3B,hh1&OGG!JSE9u4%#b>C b Af`෇Apphh1OGGS!JE9@@ՠu2%6b>C b Af`෇Apphh1GG!JSE9u2%#bbLb B 4aֵC}hh1GGS!JE9@@u4%6bLb B 4aֵC}hh1sGG!JSE9u4%b>Do b ATft d7{llhh1GGS!JE9@@՟u2%6b>Do b ATft d7{llhh1.GG!JSE9u2%1%bLc B n9F!>A(hh1GGS!JE9@@u4%6bLc B n9F!>A(hh1GG!JSE9u4%b>E b .Tf uc&hhh1GGS!JE9@@՞u2%6b>E b .Tf uc&hhh17GG!JSE9u2%5bLd\ B nfgv?3 -¨hh1m8GGS!JE9@@u4%6bLd\ B nfgv?3 -¨hh18GG!JSE9u4%cb>F b Agn|58hh1I9GGS!JE9@@՝u2%6b>F b Agn|58hh11GG!JSE9u2%nbLe B gohh1GGS!JE9@@u4%6bLe B gohh1GG!JSE9u4%|b>GO b EzΨhh1GGS!JE9@@՜u2%6b>GO b EzΨh1j``!JSER>u r.,' 1P>2'(  ?? p ..%@X166S!JE(yS@@?} >u 1r.,QP<Xh1GG!JSE9 u2%X>bLf B 4qޥݹ@aڨhh1OGGS!JE9@@u4%6bLf B 4qޥݹ@aڨhh1GG!JSE9!u4%(b>H b yfeN 5ldhh1#GGS!JE9@@՛u2%6b>H b yfeN 5ldhh1"GG!JSE9"u2%bLg< B ,5fM ~hh1#GGS!JE9@@u4%6bLg< B ,5fM ~hh1#GG!JSE9#u4%cb>I b  M,S5hh1j$GGS!JE9@@՚u2%6b>I b  M,S5hh1!kGG!JSE9$u2%d߀bLh B 45f7 ZI;(hh1kGGS!JE9@@u4%6bLh B 45f7 ZI;(hh1lGG!JSE9%u4%Ub>J/ b nyfܔ9k8D(hh1lGGS!JE9@@ՙu2%6b>J/ b nyfܔ9k8D(h1}``!JSER&>u r.,Q 1P>7z'( ?? p ,-%?X1 ~66S!JE(yT@@?| >u 1r.,{P<Xh1GG!JSE9'u2%DbLi| B ~5f}֘hh1GGS!JE9@@ u4%6bLi| B ~5f}֘hh1GG!JSE9(u4%5b>K b  x^q @hh1GGS!JE9@@՘u2%6b>K b  x^q @hh1 GG!JSE9)u2%}+bLj B 5f j?'7v8hh1 GGS!JE9@@ u4%6bLj B 5f j?'7v8hh1 GG!JSE9*u4%^b>Lo b yf:zGU5 |hh1GGS!JE9@@՗u2%6b>Lo b yf:zGU5 |hh1UGG!JSE9+u2%.bLk B l5fM>v2%xhh1UGGS!JE9@@ u4%6bLk B l5fM>v2%xhh1UGG!JSE9,u4%Mπb>M b ibsD(hh1sVGGS!JE9@@Ֆu2%6b>M b ibsD(hh1GG!JSE9-u2%obLl\ B fE Xhh1bGGS!JE9@@ u4%6bLl\ B fE Xhh1GG!JSE9.u4%cb>N b ,yft{%%hh1NGGS!JE9@@Օu2%6b>N b ,yft{%%hh1GG!JSE9/u2%=bLm B l5f5QiThh1GGS!JE9@@ u4%6bLm B l5f5QiThh1GG!JSE90u4%sb>OO b ,N*oPⓅ{`hh1jGGS!JE9@@Քu2%6b>OO b ,N*oPⓅ{`hh1?GG!JSE91u2%bLn B 4x7@|( hh1b@GGS!JE9@@u4%6bLn B 4x7@|( hh1@GG!JSE92u4%ub>P b 45tk7"1whh1BAGGS!JE9 @@Փu2%6b>P b 45tk7"1whh1GG!JSE93u2%bLo< B lϞzeưbUUhh1 GGS!JE9@@u4%6bLo< B lϞzeưbUUhh1GG!JSE94u4%Gb>Q b nϞzaP'C8hh1GGS!JE9!@@Ւu2%6b>Q b nϞzaP'C8hh1GG!JSE95u2%QDbLp B 4xC֬j`d<hh10GG!JSE96u4%j_b>R/ b Ξrlc `CLhh1GGS!JE9"@@Ցu2%6b>R/ b Ξrlc `CLhh1GGS!JE9@@u4%6bLp B 4xC֬j`d<hh10*GG!JSE97~u2%=bLq| B lwh e)b hh1Q*GG!JSE98}u4%9b>S b D~ C`j"M8hh1*GGS!JE9#@@Րu2%6b>S b D~ C`j"M8hh1*GGS!JE9@@u4%6bLq| B lwh e)b hh1GG!JSE99|u2%t&bLr B 4~To b 4'f9]qN. hh1GGS!JE9$@@Տu2%6b>To b 4'f9]qN. hh1„GGS!JE9@@u4%6bLr B 4~U b 'x U ¢&(hh1GGS!JE9%@@Վu2%6b>U b 'x U ¢&(hh1GGS!JE9@@u4%6bLs B }?5%dhh1GG!JSE9=xu2%m^bLt\ B 4}78hh17GG!JSE9>wu4%ab>V b 'x)8hh1GGS!JE9&@@Սu2%6b>V b 'x)8hh1GGS!JE9@@u4%6bLt\ B 4}78hh1nGG!JSE9?vu2%eHbLu B Ξp9PȣHhh1nGG!JSE9@uu4%f[b>WO b nxcfQ#hhh1UoGGS!JE9'@@Ռu2%6b>WO b nxcfQ#hhh1soGGS!JE9@@u4%6bLu B Ξp9PȣHhh1˶GG!JSE9Atu2%EbLv B 4z{$hh1GG!JSE9Bsu4%b>X b 'z1jU"hh1[GGS!JE9(@@Ջu2%6b>X b 'z1jU"hh1yGGS!JE9@@u4%6bLv B 4z{$hh1GG!JSE9Cru2%bLw< B q}euGhh1GG!JSE9Dqu4% ob>Y b yxOX!ыfhh1zGGS!JE9)@@Պu2%6b>Y b yxOX!ыfhh1GGS!JE9@@u4%6bLw< B q}euGhh1!YGG!JSE9Epu2%-bLx B 4xYEBphh1YGGS!JE9@@u4%6bLx B 4xYEBphh1 ZGG!JSE9Fou4%b>Z/ b T y!gshh1ZGGS!JE9*@@Չu2%6b>Z/ b T y!gshh1àGG!JSE9Gnu2%ObLy| B 4qxQ hh1PGGS!JE9@@u4%6bLy| B 4qxQ hh1GG!JSE9Hmu4%>b>[ b V|$L hh1'GGS!JE9+@@Ոu2%6b>[ b V|$L hh1GG!JSE9Ilu2%SրbLz B x[૮hh1GGS!JE9@@u4%6bLz B x[૮hh1GG!JSE9Jku4%Rb>\o b Wy|ƣ>3XO"Nhh1}GGS!JE9,@@Շu2%6b>\o b Wy|ƣ>3XO"Nhh1BGG!JSE9Kju2%hbL{ B nH7fb͆( hh1CGGS!JE9@@u4%6bL{ B nH7fb͆( hh1CGG!JSE9Liu4%b>] b .Z%5i:EǤhh1eDGGS!JE9-@@Նu2%6b>] b .Z%5i:EǤhh1RGG!JSE9Mhu2%)bL|\ B 4:U@ۂ~fhh1GGS!JE9@@u4%6bL|\ B 4:U@ۂ~fhh19GG!JSE9Ngu4%zb>^¯ b (8U_i+ihhh1njGGS!JE9.@@Յu2%6b>^¯ b (8U_i+ihhh1GG!JSE9Ofu2%cԀbL} B qFetF4hh1kGGS!JE9@@u4%6bL} B qFetF4hh1uGG!JSE9Peu4%Yb>_O b \XJ si(hh1GGS!JE9/@@Մu2%6b>_O b \XJ si(h1:``!JSERQV>u r.,{ 1P>2O'(  ?? p --%@X1k66S!JE(yU@@?{ >u 1r.,P<Xh1!. GG!JSE9Rcu2%|bL~ B 5e4.Pr,t$hh1C. GG!JSE9Sbu4%r` b t``7%[D.hh1 / GGS!JE90@@Ճu2%6b>` b t``7%[D.hh1+/ GGS!JE9@@u4%6bL~ B 5e4.Pr,t$hh1u GG!JSE9Tau2%۝bL< B A58G?Ӕ{Hhh1_v GGS!JE9@@u4%6bL< B A58G?Ӕ{Hhh1v GG!JSE9U`u4%hb>aď b {Y* 7^8 hh1w GGS!JE91@@Ղu2%6b>aď b {Y* 7^8 hh1޽ GG!JSE9V_u2%>߀bL B A5|ϾrZhh1 GG!JSE9W^u4%b>b/ b ty# hh1þ GGS!JE92@@Ձu2%6b>b/ b ty# hh1 GGS!JE9@@u4%6bL B A5|ϾrZh1q ``!JSERXO>u r., 1P>1"'( ?? p 11%?X1 66S!JE(yV@@?z >u 1r.,P<Xh1!GG!JSE9Y\u2%bL| B A5z%@?p hh1k!GGS!JE9@@u4%6bL| B A5z%@?p hh1!GG!JSE9Z[u4%Rb>c b xg0&M0%hh1!GGS!JE93@@Հu2%6b>c b xg0&M0%hh1"`!GG!JSE9[Zu2%bL B ,5|a@DWphh1D`!GG!JSE9\Yu4% b>do b AyxTS~0"vhh1a!GGS!JE94@@u2%6b>do b AyxTS~0"vhh1(a!GGS!JE9@@u4%6bL B ,5|a@DWphh1U!GG!JSE9]Xu2%bL B zr!\hh1y!GG!JSE9^Wu4%׵b>e b ArS)W`;hh1>!GGS!JE95@@~u2%6b>e b ArS)W`;hh1`!GGS!JE9@@u4%6bL B zr!\hh1Q"GG!JSE9_Vu2%ŀbL \ B :x\^LoWWhh1&"GGS!JE9@@u4%6bL \ B :x\^LoWWhh1H"GG!JSE9`Uu4% b>fǯ b 2mA*]hh1"GGS!JE96@@}u2%6b>fǯ b 2mA*]hh1FK"GG!JSE9aTu2%%gbL  B 4%f VL@hh1gK"GG!JSE9bSu4%[b>gO b ~+(}%0Thh1-L"GGS!JE97@@|u2%6b>gO b ~+(}%0Thh1NL"GGS!JE9@@u4%6bL  B 4%f VL@hh1~"GG!JSE9cRu2%|bL  B ~rf%TShh1"GG!JSE9dQu4%zb>h b A)fChh1d"GGS!JE98@@{u2%6b>h b A)fChh1"GGS!JE9@@u4%6bL  B ~rf%TShh1 "GG!JSE9ePu2%2}bL < B A5fc1Uhh1F"GG!JSE9fOu4%Nb>iɏ b Af/1[`hh1"GGS!JE99@@zu2%6b>iɏ b Af/1[`hh1 "GGS!JE9@@u4%6bL < B A5fc1Uhh154#GG!JSE9gNu2%׀bL  B A.aӻ%8hh1x4#GGS!JE9@@u4%6bL  B A.aӻ%8hh1p5#GG!JSE9hMu4% ?b>j/ b T߅\Gr rDhh15#GGS!JE9:@@yu2%6b>j/ b T߅\Gr rDhh1|#GG!JSE9iLu2%bL | B ,oJ2v%zhh1 }#GG!JSE9jKu4%Pb>k b j;V)#hh1}#GGS!JE9;@@xu2%6b>k b j;V)#hh1}#GGS!JE9@@u4%6bL | B ,oJ2v%zhh1#GG!JSE9kJu2%bL  B ,[L8QzsV8*hh1#GG!JSE9lIu4%b>lo b zf0NL~vO$ hh1T#GGS!JE9<@@wu2%6b>lo b zf0NL~vO$ hh1q#GGS!JE9@@u4%6bL  B ,[L8QzsV8*hh1$GG!JSE9mHu2%bL  B VNh[fj8hh1?$GG!JSE9nGu4%3fb>m b Pf[#sKJ/,hh1$GGS!JE9=@@vu2%6b>m b Pf[#sKJ/,hh1 $GGS!JE9@@u4%6bL  B VNh[fj8hh1g$GG!JSE9oFu2%?bL\ B :'>ΚDJ{1hh1g$GG!JSE9pEu4%h1b>n̯ b n%TI)xhh1nh$GGS!JE9>@@uu2%6b>n̯ b n%TI)xhh1h$GGS!JE9@@u4%6bL\ B :'>ΚDJ{1hh1$GG!JSE9qDu2%IbL B V+ ݙ{U>δhh1$GG!JSE9rCu4%(b>oO b ~fUȳ[ahh1$GGS!JE9?@@tu2%6b>oO b ~fUȳ[ahh1$GGS!JE9@@u4%6bL B V+ ݙ{U>δh1$]]!JSEOs7>u r., 1P>܏$ (08AIQYaiqy X1$66S!JE(yW@@?y >u 1r.,P<Xh1 %GG!JSE9tAu2%cL B KNزOhh1+ %GG!JSE9u@u4%Nb>p b nެS.M4hh1 %GGS!JE9@@@su2%6b>p b nެS.M4hh1 %GGS!JE9@@u4%6L B KNزOhh1aQ%GG!JSE9v?u2%cbL< B `2`] /athh1Q%GG!JSE9w>u4%kހb>qΏ b Z^eSU`hh1Q%GGS!JE9A@@ru2%6b>qΏ b Z^eSU`hh1R%GGS!JE9@@u4%6bL< B `2`] /athh1%GG!JSE9x=u2%"=bL B K:ܤUx6άhh12%GG!JSE9y<u4%l b>r/ b <O*|4 dhh1%GGS!JE9B@@qu2%6b>r/ b <O*|4 dhh1%GGS!JE9@@u4%6bL B K:ܤUx6άhh1%GG!JSE9z;u2%<߀bL| B 342;hBYhh1%GGS!JE9@@u4%6bL| B 342;hBYhh1T%GG!JSE9{:u4%b>s b 7Ӏ6 \'xhh1%GGS!JE9C@@pu2%6b>s b 7Ӏ6 \'xhh1;&GG!JSE9|9u2%pbL B =?}hh1W<&GGS!JE9@@u4%6bL B =?}hh1<&GG!JSE9}8u4%`b>to b h,egWrd|hh15=&GGS!JE9D@@ou2%6b>to b h,egWrd|hh1$&GG!JSE9~7u2%bL B uf0l@hh1&GGS!JE9@@u4%6bL B uf0l@hh1&GG!JSE96u4%b>u b  N0HkRNhh1&GGS!JE9E@@nu2%6b>u b  N0HkRNhh1&GG!JSE95u2%!bL\ B %8^}xhh1&GGS!JE9@@u4%6bL\ B %8^}xhh1n&GG!JSE94u4%b>vѯ b f@8YDhh1&GGS!JE9F@@mu2%6b>vѯ b f@8YDhh1&'GG!JSE93u2%(PbL B %sb~zhJhh16''GGS!JE9@@u4%6bL B %sb~zhJhh1''GG!JSE92u4%>b>wO b lƞpoϣΎ"bhh1('GGS!JE9G@@lu2%6b>wO b lƞpoϣΎ"bh1Y7'``!JSER#>u r., 1P>2'(  ?? p ++%@X17'66S!JE(yX@@?x >u 1r.- P<Xh1'GG!JSE90u2%ƀbL B % q?zUn Khh1D'GGS!JE9@@u4%6bL B % q?zUn Khh1'GG!JSE9/u4%F܀b>x b hW?:`UXhh1'GGS!JE9H@@ku2%6b>x b hW?:`UXhh1'GG!JSE9.u2%PbL< B :'~R#M',hh1Q'GGS!JE9@@u4%6bL< B :'~R#M',hh1'GG!JSE9-u4%Sb>yӏ b :w~f[5@-hh1"'GGS!JE9I@@ju2%6b>yӏ b :w~f[5@-hh1O(GG!JSE9,u2%ʀbL B :5x~zL$hh1(GGS!JE9@@u4%6bL B :5x~zL$hh1-(GG!JSE9+u4%b>z/ b 4};-e:$hh1(GGS!JE9J@@iu2%6b>z/ b 4};-e:$h1((``!JSER>u r.- 1P>0'(  ?? p 01%?X14((66S!JE(yY@@?w >u 1r.-JP<Xh1k(GG!JSE9)u2%;rbL| B p~͜X~Uhh19k(GG!JSE9(u4%#b>{ b 4~L!s\hh1k(GGS!JE9K@@hu2%6b>{ b 4~L!s\hh1k(GGS!JE9@@u4%6bL| B p~͜X~Uhh1(GG!JSE9'u2%7`bL B lv!C4` thh1(GGS!JE9@@u4%6bL B lv!C4` thh1^(GG!JSE9&u4% b>|o b sq9Xthh1(GGS!JE9L@@gu2%6b>|o b sq9Xthh1(GG!JSE9%u2%bL B :S|qyC_Xhh1(GG!JSE9$u4%b>} b S|ƻءiG4hh1(GGS!JE9M@@fu2%6b>} b S|ƻءiG4hh1>(GGS!JE9@@u4%6bL B :S|qyC_Xhh1U)GG!JSE9#u2%bL\ B :Qz<_hh1CV)GGS!JE9@@u4%6bL\ B :Qz<_hh1V)GG!JSE9"u4%Bb>~֯ b \(Os,hh1VW)GGS!JE9N@@eu2%6b>~֯ b \(Os,hh1%)GG!JSE9!u2%bL B uN8~{!hh1)GGS!JE9@@u4%6bL B uN8~{!hh1)GG!JSE9 u4%b>O b lQm7w &Phh1 )GGS!JE9O@@du2%6b>O b lQm7w &Phh1)GG!JSE9u2%ȀbL B :E7ߒ{hh1)GG!JSE9u4% b> b As%Phh1c)GGS!JE9P@@cu2%6b> b As%Phh1)GGS!JE9@@u4%6bL B :E7ߒ{hh1?*GG!JSE9u2%!bL< B %|Jިhh1?*GG!JSE9u4%Ub>؏ b >ոhni 0(hh1\@*GGS!JE9Q@@bu2%6b>؏ b >ոhni 0(hh1x@*GGS!JE9@@u4%6bL< B %|Jިhh1*GG!JSE9u2%ǀbL B yRnrQhh1A*GGS!JE9@@u4%6bL B yRnrQhh1 *GG!JSE9u4%̀b>/ b xq+GNhh1*GGS!JE9R@@au2%6b>/ b xq+GNhh1n*GG!JSE9u2%bL| B %z#LFhh1*GGS!JE9@@u4%6bL| B %z#LFhh1Z*GG!JSE9u4%ὀb> b zWOnFe,hh1*GGS!JE9S@@`u2%6b> b zWOnFe,hh1*+GG!JSE9u2%2bL B j6/s0hh1[*+GGS!JE9@@u4%6bL B j6/s0hh1U++GG!JSE9u4%Xb>o b AN^ cT|hh1++GGS!JE9T@@_u2%6b>o b AN^ cT|hh1Mp+GG!JSE9u2%bL B V15M`&B"hh1p+GGS!JE9@@u4%6bL B V15M`&B"hh1t+GG!JSE9u4%ʀb> b >UG\Z4hh1t+GGS!JE9U@@^u2%6b> b >UG\Z4hh1S+GG!JSE9u2%WbL\ B :#-$H Xhh1+GGS!JE9@@u4%6bL\ B :#-$H Xhh1G+GG!JSE9u4%\b>ۯ b A7j\qt8hh1ؼ+GGS!JE9V@@]u2%6b>ۯ b A7j\qt8hh1Z,GG!JSE9u2%sbL B %$TChh1,GGS!JE9@@u4%6bL B %$TChh1',GG!JSE9u4%2b>O b A۞`7.n0hh1,GGS!JE9W@@\u2%6b>O b A۞`7.n0hh1[Z,GG!JSE9u2%PbL B چthh1Z,GGS!JE9@@u4%6bL B چthh17^,GG!JSE9u4% b> b lsrhh1^,GGS!JE9X@@[u2%6b> b lsrhh1\,GG!JSE9 u2%`ObL< B =۞ Vu0hh1,GGS!JE9@@u4%6bL< B =۞ Vu0hh1,GG!JSE9 u4%b>ݏ b 9:ū9L8\hh1!,GGS!JE9Y@@Zu2%6b>ݏ b 9:ū9L8\hh1,GG!JSE9 u2%5bL B dk hh1),GGS!JE9@@u4%6bL B dk hh1-GG!JSE9 u4%ȴb>/ b #e#:\ Jhh1(-GGS!JE9Z@@Yu2%6b>/ b #e#:\ Jhh1D-GG!JSE9 u2%("bL | B ~5o;.竈uhhh17E-GGS!JE9@@u4%6bL | B ~5o;.竈uhhh1H-GG!JSE9u4%ۀb> b 5gzFʵ9hh1uI-GGS!JE9[@@Xu2%6b> b 5gzFʵ9hh1ߌ-GG!JSE9u2%bL! B W 2](S W0hh1m-GGS!JE9@@u4%6bL! B W 2](S W0hh1-GG!JSE9u4%1b>o b 9r1ʆ0hh1-GGS!JE9\@@Wu2%6b>o b 9r1ʆ0hh1 -GG!JSE9u2%K-bL! B px'CSIhh1-GGS!JE9@@u4%6bL! B px'CSIhh1-GG!JSE9u4%lb> b Wx&uˀhh1-GGS!JE9]@@Vu2%6b> b Wx&uˀhh1/.GG!JSE9u2%RbL"\ B ny$g=6hh1/.GGS!JE9@@u4%6bL"\ B ny$g=6hh12.GG!JSE9u4% wb> b Axgc7I7hh13.GGS!JE9^@@Uu2%6b> b Axgc7I7hh1.w.GG!JSE9u2%bL" B Dze=)A hh1w.GGS!JE9@@u4%6bL" B Dze=)A hh1{.GG!JSE9u4%_b>O b A8%,hh1(|.GGS!JE9_@@Tu2%6b>O b A8%,h1.``!JSER>u r.-J 1P>0'( ?? p ,,%@X1.66S!JE(yZ@@?v >u 1r.-tP<Xh19.GG!JSE9u2%7bL# B :f ֡0hh1.GGS!JE9@@u4%6bL# B :f ֡0hh1.GG!JSE9u4%"Cb> b 6UI!%[(hh1}.GGS!JE9`@@Su2%6b> b 6UI!%[(hh1/GG!JSE9u2%|bL$< B 3xgo(ӹx\hh1$/GGS!JE9@@u4%6bL$< B 3xgo(ӹx\hh1@/GG!JSE9u4%?b> b ~6[C1de@Zhh1/GGS!JE9a@@Ru2%6b> b ~6[C1de@Zhh1 d/GG!JSE9u2%lNbL$ B =Q$hh1,d/GG!JSE9u4%ѓb>/ b ~%1*Ӭhh1d/GGS!JE9b@@Qu2%6b>/ b ~%1*Ӭhh1d/GGS!JE9@@u4%6bL$ B =Q$h1^v/``!JSER>u r.-t 1P>.S'(  ?? p 11%?X1v/66S!JE(y[@@?u >u 1r.-P<Xh1ѻ/GG!JSE9u2%bL%| B =6Y& hh1^/GGS!JE9@@u4%6bL%| B =6Y& hh1g/GG!JSE9u4%8b> b 'qBZ2(uhh1/GGS!JE9c@@Pu2%6b> b 'qBZ2(uhh10GG!JSE9u2%bL& B =N74κhh1z0GGS!JE9@@u4%6bL& B =N74κhh1v0GG!JSE9u4%̀b>o b :N;?qShh1& 0GGS!JE9d@@Ou2%6b>o b :N;?qShh1L0GG!JSE9u2%|bL& B 9V3y#hh1L0GGS!JE9@@u4%6bL& B 9V3y#hh1O0GG!JSE9u4%b> b Wl*Wלhh1TP0GGS!JE9e@@Nu2%6b> b Wl*Wלhh180GG!JSE9u2% bL'\ B 6Oٔhh1ʦ0GGS!JE9@@u4%6bL'\ B 6Oٔhh10GG!JSE9u4%&Zb> b sYn?9v8hh100GGS!JE9f@@Mu2%6b> b sYn?9v8hh1L0GG!JSE9u2%bL' B ARS239Hhh10GGS!JE9@@u4%6bL' B ARS239Hhh10GG!JSE9u4%eb>O b u6şUe hh1?0GGS!JE9g@@Lu2%6b>O b u6şUe hh161GG!JSE9u2%=bL( B f$Ó|Gw#&hh161GGS!JE9@@u4%6bL( B f$Ó|Gw#&hh11:1GG!JSE9u4%γb> b 72PBtphh1:1GGS!JE9h@@Ku2%6b> b 72PBtphh11GG!JSE9u2%rbL)< B A"{n7s(hh1b1GGS!JE9@@ӿu4%6bL)< B A"{n7s(hh1Г1GG!JSE9u4%8b> b ͣT7Vhh1a1GGS!JE9i@@Ju2%6b> b ͣT7Vhh11GG!JSE9u2%ebL) B .f7}Tok8hh1F1GGS!JE9@@Ӿu4%6bL) B .f7}Tok8hh11GG!JSE9u4%9_b>/ b u&Pӈdhh1"1GGS!JE9j@@Iu2%6b>/ b u&Pӈdhh1 2GG!JSE9u2%bL*| B 8ԎV hh1h!2GGS!JE9@@ӽu4%6bL*| B 8ԎV hh1e%2GG!JSE9u4%Ob> b Ϭ6hh1%2GGS!JE9k@@Hu2%6b> b Ϭ6hh1z2GG!JSE9u2%oɀbL+ B l v'CW$hh1{2GGS!JE9@@Ӽu4%6bL+ B l v'CW$hh12GG!JSE9u4%'Tb>o b 3RP7& Z8hh1G2GGS!JE9l@@Gu2%6b>o b 3RP7& Z8hh12GG!JSE9u2%:bL+ B 4 ebߢ[hh1 2GGS!JE9@@ӻu4%6bL+ B 4 ebߢ[hh1\2GG!JSE9u4%<b> b p[Oa#hpkbhh12GGS!JE9m@@Fu2%6b> b p[Oa#hpkbhh1e 3GG!JSE9u2%j9bL,\ B :n\Wk0hh1 3GGS!JE9@@Ӻu4%6bL,\ B :n\Wk0hh1l3GG!JSE9u4%vb> b `@(Thh13GGS!JE9n@@Eu2%6b> b `@(Thh1Xe3GG!JSE9u2%+bL, B O b lK19r& 0hh1i3GGS!JE9o@@Du2%6b>O b lK19r& 0hh1y3GG!JSE9u2%%߀bL- B :`{=N9a[hh13GGS!JE9@@Ӹu4%6bL- B :`{=N9a[hh1(3GG!JSE9u4%߀b> b Dyob?o$ۘhh13GGS!JE9p@@Cu2%6b> b Dyob?o$ۘhh13GG!JSE9u2%(UbL.< B vsϏ*N$hh13GGS!JE9@@ӷu4%6bL.< B vsϏ*N$hh13GG!JSE9u4%yb> b D^Yphh13GGS!JE9q@@Bu2%6b> b D^Yphh1O4GG!JSE9u2%bL. B ,ao =//RM8hh1MP4GGS!JE9@@Ӷu4%6bL. B ,ao =//RM8hh1S4GG!JSE9u4%nAb>/ b $gJO[!P 40hh1T4GGS!JE9r@@Au2%6b>/ b $gJO[!P 40hh14GG!JSE9u2%bL/| B sΞZ93Whh1{4GGS!JE9@@ӵu4%6bL/| B sΞZ93Whh1e4GG!JSE9u4%\b> b z<۹+tJ՜hh134GGS!JE9s@@@u2%6b> b z<۹+tJ՜hh1 4GG!JSE9u2%JbL0 B 40#hA<xS thh14GGS!JE9@@Ӵu4%6bL0 B 40#hA<xS thh174GG!JSE9u4%b>o b -i()dm*Z hh14GGS!JE9t@@?u2%6b>o b -i()dm*Z h\14<<!JSE, Xk=`P> \X1466S!JE((@@  Xk=`P\ƂX\14::S!JE,)@@  Xk=`P\Ƃ\h1):5GG!JSE9u2%bL0 B 4 sPhh1:5GGS!JE9@@ӳu4%6bL0 B 4 sPhh1h>5GG!JSE9u4%b> b 4k(wz68GEhh1>5GGS!JE9u@@>u2%6b> b 4k(wz68GEhh1O5GG!JSE9u2%ԀbL1\ B 4灜bnqjA[Thh15GGS!JE9@@Ӳu4%6bL1\ B 4灜bnqjA[Thh1O5GG!JSE9u4%b> b 4灘'?<[ hh1ۆ5GGS!JE9v@@=u2%6b> b 4灘'?<[ hh1T5GG!JSE9u2%߀bL1 B  p=_khh15GGS!JE9@@ӱu4%6bL1 B  p=_khh15GG!JSE9u4%b>O b 4~zU6Hhh1X5GGS!JE9w@@<u2%6b>O b 4~zU6Hh155``!JSER>u r.- 1P>.,'( ?? p --%@X1a566S!JE(y\@@?t >u 1r.-P<Xh1y$6GG!JSE9u2%쬀bL2 B :Q~Lu׎*(Bhh1%6GGS!JE9@@Ӱu4%6bL2 B :Q~Lu׎*(Bhh1(6GG!JSE9u4%?jb> b l/~'̺4chh1)6GGS!JE9x@@;u2%6b> b l/~'̺4chh1l6GG!JSE9u2%bL3< B % ,U)phh1m6GGS!JE9@@ӯu4%6bL3< B % ,U)phh1@p6GG!JSE9u4%"b> b ~ u60`Qfhh1p6GGS!JE9y@@:u2%6b> b ~ u60`Qfhh16GG!JSE9u2%ڀbL3 B :Q~<"Tdhh1?6GGS!JE9@@Ӯu4%6bL3 B :Q~<"Tdhh1m6GG!JSE9u4%Hb>/ b %~' hh16GGS!JE9z@@9u2%6b>/ b %~' h16``!JSER>u r.- 1P>,'(  ?? p 11%?X1 666S!JE(y]@@?s >u 1r.-P<Xh17GG!JSE9u2%qbL4| B frC\&hh1g7GGS!JE9@@ӭu4%6bL4| B frC\&hh17GG!JSE9u4%Ӏb> b :fpI"K$Mhh1f7GGS!JE9{@@8u2%6b> b :fpI"K$Mhh1V7GG!JSE9u2%ƀbL5 B %z5uf7Øhh1YW7GGS!JE9@@Ӭu4%6bL5 B %z5uf7Øhh1Z7GG!JSE9u4% b>o b fy6EFLhh1[7GGS!JE9|@@7u2%6b>o b fy6EFLhh17GG!JSE9u2%gbL5 B  :պ湈lhh17GGS!JE9@@ӫu4%6bL5 B  :պ湈lhh137GG!JSE9u4%b> b :s[;"H!m}hh17GGS!JE9}@@6u2%6b> b :s[;"H!m}hh1 7GG!JSE9u2%obL6\ B :AVBhh17GGS!JE9 @@Ӫu4%6bL6\ B :AVBh\17<<!JSE( Xk=dP> \h157GG!JSE9u4%=b> b :gZmX\:hh17GGS!JE9~@@5u2%6b> b :gZmX\:hh17A8GG!JSE9u2%&܀bL6 B wdl98 hh1A8GGS!JE9 @@өu4%6bL6 B wdl98 hh1SE8GG!JSE9u4%^b>O b fg\o?Bhh1E8GGS!JE9@@4u2%6b>O b fg\o?Bhh1C8GG!JSE9u2%ݦbL7 B f']hh1Љ8GGS!JE9 @@Өu4%6bL7 B f']hh1͌8GG!JSE9u4%@b> b :/f!i܄hh1^8GGS!JE9@@3u2%6b> b :/f!i܄hh1v8GG!JSE9u2%bL8< B  }U@hh1 8GGS!JE9 @@ӧu4%6bL8< B  }U@hh18GG!JSE9u4%Lb> b :,mg[4hh18GGS!JE9@@2u2%6b> b :,mg[4hh1+9GG!JSE9u2%bL8 B :N=:7F`hh1,,9GGS!JE9 @@Ӧu4%6bL8 B :N=:7F`hh1/9GG!JSE9u4%tb>/ b :f 4Nʢthh1 09GGS!JE9@@1u2%6b>/ b :f 4Nʢthh1s9GG!JSE9u2%bL9| B  v_&Qhh1&t9GGS!JE9@@ӥu4%6bL9| B  v_&Qhh1w9GG!JSE9u4%jb> b  .1sr\\hh1Ix9GGS!JE9@@0u2%6b> b  .1sr\\hh19GG!JSE9u2%obL: B f@;n` hh1V9GGS!JE9@@Ӥu4%6bL: B f@;n` hh19GG!JSE9u4%0b>o b :N:j"Cj$hh1R9GGS!JE9@@/u2%6b>o b :N:j"Cj$hh1:GG!JSE9u2%bL: B  ~CW.>lhh1:GGS!JE9@@ӣu4%6bL: B  ~CW.>lhh1:GG!JSE9u4%b> b ˞|c>Сhh1:GGS!JE9@@.u2%6b> b ˞|c>Сhh1]:GG!JSE9u2%ŀbL;\ B % Y +hh1^:GGS!JE9@@Ӣu4%6bL;\ B % Y +hh13b:GG!JSE9 u4%b> b l\Cohh1b:GGS!JE9@@-u2%6b> b l\Cohh1:GG!JSE9 u2%rbL; B f`ַlhh1Z:GGS!JE9@@ӡu4%6bL; B f`ַlhh1:GG!JSE9 u4%b>O b e6ZEy{ _S،hh1ռ:GGS!JE9@@,u2%6b>O b e6ZEy{ _S،hh1;GG!JSE9 u2%bL< B :2BWN.Shh1>;GGS!JE9@@Ӡu4%6bL< B :2BWN.Shh1M;GG!JSE9 u4%wBb> b 4ᒻTthh1;GGS!JE9@@+u2%6b> b 4ᒻTthh1gH;GG!JSE9u2%qbL=< B f /ICN`hh1H;GGS!JE9@@ӟu4%6bL=< B f /ICN`hh1L;GG!JSE9u4%ۀb> b ,/fr|8hh1=M;GGS!JE9@@*u2%6b> b ,/fr|8hh1;GG!JSE9u2%!,bL= B :  #Ȃn$hh12;GGS!JE9@@Ӟu4%6bL= B :  #Ȃn$hh12;GG!JSE9u4%F`b>/ b WfamaR&\hh1ŧ;GGS!JE9@@)u2%6b>/ b WfamaR&\hh1;GG!JSE9u2%bL>| B :ˆhh15;GGS!JE9@@ӝu4%6bL>| B :ˆhh1;GG!JSE9u4%b> b W'ćRW hh1;GGS!JE9@@(u2%6b> b W'ćRW hh12o b T-gUPܨ-hh1@7o b T-gUPܨ-hh1 b WAUB hh1 b WAUB hh1 b Afƿ[5Yahh1 b Afƿ[5Yahh1=GG!JSE9u2%msbL@ B : OoMd hh1=GGS!JE9@@әu4%6bL@ B : OoMd hh12!=GG!JSE9u4%b>O b 0f ǻ0,_ 4hh1!=GGS!JE9@@$u2%6b>O b 0f ǻ0,_ 4h1K/=``!JSER>u r.- 1P>+'( ?? p ..%@X1{/=66S!JE(y^@@?r >u 1r..P<Xh1]w=GG!JSE9u2%0bLA B Vf R0Bhhh1w=GGS!JE9@@Әu4%6bLA B Vf R0Bhhh1r{=GG!JSE9u4%=b> b Af~bSlhh1{=GGS!JE9@@#u2%6b> b Af~bSlhh1~=GG!JSE9u2%bLB< B oN?(nDhh1 =GGS!JE9@@ӗu4%6bLB< B oN?(nDhh1=GG!JSE9 u4%!b> b -ΙXdr?hh1z=GGS!JE9@@"u2%6b> b -ΙXdr?hh1~>GG!JSE9!u2%bLB B 3Nthh1 >GGS!JE9@@Ӗu4%6bLB B 3Nthh1H >GG!JSE9"u4%b>/ b n-_zCGGS!JE9@@!u2%6b>/ b n-_zC``!JSER#>u r.. 1P>+'(  ?? p 11%?X1!>66S!JE(y_@@?q >u 1r..FP<Xh1a>GG!JSE9$u2%bLC| B K-񐌳hh13b>GGS!JE9@@ӕu4%6bLC| B K-񐌳hh15f>GG!JSE9%u4% b> b :u2Z|hh1f>GGS!JE9@@ u2%6b> b :u2Z|hh1>GG!JSE9&u2%.3bLD B ض("qNhh1m>GGS!JE9@@Ӕu4%6bLD B ض("qNhh1>GG!JSE9'u4%Gpb>o b D06K_{#6 lhh1->GGS!JE9@@u2%6b>o b D06K_{#6 lhh1>GG!JSE9(u2%AVbLD B  |$߿2phh1o>GGS!JE9 @@ӓu4%6bLD B  |$߿2phh1>GG!JSE9)u4%8Zb> b GGS!JE9@@u2%6b> b  b GgzVͼhh1.P?GGS!JE9@@u2%6b> b GgzVͼhh1 ?GG!JSE9,u2%ŀbLE B ذ<hh1?GGS!JE9"@@ӑu4%6bLE B ذ<hh1Ș?GG!JSE9-u4%qb>O b N?2<'~0\hh1T?GGS!JE9@@u2%6b>O b N?2<'~0\hh1>?GG!JSE9.u2%.bLF B ˚m?%DLhh1?GGS!JE9#@@Ӑu4%6bLF B ˚m?%DLhh1?GG!JSE9/u4%j%b> b K?0Fhh1o?GGS!JE9@@u2%6b> b K?0Fhh16@GG!JSE90u2%K)bLG< B VoL4ߩBhh167@GGS!JE9$@@ӏu4%6bLG< B VoL4ߩBhh1;@GG!JSE91u4%)b> b :j`}Phh1.<@GGS!JE9@@u2%6b> b :j`}Phh1~@GG!JSE92u2%_bLG B D˘5P`\hh1@GGS!JE9%@@ӎu4%6bLG B D˘5P`\hh1@GG!JSE93u4%m'b>/ b :-*ӨXhh1@GGS!JE9@@u2%6b>/ b :-*ӨXhh1@GG!JSE94u2%$bLH| B P:6NHhh1w@GGS!JE9&@@Ӎu4%6bLH| B P:6NHhh1F@GG!JSE95u4%®b> b R`o:k3šhh1@GGS!JE9@@u2%6b> b R`o:k3šhh1 AGG!JSE96u2%bLI B -υN1WK hh1]!AGGS!JE9'@@ӌu4%6bLI B -υN1WK hh1$AGG!JSE97~u4%7b>o b >|x,hh1%AGGS!JE9@@u2%6b>o b >|x,hh1hAGG!JSE98}u2%ubLI B 81`Phh1iAGGS!JE9(@@Ӌu4%6bLI B 81`Phh1mlAGG!JSE99|u4%b> b VQmޘX~hh1lAGGS!JE9@@u2%6b> b VQmޘX~hh1AGG!JSE9:{u2%bLJ\ B  vZ,hh1AGGS!JE9)@@ӊu4%6bLJ\ B  vZ,hh1AGG!JSE9;zu4%㔀b> b 37l|τDXhh1AGGS!JE9@@u2%6b> b 37l|τDXhh1 BGG!JSE9<yu2%y*bLJ B P`6OFFd$ hh1 BGGS!JE9*@@Ӊu4%6bLJ B P`6OFFd$ hh1BGG!JSE9=xu4%cŀb> O b קkv$Lhh1kBGGS!JE9@@u2%6b> O b קkv$Lhh13SBGG!JSE9>wu2%5ɀbLK B .7EXČ .lhh1qSBGGS!JE9+@@ӈu4%6bLK B .7EXČ .lhh1WBGG!JSE9?vu4%b>  b ~mMsڟ)phh1WBGGS!JE9@@u2%6b>  b ~mMsڟ)phh1BGG!JSE9@uu2%(sbLL< B 7"w~ĺ$&jhhh1^BGGS!JE9,@@Ӈu4%6bLL< B 7"w~ĺ$&jhhh1DBGG!JSE9Atu4%u b>  b QE dNhh1ՠBGGS!JE9@@u2%6b>  b QE dNhh1BGG!JSE9Bsu2%̀bLL B ӤBBhh12BGGS!JE9-@@ӆu4%6bLL B ӤBBhh1BGG!JSE9Cru4%Ѐb> / b :Zt~`22hh1UBGGS!JE9@@u2%6b> / b :Zt~`22hh1=CGG!JSE9Dqu2%bLM| B "_^XHhh1<>CGGS!JE9.@@Ӆu4%6bLM| B "_^XHhh1ACGG!JSE9Epu4%|b>  b '}ƿhhh14BCGGS!JE9@@u2%6b>  b '}ƿhhh1CGG!JSE9Fou2%}bLN B ZOi,p(&hh1BCGGS!JE9/@@ӄu4%6bLN B ZOi,p(&hh1KCGG!JSE9Gnu4%Kb> o b EOBDhh1؉CGGS!JE9@@u2%6b> o b EOBDhh1CGG!JSE9Hmu2%bLN B 2lĢ ,hh1NCGGS!JE90@@Ӄu4%6bLN B 2lĢ ,hh1"CGG!JSE9Ilu4%Dƀb>  b ~ܹJchh1CGGS!JE9@@u2%6b>  b ~ܹJchh1(DGG!JSE9Jku2%_bLO\ B us/Wbhh1(DGGS!JE91@@ӂu4%6bLO\ B us/Wbhh1+DGG!JSE9Kju4%wb>  b P"'.ו{jghh1,DGGS!JE9@@ u2%6b>  b P"'.ו{jghh1pDGG!JSE9Liu2%?9bLO B 71י>|hh1pDGGS!JE92@@Ӂu4%6bLO B 71י>|hh1btDGG!JSE9Mhu4%b>O b  27>GBi Lhh1tDGGS!JE9@@ u2%6b>O b  27>GBi Lh1D``!JSERNY>u r..F 1P>+'( ?? p --%@X1΃D66S!JE(y`@@?p >u 1r..pP<Xh1jDGG!JSE9Ofu2%bLP B  nYnbhh1DGGS!JE93@@Ӏu4%6bLP B  nYnbhh1hDGG!JSE9Peu4%؀b> b P-ۙ Hlhh1DGGS!JE9@@ u2%6b> b P-ۙ Hlhh1MEGG!JSE9Qdu2%k^bLQ< B 7=%8d&j(hh1EGGS!JE94@@u4%6bLQ< B 7=%8d&j(hh1EGG!JSE9Rcu4%b> b SW՝,ג*|hh1EGGS!JE9@@ u2%6b> b SW՝,ג*|hh1|ZEGG!JSE9Sbu2%(bLQ B f7N`hh1[EGGS!JE95@@~u4%6bLQ B f7N`hh1^EGG!JSE9Tau4%.b>/ b ??Sx kBhh16_EGGS!JE9@@ u2%6b>/ b ??Sx kBh1oE``!JSERUR>u r..p 1P>*W'(  ?? p 11%?X1oE66S!JE(ya@@?o >u 1r..P<Xh1˴EGG!JSE9V_u2%@DbLR| B NZER^jn֤hh1WEGGS!JE96@@}u4%6bLR| B NZER^jn֤hh1EGG!JSE9W^u4%3vb> b  1g@(hh1 EGGS!JE9@@u2%6b> b  1g@(hh1EGG!JSE9X]u2%bLS B  o_Ov|̮B(hh1AEGGS!JE97@@|u4%6bLS B  o_Ov|̮B(hh1FGG!JSE9Y\u4%bDb>o b 7P?RDJhh1SFGGS!JE9@@u2%6b>o b 7P?RDJhh1DFGG!JSE9Z[u2%DlbLS B 8Zww hh1eEFGGS!JE98@@{u4%6bLS B 8Zww hh1uHFGG!JSE9[Zu4%G"b> b {H8hh1IFGGS!JE9@@u2%6b> b {H8hh1FGG!JSE9\Yu2%3bLT\ B  燃^"Lhh1FGGS!JE99@@zu4%6bLT\ B  燃^"Lhh1'FGG!JSE9]Xu4%b> b NnVRnhh1FGGS!JE9@@u2%6b> b NnVRnhh17FGG!JSE9^Wu2%bLT B GThh1FGGS!JE9:@@yu4%6bLT B GThh12FGG!JSE9_Vu4%sb>O b Dǻ7k(\lhh1FGGS!JE9@@u2%6b>O b Dǻ7k(\lhh13/GGG!JSE9`Uu2% bLU B \_p|ʨhh1/GGGS!JE9;@@xu4%6bLU B \_p|ʨhh1W3GGG!JSE9aTu4%Yb> b 2`h'Nܹ$hh13GGGS!JE9@@u2%6b> b 2`h'Nܹ$hh1eGGG!JSE9bSu2%ȑbLV< B ½7^&x (hh1GGGS!JE9<@@wu4%6bLV< B ½7^&x (hh1JGGG!JSE9cRu4%6b> b  A/b4hh1ۍGGGS!JE9@@u2%6b> b  A/b4hh1GGG!JSE9dQu2%GbMV B R|5qjDhh1/ b ZU?v.JDhh1GGGS!JE9@@u2%6b>/ b ZU?v.JDhh1HGG!JSE9fOu2%kԀbMW| B 8wϷ^yJꂨhh14HGGS!JE9>@@uu4%6bMW| B 8wϷ^yJꂨhh1HGG!JSE9gNu4%Yxb> b ~`khh1=HGGS!JE9@@u2%6b> b ~`khh1sHGG!JSE9hMu2%1bMX B ԎcvXld hh1jtHGGS!JE9?@@tu4%6bMX B ԎcvXld hh1wHGG!JSE9iLu4%4Bb>o b 6ޭ̦Nhh1AxHGGS!JE9@@u2%6b>o b 6ޭ̦Nhh1޻HGG!JSE9jKu2%ZbMX B #OwلDn hh1jHGGS!JE9@@@su4%6bMX B #OwلDn hh1HGG!JSE9kJu4%b> b fhlhh1pHGGS!JE9@@u2%6b> b fhlhh1IGG!JSE9lIu2%bMY\ B ~l$hHhh1IGGS!JE9A@@ru4%6bMY\ B ~l$hHhh1IGG!JSE9mHu4%b> b Sk߿|XN*,lhh1IGGS!JE9@@u2%6b> b Sk߿|XN*,lhh1^IGG!JSE9nGu2%bMY B  |7\@hh1^IGGS!JE9B@@qu4%6bMY B  |7\@hh1bIGG!JSE9oFu4%ѽb>O b uZwݛ^dl¨hh1cIGGS!JE9@@u2%6b>O b uZwݛ^dl¨hh1IGG!JSE9pEu2%HbMZ B Z1ڣJ hh1IGGS!JE9C@@pu4%6bMZ B Z1ڣJ hh1#IGG!JSE9qDu4% €b> b tdhh1IGGS!JE9@@u2%6b> b tdhh1`IGG!JSE9rCu2%~bM[< B 7O1uZנh@hh1IGGS!JE9D@@ou4%6bM[< B 7O1uZנh@hh1IGG!JSE9sBu4%&b> b Z0N^5E.hh1IGGS!JE9@@u2%6b> b Z0N^5E.hh1iHJGG!JSE9tAu2%와bM[ B =ْNhh1HJGGS!JE9E@@nu4%6bM[ B =ْNhh1 LJGG!JSE9u@u4%Bb>/ b 7&lLhh15LJGGS!JE9@@u2%6b>/ b 7&lLhh1JGG!JSE9v?u2%ubM \| B _~P hh1JGGS!JE9F@@mu4%6bM \| B _~P hh1JGG!JSE9w>u4%b> b # nfhh1JGGS!JE9@@u2%6b> b # nfhh1JGG!JSE9x=u2%ȠbM ] B o b *Ý7koDhh1JGGS!JE9@@u2%6b>o b *Ý7koDhh12KGG!JSE9z;u2%̀bM ] B f*Owx.hh1n3KGGS!JE9H@@ku4%6bM ] B f*Owx.hh17KGG!JSE9{:u4%mb> b #RCӞTDhh17KGGS!JE9@@u2%6b> b #RCӞTDhh1{KGG!JSE9|9u2%bM ^\ B SF--\Lꀠhh1{KGGS!JE9I@@ju4%6bM ^\ B SF--\Lꀠhh1wKGG!JSE9}8u4%b> b  rێ'fbhh1KGGS!JE9@@u2%6b> b  rێ'fbhh1QKGG!JSE9~7u2%dM ^ B I`ׇ>b(hh1KGGS!JE9J@@iu4%6M ^ B I`ׇ>b(hh1KGG!JSE96u4%b>O b 2'GՖw`.hh1mKGGS!JE9@@u2%6b>O b 2'GՖw`.h1K``!JSER'>u r.. 1P>*/'( ?? p -.%@X1IK66S!JE(yb@@?n >u 1r..P<Xh1cLGG!JSE94u2%܀bM_ B Ԓv(H,lhh1LGGS!JE9K@@hu4%6bM_ B Ԓv(H,lhh1!LGG!JSE93u4%<*b> b  G/_Lh hh1<"LGGS!JE9@@u2%6b> b  G/_Lh hh1qeLGG!JSE92u2%gbM`< B  +?\Ƥʨhh1fLGGS!JE9L@@gu4%6bM`< B  +?\Ƥʨhh1hLGG!JSE91u4%b> b 8 }ɾx(&phh1ziLGGS!JE9@@u2%6b> b 8 }ɾx(&phh1QLGG!JSE90u2%bM` B Ȏ Ws`hh1LGGS!JE9M@@fu4%6bM` B Ȏ Ws`hh1LGG!JSE9/u4%ڗb>/ b  S˴v[hhh1!LGGS!JE9@@u2%6b>/ b  S˴v[hh1wL``!JSER >u r.. 1P>)'( ?? p 11%?X1L66S!JE(yc@@?m >u 1r..P<Xh1MGG!JSE9-u2%/bMa| B 'vr$hh1)MGGS!JE9N@@eu4%6bMa| B 'vr$hh1{ MGG!JSE9,u4%tb> b 2v˰hh1 MGGS!JE9@@u2%6b> b 2v˰hh1OMGG!JSE9+u2%bMb B *ZzlHj(hh1oPMGGS!JE9O@@du4%6bMb B *ZzlHj(hh1SMGG!JSE9*u4%Eb> o b .Yhh1TMGGS!JE9@@u2%6b> o b .Yhh1MGG!JSE9)u2%obMb B [כw@ hh1mMGGS!JE9P@@cu4%6bMb B [כw@ hh1TMGG!JSE9(u4%b>! b 17=Gqڑ hh1ߜMGGS!JE9@@u2%6b>! b 17=Gqڑ hh1MGG!JSE9'u2%òbMc\ B sA5ZJ$hh1MGGS!JE9Q@@bu4%6bMc\ B sA5ZJ$hh1TMGG!JSE9&u4%5b>! b S_߰&Rdhh1MGGS!JE9@@u2%6b>! b S_߰&Rdhh1:NGG!JSE9%u2%bMc B #_䈣Hhh1:NGGS!JE9R@@au4%6bMc B #_䈣Hhh1w>NGG!JSE9$u4%"b>"O b I}hh1?NGGS!JE9@@u2%6b>"O b I}hh17NGG!JSE9#u2%gbMd B J_v4 , $hh1ȂNGGS!JE9S@@`u4%6bMd B J_v4 , $hh1̅NGG!JSE9"u4%Ǩb>" b #R5/_Nkʸ@hh1\NGGS!JE9@@u2%6b>" b #R5/_Nkʸ@hh1UNGG!JSE9!u2%KbMe< B M/krYhh1NGGS!JE9T@@_u4%6bMe< B M/krYhh1NGG!JSE9 u4%#b># b J왜xiThh1NGGS!JE9@@u2%6b># b J왜xiThh1$OGG!JSE9u2%̀bMe B FH, hh1%OGGS!JE9U@@^u4%6bMe B FH, hh1(OGG!JSE9u4%#b>$/ b SGH(d@lhh1(OGGS!JE9@@u2%6b>$/ b SGH(d@lhh1lOGG!JSE9u2%bMf| B *G7p0hh1mOGGS!JE9V@@]u4%6bMf| B *G7p0hh1hpOGG!JSE9u4% b>$ b  )e,hh1pOGGS!JE9@@u2%6b>$ b  )e,hh1OGG!JSE9u2%(bMg B  q/VמH.(hh1FOGGS!JE9W@@\u4%6bMg B  q/VמH.(hh1OGG!JSE9u4%íb>%o b  ;J^x;Ahh1OGGS!JE9@@u2%6b>%o b  ;J^x;Ahh1PGG!JSE9u2%jbMg B  n|0Ҩhh1gPGGS!JE9X@@[u4%6bMg B  n|0Ҩhh1WPGG!JSE9u4%܀b>& b k^V2dhhh1PGGS!JE9@@u2%6b>& b k^V2dhhh1!WPGG!JSE9u2%.VbMh\ B \`4~*Bnhh1WPGGS!JE9Y@@Zu4%6bMh\ B \`4~*Bnhh1x[PGG!JSE9u4%ab>& b +S-T҂.Ahh1 \PGGS!JE9@@u2%6b>& b +S-T҂.Ahh1!PGG!JSE9u2%bMh B h kg\D"(hh1PGGS!JE9Z@@Yu4%6bMh B h kg\D"(hh1"PGG!JSE9u4%rb>'O b *7^o$VʻDhh1PGGS!JE9@@u2%6b>'O b *7^o$VʻDh1:P]]!JSEO>u r.. 1P>p$ (08AIQYaiqy X1eP66S!JE(yd@@?l >u 1r./P<Xh1YPGG!JSE9u2%,bMi B ¦6Bhh1PGGS!JE9[@@Xu4%6bMi B ¦6Bhh1MPGG!JSE9u4%Ȁb?' b w0Lhh1PGGS!JE9@@u2%6b?' b w0Lhh1/AQGG!JSE9u2%RbMj< B WW\hh1AQGGS!JE9\@@Wu4%6bMj< B WW\hh1DQGG!JSE9u4%Pb?( b 7hշmh)+hh1EQGGS!JE9@@u2%6b?( b 7hշmh)+hh1QGG!JSE9u2%O3bM j B  Xw~D hh1#QGGS!JE9]@@Vu4%6bM j B  Xw~D hh1QGG!JSE9 u4%b?)/ b  G.̿hh1QGGS!JE9@@u2%6b?)/ b  G.̿hh1xQGG!JSE9 u2%|bM!k| B S7 ׷vĪ@ hh1QGGS!JE9^@@Uu4%6bM!k| B S7 ׷vĪ@ hh1QGG!JSE9 u4%b?) b  G?ϕTBsH(hh1GQGGS!JE9@@u2%6b?) b  G?ϕTBsH(hh1,RGG!JSE9 u2%bVbM"l B SRgZfhh1,RGGS!JE9_@@Tu4%6bM"l B SRgZfhh1.0RGG!JSE9 u4%tb?*o b X'$6YƘhh10RGGS!JE9@@u2%6b?*o b X'$6YƘhh1RGG!JSE9u2%bM#l B  Ag>9 hh1rRGGS!JE9`@@Su4%6bM#l B  Ag>9 hh1RGG!JSE9u4%b?+ b # 5͎la`hh1RGGS!JE9@@u2%6b?+ b # 5͎la`hh1RGG!JSE9u2%޾bM$m\ B RavF Bdhh1sRGGS!JE9a@@Ru4%6bM$m\ B RavF Bdhh1]RGG!JSE9u4%hb?+ b Z!5וHlfhh1RGGS!JE9@@u2%6b?+ b Z!5וHlfhh1BSGG!JSE9u2%5ƀbM%m B fvPdhh1SGGS!JE9b@@Qu4%6bM%m B fvPdhh1KSGG!JSE9u4%Hb?,O b Sx7Bhh1SGGS!JE9@@u2%6b?,O b Sx7Bh1(S``!JSER>u r./ 1P>''( ?? p ..%@X1@(S66S!JE(ye@@?k >u 1r./?P<Xh1RpSGG!JSE9u2%tbM&n B  1^Yhh1pSGGS!JE9c@@Pu4%6bM&n B  1^Yhh1tSGG!JSE9u4%A?, b *W׿uƎhh1HuSGGS!JE9@@u2%6?, b *W׿uƎhh1nSGG!JSE9u2%}3bM'o< B  I#Oƾ{k(hh1SGGS!JE9d@@Ou4%6bM'o< B  I#Oƾ{k(hh1`SGG!JSE9u4%gb? - b RtQ@hh1SGGS!JE9@@u2%6b? - b RtQ@hh1lTGG!JSE9u2% ݀bM(o B  sd @hh1TGGS!JE9e@@Nu4%6bM(o B  sd @hh1 TGG!JSE9u4%Eb? ./ b S/_=^ҕ<% hh1TGGS!JE9@@u2%6b? ./ b S/_=^ҕ<% h1T``!JSER>u r./? 1P>''( ?? p 11%?X1(T66S!JE(yf@@?j >u 1r./iP<Xh1ZTGG!JSE9u2%8ۀbM)p| B RNHrhh12[TGGS!JE9f@@Mu4%6bM)p| B RNHrhh1^TGG!JSE9u4%Pb? . b  >GڤM4hh1e_TGGS!JE9@@u2%6b? . b  >GڤM4hh1TGG!JSE9u2%:bM*q B e?̔Xhh1JTGGS!JE9g@@Lu4%6bM*q B e?̔Xhh1æTGG!JSE9u4%!b? /o b HISoaLhhh1OTGGS!JE9@@u2%6b? /o b HISoaLhhh1TGG!JSE9u2%bM+q B  7%w<hh1^TGGS!JE9h@@Ku4%6bM+q B  7%w<hh1TGG!JSE9u4%-b? 0 b *?X;׎܈hh1TGGS!JE9@@u2%6b? 0 b *?X;׎܈hh1DUGG!JSE9u2%5bM,r\ B 1׼^x`hh1EUGGS!JE9i@@Ju4%6bM,r\ B 1׼^x`hh1HUGG!JSE9u4%Ȅb?0 b  h|N̈hh1JIUGGS!JE9@@u2%6b?0 b  h|N̈hh1UGG!JSE9u2%bM-r B fezhh1yUGGS!JE9j@@Iu4%6bM-r B fezhh1UGG!JSE9u4%Tb?1O b S7)o~\݄ hh1XUGGS!JE9@@u2%6b?1O b S7)o~\݄ hh1>UGG!JSE9u2%bM.s B G )?]rС.a hh1UGGS!JE9k@@Hu4%6bM.s B G )?]rС.a hh1fUGG!JSE9u4%9b?1 b  u @`(Dhh1UGGS!JE9@@u2%6b?1 b  u @`(Dhh1P/VGG!JSE9u2%EbM/t< B 7ޑ(@ hh1/VGGS!JE9l@@Gu4%6bM/t< B 7ޑ(@ hh1J3VGG!JSE9u4%mb?2 b 7Zg5>` hh13VGGS!JE9@@u2%6b?2 b 7Zg5>` hh1iwVGG!JSE9u2%bM0t B  #ǯ(Bhh1wVGGS!JE9m@@Fu4%6bM0t B  #ǯ(Bhh1t{VGG!JSE9u4% ݀b?3/ b  Wh`dhh1|VGGS!JE9@@u2%6b?3/ b  Wh`dhh1VGG!JSE9u2%lbM1u| B G b7~JK)(hh1VGGS!JE9n@@Eu4%6bM1u| B G b7~JK)(hh1VGG!JSE9u4%7b?3 b 0ǟKahh1yVGGS!JE9@@u2%6b?3 b 0ǟKahh1WGG!JSE9u2%%bM2v B ŶʮOhh15WGGS!JE9o@@Du4%6bM2v B ŶʮOhh1DWGG!JSE9u4%b?4o b  C.}+2{ hh1WGGS!JE9@@u2%6b?4o b  C.}+2{ hh1aWGG!JSE9u2%bM3v B ll$`hh1jbWGGS!JE9p@@Cu4%6bM3v B ll$`hh1eWGG!JSE9u4%eЀb?5 b SZ:ߗFˡjhh1IfWGGS!JE9@@u2%6b?5 b SZ:ߗFˡjhh1WGG!JSE9u2%rۀbM4w\ B 74-nBBhh1WGGS!JE9q@@Bu4%6bM4w\ B 74-nBBhh1WGG!JSE9u4%7Yb?5 b ?<:Nhh19WGGS!JE9@@u2%6b?5 b ?<:Nhh1 XGG!JSE9u2% bM5w B G?VF*hh1XGGS!JE9r@@Au4%6bM5w B G?VF*hh1XGG!JSE9u4%#b?6O b GZzUqh2dhh1MXGGS!JE9@@u2%6b?6O b GZzUqh2dhh1?LXGG!JSE9u2%PbM6x B X=OX]6F($,hh1LXGGS!JE9s@@@u4%6bM6x B X=OX]6F($,hh1PXGG!JSE9u4% Rb?6 b |_R,hh1PXGGS!JE9@@u2%6b?6 b |_R,hh1^XGG!JSE9u2%bM7y< B -vԿ,hh1XGGS!JE9t@@?u4%6bM7y< B -vԿ,hh1nXGG!JSE9u4%sb?7 b  nUX`B0hh1XGGS!JE9@@u2%6b?7 b  nUX`B0hh1RXGG!JSE9u2%M8y B 7`Fia hh1XGGS!JE9u@@>u4%6M8y B 7`Fia hh1XGG!JSE9u4%*b?8/ b ZA[ S8hh1;XGGS!JE9@@u2%6b?8/ b ZA[ S8hh16YGG!JSE9u2% bM9z| B /ٕLhh1*7YGGS!JE9v@@=u4%6bM9z| B /ٕLhh1;YGG!JSE9u4%Sb?8 b  m_ygEJ0hh1;YGGS!JE9@@u2%6b?8 b  m_ygEJ0hh1~YGG!JSE9u2%nbM:{ B Z9ٌ>&Chh1YGGS!JE9w@@<u4%6bM:{ B Z9ٌ>&Chh1YGG!JSE9u4%#.b?9o b a°_׾_֝*hh1YGGS!JE9@@u2%6b?9o b a°_׾_֝*hh1YGG!JSE9u2%OBbM;{ B ϯ^;wLhh1YGGS!JE9x@@;u4%6bM;{ B ϯ^;wLhh1%YGG!JSE9u4%Tb?: b .َ_MAlnLhh1JYGGS!JE9@@u2%6b?: b .َ_MAlnLhh11!ZGG!JSE9u2%GbM<|\ B žVN"*hh1!ZGGS!JE9y@@:u4%6bM<|\ B žVN"*hh18$ZGG!JSE9u4%b?: b SD.޽xhh1$ZGGS!JE9@@u2%6b?: b SD.޽xhh1hZGG!JSE9u2%GbM=| B i=W6hh1|iZGGS!JE9z@@9u4%6bM=| B i=W6hh1lZGG!JSE9u4%4b?;O b `?[?j#hh1}mZGGS!JE9@@u2%6b?;O b `?[?j#h1h|Z``!JSER>u r./i 1P>'`'( ?? p -.%@X1|Z66S!JE(yg@@?i >u 1r./P<Xh1NZGG!JSE9u2%\bM>} B P?!|Xfl hh1ZGGS!JE9{@@8u4%6bM>} B P?!|Xfl hh1ZGG!JSE9u4%ڀb? ; b Ieޱ h@ hh1JZGGS!JE9@@u2%6b? ; b Ieޱ h@ hh1G [GG!JSE9u2%"bM?~< B hnCyn,B(hh1 [GGS!JE9|@@7u4%6bM?~< B hnCyn,B(hh1[GG!JSE9u4%LՀb?!< b S0?y>D @hh1x[GGS!JE9@@u2%6b?!< b S0?y>D @hh1sS[GG!JSE9u2%(bM@~ B Ԙ?t߮ &B$hh1T[GGS!JE9}@@6u4%6bM@~ B Ԙ?t߮ &B$hh1W[GG!JSE9u4%{b?"=/ b SA1@Xhh1X[GGS!JE9@@u2%6b?"=/ b SA1@Xh16h[``!JSER>u r./ 1P>&3'( ?? p 12%?X1ah[66S!JE(yh@@?h >u 1r./P<Xh1[GG!JSE9u2%fbMA| B <I hh15[GGS!JE9~@@5u4%6bMA| B <I hh1[GG!JSE9u4%b?#= b o^hh1[GGS!JE9@@u2%6b?#= b o^hh1[GG!JSE9u2%!bMB B f{Uߒ&$(Lhh1([GGS!JE9@@4u4%6bMB B f{Uߒ&$(Lhh1[GG!JSE9u4%b?$>o b #ώ[mKV0hh1[GGS!JE9@@Կu2%6b?$>o b #ώ[mKV0hh1=\GG!JSE9u2%bMC B \/|ـB`,hh1l>\GGS!JE9@@3u4%6bMC B \/|ـB`,hh1WA\GG!JSE9u4%1b?%? b CDchh1A\GGS!JE9@@Ծu2%6b?%? b CDchh1\GG!JSE9u2%6bMD\ B  hh1Y\GGS!JE9@@2u4%6bMD\ B  hh1\GG!JSE9u4%b?&? b w6IJB`@hh1\GGS!JE9@@Խu2%6b?&? b w6IJB`@hh1\GG!JSE9u2%VbME B a'qƝhh1\GGS!JE9@@1u4%6bME B a'qƝhh1\GG!JSE9u4%zb?'@O b R Y}fhh1\GGS!JE9@@Լu2%6b?'@O b R Y}fhh1(]GG!JSE9u2% GbMF B ]Bhh1(]GGS!JE9@@0u4%6bMF B ]Bhh1,]GG!JSE9u4%b?(@ b  W{ƛh"΀hh1,]GGS!JE9@@Իu2%6b?(@ b  W{ƛh"΀hh1D]GG!JSE9u2%4bMG< B "hb &,hh1т]GGS!JE9@@/u4%6bMG< B "hb &,hh1څ]GG!JSE9u4%Nb?)A b  LRhFphh1f]GGS!JE9@@Ժu2%6b?)A b  LRhFphh1V]GG!JSE9u2%LbMH B !_a1Hhh1]GGS!JE9@@.u4%6bMH B !_a1Hhh1]GG!JSE9u4%zb?*B/ b ½w6זD@hh1g]GGS!JE9@@Թu2%6b?*B/ b ½w6זD@hh1^GG!JSE9u2%aȀbMI| B H꟟ Fhh1Q^GGS!JE9@@-u4%6bMI| B H꟟ Fhh1^GG!JSE9u4%b?+B b SA.׃-Ihh1)^GGS!JE9@@Ըu2%6b?+B b SA.׃-Ihh1l^GG!JSE9u2%bMJ B j_q hh1Hm^GGS!JE9@@,u4%6bMJ B j_q hh1p^GG!JSE9u4%b?,Co b ?v|, (hh1\q^GGS!JE9@@Էu2%6b?,Co b ?v|, (hh1^GG!JSE9u2%ՀbMK B  τ},hh1L^GGS!JE9@@+u4%6bMK B  τ},hh1ظ^GG!JSE9u4%]b?-D b  OF%^zHhh1h^GGS!JE9@@Զu2%6b?-D b  OF%^zHhh1^GG!JSE9u2%;bML\ B ȯ>̉\hh1`^GGS!JE9@@*u4%6bML\ B ȯ>̉\hh1_GG!JSE9u4%ɮb?.D b ˯zΛ Hhh1j_GGS!JE9@@Եu2%6b?.D b ˯zΛ Hhh1"W_GG!JSE9u2% CbMM B ˯ϲb$h(hh1A`GGS!JE9@@&u4%6bMP B  o>b$h(hh1vE`GG!JSE9 u4%%b?2G/ b fTP"0hh1F`GGS!JE9@@Աu2%6b?2G/ b fTP"0hh1^`GG!JSE9 u2%ᒀbMQ| B  {j<)hh1`GGS!JE9@@%u4%6bMQ| B  {j<)hh1`GG!JSE9u4%Bb?3G b SGҞ 'hh1(`GGS!JE9@@԰u2%6b?3G b SGҞ 'hh1`GG!JSE9u2%ڡbMR B  bǪ@Lhh1+`GGS!JE9@@$u4%6bMR B  bǪ@Lhh1`GG!JSE9u4%Ӏb?4Ho b u r./ 1P>& '( ?? p --%@X1`a66S!JE(yi@@?g >u 1r./P<Xh1+bGG!JSE9u2% bMV B Q/wVn$Hlhh1bGGS!JE9@@ u4%6bMV B Q/wVn$Hlhh1*bGG!JSE9u4%b?8J b  9V^Fk0hh1bGGS!JE9@@ԫu2%6b?8J b  9V^Fk0hh15^bGG!JSE9u2%pڀbMW< B Gٔ`hh1^bGGS!JE9@@u4%6bMW< B Gٔ`hh1=bbGG!JSE9u4%܀b?9K b AQl9hh1bbGGS!JE9 @@Ԫu2%6b?9K b AQl9hh1bGG!JSE9u2%bMX B aQJ_߀ Bhh1bGGS!JE9@@u4%6bMX B aQJ_߀ Bhh1rbGG!JSE9u4%^b?:L/ b  +OV_۴l:thh1bGGS!JE9 @@ԩu2%6b?:L/ b  +OV_۴l:th1b``!JSER>u r./ 1P>$'( ?? p 12%?X1b66S!JE(yj@@?f >u 1r.0P<Xh1cGG!JSE9u2%bMY| B Iul$,J(hh12cGGS!JE9@@u4%6bMY| B Iul$,J(hh1cGG!JSE9 u4%wb?;L b S ,W|֢ਤhh13cGGS!JE9 @@Ԩu2%6b?;L b S ,W|֢ਤhh1HcGG!JSE9!u2%mbMZ B G7ORHhh1"IcGGS!JE9@@u4%6bMZ B G7ORHhh1LcGG!JSE9"u4%b?<Mo b ,n!hh1'McGGS!JE9 @@ԧu2%6b?<Mo b ,n!hh1cGG!JSE9#u2%MbM[ B f-d@ hh10cGGS!JE9@@u4%6bM[ B f-d@ hh1۔cGG!JSE9$u4%Ib?=N b IWi0,hh1fcGGS!JE9 @@Ԧu2%6b?=N b IWi0,hh1cGG!JSE9%u2%VbM\\ B KNc@ehh1cGGS!JE9@@u4%6bM\\ B KNc@ehh1cGG!JSE9&u4%Ipb?>N b 7LK2hh1EcGGS!JE9@@ԥu2%6b?>N b 7LK2hh13dGG!JSE9'u2%zbM] B f>dbjhh13dGGS!JE9@@u4%6bM] B f>dbjhh17dGG!JSE9(u4%5b??OO b UI_1º&/_hh17dGGS!JE9@@Ԥu2%6b??OO b UI_1º&/_hh1 {dGG!JSE9)u2%bM^ B h9/vDd.`hh1jeGGS!JE9@@Ԡu2%6b?CQ b ZC>vDd.`hh1eGG!JSE91u2%隀bMb B AWw/ ,hh1BeGGS!JE9@@u4%6bMb B AWw/ ,hh1$eGG!JSE92u4%rb?DRo b  RR֝&B hh1eGGS!JE9@@ԟu2%6b?DRo b  RR֝&B hh1fGG!JSE93u2%sbMc B Q>@fJhh1?fGGS!JE9@@u4%6bMc B Q>@fJhh1 fGG!JSE94u4%Kb?ES b S ܍ʴhh11 fGGS!JE9@@Ԟu2%6b?ES b S ܍ʴhh1OfGG!JSE95u2% bMd\ B š'6CD˨hh1xPfGGS!JE9@@u4%6bMd\ B š'6CD˨hh1TfGG!JSE96~u4%b?FS b 뿻-_wڢhh1TfGGS!JE9@@ԝu2%6b?FS b 뿻-_wڢhh1fGG!JSE97}u2%1bMe B g'Z bhh1fGGS!JE9@@u4%6bMe B g'Z bhh1fGG!JSE98|u4%b?GTO b  #9`(hh1yfGGS!JE9@@Ԝu2%6b?GTO b  #9`(hh1[fGG!JSE99{u2%ibMf B  ޵نF.bhh1fGGS!JE9@@u4%6bMf B  ޵نF.bhh1fGG!JSE9:zu4%:b?HT b MBhh1fGGS!JE9@@ԛu2%6b?HT b MBhh1U:gGG!JSE9;yu2% @bMg< B 0=6&j&dhh1:gGGS!JE9@@u4%6bMg< B 0=6&j&dhh19>gGG!JSE9<xu4%;b?IU b #C9gb8hh1>gGGS!JE9@@Ԛu2%6b?IU b #C9gb8hh1ogGG!JSE9=wu2%bMh B  j|OFFi0hh1gGGS!JE9@@u4%6bMh B  j|OFFi0hh1ҘgGG!JSE9>vu4%b?JV/ b 7;G~ܘ hh1^gGGS!JE9@@ԙu2%6b?JV/ b 7;G~ܘ hh1gGG!JSE9?uu2%bMi| B ׫^h| hB hh1gGGS!JE9@@ u4%6bMi| B ׫^h| hB hh1gGG!JSE9@tu4%b?KV b SuvU hh1gGGS!JE9@@Ԙu2%6b?KV b SuvU hh1$hGG!JSE9Asu2%ZbMj B aN՟ނ hh1%hGGS!JE9@@ u4%6bMj B aN՟ނ hh1/)hGG!JSE9Bru4%Lb?LWo b 2 t/z*hh1)hGGS!JE9@@ԗu2%6b?LWo b 2 t/z*hh1~hGG!JSE9Cqu2%bMk B \ iޙ} hh1\hGGS!JE9@@ u4%6bMk B \ iޙ} hh1bhGG!JSE9Dpu4%nb?MX b h&YB/ڇ8hh1hGGS!JE9@@Ԗu2%6b?MX b h&YB/ڇ8hh1hGG!JSE9Eou2%0 bMl\ B ZG'~j.j,hh1mhGGS!JE9@@ u4%6bMl\ B ZG'~j.j,hh1hGG!JSE9Fnu4%b?NX b #Z(Ohh1]hGGS!JE9@@ԕu2%6b?NX b #Z(Ohh1iGG!JSE9Gmu2%̀bMm B `{w$hh1iGGS!JE9@@ u4%6bMm B `{w$hh1iGG!JSE9Hlu4%!b?OYO b 7rPhh1iGGS!JE9@@Ԕu2%6b?OYO b 7rPh1!i``!JSERI]>u r.0 1P>$'( ?? p --%@X10!i66S!JE(yk@@?e >u 1r.0;P<Xh1iiGG!JSE9Jju2%VbMn B Z ǎ[&,hh1CiiGGS!JE9@@u4%6bMn B Z ǎ[&,hh1vmiGG!JSE9Kiu4%tb?PY b S-1y?Zxhh1miGGS!JE9 @@ԓu2%6b?PY b S-1y?Zxhh1miGG!JSE9Lhu2%dbMo< B Owh(lhh1eiGGS!JE9@@u4%6bMo< B Owh(lhh1ԵiGG!JSE9Mgu4%d߀b?QZ b #Zw&-~ hhh1ĶiGGS!JE9!@@Ԓu2%6b?QZ b #Zw&-~ hhh1iGG!JSE9Nfu2%bMp B S7ld&hh1ziGGS!JE9@@u4%6bMp B S7ld&hh1iGG!JSE9Oeu4%b?R[/ b  B?j,hh1iGGS!JE9"@@ԑu2%6b?R[/ b  B?j,h1Wj``!JSERPV>u r.0; 1P>#'( ?? p 12%?X1j66S!JE(yl@@?d >u 1r.0eP<Xh1SjGG!JSE9Qcu2%JbMq| B  U^{Ȅ|hh1nTjGGS!JE9@@u4%6bMq| B  U^{Ȅ|hh1WjGG!JSE9Rbu4%$Vb?S[ b >}t$&hh1XjGGS!JE9#@@Ԑu2%6b?S[ b >}t$&hh1jGG!JSE9Sau2%ebMr B  7<ۆꢀhh1jGGS!JE9@@u4%6bMr B  7<ۆꢀhh1jGG!JSE9T`u4%Ềb?T\o b 7[dƯ0hh1şjGGS!JE9$@@ԏu2%6b?T\o b 7[dƯ0hh1jGG!JSE9U_u2%CbMs B  |Jl hh1jGGS!JE9@@u4%6bMs B  |Jl hh1jGG!JSE9V^u4% b?U] b Բovd$J(hh1jGGS!JE9%@@Ԏu2%6b?U] b Բovd$J(hh1=kGG!JSE9W]u2%퓀bMt\ B ڗb ,hh1>kGGS!JE9@@u4%6bMt\ B ڗb ,hh1AkGG!JSE9X\u4%ʀb?V] b R^ǣ X hh1BkGGS!JE9&@@ԍu2%6b?V] b R^ǣ X hh1kGG!JSE9Y[u2%bMu B G?WN٦FBhh1kGGS!JE9@@u4%6bMu B G?WN٦FBhh1|kGG!JSE9ZZu4%b?W^O b b#?@L-hh1NkGGS!JE9'@@Ԍu2%6b?W^O b b#?@L-hh1YkGG!JSE9[Yu2%bMv B I&tƮhh1kGGS!JE9@@u4%6bMv B I&tƮhh1rkGG!JSE9\Xu4%nb?X^ b 8R7/n]G%hh1kGGS!JE9(@@ԋu2%6b?X^ b 8R7/n]G%hh1(lGG!JSE9]Wu2%dbMw< B ԗN[(*hh1(lGGS!JE9@@u4%6bMw< B ԗN[(*hh1u,lGG!JSE9^Vu4% b?Y_ b 1fP=Ӟ߳ȁBhh1-lGGS!JE9)@@Ԋu2%6b?Y_ b 1fP=Ӟ߳ȁBhh1PplGG!JSE9_Uu2%bMx B RF|L*lhh1plGGS!JE9@@u4%6bMx B RF|L*lhh1XtlGG!JSE9`Tu4%bb?Z`/ b G w hh1tlGGS!JE9*@@ԉu2%6b?Z`/ b G w hh1blGG!JSE9aSu2%>bMy| B  u~xM*hh1lGGS!JE9@@u4%6bMy| B  u~xM*hh1lGG!JSE9bRu4%eb?[` b 1Wx2Ek hh1lGGS!JE9+@@Ԉu2%6b?[` b 1Wx2Ek hh1mGG!JSE9cQu2%bMz B Xwӧ$P֠ hh1@mGGS!JE9@@u4%6bMz B Xwӧ$P֠ hh1mGG!JSE9dPu4%b?\ao b Zy ܼnhh1jmGGS!JE9,@@ԇu2%6b?\ao b Zy ܼnhh1ZmGG!JSE9eOu2%bM{ B )Edꬨhh1_[mGGS!JE9@@u4%6bM{ B )Edꬨhh1B^mGG!JSE9fNu4%b?]b b O=Z)8hh1^mGGS!JE9-@@Ԇu2%6b?]b b O=Z)8hh1̢mGG!JSE9gMu2%bM|\ B GVJQ,phh1ZmGGS!JE9@@u4%6bM|\ B GVJQ,phh1mGG!JSE9hLu4% b?^b b bfu]hhh1mGGS!JE9.@@ԅu2%6b?^b b bfu]hhh1mGG!JSE9iKu2%bM} B K7 詀hh1xmGGS!JE9@@u4%6bM} B K7 詀hh1nGG!JSE9jJu4%2b?_cO b ԀܟԞhh1nGGS!JE9/@@Ԅu2%6b?_cO b ԀܟԞhh1EnGG!JSE9kIu2%;bM~ B Qz|nkdhh1EnGGS!JE9@@u4%6bM~ B Qz|nkdhh15InGG!JSE9lHu4%b_b?`c b #;Rhh1InGGS!JE90@@ԃu2%6b?`c b #;Rhh1(nGG!JSE9mGu2%bM< B  oS,0hh1nGGS!JE9@@u4%6bM< B  oS,0hh1CnGG!JSE9nFu4% b?ad b *U~shh1ϑnGGS!JE91@@Ԃu2%6b?ad b *U~shh1jnGG!JSE9oEu2% bM B ϯ~|n&hh1nGGS!JE9@@u4%6bM B ϯ~|n&hh19nGG!JSE9pDu4%w~b?be/ b 1_ithh1nGGS!JE92@@ԁu2%6b?be/ b 1_ithh1/oGG!JSE9qCu2%Q@bM| B whjJ(hh10oGGS!JE9@@u4%6bM| B whjJ(hh1 4oGG!JSE9rBu4%b?ce b g~P."7hh14oGGS!JE93@@Ԁu2%6b?ce b g~P."7hh1woGG!JSE9sAu2%ȀbM B  ^׀h(hh1jxoGGS!JE9@@u4%6bM B  ^׀h(hh1({oGG!JSE9t@u4%b?dfo b Z?_ϵ7<.Whh1{oGGS!JE94@@u2%6b?dfo b Z?_ϵ7<.Whh1oGG!JSE9u?u2%T bM B `/6v*bhh1u4%ab?eg b aqћ" hh1foGGS!JE95@@~u2%6b?eg b aqћ" hh1pGG!JSE9w=u2%փbM\ B *f0?>] hh1epGGS!JE9@@u4%6bM\ B *f0?>] hh1pGG!JSE9x<u4%Zb?fg b `|~Nو^&\hh1spGGS!JE96@@}u2%6b?fg b `|~Nو^&\hh1apGG!JSE9y;u2%bM B X7vP.b$(hh1ibpGGS!JE9@@u4%6bM B X7vP.b$(hh1fpGG!JSE9z:u4%Zb?ghO b SK_wHthh1fpGGS!JE97@@|u2%6b?ghO b SK_wHth1mtp``!JSER{+>u r.0e 1P>#f'( ?? p --%?X1tp66S!JE(ym@@?c >u 1r.0P<Xh19pGG!JSE9|8u2%bM B  9nzhh1ɼpGGS!JE9@@u4%6bM B  9nzhh1pGG!JSE9}7u4%b?hh b  PڱλǬaA<hh1>pGGS!JE98@@{u2%6b?hh b  PڱλǬaA<hh1qGG!JSE9~6u2%bM< B *f+U%㘯&¤hh1[qGGS!JE9@@u4%6bM< B *f+U%㘯&¤hh1qGG!JSE95u4%b?ii b R xXhh1IqGGS!JE99@@zu2%6b?ii b R xXhh1LqGG!JSE94u2%bM B /=FtV=Yhh1=MqGGS!JE9@@u4%6bM B /=FtV=Yhh1wPqGG!JSE93u4%Hcb?jj/ b  R7ŇD(hh1QqGGS!JE9:@@yu2%6b?jj/ b  R7ŇD(h1 aq``!JSER$>u r.0 1P>"8'( ?? p 11%?X1Paq66S!JE(yn@@?b >u 1r.0P<Xh1FqGG!JSE91u2%bM| B +gq|,Thh1qGGS!JE9@@u4%6bM| B +gq|,Thh1qGG!JSE90u4%b?kj b S 6Z{++o<hh1qGGS!JE9;@@xu2%6b?kj b S 6Z{++o<hh1qGG!JSE9/u2%>bM B R gVL Bbhh1 qGGS!JE9@@u4%6bM B R gVL Bbhh1qGG!JSE9.u4%b?lko b  7Nפ[C8hh1qGGS!JE9<@@wu2%6b?lko b  7Nפ[C8hh16rGG!JSE9-u2%bM B xzЎ@@Lhh1U7rGGS!JE9@@u4%6bM B xzЎ@@Lhh1-:rGG!JSE9,u4%Sb?ml b R@'vH>jehh1:rGGS!JE9=@@vu2%6b?ml b R@'vH>jehh1ܐrGG!JSE9+u2%bM\ B 0ߥhhh1hrGGS!JE9@@u4%6bM\ B 0ߥhhh1(rGG!JSE9*u4%{b?nl b Qw`Ŭhh1rGGS!JE9>@@uu2%6b?nl b Qw`Ŭhh1rGG!JSE9)u2%bM B i͢~DI<hh1~rGGS!JE9@@u4%6bM B i͢~DI<hh1zrGG!JSE9(u4%{b?omO b b-W]Chh1rGGS!JE9?@@tu2%6b?omO b b-W]Chh1!sGG!JSE9'u2%vbM B \Whh1!sGGS!JE9@@u4%6bM B \Whh1*%sGG!JSE9&u4%-b?pm b 1%'^dhh1%sGGS!JE9@@@su2%6b?pm b 1%'^dhh1D{sGG!JSE9%u2%bM< B `v'GVRH$dhh1{sGGS!JE9@@u4%6bM< B `v'GVRH$dhh1~sGG!JSE9$u4%Jb?qn b Qwr$7hh1[sGGS!JE9A@@ru2%6b?qn b Qwr$7hh1;sGG!JSE9#u2%mLbM B 02Sz@$hh1sGGS!JE9@@u4%6bM B 02Sz@$hh1'sGG!JSE9"u4%b?ro/ b SQQջڳhh1sGGS!JE9B@@qu2%6b?ro/ b SQQջڳhh1i tGG!JSE9!u2%bM| B  7Ǿdihh1 tGGS!JE9@@u4%6bM| B  7Ǿdihh1tGG!JSE9 u4%b?so b 0?|&*|hh1tGGS!JE9C@@pu2%6b?so b 0?|&*|hh1etGG!JSE9u2%ҀbM B 7uO6 nDhh1ftGGS!JE9@@u4%6bM B 7uO6 nDhh1jtGG!JSE9u4%kb?tpo b  W~pн2phh1jtGGS!JE9D@@ou2%6b?tpo b  W~pн2phh1ĭtGG!JSE9u2%!bM B Ag7W!@hh1VtGGS!JE9@@u4%6bM B Ag7W!@hh1!tGG!JSE9u4%jb?uq b >X=H殀hh1tGGS!JE9E@@nu2%6b?uq b >X=H殀hh1tGG!JSE9u2%KXbM\ B ZY7ϡ~SBE5hh1mtGGS!JE9@@u4%6bM\ B ZY7ϡ~SBE5hh1NtGG!JSE9u4%-ƀb?vq b ZG<ƚl.hh1tGGS!JE9F@@mu2%6b?vq b ZG<ƚl.hh1OuGG!JSE9u2%bM B bhh1tPuGGS!JE9@@u4%6bM B bhh1TuGG!JSE9u4%~b?wrO b S6o7 Hhh1TuGGS!JE9G@@lu2%6b?wrO b S6o7 Hhh1uGG!JSE9u2%kbM B *^ o3/Qhh1uGGS!JE9@@u4%6bM B *^ o3/Qhh1uGG!JSE9u4%4Gb?xr b Sw5M6\d褠hh1-uGGS!JE9H@@ku2%6b?xr b Sw5M6\d褠hh1 uGG!JSE9u2%BBbM< B 7@wג^ۆN`hh1uGGS!JE9@@u4%6bM< B 7@wג^ۆN`hh1uGG!JSE9u4%Zb?ys b O|% hh1uGGS!JE9I@@ju2%6b?ys b O|% hh1F:vGG!JSE9u2%r1bM B Ujh%hh1:vGGS!JE9@@u4%6bM B Ujh%hh1=vGG!JSE9u4%:9b?zt/ b 72?QzR hh1>vGGS!JE9J@@iu2%6b?zt/ b 72?QzR hh1ZvGG!JSE9u2%cbM| B G}o&|(B,hh1vGGS!JE9@@u4%6bM| B G}o&|(B,hh1vGG!JSE9u4% b?{t b a~|H@ F hh1vGGS!JE9K@@hu2%6b?{t b a~|H@ F hh1vGG!JSE9u2%bM B  ##d$ hh1gvGGS!JE9@@u4%6bM B  ##d$ hh1vGG!JSE9u4%$ab?|uo b  Z gjRKhh1vGGS!JE9L@@gu2%6b?|uo b  Z gjRKhh1$wGG!JSE9 u2%bM B \%bu=P`hh1A%wGGS!JE9@@u4%6bM B \%bu=P`hh1c)wGG!JSE9 u4%b?}v b -ft`hh1)wGGS!JE9M@@fu2%6b?}v b -ft`hh1lwGG!JSE9 u2%݀bM\ B 1` ȏZAhh1]mwGGS!JE9@@u4%6bM\ B 1` ȏZAhh1GqwGG!JSE9 u4%Jb?~v b =v_++lmhh1qwGGS!JE9N@@eu2%6b?~v b =v_++lmhh1wGG!JSE9 u2%xbM B n>Jf($hh1wGGS!JE9@@u4%6bM B n>Jf($hh1wGG!JSE9u4%b?wO b "jHVdhh1wGGS!JE9O@@du2%6b?wO b "jHVdh1w``!JSER>u r.0 1P>"'( ?? p --%?X1;w66S!JE(yo@@?a >u 1r.0P<Xh1+xGG!JSE9u2% qbM B 9Ӻ][Chh1xGGS!JE9@@u4%6bM B 9Ӻ][Chh1&xGG!JSE9u4%b?w b n{ =hh1xGGS!JE9P@@cu2%6b?w b n{ =hh18WxGG!JSE9u2%[bM< B 4En@'Iǒͬhh1WxGGS!JE9@@u4%6bM< B 4En@'Iǒͬhh1ZxGG!JSE9u4%#2b?x b 4#@-l -4hh1K[xGGS!JE9Q@@bu2%6b?x b 4#@-l -4hh1=xGG!JSE9u2%ĀbM B l#krЯԁhh1џxGGS!JE9@@u4%6bM B l#krЯԁhh1xGG!JSE9u4%Wb?y/ b l{gYxٴhh1"xGGS!JE9R@@au2%6b?y/ b l{gYxٴh1}x``!JSER>u r.0 1P> '( ?? p 12%?X1x66S!JE(yp@@?` >u 1r.1 P<Xh1BxGG!JSE9u2%qbM| B {9_P@hh1xGGS!JE9@@u4%6bM| B {9_P@hh1xGG!JSE9u4%Еb?y b Kzf9Jlyhhh1xGGS!JE9S@@`u2%6b?y b Kzf9Jlyhhh1AyGG!JSE9u2%bM B {RG]Nhh1nByGGS!JE9@@u4%6bM B {RG]Nhh1EyGG!JSE9u4%4b?zo b У$hh1%FyGGS!JE9T@@_u2%6b?zo b У$hh1yGG!JSE9u2%?ybM B =N96M(`GPhh1/yGGS!JE9@@u4%6bM B =N96M(`GPhh1ÍyGG!JSE9u4%|b?{ b @y4hDhh1TyGGS!JE9U@@^u2%6b?{ b @y4hDhh1yGG!JSE9u2%bM\ B 4shUL(Ġhh1eyGGS!JE9@@u4%6bM\ B 4shUL(Ġhh1yGG!JSE9u4%b?{ b 4z\L@86]*=3hh1#yGGS!JE9V@@]u2%6b?{ b 4z\L@86]*=3hh1+zGG!JSE9u2%bM B 4[fSݓ`hh1x,zGGS!JE9@@u4%6bM B 4[fSݓ`hh1/zGG!JSE9u4%7b?|O b lP+3yDq;dhh10zGGS!JE9W@@\u2%6b?|O b lP+3yDq;dhh1szGG!JSE9u2%bM B %+]4~TVhh1ttzGGS!JE9@@u4%6bM B %+]4~TVhh1wzGG!JSE9u4%b?| b ^shh11xzGGS!JE9X@@[u2%6b?| b ^shh1>zGG!JSE9u2%-jbM< B fO=˕j4hh1zGGS!JE9@@u4%6bM< B fO=˕j4hh1HzGG!JSE9u4%Qb?} b fD[p؄hh1zGGS!JE9Y@@Zu2%6b?} b fD[p؄hh1%{GG!JSE9u2%xibM B 42+SN䯀hh1{GGS!JE9@@u4%6bM B 42+SN䯀hh1R{GG!JSE9u4%@b?~/ b N8'8;ڪbhh1{GGS!JE9Z@@Yu2%6b?~/ b N8'8;ڪbhh1r^{GG!JSE9u2%/݀bM| B ylrZ&9phh1_{GGS!JE9@@u4%6bM| B ylrZ&9phh1c{GG!JSE9u4%"db?~ b ,xnx0{hh1c{GGS!JE9[@@Xu2%6b?~ b ,xnx0{hh1{GG!JSE9u2%LbM B 4wx(5Mhh14{GGS!JE9@@u4%6bM B 4wx(5Mhh1{{GG!JSE9u4%2b?o b x y]<thh1 {GGS!JE9\@@Wu2%6b?o b x y]<thh1|GG!JSE9u2%5cbM B wxX fQhh1.|GGS!JE9@@u4%6bM B wxX fQhh1|GG!JSE9u4%tǀb? b lx&tDlhh1|GGS!JE9]@@Vu2%6b? b lx&tDlhh1H|GG!JSE9u2%bM\ B 4+z'=Y&F8hh1`I|GGS!JE9@@u4%6bM\ B 4+z'=Y&F8hh1 M|GG!JSE9u4%b? b xmc-&(hh1M|GGS!JE9^@@Uu2%6b? b xmc-&(hh1|GG!JSE9u2%kpbM B ,r RuaEhh1t|GGS!JE9@@u4%6bM B ,r RuaEhh1|GG!JSE9u4%gb?O b 4s8GU>)mdhh1|GGS!JE9_@@Tu2%6b?O b 4s8GU>)mdh1|]]!JSEO>u r.1 1P>Q$ (08AIQYaiqy X1D|66S!JE(yq@@?_ >u 1r.14P<Xh1.|GG!JSE9u2%5Shh1_}GGS!JE9b@@Qu2%6b?/ b ,Sk>Shh1p}GG!JSE9u2%RibM| B 4g*phhh1}GGS!JE9@@u4%6bM| B 4g*phhh1S}GG!JSE9u4%kb? b ewߟ+|hh1}GGS!JE9c@@Pu2%6b? b ewߟ+|hh1~GG!JSE9u2%?{bM B Ϟ Wu Vhh1~GGS!JE9@@u4%6bM B Ϟ Wu Vhh1H!~GG!JSE9u4%\b?o b gR 'f۠hh1!~GGS!JE9d@@Ou2%6b?o b gR 'f۠hh1w~GG!JSE9u2%UbMƼ B 4G/fNj$hh1u r.14 1P>!'( ?? p ,,%?X1.66S!JE(yr@@?^ >u 1r.1^P<Xh1*bGG!JSE9u2%SbMȜ B 4K>_<hh1bGGS!JE9@@u4%6bMȜ B 4K>_<hh1fGG!JSE9u4%eb? b ְ5Ň0hh1&gGGS!JE9h@@Ku2%6b? b ְ5Ň0hh13GG!JSE9u2%+bM< B 4+ p0U\hh1ĪGGS!JE9@@ҿu4%6bM< B 4+ p0U\hh1GG!JSE9u4%Yb? b p=EMihh1AGGS!JE9i@@Ju2%6b? b p=EMihh1GG!JSE9u2%dbM B 44Ng-N "hh1GGS!JE9@@Ҿu4%6bM B 44Ng-N "hh1GG!JSE9u4%0b?/ b 3}=<hh1GGS!JE9j@@Iu2%6b?/ b 3}=<h1' ``!JSER>u r.1^ 1P>i'( ?? p 11%?X1R 66S!JE(ys@@?] >u 1r.1P<Xh1LGG!JSE9u2%bM| B 4llhh1MGGS!JE9@@ҽu4%6bM| B 4llhh1PGG!JSE9u4%=b? b fOZkUǼhh1^QGGS!JE9k@@Hu2%6b? b fOZkUǼhh1MGG!JSE9u2%bM B 4ߠؔhh1GGS!JE9@@Ҽu4%6bM B 4ߠؔhh1GG!JSE9u4%|b?o b /i&%hh13GGS!JE9l@@Gu2%6b?o b /i&%hh1܀GG!JSE9u2%MQbM˼ B :nhh1݀GGS!JE9@@һu4%6bM˼ B :nhh1 GG!JSE9u4%Sb? b ,ۯoRJhhh1GGS!JE9m@@Fu2%6b? b ,ۯoRJhhh17GG!JSE9u2%u2%6b? b ܃zU<hh1GG!JSE9u2%ebM\ B 4-?Ihh19GGS!JE9@@Ҳu4%6bM\ B 4-?Ihh1GG!JSE9u4%Ub? b ۞yTt2hh15GGS!JE9v@@=u2%6b? b ۞yTt2hh1GG!JSE9u2%gÀbM B V/V*chh1ZGGS!JE9@@ұu4%6bM B V/V*chh1GG!JSE9u4%s=b?O b iUYBHlhh1GGS!JE9w@@<u2%6b?O b iUYBHlhh1>GG!JSE9u2%bMҜ B (W85き.lhh1>GGS!JE9@@Ұu4%6bMҜ B (W85き.lhh1wBGG!JSE9u4%yրb? b ( hh1CGGS!JE9x@@;u2%6b? b ( hh1%GG!JSE9u2%bM< B 4cnhh1GGS!JE9@@үu4%6bM< B 4cnhh1{GG!JSE9u4%b? b 3('&k;>Thh1 GGS!JE9y@@:u2%6b? b 3('&k;>Thh1PGG!JSE9u2%X1bM B Ve hh1GGS!JE9@@Үu4%6bM B Ve hh1m䄽GG!JSE9u4%Ub?/ b >yTDhh1䄽GGS!JE9z@@9u2%6b?/ b >yTDhh1=(GG!JSE9 u2%DbM| B |*VThh1(GGS!JE9@@ҭu4%6bM| B |*VThh1m,GG!JSE9 u4%^jb? b .[OEhh1,GGS!JE9{@@8u2%6b? b .[OEhh1|pGG!JSE9 u2%"bM B S˹|!hh1qGGS!JE9@@Ҭu4%6bM B S˹|!h1tvv!JSEh yu3T<Ձ  B b?* B 192.168.0.174h1#tGG!JSE9 u4%Tb?o b S ڜ_бMZ$hh1tGGS!JE9|@@7u2%6b?o b S ڜ_бMZ$h1tvvS!JEh-@@Wu5Te  B b?* B 192.168.0.174h1ʅGG!JSE9u2%WbMռ B G#̊AVhh1^˅GGS!JE9@@ҫu4%6bMռ B G#̊AVhh1΅GG!JSE9u4%7b? b cK%ːhh1UυGGS!JE9}@@6u2%6b? b cK%ːhh1GG!JSE9u2%SbM\ B K`_?| q\hh1NGGS!JE9 @@Ҫu4%6bM\ B K`_?| q\hh1GG!JSE9u4%sb? b DLڇش_7 0*hh1GGS!JE9~@@5u2%6b? b DLڇش_7 0*hh1ZGG!JSE9u2%qbM B `?Q8|hh1a[GGS!JE9 @@ҩu4%6bM B `?Q8|hh1_GG!JSE9u4%]b?O b V$ק/T'kHhh1_GGS!JE9@@4u2%6b?O b V$ק/T'kHh1pn``!JSER>u r.1 1P>"F'( ?? p **%?X1n66S!JE(yt@@?\ >u 1r.1P<Xh1 GG!JSE9u2%ۀbMל B }-? B)0hh1GGS!JE9 @@Ҩu4%6bMל B }-? B)0hh1=GG!JSE9u4%(b? b ܟ:ۥhh1ιGGS!JE9@@3u2%6b? b ܟ:ۥhh11GG!JSE9u2%P bM< B `ި߶h (hh1GGS!JE9 @@ҧu4%6bM< B `ި߶h (hh1KGG!JSE9u4%zb? b  H hh1GGS!JE9@@2u2%6b? b  H hh16EGG!JSE9u2%bM B Q7@D,@hh1EGGS!JE9 @@Ҧu4%6bM B Q7@D,@hh1IGG!JSE9u4%π?/ b 4,T Nhh1uJGGS!JE9@@1u2%6?/ b 4,T Nh1Z``!JSER>u r.1 1P>'( ?? p 11%?X1Z66S!JE(yu@@?[ >u 1r.1P<Xh1fGG!JSE9u2%^bM| B ]{ %hh1GGS!JE9@@ҥu4%6bM| B ]{ %hh1CGG!JSE9u4%2'b? b ~Y_C@+zL!hh1%NGGS!JE9@@$u2%6b?O b >C@+zL!hh1GG!JSE96~u2%%IbM B P _Q̿0hh1GGS!JE9@@Ҙu4%6bM B P _Q̿0hh1GG!JSE97}u4%%b? b >QJhBhh1lGGS!JE9@@#u2%6b? b >QJhBhh1؋GG!JSE98|u2%bM< B #L ׿rjhh1ًGGS!JE9@@җu4%6bM< B #L ׿rjhh1܋GG!JSE99{u4%0b? b IJhF'a¶zf&hh1p݋GGS!JE9@@"u2%6b? b IJhF'a¶zf&hh163GG!JSE9:zu2%1bM B QǼzc 4hh13GGS!JE9@@Җu4%6bM B QǼzc 4hh16GG!JSE9;yu4%ـb?/ b >p)1w8hh1t7GGS!JE9@@!u2%6b?/ b >p)1w8hh1D{GG!JSE9<xu2%dbM| B fߏBA(hh1{GGS!JE9@@ҕu4%6bM| B fߏBA(hh1@GG!JSE9=wu4%3b? b °\@ $hh1GGS!JE9@@ u2%6b? b °\@ $hh1qÌGG!JSE9>vu2%ÀbM B 't8u r.1 1P>'( ?? p ++%?X166S!JE(yv@@?Z >u 1r.2P<Xh1GG!JSE9Gmu2%bM B 2bPWRIhh1GGS!JE9#@@Ґu4%6bM B 2bPWRIhh1 GG!JSE9Hlu4%b? b GGϓSI33v+dhh1 GGS!JE9@@u2%6b? b GGϓSI33v+dhh1RGG!JSE9Iku2%vbM< B ϳAW1$h ,hh1SGGS!JE9$@@ҏu4%6bM< B ϳAW1$h ,hh1>UGG!JSE9Ju>u r.2 1P>&  ehX1hU66S!JE(yw@@?Y >u 1r.2P<Xh1[VHHS!JE:yx@@?F >u 1r.2P<,  -hh1ۜGG!JSE9Kiu4%JQb? b yJbhh1lGGS!JE9@@u2%6b? b yJbhh1ơGG!JSE9Ls>u r.2 CP>r  ehh1GGS!JE9yy@@?F >u Cr.2(P<+  %h1``!JSERMY>u r.2( TP>|'( ?? p 11%?h1(HHS!JE:yz@@?D >u Tr.2RP<,  -hh1zGG!JSE9Nfu2%bM B y4\@hh1GGS!JE9%@@Ҏu4%6bM B y4\@hh1GG!JSE9Oeu4%b?/ b ۃ)hh1`GGS!JE9@@u2%6b?/ b ۃ)hh1m:GG!JSE9Pdu2%bM| B 1 hh1:GGS!JE9&@@ҍu4%6bM| B 1 hh1D>GG!JSE9Qcu4%9b? b y꟪xhh1>GGS!JE9@@u2%6b? b y꟪xhh1GG!JSE9Rbu2%bM B yޓ Fhh1HGGS!JE9'@@Ҍu4%6bM B yޓ Fhh1GG!JSE9Sau4%nib?o b &3eThh10GGS!JE9@@u2%6b?o b &3eThh1܏GG!JSE9T`u2%ԀbM B hh1>ݏGGS!JE9(@@ҋu4%6bM B hh1GG!JSE9U_u4%*Ҁb? b y$hh1ᏽGGS!JE9@@u2%6b? b y$hh1$GG!JSE9V^u2%bM\ B y빟ꫯdhh1$GGS!JE9)@@Ҋu4%6bM\ B y빟ꫯdhh1#)GG!JSE9W]u4%ab? b 欄hh18)GGS!JE9@@u2%6b? b 欄hd15qDD!JSE6Xj>u r.2R fP>   -dh1prEES!JE7y{@@?F >u fr.2`P<)    hd1uDD!JSE6Yi>u r.2` fP>   *dh1ǐGG!JSE9ZZu2%gbM B y¤LHhh1ǐGGS!JE9*@@҉u4%6bM B y¤LHhh1oːGG!JSE9[Yu4%2b?O b gٟ֍thh1>̐GGS!JE9@@u2%6b?O b gٟ֍thX1i66S!JE(y|@@?T >u ur.2nP<Xh1NGG!JSE9\Xu2%bM B *Yhh1GGS!JE9+@@҈u4%6bM B *Yhh1GG!JSE9]Wu4%Cb? b y lhh1XGGS!JE9@@u2%6b? b y lhh1RWGG!JSE9^Vu2%t!bM< B yuhh1WGGS!JE9,@@҇u4%6bM< B yuhh1+[GG!JSE9_Uu4%Ib? b |hh1[GGS!JE9@@u2%6b? b |hh1`GG!JSE9`Tu2%rbM B Ob$hh1򱑽GGS!JE9-@@҆u4%6bM B Ob$hh1 GG!JSE9aSu4%LIb?/ b y3Phh1GGS!JE9@@u2%6b?/ b y3Phh1GG!JSE9bRu4%_b? b __hh1BGGS!JE9@@u2%6b? b __hh1AGG!JSE9cQu2%^bM| B 4hh15BGGS!JE9.@@҅u4%6bM| B 4hh1+FGG!JSE9dPu4%b?o b yyp10hh1FGGS!JE9@@u2%6b?o b yyp10hh1ɛGG!JSE9eOu2%!bM B yIhh1[GGS!JE9/@@҄u4%6bM B yIhh1GG!JSE9fNu4%b? b /hh1GGS!JE9@@u2%6b? b /hh1㒽GG!JSE9gMu2%bM B ĿNhh1c䒽GGS!JE90@@҃u4%6bM B ĿNhh1璽GG!JSE9hLu4%Gb? b ygٟuLhh1蒽GGS!JE9@@ u2%6b? b ygٟuLhh1%,GG!JSE9iKu2%іbM\ B y'thh1,GGS!JE91@@҂u4%6bM\ B y'thh1/GG!JSE9jJu4%b?O b eDhh1-0GGS!JE9@@ u2%6b?O b eDh\1g<<!JSE(ke>u r.2n uP>\t1 hSSS!JEEy}@@?6 >u ur.2nP<7%    % th1GG!JSE9lHu2%:bM B |hh1HGGS!JE92@@ҁu4%6bM B |hh1GG!JSE9mGu4%b? b yhh1GGS!JE9@@ u2%6b? b yhh1ГGG!JSE9nFu4%+b? b ﹟thh1sѓGGS!JE9@@ u2%6b? b ﹟thh1yGG!JSE9oEu2%+bM B lhh1GGS!JE93@@Ҁu4%6bM B lhh1GG!JSE9pDu4%KFb?/ b yX hh1LGGS!JE9@@ u2%6b?/ b yX h1+aa!JSESq4>u r.2n ߒP>)t(~v " "2X1,66S!JE(y~@@?R >u ߒr.2P<X`1/??!JSE1rU>u r.2 ߒP>  `X11/66S!JE(y@@?Q >u ߒr.2P<X`1/==S!JE/y@@?I >u ߒr.2Pu r.2 ߙP>ֈ3 `h1mGG!JSE9u?u4% -b?o b yCĐhX1 66S!JE(y@@?O >u ߙr.2P<X1aa!JSESv/>u r.2 ߙP>((~v  ""?X166S!JE(y@@?N >u ߙr.2P<X`1??!JSE1wP>u r.2 ߙP>N  `X1$66S!JE(y@@?M >u ߙr.2P<X`1==S!JE/y@@?E >u ߙr.2Pu r.2 ߠP>F3 `X1 66S!JE(y@@?K >u ߠr.2P<X1]]!JSEOy0>u r.2 ߠP> $ (08AIQYaiqy X166S!JE(y@@?J >u ߠr.3 P<X1RԽaa!JSESz+>u r.3 ߠP>($ (08AIQYaiqy X1Խ66S!JE(y@@?I >u ߠr.36P<Xlibosmo-netif-0.0.6/tests/osmo-pcap-test/proto.c000066400000000000000000000024751261607103500216210ustar00rootroot00000000000000/* * (C) 2012 by Pablo Neira Ayuso * (C) 2012 by On Waves ehf * * 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 vers */ #include #include #include #include #include "proto.h" static LLIST_HEAD(l2l3_proto_list); static LLIST_HEAD(l4_proto_list); struct osmo_pcap_proto_l2l3 *osmo_pcap_proto_l2l3_find(const uint8_t *pkt) { const struct ethhdr *eh = (const struct ethhdr *)pkt; struct osmo_pcap_proto_l2l3 *cur; llist_for_each_entry(cur, &l2l3_proto_list, head) { if (ntohs(cur->l2protonum) == eh->h_proto) return cur; } return NULL; } void osmo_pcap_proto_l2l3_register(struct osmo_pcap_proto_l2l3 *h) { llist_add(&h->head, &l2l3_proto_list); } struct osmo_pcap_proto_l4 * osmo_pcap_proto_l4_find(const uint8_t *pkt, unsigned int l4protocol) { struct osmo_pcap_proto_l4 *cur; llist_for_each_entry(cur, &l4_proto_list, head) { if (cur->l4protonum == l4protocol) return cur; } return NULL; } void osmo_pcap_proto_l4_register(struct osmo_pcap_proto_l4 *h) { llist_add(&h->head, &l4_proto_list); } libosmo-netif-0.0.6/tests/osmo-pcap-test/proto.h000066400000000000000000000016711261607103500216230ustar00rootroot00000000000000#ifndef _OSMO_PCAP_PROTO_H_ #define _OSMO_PCAP_PROTO_H_ #include #include struct osmo_pcap_proto_l4 { struct llist_head head; unsigned int l4protonum; int (*l4pkt_hdr_len)(const uint8_t *pkt); int (*l4pkt_no_data)(const uint8_t *pkt); }; struct osmo_pcap_proto_l2l3 { struct llist_head head; unsigned int l2protonum; unsigned int l2hdr_len; unsigned int l3protonum; int (*l3pkt_hdr_len)(const uint8_t *pkt); int (*l4pkt_proto)(const uint8_t *pkt); }; struct osmo_pcap_proto_l2l3 *osmo_pcap_proto_l2l3_find(const uint8_t *pkt); void osmo_pcap_proto_l2l3_register(struct osmo_pcap_proto_l2l3 *h); struct osmo_pcap_proto_l4 *osmo_pcap_proto_l4_find(const uint8_t *pkt, unsigned int l4protonum); void osmo_pcap_proto_l4_register(struct osmo_pcap_proto_l4 *h); /* Initialization of supported protocols here. */ void l2l3_ipv4_init(void); void l4_tcp_init(void); void l4_udp_init(void); #endif libosmo-netif-0.0.6/tests/osmux/000077500000000000000000000000001261607103500166025ustar00rootroot00000000000000libosmo-netif-0.0.6/tests/osmux/osmux_test.c000066400000000000000000000127641261607103500211720ustar00rootroot00000000000000/* * (C) 2013 by Pablo Neira Ayuso * (C) 2013 by On Waves ehf * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DOSMUX_TEST 0 struct log_info_cat osmux_test_cat[] = { [DOSMUX_TEST] = { .name = "DOSMUX_TEST", .description = "osmux test", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; const struct log_info osmux_test_log_info = { .filter_fn = NULL, .cat = osmux_test_cat, .num_cat = ARRAY_SIZE(osmux_test_cat), }; /* RTP packet with AMR payload */ static uint8_t rtp_pkt[] = { 0x80, 0x62, 0x3f, 0xcc, 0x00, 0x01, 0xa7, 0x6f, /* RTP */ 0x07, 0x09, 0x00, 0x62, 0x20, 0x14, 0xff, 0xd4, /* AMR */ 0xf9, 0xff, 0xfb, 0xe7, 0xeb, 0xf9, 0x9f, 0xf8, 0xf2, 0x26, 0x33, 0x65, 0x54, }; static int rtp_pkts; static struct timeval last; static void tx_cb(struct msgb *msg, void *data) { char buf[4096]; struct timeval now, diff; gettimeofday(&now, NULL); timersub(&now, &last, &diff); last = now; if (diff.tv_usec > 2*17000) { fprintf(stdout, "lagging to deliver reconstructed RTP\n"); exit(EXIT_FAILURE); } osmo_rtp_snprintf(buf, sizeof(buf), msg); fprintf(stderr, "extracted packet: %s\n", buf); if (memcmp(msg->data + sizeof(struct rtp_hdr), rtp_pkt + sizeof(struct rtp_hdr), sizeof(rtp_pkt) - sizeof(struct rtp_hdr)) != 0) { fprintf(stdout, "payload mismatch!\n"); exit(EXIT_FAILURE); } rtp_pkts--; msgb_free(msg); } static struct osmux_out_handle h_output; static void osmux_deliver(struct msgb *batch_msg, void *data) { char buf[1024]; struct osmux_hdr *osmuxh; LLIST_HEAD(list); osmux_snprintf(buf, sizeof(buf), batch_msg); fprintf(stderr, "OSMUX message (len=%d) %s\n", batch_msg->len, buf); /* For each OSMUX message, extract the RTP messages and put them * in a list. Then, reconstruct transmission timing. */ while((osmuxh = osmux_xfrm_output_pull(batch_msg)) != NULL) { osmux_xfrm_output(osmuxh, &h_output, &list); osmux_tx_sched(&list, tx_cb, NULL); } msgb_free(batch_msg); } struct osmux_in_handle h_input = { .osmux_seq = 0, /* sequence number to start OSmux message from */ .batch_factor = 4, /* batch up to 4 RTP messages */ .deliver = osmux_deliver, }; static void sigalarm_handler(int foo) { printf("FAIL: test did not run successfully\n"); exit(EXIT_FAILURE); } static void osmux_test_loop(int ccid) { struct msgb *msg; char buf[1024]; struct rtp_hdr *rtph = (struct rtp_hdr *)rtp_pkt; uint16_t seq; int i, j, k = 0; for (i = 1; i < 65; i++) { msg = msgb_alloc(1500, "test"); if (!msg) exit(EXIT_FAILURE); memcpy(msg->data, rtp_pkt, sizeof(rtp_pkt)); msgb_put(msg, sizeof(rtp_pkt)); seq = ntohs(rtph->sequence); seq++; rtph->sequence = htons(seq); osmo_rtp_snprintf(buf, sizeof(buf), msg); fprintf(stderr, "adding to ccid=%u %s\n", (i % 2) + ccid, buf); rtp_pkts++; k++; /* Fan out RTP packets between two circuit IDs to test * multi-batch support. Mind that this approach implicitly add * gaps between two messages to test the osmux replaying * feature. */ osmux_xfrm_input(&h_input, msg, (i % 2) + ccid); if (i % 4 == 0) { gettimeofday(&last, NULL); /* After four RTP messages, squash them into the OSMUX * batch and call the routine to deliver it. */ osmux_xfrm_input_deliver(&h_input); /* The first two RTP message (one per circuit ID batch) * are delivered immediately, wait until the three RTP * messages that are extracted from OSMUX has been * delivered. */ for (j = 0; j < k-2; j++) osmo_select_main(0); k = 0; } } } int main(void) { int i; if (signal(SIGALRM, sigalarm_handler) == SIG_ERR) { perror("signal"); exit(EXIT_FAILURE); } /* This test doesn't use it, but osmux requires it internally. */ osmo_init_logging(&osmux_test_log_info); log_set_log_level(osmo_stderr_target, LOGL_DEBUG); osmux_xfrm_input_init(&h_input); osmux_xfrm_output_init(&h_output, 0x7000000); /* If the test takes longer than 10 seconds, abort it */ alarm(10); for (i = 0; i < 2; i++) osmux_xfrm_input_open_circuit(&h_input, i, 0); /* Add two circuits with dummy padding */ osmux_xfrm_input_open_circuit(&h_input, 2, 1); osmux_xfrm_input_open_circuit(&h_input, 3, 1); /* Wait 10 times to make sure dummy padding timer works fine */ for (i = 0; i < 10; i++) osmo_select_main(0); /* Start pushing voice data to circuits 0 and 1 */ osmux_test_loop(0); /* ... now start pushing voice data to circuits 2 and 3. This circuits * comes with dummy padding enabled. */ osmux_test_loop(2); for (i = 0; i < 4; i++) osmux_xfrm_input_close_circuit(&h_input, i); /* Reopen with two circuits and retest */ osmux_xfrm_input_open_circuit(&h_input, 0, 0); osmux_xfrm_input_open_circuit(&h_input, 1, 1); osmux_test_loop(0); osmux_xfrm_input_close_circuit(&h_input, 0); osmux_xfrm_input_close_circuit(&h_input, 1); osmux_xfrm_input_fini(&h_input); fprintf(stdout, "OK: Test passed\n"); return EXIT_SUCCESS; } libosmo-netif-0.0.6/tests/osmux/osmux_test.ok000066400000000000000000000000201261607103500213370ustar00rootroot00000000000000OK: Test passed libosmo-netif-0.0.6/tests/testsuite.at000066400000000000000000000003371261607103500200110ustar00rootroot00000000000000AT_INIT AT_BANNER([Regression tests.]) AT_SETUP([osmux_test]) AT_KEYWORDS([osmux_test]) cat $abs_srcdir/osmux/osmux_test.ok > expout AT_CHECK([$abs_top_builddir/tests/osmux/osmux_test], [0], [expout], [ignore]) AT_CLEANUP