diff options
116 files changed, 24342 insertions, 0 deletions
@@ -0,0 +1,23 @@ +axspawn Joerg Reuter DL1BKE <jreuter@poboxes.com> +ax25ipd Rob Mayfield VK5XXX <mayfieldrob@mail.dec.com> +ax25rtd Klaus Kudielka <oe1kib@oe1xtu.ampr.org> +bpqparms Joerg Reuter DL1BKE <jreuter@poboxes.com> +call Alexander Tietzel DG6XA <tietze_a@etech.fh-hamburg.de> +mkiss Tomi Manninen OH2BNS <tpmannin@cc.hut.fi> +kissnetd Frederic Rible F1OAT <frible@teaser.fr> +listen Heikki Hannikainen OH7LZB <hessu@pspt.fi> +net2kiss Thomas Sailer HB9JNX <sailer@ife.ee.ethz.ch> +node Tomi Manninen OH2BNS <tpmannin@cc.hut.fi> +nodesave Tomi Manninen OH2BNS <tpmannin@cc.hut.fi> +nrsdrv Dave Brown N2RJT <dcb@vectorbd.com> +piconfig John Paul Morrison VE7JPM <jmorriso@bogomips.com> +pms David Brown N2RJT <dcb@vectorbd.com> +rxecho Tomi Manninen OH2BNS <tpmannin@cc.hut.fi> +setcrystal Thomas Sailer HB9JNX <sailer@ife.ee.ethz.ch> +sethdlc Thomas Sailer HB9JNX <sailer@ife.ee.ethz.ch> +smdiag Thomas Sailer HB9JNX <sailer@ife.ee.ethz.ch> +smmixer Thomas Sailer HB9JNX <sailer@ife.ee.ethz.ch> +ttylinkd Craig Small VK2XLZ <csmall@small.dropbear.id.au> + +All others Jonathon Naylor G4KLX <g4klx@g4klx.demon.co.uk> + @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <signature of Ty Coon>, 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 Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..c154a78 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4 @@ +1999-04-21 Craig Small <csmall@small.dropbear.id.au> + + * Initial version from Terry Dawson's code, split from the old + ax25-utils package. Uses new ntoa aton calls. @@ -0,0 +1,18 @@ +Installation Instructions for AX.25 Tools +========================================= + +To make this library you will need the following: + glibc2.1 + A Modern kernel + libtool + ax25-lib 0.0.2 or better + +To build it you type: + ./configure + make + make install + +By default, it will install the files in /usr/local. To change this +so that binaries go in /usr and the conf files go in /etc +type 'make install prefix=/usr' + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..68f5e15 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,11 @@ + +installconf: + @echo "**** WARNING - This will overwrite any existing files ****" + @echo "**** WARNING - This will overwrite any existing files ****" + @echo "**** WARNING - This will overwrite any existing files ****" + @echo + @echo Hit the return key to proceed, or ^C to exit. + @read + @for app in $(SUBDIRS); do $(MAKE) -C $$app installconf; done + +SUBDIRS = ax25 hdlcutil kiss netrom rose tcpip user_call diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..dcdcc0e --- /dev/null +++ b/Makefile.in @@ -0,0 +1,358 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SUBDIRS = ax25 hdlcutil kiss netrom rose tcpip user_call +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = README ./stamp-h.in AUTHORS COPYING ChangeLog INSTALL \ +Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 config.h.in \ +configure configure.in install-sh missing mkinstalldirs + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): configure.in + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +config.h: stamp-h + @if test ! -f $@; then \ + rm -f stamp-h; \ + $(MAKE) stamp-h; \ + else :; fi +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h 2> /dev/null +$(srcdir)/config.h.in: $(srcdir)/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/stamp-h.in; \ + $(MAKE) $(srcdir)/stamp-h.in; \ + else :; fi +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) dist + -rm -rf $(distdir) + @banner="$(distdir).tar.gz is ready for distribution"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +all-recursive-am: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +install-exec-am: +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile config.h +all-redirect: all-recursive-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-hdr clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-hdr distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + -rm -f config.status + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +install-data-recursive uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \ +install-exec-am install-exec install-data-am install-data install-am \ +install uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +installconf: + @echo "**** WARNING - This will overwrite any existing files ****" + @echo "**** WARNING - This will overwrite any existing files ****" + @echo "**** WARNING - This will overwrite any existing files ****" + @echo + @echo Hit the return key to proceed, or ^C to exit. + @read + @for app in $(SUBDIRS); do $(MAKE) -C $$app installconf; done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: @@ -0,0 +1,3 @@ +This is some news about ax25-tools + + @@ -0,0 +1,17 @@ +AX25 Tools +========== + +THESE TOOLS ARE ALPHA CODE AND IS ONLY BEEN RELEASE FOR DEVELOPERS FOR +DEBUGGING. + +This means if you are only installing this because it is the latest +and greatest and you don't understand how to diagnose bugs, then you +should probably not run it and go back to the ax25-utils-2* +packages. + +You are supposed to use glibc 2.1 (libc6 unstable libraries) for this +package. I have attempted to cater for glibc 2.0 users here. + + - Craig Small <csmall@small.dropbear.id.au> + + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..4498431 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,10 @@ + +#undef HAVE_AX25_FWD_STRUCT + +#undef HAVE_AX25_IAMDIGI +#undef HAVE_AX25_PIDINCL + +/* #undef PACKAGE */ +/* #undef VERSION */ + + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..f23ba29 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,127 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<<am_indx=1 +for am_file in <<$1>>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + diff --git a/ax25/Makefile.am b/ax25/Makefile.am new file mode 100644 index 0000000..55dc33d --- /dev/null +++ b/ax25/Makefile.am @@ -0,0 +1,38 @@ + +etcfiles = ax25.profile ax25d.conf axspawn.conf rxecho.conf +varfiles = mheard.dat + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + $(mkinstalldirs) $(DESTDIR)$(vardir) + @list='$(varfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(vardir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(vardir)/$$p; \ + done + + +sbin_PROGRAMS = ax25d axctl axparms axspawn beacon bpqparms mheardd rxecho + +bin_PROGRAMS = mheard + +man_MANS = ax25.4 ax25d.conf.5 axports.5 axspawn.conf.5 rxecho.conf.5 \ + ax25d.8 axctl.8 axparms.8 axspawn.8 beacon.8 bpqparms.8 \ + mheard.1 mheardd.8 rxecho.8 + + + +EXTRA_DIST = $(man_MANS) $(etcfiles) $(varfiles) + +ax25d_SOURCES = ax25d.c +axctl_SOURCES = axctl.c +axparms_SOURCES = axparms.c +axspawn_SOURCES = axspawn.c +beacon_SOURCES = beacon.c +bpqparms_SOURCES = bpqparms.c +mheard_SOURCES = mheard.c +mheardd_SOURCES = mheardd.c +rxecho_SOURCES = rxecho.c diff --git a/ax25/Makefile.in b/ax25/Makefile.in new file mode 100644 index 0000000..ef14c64 --- /dev/null +++ b/ax25/Makefile.in @@ -0,0 +1,563 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +etcfiles = ax25.profile ax25d.conf axspawn.conf rxecho.conf +varfiles = mheard.dat + +sbin_PROGRAMS = ax25d axctl axparms axspawn beacon bpqparms mheardd rxecho + +bin_PROGRAMS = mheard + +man_MANS = ax25.4 ax25d.conf.5 axports.5 axspawn.conf.5 rxecho.conf.5 ax25d.8 axctl.8 axparms.8 axspawn.8 beacon.8 bpqparms.8 mheard.1 mheardd.8 rxecho.8 + + +EXTRA_DIST = $(man_MANS) $(etcfiles) $(varfiles) + +ax25d_SOURCES = ax25d.c +axctl_SOURCES = axctl.c +axparms_SOURCES = axparms.c +axspawn_SOURCES = axspawn.c +beacon_SOURCES = beacon.c +bpqparms_SOURCES = bpqparms.c +mheard_SOURCES = mheard.c +mheardd_SOURCES = mheardd.c +rxecho_SOURCES = rxecho.c +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +mheard_OBJECTS = mheard.o +mheard_LDADD = $(LDADD) +mheard_DEPENDENCIES = +mheard_LDFLAGS = +ax25d_OBJECTS = ax25d.o +ax25d_LDADD = $(LDADD) +ax25d_DEPENDENCIES = +ax25d_LDFLAGS = +axctl_OBJECTS = axctl.o +axctl_LDADD = $(LDADD) +axctl_DEPENDENCIES = +axctl_LDFLAGS = +axparms_OBJECTS = axparms.o +axparms_LDADD = $(LDADD) +axparms_DEPENDENCIES = +axparms_LDFLAGS = +axspawn_OBJECTS = axspawn.o +axspawn_LDADD = $(LDADD) +axspawn_DEPENDENCIES = +axspawn_LDFLAGS = +beacon_OBJECTS = beacon.o +beacon_LDADD = $(LDADD) +beacon_DEPENDENCIES = +beacon_LDFLAGS = +bpqparms_OBJECTS = bpqparms.o +bpqparms_LDADD = $(LDADD) +bpqparms_DEPENDENCIES = +bpqparms_LDFLAGS = +mheardd_OBJECTS = mheardd.o +mheardd_LDADD = $(LDADD) +mheardd_DEPENDENCIES = +mheardd_LDFLAGS = +rxecho_OBJECTS = rxecho.o +rxecho_LDADD = $(LDADD) +rxecho_DEPENDENCIES = +rxecho_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man1dir = $(mandir)/man1 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man8dir = $(mandir)/man8 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mheard_SOURCES) $(ax25d_SOURCES) $(axctl_SOURCES) $(axparms_SOURCES) $(axspawn_SOURCES) $(beacon_SOURCES) $(bpqparms_SOURCES) $(mheardd_SOURCES) $(rxecho_SOURCES) +OBJECTS = $(mheard_OBJECTS) $(ax25d_OBJECTS) $(axctl_OBJECTS) $(axparms_OBJECTS) $(axspawn_OBJECTS) $(beacon_OBJECTS) $(bpqparms_OBJECTS) $(mheardd_OBJECTS) $(rxecho_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ax25/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mheard: $(mheard_OBJECTS) $(mheard_DEPENDENCIES) + @rm -f mheard + $(LINK) $(mheard_LDFLAGS) $(mheard_OBJECTS) $(mheard_LDADD) $(LIBS) + +ax25d: $(ax25d_OBJECTS) $(ax25d_DEPENDENCIES) + @rm -f ax25d + $(LINK) $(ax25d_LDFLAGS) $(ax25d_OBJECTS) $(ax25d_LDADD) $(LIBS) + +axctl: $(axctl_OBJECTS) $(axctl_DEPENDENCIES) + @rm -f axctl + $(LINK) $(axctl_LDFLAGS) $(axctl_OBJECTS) $(axctl_LDADD) $(LIBS) + +axparms: $(axparms_OBJECTS) $(axparms_DEPENDENCIES) + @rm -f axparms + $(LINK) $(axparms_LDFLAGS) $(axparms_OBJECTS) $(axparms_LDADD) $(LIBS) + +axspawn: $(axspawn_OBJECTS) $(axspawn_DEPENDENCIES) + @rm -f axspawn + $(LINK) $(axspawn_LDFLAGS) $(axspawn_OBJECTS) $(axspawn_LDADD) $(LIBS) + +beacon: $(beacon_OBJECTS) $(beacon_DEPENDENCIES) + @rm -f beacon + $(LINK) $(beacon_LDFLAGS) $(beacon_OBJECTS) $(beacon_LDADD) $(LIBS) + +bpqparms: $(bpqparms_OBJECTS) $(bpqparms_DEPENDENCIES) + @rm -f bpqparms + $(LINK) $(bpqparms_LDFLAGS) $(bpqparms_OBJECTS) $(bpqparms_LDADD) $(LIBS) + +mheardd: $(mheardd_OBJECTS) $(mheardd_DEPENDENCIES) + @rm -f mheardd + $(LINK) $(mheardd_LDFLAGS) $(mheardd_OBJECTS) $(mheardd_LDADD) $(LIBS) + +rxecho: $(rxecho_OBJECTS) $(rxecho_DEPENDENCIES) + @rm -f rxecho + $(LINK) $(rxecho_LDFLAGS) $(rxecho_OBJECTS) $(rxecho_LDADD) $(LIBS) + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done + +install-man4: + $(mkinstalldirs) $(DESTDIR)$(man4dir) + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man4dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man4dir)/$$inst; \ + done + +uninstall-man4: + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man4dir)/$$inst"; \ + rm -f $(DESTDIR)$(man4dir)/$$inst; \ + done + +install-man5: + $(mkinstalldirs) $(DESTDIR)$(man5dir) + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \ + done + +uninstall-man5: + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \ + rm -f $(DESTDIR)$(man5dir)/$$inst; \ + done + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man1 install-man4 install-man5 \ + install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man1 uninstall-man4 uninstall-man5 \ + uninstall-man8 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = ax25 + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +ax25d.o: ax25d.c ../config.h ../pathnames.h +axctl.o: axctl.c ../config.h +axparms.o: axparms.c ../config.h ../pathnames.h +axspawn.o: axspawn.c ../pathnames.h +beacon.o: beacon.c ../config.h +bpqparms.o: bpqparms.c ../config.h +mheard.o: mheard.c ../config.h ../pathnames.h +mheardd.o: mheardd.c ../config.h ../pathnames.h +rxecho.o: rxecho.c ../config.h ../pathnames.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(sbindir) \ + $(DESTDIR)$(mandir)/man1 $(DESTDIR)$(mandir)/man4 \ + $(DESTDIR)$(mandir)/man5 $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-sbinPROGRAMS \ + mostlyclean-compile mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-sbinPROGRAMS clean-compile clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-sbinPROGRAMS \ + distclean-compile distclean-tags distclean-generic \ + clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-sbinPROGRAMS maintainer-clean-compile \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS clean-sbinPROGRAMS \ +maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile install-man1 uninstall-man1 \ +install-man4 uninstall-man4 install-man5 uninstall-man5 install-man8 \ +uninstall-man8 install-man uninstall-man tags mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + $(mkinstalldirs) $(DESTDIR)$(vardir) + @list='$(varfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(vardir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(vardir)/$$p; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ax25/ax25.4 b/ax25/ax25.4 new file mode 100644 index 0000000..6456971 --- /dev/null +++ b/ax25/ax25.4 @@ -0,0 +1,77 @@ +.TH AX25 4 "15 October 1996" Linux "Linux Programmer's Manual" +.SH NAME +AF_AX25 \- AX.25 amateur packet radio protocol family +.SH DESCRIPTION +.LP +.B AX.25 +is a protocol used extensively by radio amateurs. The Linux AX.25 protocol +family permits access to these protocols via the standard networking +.B socket +metaphor. +.LP +The AX.25 protocol layer supports both connected mode and datagram (UI) +frame modes. IP traffic may be stacked on top of AX.25 frames for IP +transmission over the AX.25 medium. +.LP +The primary mode of operation is connected mode which is the mode used for a +socket of type SOCK_SEQPACKET (stream sockets are not available in AX.25). +This requires that the user ensures output data is suitably packetised, and +that input data is read a packet at a time into a buffer of suitable size. +The Linux AX.25 protocol layer can operate in standard AX.25 mode with three +bit sequence numbers or in PE1CHL extended AX.25 mode which uses seven bit +sequence numbers. The protocol passed to the socket is used for all outgoing +frames. Passing 0 causes the normal AX.25 Text PID to be used. +.LP +SOCK_DGRAM gives access to AX.25 UI frames. For access to special frames (of +any form) SOCK_RAW can be used. There is no SOCK_PACKET support under AX.25. +Instead an AF_INET socket of type SOCK_PACKET should be used. +.LP +AX.25 addresses consist of 6 ascii characters and a number called the SSID. +These are encoded into a sockaddr_ax25 structure which is provided to the +relevant system calls. When digipeaters are included a callsign path can be +much more complex. When this is the case a struct full_sockaddr_ax25 should +be passed to the system calls. +.LP +AX.25 has some unusual properties. Notably in a multi-user system an AX.25 +address is often associated with a user, and some users may not have such an +association. a set of ioctl calls are provided to manage an association +table, and in addition the superuser may use an arbitary callsign by binding +to the callsign desired and specifying the port to use as a first digipeated +hop. +.LP +AX.25 supports the following socket options for SOL_AX25. AX25_T1 is the T1 +timer in 1/10ths of a second, AX25_T2 is the T2 timer in 1/10ths of a +second, AX25_T3 is the T3 timer. The window is settable with AX25_WINDOW. +AX25_N2, the retry counter is also configurable. There is no 'infinite +retry' option supported however. The method of backoff for retries is +configurable via the socket option AX25_BACKOFF, a value of true indicates +the use of exponential backoff and false simple linear backoff. The mode of +a connection made be altered to be either standard AX.25 or extended AX.25 +via AX25_EXTSEQ. It is possible to have the complete AX.25 header returned +to the application by setting AX25_HDRINCL to true, programs must be aware +of the internal structure of AX.25 frames to use this option. Note that if +AX.25 fragmentation is encountered, only the control information of the +first frame is returned along with the defragmented data. +.SH "SEE ALSO" +.BR call (1), +.BR socket (2), +.BR setsockopt (2), +.BR getsockopt (2), +.BR axctl (8), +.BR axparms (5), +.BR axassociate (8), +.BR axparms (8), +.BR kissattach (8). +.LP +.SH BUGS +.LP +Too numerous to list in full currently. +.TP 3 +\(bu +Minor protocol violations exist. +.SH AUTHOR +.nf +Alan Cox GW4PTS <alan@cymru.net> +.br +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> +.fi diff --git a/ax25/ax25.profile b/ax25/ax25.profile new file mode 100644 index 0000000..dbb2c5c --- /dev/null +++ b/ax25/ax25.profile @@ -0,0 +1,2 @@ +#! /bin/bash +echo "/char ibmpc ibmpc" >.conversrc diff --git a/ax25/ax25d.8 b/ax25/ax25d.8 new file mode 100644 index 0000000..96ceec4 --- /dev/null +++ b/ax25/ax25d.8 @@ -0,0 +1,46 @@ +.TH AX25D 8 "27 August 1996" Linux "Linux System Managers Manual" +.SH NAME +ax25d \- General purpose AX.25, NET/ROM and Rose daemon +.SH SYNOPSIS +.B ax25d [-v] [-c altconffile] [-l] +.SH DESCRIPTION +.LP +.B Ax25d +is a general purpose server daemon that listens on a number of AX.25, NET/ROM +and Rose ports and offers different services depending upon port, callsign +and other parameters. +.B Ax25d +is driven by a complex configuration file, a full description of which may +be found in another manual page. +.sp 1 +.B AX25d +has the facility to log information about incoming connections to the +system log file. By default no logging is done. When +.B ax25d +is running, and a change in the configuration file is made, +.B ax25d +can be forced to re-read its configuration file by sending it a SIGHUP. +.SH OPTIONS +.TP 15 +.BI "\-c altconffile" +Specifies an alternate configuration file name. +.TP 15 +.BI \-l +Specifies that messages should be logged into the system log file. By default +no messages are logged. +.TP 15 +.BI \-v +Display the version. +.SH FILES +.LP +/etc/ax25/ax25d.conf +.SH "SEE ALSO" +.BR kill (1), +.BR ax25 (4), +.BR netrom (4), +.BR rose (4), +.BR ax25d.conf (5). +.SH AUTHOR +Darryl Miles G7LED <dlm@frink.demon.co.uk> +.br +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/ax25/ax25d.c b/ax25/ax25d.c new file mode 100644 index 0000000..8d45713 --- /dev/null +++ b/ax25/ax25d.c @@ -0,0 +1,1195 @@ +/* + * This is my version of axl.c, written for the LBBS code to make it + * compatable with the kernel AX25 driver. It appears to work, with + * my setup, so it'll probably not work else where :-). + * + * This was inspired by the example code written by Alan Cox (GW4PTS) + * axl.c in AX25USER.TGZ from sunacm.swan.ac.uk. + * + * + * Copyright (C) 1995, 1996 by Darryl L. Miles, G7LED. + * Copyright (C) 1996 by Jonathan Naylor G4KLX + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * + * Just a quickie Feb 1995. + * It *was* just a quickie (at the time) but you'd know how these things + * just... Apr 1995. + * + * If your AX25/NETROM system is relying on this code for + * securetty/firewalling then please be aware this has been coded + * with the intent on striving on through system/(mis)configuration + * errors in the hope that at worst it will run with a degraded + * service. Rather than leave your system providing no service at + * all, if opinions require the old behavior back when let me know + * and I'll #ifdef it in. + * + * + * History: + * + * 1.0 Feb 1995 Basic AX25 listening daemon, Multi-port, Call + * matching, etc... + * + * 1.1 Feb 1995 Moved entry scanning before fork(). + * Added setgroups() to plug security hole. + * Minor fixes + Improved handling. + * + * 1.2 Apr 1995 NETROM support added from developing AX25 + * 028b/029. + * Added 'defaults' port setting. + * Added FLAG_NODIGIS. + * + * 1.3 Jul 1995 Make it a little more intelligent about what to + * do with errors. + * Added exec and argv[0] as two different fields, + * much like inetd uses. + * + * 1.4 Aug 1995 Confirmed support for AX25 030 (1.3.20 + hacks), + * it appears to work. + * It will now bootup even if initial config errors + * occur when setting up and binding (e.g. port(s) + * down), it will skip the port(s) with a problem + * and listen out on those which are left standing. + * + * 1.5 Aug 1995 Updated old (buggy) libax25.a function copies in axl. + * Causing all sorts of problems. + * + * 1.6 Aug 1995 Reset the 'defaults' entry's when we start parsing + * a new interface. + * + * 1.7 Dec 1995 Added BROKEN_NETROM_KERNEL define for setsockopt. + * + * 1.8 Jan 1996 Added support for AX25_BIND_ANY_DEVICE, specify just + * [CALL-X VIA *]. + * Better param parsing, T1 and T2 now using the real + * time in seconds as params, and not kernel units. + * Connection loggin added, either via it's own logfile + * or syslog. + * Modified 'defaults' to 'parameters'. + * + * 1.9 Jun 1996 Reworked config file parsing to use port names instead + * of callsigns. Reformated source code. + * + * Under alpha: + * BPQ like clever mode called for.... also a mode that + * requires a packet to kick application open. + * A flag/mode which will cause a call to initgroups() + * based on uid. + * Callsign validation check. + * Logging of errors. + * + * + * TODO: + * The timing of the 'accept()' might be changed, defered to the + * child, then that child fork() itself, to stop race conditions + * around 'accept()'. + * Add a config file to allow/disallow connections/services at + * different times of the day to restrict access say. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <pwd.h> +#include <grp.h> +#include <syslog.h> +#include <errno.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <netax25/ax25.h> +#include <netrom/netrom.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/nrconfig.h> +#include <netax25/rsconfig.h> +#include <netax25/daemon.h> + +#include <config.h> + +#include "../pathnames.h" + +/* Maximum number of command line arguments for the application we run */ +#define MAX_ARGS 32 + +#define FLAG_VALIDCALL 0x01 /* NOTUSED */ +#define FLAG_NOLOGGING 0x02 /* Don't log this connection */ +#define FLAG_CHKNRN 0x04 /* Check NetRom Neighbour - NOTUSED */ +#define FLAG_NODIGIS 0x08 /* Disallow digipeated uplinks */ +#define FLAG_LOCKOUT 0x10 /* Disallow connection */ + + +struct axlist { /* Have used same struct for quickness */ + struct axlist *next; /* Port list */ + + char *port; /* Port call, only set across the port list */ + int fd; /* The listening socket fd */ + + int af_type; /* AF_AX25, AF_NETROM or AF_ROSE port */ + + struct axlist *ents; /* Exec line entries */ + char *call; /* Call in listing entries */ + char *node; /* Node call in listing entries */ + uid_t uid; /* UID to run program as */ + gid_t gid; /* GID to run program as */ + char *exec; /* Real exec */ + char *shell; /* Command line. With possible escapes. */ + + unsigned int window; /* Set window to... */ + unsigned long t1; /* Set T1 to... (Retrans timer) */ + unsigned long t2; /* Set T2 to... (Ack delay) */ + unsigned long t3; /* Set T3 to... (Idle Poll timer) */ + unsigned long idle; /* Set T4 to... (Link Drop timer) */ + unsigned long n2; /* Set N2 to... (Retries) */ + unsigned long flags; /* FLAG_ values ORed... */ +}; + +static struct axlist *AXL = NULL; +static char *ConfigFile = CONF_AX25D_FILE; +static char User[10]; /* Room for 'GB9ZZZ-15\0' */ +static char Node[11]; /* Room for 'GB9ZZZ-15\0' */ +static char *Port; +static sig_atomic_t Update = TRUE; /* Cause update on bootup */ +static int Logging = FALSE; + +static void SignalHUP(int); +static void SignalTERM(int); +static void WorkoutArgs(int, char *, int *, char **); +static void SetupOptions(int, struct axlist *); +static int ReadConfig(void); +static unsigned long ParseFlags(const char *, int); +static struct axlist *ClearList(struct axlist *); +static char *stripssid(const char *); + + +int main(int argc, char *argv[]) +{ + struct axlist *axltmp, *paxl, *raxl; + union { + struct full_sockaddr_ax25 ax25; + struct sockaddr_rose rose; + } sockaddr; + struct sigaction act, oact; + int maxfd = -1; + fd_set fdread; + int addrlen; + int cnt; + + while ((cnt = getopt(argc, argv, "c:lv")) != EOF) { + switch (cnt) { + case 'c': + ConfigFile = optarg; + break; + + case 'l': + Logging = TRUE; + break; + + case 'v': + printf("ax25d: %s\n", VERSION); + return 1; + + default: + fprintf(stderr, "Usage: ax25d [-v] [-c altfile] [-l]\n"); + return 1; + } + } + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "ax25d: no AX.25 port data configured\n"); + return 1; + } + + nr_config_load_ports(); + + rs_config_load_ports(); + + if (!daemon_start(TRUE)) { + fprintf(stderr, "ax25d: cannot become a daemon\n"); + return 1; + } + + if (Logging) { + openlog("ax25d", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + act.sa_handler = SignalHUP; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGHUP, &act, &oact); + + act.sa_handler = SignalTERM; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGTERM, &act, &oact); + + for (;;) { + if (Update) { + if (ReadConfig() < 0) { + if (AXL == NULL) { + if (Logging) + syslog(LOG_ERR, "config file reload error, exiting"); + return 1; + } else { + if (Logging) + syslog(LOG_INFO, "config file reload error, continuing with original"); + } + } else { + if (Logging) + syslog(LOG_INFO, "new config file loaded successfuly"); + } + + Update = FALSE; + } + + FD_ZERO(&fdread); + + for (paxl = AXL; paxl != NULL && paxl->fd >= 0; paxl = paxl->next) { + FD_SET(paxl->fd, &fdread); + + if (paxl->fd > maxfd) + maxfd = paxl->fd; + } + + if (select(maxfd + 1, &fdread, NULL, NULL, NULL) <= 0) + continue; + + for (paxl = AXL; paxl != NULL; paxl = paxl->next) { + if (FD_ISSET(paxl->fd, &fdread)) { + pid_t pid; + gid_t grps[2]; + char *argv[MAX_ARGS]; + int argc; + int new; + int i; + + /* + * Setting up a non-blocking accept() so is does not hang up + * - I am not sure at this time why I didn't/don't assign + * the socket non-blocking to start with. + */ + /* + * We really need to setup the netrom window option here so + * that it's negotiated correctly on accepting the connection. + */ + /* + * It would be very useful if recvmsg/sendmsg were supported + * then we can move the call checking up here. + */ + i = TRUE; + ioctl(paxl->fd, FIONBIO, &i); + + addrlen = sizeof(struct full_sockaddr_ax25); + new = accept(paxl->fd, (struct sockaddr *)&sockaddr, &addrlen); + + i = FALSE; + ioctl(paxl->fd, FIONBIO, &i); + + if (new < 0) { + if (errno == EWOULDBLOCK) + continue; /* It's gone ??? */ + + if (Logging) + syslog(LOG_ERR, "accept error %m, closing socket on port %s", paxl->port); + close(paxl->fd); + paxl->fd = -1; + continue; + } + + switch (paxl->af_type) { + case AF_AX25: + strcpy(User, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); + strcpy(Node, ""); + break; + case AF_NETROM: + strcpy(User, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); + strcpy(Node, ax25_ntoa(&sockaddr.ax25.fsa_digipeater[0])); + break; + case AF_ROSE: + strcpy(User, ax25_ntoa(&sockaddr.rose.srose_call)); + strcpy(Node, rose_ntoa(&sockaddr.rose.srose_addr)); + break; + } + + for (raxl = paxl->ents; raxl != NULL; raxl = raxl->ents) { + if (paxl->af_type == AF_NETROM && raxl->node != NULL && Node[0] != '\0') { + if (strchr(raxl->node, '-') == NULL) { + if (strcasecmp(raxl->node, stripssid(Node)) != 0) + continue; /* Found no match (for any SSID) */ + } else { + if (strcasecmp(raxl->node, Node) != 0) + continue; /* Found no match */ + } + } + + if (raxl->call == NULL) /* default */ + break; + + if (strchr(raxl->call, '-') == NULL) { + if (strcasecmp(raxl->call, stripssid(User)) == 0) + break; /* Found a match (for any SSID) */ + } else { + if (strcasecmp(raxl->call, User) == 0) + break; /* Found a match */ + } + } + + addrlen = sizeof(struct full_sockaddr_ax25); + getsockname(new, (struct sockaddr *)&sockaddr, &addrlen); + + switch (paxl->af_type) { + case AF_AX25: + Port = ax25_config_get_port(&sockaddr.ax25.fsa_digipeater[0]); + break; + case AF_NETROM: + Port = nr_config_get_port(&sockaddr.ax25.fsa_ax25.sax25_call); + break; + case AF_ROSE: + Port = rs_config_get_port(&sockaddr.rose.srose_addr); + break; + default: + Port = "???"; + break; + } + + if (raxl == NULL) { + /* No default */ + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { + switch (paxl->af_type) { + case AF_AX25: + syslog(LOG_INFO, "AX.25 %s (%s) rejected - no default", User, Port); + break; + case AF_NETROM: + syslog(LOG_INFO, "NET/ROM %s@%s (%s) rejected - no default", User, Node, Port); + break; + case AF_ROSE: + syslog(LOG_INFO, "Rose %s@%s (%s) rejected - no default", User, Node, Port); + break; + } + } + close(new); + continue; + } + + if (raxl->flags & FLAG_LOCKOUT) { + /* Not allowed to connect */ + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { + switch (raxl->af_type) { + case AF_AX25: + syslog(LOG_INFO, "AX.25 %s (%s) rejected - port locked", User, Port); + break; + case AF_NETROM: + syslog(LOG_INFO, "NET/ROM %s@%s (%s) rejected - port locked", User, Node, Port); + break; + case AF_ROSE: + syslog(LOG_INFO, "Rose %s@%s (%s) rejected - port locked", User, Node, Port); + break; + } + } + close(new); + continue; + } + + if (raxl->af_type == AF_AX25 && (raxl->flags & FLAG_NODIGIS) && sockaddr.ax25.fsa_ax25.sax25_ndigis != 0) { + /* Not allowed to uplink via digi's */ + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) + syslog(LOG_INFO, "AX.25 %s (%s) rejected - digipeaters", User, Port); + close(new); + continue; + } + + pid = fork(); + + switch (pid) { + case -1: + if (Logging) + syslog(LOG_ERR, "fork error %m"); + /* + * I don't think AX25 at the moment will hold the + * connection open, if the above does not make it + * through first time. + */ + close(new); + break; /* Oh well... */ + + case 0: + SetupOptions(new, raxl); + WorkoutArgs(raxl->af_type, raxl->shell, &argc, argv); + + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { + switch (paxl->af_type) { + case AF_AX25: + syslog(LOG_INFO, "AX.25 %s (%s) %s", User, Port, argv[0]); + break; + case AF_NETROM: + syslog(LOG_INFO, "NET/ROM %s@%s (%s) %s", User, Node, Port, argv[0]); + break; + case AF_ROSE: + syslog(LOG_INFO, "Rose %s@%s (%s) %s", User, Node, Port, argv[0]); + break; + } + } + + dup2(new, STDIN_FILENO); + dup2(new, STDOUT_FILENO); + close(new); + + /* + * Might be more efficient if we just went down AXL, + * we cleaned up our parents left overs on bootup. + */ + for (axltmp = AXL; axltmp != NULL; axltmp = axltmp->next) + close(axltmp->fd); + + if (Logging) + closelog(); + + /* Make root secure, before we exec() */ + setgroups(0, grps); /* Strip any supplementary gid's */ + setgid(raxl->gid); + setuid(raxl->uid); + execve(raxl->exec, argv, NULL); + return 1; + + default: + close(new); + break; + } + } + } + } + + /* NOT REACHED */ + return 0; +} + +static void SignalHUP(int code) +{ + Update = TRUE; /* Schedule an update */ +} + +static void SignalTERM(int code) +{ + if (Logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +static void WorkoutArgs(int af_type, char *shell, int *argc, char **argv) +{ + char buffer[1024]; /* Maximum arg size */ + char *sp, *cp; + int cnt = 0; + int args = 0; + + for (cp = shell; *cp != '\0'; cp++) { + if (isspace(*cp) && cnt != 0) { + buffer[cnt] = '\0'; + argv[args++] = strdup(buffer); + cnt = 0; + + if (args == MAX_ARGS - 1) { + argv[args] = NULL; + *argc = args; + return; + } + + continue; + } else if (isspace(*cp)) /* && !cnt */ + continue; + + if (*cp == '%') { + cp++; + + switch(*cp) { + case 'd': /* portname */ + for (sp = Port; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = *sp; + break; + + case 'U': /* username in UPPER */ + for (sp = User; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = toupper(*sp); + break; + + case 'u': /* USERNAME IN lower */ + for (sp = User; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = tolower(*sp); + break; + + case 'S': /* username in UPPER (with SSID) */ + for (sp = User; *sp != '\0'; sp++) + buffer[cnt++] = toupper(*sp); + break; + + case 's': /* USERNAME IN lower (with SSID) */ + for (sp = User; *sp != '\0'; sp++) + buffer[cnt++] = tolower(*sp); + break; + + case 'P': /* nodename in UPPER */ + if (af_type == AF_NETROM) { + for (sp = Node; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = toupper(*sp); + } else { + buffer[cnt++] = '%'; + } + break; + + case 'p': /* NODENAME IN lower */ + if (af_type == AF_NETROM) { + for(sp = Node; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = tolower(*sp); + } else { + buffer[cnt++] = '%'; + } + break; + + case 'R': /* nodename in UPPER (with SSID) */ + if (af_type == AF_NETROM) { + for (sp = Node; *sp != '\0'; sp++) + buffer[cnt++] = toupper(*sp); + } else { + buffer[cnt++] = '%'; + } + break; + + case 'r': /* NODENAME IN lower (with SSID) */ + if (af_type == AF_NETROM) { + for (sp = Node; *sp != '\0'; sp++) + buffer[cnt++] = tolower(*sp); + } else { + buffer[cnt++] = '%'; + } + break; + + case '\0': + case '%': + default: + buffer[cnt++] = '%'; + break; + } + } else { + buffer[cnt++] = *cp; + } + } + + if (cnt != 0) { + buffer[cnt] = '\0'; + argv[args++] = strdup(buffer); + } + + argv[args] = NULL; + *argc = args; +} + +static void SetupOptions(int new, struct axlist *axl) +{ + switch (axl->af_type) { + case AF_AX25: + if (axl->window != 0) + setsockopt(new, SOL_AX25, AX25_WINDOW, &axl->window, sizeof(axl->window)); + if (axl->t1 != 0) + setsockopt(new, SOL_AX25, AX25_T1, &axl->t1, sizeof(axl->t1)); + if (axl->n2 != 0) + setsockopt(new, SOL_AX25, AX25_N2, &axl->n2, sizeof(axl->n2)); + if (axl->t2 != 0) + setsockopt(new, SOL_AX25, AX25_T2, &axl->t2, sizeof(axl->t2)); + if (axl->t3 != 0) + setsockopt(new, SOL_AX25, AX25_T3, &axl->t3, sizeof(axl->t3)); + if (axl->idle != 0) + setsockopt(new, SOL_AX25, AX25_IDLE, &axl->idle, sizeof(axl->idle)); + break; + case AF_NETROM: + if (axl->t1 != 0) + setsockopt(new, SOL_NETROM, NETROM_T1, &axl->t1, sizeof(axl->t1)); + if (axl->n2 != 0) + setsockopt(new, SOL_NETROM, NETROM_N2, &axl->n2, sizeof(axl->n2)); + if (axl->t2 != 0) + setsockopt(new, SOL_NETROM, NETROM_T2, &axl->t2, sizeof(axl->t2)); + break; + case AF_ROSE: + if (axl->idle != 0) + setsockopt(new, SOL_ROSE, ROSE_IDLE, &axl->idle, sizeof(axl->idle)); + break; + } +} + +/**************************** CONFIGURATION STUFF ***************************/ + +static int ReadConfig(void) +{ + struct axlist axl_defaults; + struct axlist *axl_build = NULL; + struct axlist *axl_port = NULL; + struct axlist *axl_ent, *axltmp; + union { + struct full_sockaddr_ax25 ax25; + struct sockaddr_rose rose; + } sockaddr; + struct passwd *pwd; + FILE *fp; + char buffer[2048]; + char *s, *port, *call, *node, *addr = NULL; + unsigned long val; + int addrlen; + int af_type = 0; /* Keep GCC happy */ + int line = 0; + int hunt = TRUE, error = FALSE; + int iamdigi = FALSE, yes; + int parameters = 0; + + memset(&axl_defaults, 0, sizeof(axl_defaults)); + + if ((fp = fopen(ConfigFile, "r")) == NULL) + return -1; + + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + line++; + + if ((s = strchr(buffer, '\n')) != NULL) + *s = '\0'; + if ((s = strchr(buffer, '\r')) != NULL) + *s = '\0'; + + if (buffer[0] == '#') + continue; + + switch (buffer[0]) { + case '[': /* AX25 port call */ + af_type = AF_AX25; + hunt = TRUE; + error = FALSE; + iamdigi = FALSE; + break; + + case '<': /* NETROM iface call */ + af_type = AF_NETROM; + hunt = TRUE; + error = FALSE; + iamdigi = FALSE; + break; + + case '{': /* ROSE iface call */ + af_type = AF_ROSE; + hunt = TRUE; + error = FALSE; + iamdigi = FALSE; + break; + + default: + if (hunt && !error) + goto BadLine; + break; + } + + if (hunt) { /* We've found a Iface entry */ + /* Reset 'defaults' entry on the interface */ + memset(&axl_defaults, 0, sizeof(axl_defaults)); + + switch (af_type) { + case AF_AX25: + if ((s = strchr(buffer, ']')) == NULL) + goto BadLine; + *s = '\0'; + if ((s = strtok(buffer + 1, " \t")) == NULL) + goto BadLine; + port = s; + call = NULL; + if ((s = strtok(NULL, " \t")) != NULL) { + if (strcasecmp(s, "VIA") == 0 || strcasecmp(s, "V") == 0) { + if ((s = strtok(NULL, " \t")) == NULL) + goto BadLine; + } + + call = port; + port = s; + + if ((s = strchr(call, '*')) != NULL) { + iamdigi = TRUE; + *s = '\0'; + } + } + if (strcmp(port, "*") == 0 && call == NULL) { + fprintf(stderr, "ax25d: invalid port name\n"); + continue; + } + if (strcmp(port, "*") != 0) { + if ((addr = ax25_config_get_addr(port)) == NULL) { + fprintf(stderr, "ax25d: invalid AX.25 port '%s'\n", port); + continue; + } + } + if (call == NULL) { + sockaddr.ax25.fsa_ax25.sax25_family = AF_AX25; + sockaddr.ax25.fsa_ax25.sax25_ndigis = 0; + ax25_aton_entry(addr, sockaddr.ax25.fsa_ax25.sax25_call.ax25_call); + } else { + sockaddr.ax25.fsa_ax25.sax25_family = AF_AX25; + sockaddr.ax25.fsa_ax25.sax25_ndigis = 1; + ax25_aton_entry(call, sockaddr.ax25.fsa_ax25.sax25_call.ax25_call); + if (strcmp(port, "*") != 0) + ax25_aton_entry(addr, sockaddr.ax25.fsa_digipeater[0].ax25_call); + else + sockaddr.ax25.fsa_digipeater[0] = null_ax25_address; + } + addrlen = sizeof(struct full_sockaddr_ax25); + break; + + case AF_NETROM: + if ((s = strchr(buffer, '>')) == NULL) + goto BadLine; + *s = '\0'; + port = buffer + 1; + if ((addr = nr_config_get_addr(port)) == NULL) { + fprintf(stderr, "ax25d: invalid NET/ROM port '%s'\n", port); + continue; + } + sockaddr.ax25.fsa_ax25.sax25_family = AF_NETROM; + sockaddr.ax25.fsa_ax25.sax25_ndigis = 0; + ax25_aton_entry(addr, sockaddr.ax25.fsa_ax25.sax25_call.ax25_call); + addrlen = sizeof(struct full_sockaddr_ax25); + break; + + case AF_ROSE: + if ((s = strchr(buffer, '}')) == NULL) + goto BadLine; + *s = '\0'; + if ((s = strtok(buffer + 1, " \t")) == NULL) + goto BadLine; + call = s; + if ((s = strtok(NULL, " \t")) == NULL) + goto BadLine; + if (strcasecmp(s, "VIA") == 0 || strcasecmp(s, "V") == 0) { + if ((s = strtok(NULL, " \t")) == NULL) + goto BadLine; + } + port = s; + if ((addr = rs_config_get_addr(port)) == NULL) { + fprintf(stderr, "ax25d: invalid Rose port '%s'\n", port); + continue; + } + if (strcmp(call, "*") == 0) { + sockaddr.rose.srose_family = AF_ROSE; + sockaddr.rose.srose_ndigis = 0; + rose_aton(addr, sockaddr.rose.srose_addr.rose_addr); + sockaddr.rose.srose_call = null_ax25_address; + } else { + sockaddr.rose.srose_family = AF_ROSE; + sockaddr.rose.srose_ndigis = 0; + rose_aton(addr, sockaddr.rose.srose_addr.rose_addr); + ax25_aton_entry(call, sockaddr.rose.srose_call.ax25_call); + } + addrlen = sizeof(struct sockaddr_rose); + break; + + default: + fprintf(stderr, "ax25d: unknown af_type=%d\n", af_type); + exit(1); + } + + if ((axl_port = calloc(1, sizeof(*axl_port))) == NULL) { + fprintf(stderr, "ax25d: out of memory\n"); + goto Error; + } + + axl_port->port = strdup(port); + axl_port->af_type = af_type; + + if ((axl_port->fd = socket(axl_port->af_type, SOCK_SEQPACKET, 0)) < 0) { + fprintf(stderr, "ax25d: socket: %s\n", strerror(errno)); + free(axl_port->port); + free(axl_port); + error = TRUE; + continue; + } + /* xlz - have to nuke this as this option is gone + * what should be here? + if (iamdigi) { + yes = 1; + setsockopt(axl_port->fd, SOL_AX25, AX25_IAMDIGI, &yes, sizeof(yes)); + } + */ + + if (bind(axl_port->fd, (struct sockaddr *)&sockaddr, addrlen) < 0) { + fprintf(stderr, "ax25d: bind: %s on port %s\n", strerror(errno), axl_port->port); + close(axl_port->fd); + free(axl_port->port); + free(axl_port); + error = TRUE; + continue; + } + + if (listen(axl_port->fd, SOMAXCONN) < 0) { + fprintf(stderr, "ax25d: listen: %s\n", strerror(errno)); + close(axl_port->fd); + free(axl_port->port); + free(axl_port); + error = TRUE; + continue; + } + + /* Add it to the head of the list we are building */ + if (axl_build == NULL) { + axl_build = axl_port; + } else { + for (axltmp = axl_build; axltmp->next != NULL; axltmp = axltmp->next); + axltmp->next = axl_port; + } + + hunt = FALSE; /* Next lines will be entries */ + } else { /* This is an entry */ + if ((axl_ent = calloc(1, sizeof(*axl_ent))) == NULL) { + fprintf(stderr, "ax25d: out of memory\n"); + goto Error; + } + + axl_ent->af_type = axl_port->af_type; /* Inherit this */ + + if ((call = strtok(buffer, " \t")) == NULL) { + free(axl_ent); + continue; + } + + strupr(call); + + if (axl_ent->af_type == AF_NETROM) { + if ((s = strchr(call, '@')) != NULL) { + node = s + 1; + *s = '\0'; + + if (*node == '\0') { + free(axl_ent); + continue; + } + + axl_ent->node = strdup(node); + + if (*call == '\0') + call = "default"; /* @NODE means default@NODE */ + } + } + + parameters = FALSE; + + if (strcasecmp("parameters", call) == 0) + parameters = TRUE; + else if (strcasecmp("default", call) != 0) + axl_ent->call = strdup(call); + + /* Window */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + if (!parameters) { + if (strcmp(s, "*") != 0) + axl_ent->window = atoi(s); + else + axl_ent->window = axl_defaults.window; + } else { + if (strcmp(s, "*") != 0) + axl_defaults.window = atoi(s); + } + + /* T1 */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + if (!parameters) { + if (strcmp(s, "*") != 0) { + val = (unsigned long)(atof(s) / 0.1); + + if (val == 0 || val > 65535) + axl_ent->t1 = axl_defaults.t1; + else + axl_ent->t1 = val; + } else { + axl_ent->t1 = axl_defaults.t1; + } + } else { + if (strcmp(s, "*") != 0) { + val = (unsigned long)(atof(s) / 0.1); + + if (val > 0 && val < 65535) + axl_defaults.t1 = val; + } + } + + /* T2 */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + if (!parameters) { + if (strcmp(s, "*") != 0) { + val = (unsigned long)(atof(s) / 0.1); + + if (val == 0 || val > 65535) + axl_ent->t2 = axl_defaults.t2; + else + axl_ent->t2 = val; + } else { + axl_ent->t2 = axl_defaults.t2; + } + } else { + if (strcmp(s, "*") != 0) { + val = (unsigned long)(atof(s) / 0.1); + + if (val > 0 && val < 65535) + axl_defaults.t2 = val; + } + } + + /* T3 */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + if (!parameters) { + if (strcmp(s, "*") != 0) + axl_ent->t3 = atoi(s); + else + axl_ent->t3 = axl_defaults.t3; + } else { + if (strcmp(s, "*") != 0) + axl_defaults.t3 = atoi(s); + } + + /* Idle */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + if (!parameters) { + if (strcmp(s, "*") != 0) + axl_ent->idle = atoi(s); + else + axl_ent->idle = axl_defaults.idle; + } else { + if (strcmp(s, "*") != 0) + axl_defaults.idle = atoi(s); + } + + /* N2 */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + if (!parameters) { + if (strcmp(s, "*") != 0) + axl_ent->n2 = atoi(s); + else + axl_ent->n2 = axl_defaults.n2; + } else { + if (strcmp(s, "*") != 0) + axl_defaults.n2 = atoi(s); + } + + if (!parameters) { + /* Flags */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + axl_ent->flags = ParseFlags(s, line); + + if (!(axl_ent->flags & FLAG_LOCKOUT)) { + /* Get username */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + if ((pwd = getpwnam(s)) == NULL) { + fprintf(stderr, "ax25d: UID for user '%s' is unknown, ignoring entry\n", s); + goto BadUID; + } + + axl_ent->uid = pwd->pw_uid; + axl_ent->gid = pwd->pw_gid; + + /* Get exec file */ + if ((s = strtok(NULL, " \t")) == NULL) + goto BadArgsFree; + + axl_ent->exec = strdup(s); + + /* Get command line */ + if ((s = strtok(NULL, "")) == NULL) + goto BadArgsFree2; + + axl_ent->shell = strdup(s); + } + + axl_ent->next = NULL; + + if (axl_port->ents == NULL) { + axl_port->ents = axl_ent; + } else { + for (axltmp = axl_port->ents; axltmp->ents != NULL; axltmp = axltmp->ents) + ; + axltmp->ents = axl_ent; + } + } + } + + continue; + +BadLine: + fprintf(stderr, "ax25d: bad config entry on line %d\n", line); + continue; + +BadUID: + if (axl_ent->call != NULL) + free(axl_ent->call); + free(axl_ent); + continue; + +BadArgsFree2: + if (axl_ent->exec != NULL) + free(axl_ent->exec); +BadArgsFree: + if (axl_ent->call != NULL) + free(axl_ent->call); + free(axl_ent); + + /* BadArgs: */ + fprintf(stderr, "ax25d: bad config entry on line %d, not enough fields.\n", line); + continue; + } + + fclose(fp); + + AXL = ClearList(AXL); + AXL = axl_build; /* Assign our built list to AXL */ + + return 0; + +Error: + axl_build = ClearList(axl_build); + return -1; +} + +static unsigned long ParseFlags(const char *kp, int line) +{ + unsigned long flags = 0UL; + + for (; *kp != '\0'; kp++) { + switch (*kp) { + case 'v': + case 'V': + flags |= FLAG_VALIDCALL; + break; + + case 'q': + case 'Q': + flags |= FLAG_NOLOGGING; + break; + + case 'n': + case 'N': + flags |= FLAG_CHKNRN; + break; + + case 'd': + case 'D': + flags |= FLAG_NODIGIS; + break; + + case 'l': + case 'L': + flags |= FLAG_LOCKOUT; + break; + + case '0': + case '*': + case '-': /* Be compatible and allow markers */ + break; + + default: + fprintf(stderr, "ax25d: config file line %d bad flag option '%c'.\n", line, *kp); + break; + } + } + + return flags; +} + +static struct axlist *ClearList(struct axlist *list) +{ + struct axlist *tp1, *tp2, *tmp; + + for (tp1 = list; tp1 != NULL; ) { + for (tp2 = tp1->ents; tp2 != NULL; ) { + if (tp2->port != NULL) + free(tp2->port); + if (tp2->call != NULL) + free(tp2->call); + if (tp2->node != NULL) + free(tp2->node); + if (tp2->exec != NULL) + free(tp2->exec); + if (tp2->shell != NULL) + free(tp2->shell); + + tmp = tp2->ents; + free(tp2); + tp2 = tmp; + } + + if (tp1->port != NULL) + free(tp1->port); + if (tp1->call != NULL) + free(tp1->call); + if (tp1->node != NULL) + free(tp1->node); + if (tp1->exec != NULL) + free(tp1->exec); + if (tp1->shell != NULL) + free(tp1->shell); + + close(tp1->fd); + + tmp = tp1->next; + free(tp1); + tp1 = tmp; + } + + return NULL; +} + +static char *stripssid(const char *call) +{ + static char newcall[10]; + char *s; + + strcpy(newcall, call); + + if ((s = strchr(newcall, '-')) != NULL) + *s = '\0'; + + return newcall; +} diff --git a/ax25/ax25d.conf b/ax25/ax25d.conf new file mode 100644 index 0000000..c55f7ba --- /dev/null +++ b/ax25/ax25d.conf @@ -0,0 +1,45 @@ +# /etc/ax25/ax25d.conf +# +# ax25d Configuration File. +# +# AX.25 Ports begin with a '['. +# +[OH2BNS VIA 1] +NOCALL * * * * * * L +default * * * * * * - root /usr/local/sbin/ttylinkd ttylinkd +# +[OH2BNS-2 VIA 1] +NOCALL * * * * * * L +default * * * * * * - root /usr/sbin/node node +# +# +[OH2BNS VIA 2] +NOCALL * * * * * * L +default * * * * * * - root /usr/local/sbin/ttylinkd ttylinkd +# +[OH2BNS-2 VIA 2] +NOCALL * * * * * * L +default * * * * * * - root /usr/sbin/node node +# +[OH2BNS-3 VIA 2] +NOCALL * * * * * * L +default * * * * * * - root /usr/local/sbin/axwrapper axwrapper /usr/bin/finger finger +# +#[OH2BNS-9] +#NOCALL * * * * * * L +#default * * * * * * - root /usr/sbin/node node +# +# NET/ROM Ports begin with a '<'. +# +#<netrom> +#NOCALL * * * * * * L +#default * * * * * * - root /usr/local/sbin/ttylinkd ttylinkd +# +<netrom> +NOCALL * * * * * * L +default * * * * * * - root /usr/sbin/node node +# +#<netrom> +#NOCALL * * * * * * L +#default * * * * * * - root /usr/sbin/node node +# diff --git a/ax25/ax25d.conf.5 b/ax25/ax25d.conf.5 new file mode 100644 index 0000000..446c0e3 --- /dev/null +++ b/ax25/ax25d.conf.5 @@ -0,0 +1,269 @@ +.TH AX25D.CONF 5 "17 January 1997" Linux "Linux Programmer's Manual" +.SH NAME +ax25d.conf \- ax25d configuration file. +.SH DESCRIPTION +.LP +.B Ax25d.conf +controls the functioning of +.B ax25d. +Its purpose is to specify on which ports to listen on, which applications +are available, and to whom they are available to. The configuration file is +common to both AX.25, NET/ROM and Rose and their is similarity between the +two parts of the file. +.sp 1 +The general layout for an entry for a given port is as follows: +.sp 1 +.RS +interface control +.br +callsign entry 1 +.br + . +.br + . +.br +callsign entry n +.RE +.sp 1 +The +.B "interface control" +line determines which port and callsigns apply to the following +.B "callsign entry" +lines, until the next +.B "interface control" +is read. There are four different variants of the +.B "interface control" +line: +.sp 1 +.RS +1. [AX.25 Port Name] +.br +2. [Callsign VIA AX.25 Port Name] +.br +3. <NET/ROM Port Name> +.br +4. {Callsign VIA Rose Port Name} +.RE +.sp 1 +Version 1 allows the following +.B "callsign entry" +lines to listen on the AX.25 port specified by the AX.25 port name using the +default callsign of that AX.25 port. +.sp 1 +Version 2 allows the following +.B "callsign entry" +lines to listen on the AX.25 port specified by the AX.25 port name using the +callsign specified instead of the default callsign of that AX.25 port. +Specifying a * for the AX.25 port name allows the following +.B "callsign entries" +to be valid for all the operating AX.25 ports using the callsign specified. VIA +can be abbreviated to just V. If the callsign has an asterisk appended to it +then the system will be listening on the port with the callsign, but as a +pseudo-digipeater instead of being the normal destination callsign. +.sp 1 +Version 3 allows the following +.B "callsign entry" +lines to listen on the NET/ROM port specified by the NET/ROM port name using +the default callsign of that NET/ROM port. +.sp 1 +Version 4 allows the following +.B "callsign entry" +lines to listen on the Rose port using the specified Rose port name using +the callsign specified as the service access point (SAP). A * may be +specified for a callsign to allow matching to any incoming Call Requests +with any SAP. +.sp 1 +The +.B "callsign entry" +lines have a similar layout for both AX.25, NET/ROM and Rose, the layout is: +.sp 1 +.RS +peer window t1 t2 t3 idle n2 mode uid exec args... +.RE +.sp 1 +All values must be entered for all entries even when they are not used (ie +window for NET/ROM, just enter a * instead), The meanings of each of the +fields is given below. All timings apart from the idle value are given in +seconds, the idle values is given in minutes. +.RS +.TP 10 +.B peer +This specifies the callsign of the remote end of the connection that should +have the following parameters and executable set up for them. The syntax of +the peer argument is explained below. +.TP 10 +.B window +This sets the the value of the window size, if a value of * is entered in this +field then the default value for the port is taken from the \(lqparameters\(rq +entry (see below) or lacking such an entry, the kernel default value is used. +This entry is used by AX.25 but not by NET/ROM or Rose. +.TP 10 +.B t1 +This sets the the value of the T1 timer, if a value of * is entered in this +field then the default value for the port is taken from the \(lqparameters\(rq +entry (see below) or lacking such an entry, the kernel default value is used. +This entry is used by both AX.25 and NET/ROM but not by Rose. +.TP 10 +.B t2 +This sets the the value of the T2 timer, if a value of * is entered in this +field then the default value for the port is taken from the \(lqparameters\(rq +entry (see below) or lacking such an entry, the kernel default value is used. +This entry is used by both AX.25 and NET/ROM but not by Rose. +.TP 10 +.B t3 +This sets the the value of the T3 timer, if a value of * is entered in this +field then the default value for the port is taken from the \(lqparameters\(rq +entry (see below) or lacking such an entry, the kernel default value is used. +This entry is used by AX.25 but not by NET/ROM or Rose. +.TP 10 +.B idle +This sets the the value of the idle timer, if a value of * is entered in +this field then the default value for the port is taken from the +\(lqparameters\(rq entry (see below) or lacking such an entry, the kernel +default value is used. +.TP 10 +.B n2 +This sets the the value of the N2 counter, if a value of * is entered in this +field then the default value for the port is taken from the \(lqparameters\(rq +entry (see below) or lacking such an entry, the kernel default value is used. +This entry is used by both AX.25 and NET/ROM but not by Rose. +.TP 10 +.B mode +This is a set of flags that control the various properties associated with +the incoming connection. The flags are single letters, may be in either +upper or lower case, and there may not be any spaces between them. If no +flags are to be specified either a 0, - or a * must be entered instead. The +valid mode flag letters are: +.RS +.TP 5 +.B D +Do not allow connections that have passed via any digi-peaters. AX.25 only. +.TP 5 +.B L +Do not allow this station to connect, they are Locked out. +.TP 5 +.B N +Check that the NET/ROM neighbour is allowed, currently unused. +.TP 5 +.B Q +Do not make an entry into the log file for this connection. +.TP 5 +.B V +Validate the callsign of the incoming connection, currently unused. +.RE +.TP 10 +.B uid +This is the userid that the following command should run under when +executing. +.TP 10 +.B exec +This is the executable that should be executed when an incoming connection +matches the criteria of both the +.B "interface control" +and the +.B "callsign entry". +.TP 10 +.B args... +These are the optional arguments that are passed to the executable. All of +the arguments are passed literally apart from the following: +.RS +.TP 5 +.B %d +The name of the port that the connection is on. +.TP 5 +.B %U +The username (callsign) of the remote station in upper case without the SSID. +.TP 5 +.B %u +The username (callsign) of the remote station in lower case without the SSID. +.TP 5 +.B %S +The username (callsign) of the remote station in upper case with the SSID. +.TP 5 +.B %s +The username (callsign) of the remote station in lower case with the SSID. +.TP 5 +.B %P +The nodename of the remote station in upper case without the SSID. +This is only valid under NET/ROM and Rose, under AX.25 a % is substituted instead. +.TP 5 +.B %p +The nodename of the remote station in lower case without the SSID. +This is only valid under NET/ROM and Rose, under AX.25 a % is substituted instead. +.TP 5 +.B %R +The nodename of the remote station in upper case with the SSID. +This is only valid under NET/ROM and Rose, under AX.25 a % is substituted instead. +.TP 5 +.B %r +The nodename of the remote station in lower case with the SSID. +This is only valid under NET/ROM and Rose, under AX.25 a % is substituted instead. +.TP 5 +.B %% +A %. +.RE +.RE +.sp 1 +The +.B peer +argument is dependant upon whether AX.25, NET/ROM or Rose is being used. There are +five formats of this argument: +.sp 1 +.RS +1. default +.br +2. parameters +.br +3. callsign +.br +4. callsign@node +.br +5. @node +.RE +.sp 1 +The first version is used by AX.25, NET/ROM and Rose to specify that all callsigns +on a given port are to be matched. The default line is usually the last of the +.B "callsign entry" +lines, so that more specific entries may have the chance to be matched +first. +.sp 1 +The second version is not a +.B "callsign entry" +that is used by any incoming connections. It is a means to specify default +values for parameters such as Window, T1, T2, T3, Idle and N2. It is used for +both AX.25, NET/ROM and Rose. +.sp 1 +The third version is used by both AX.25, NET/ROM and Rose to specify the callsign of +the remote station to match the +.B "callsign entry" +line. If no SSID is specified then the callsign will be matched with any +that has the same callsign and any SSID. Specifying an SSID causes the +callsign to be matched exactly. In the case of NET/ROM and Rose this entry does not +specify which node the originating callsign comes from. +.sp 1 +The fourth version is used by NET/ROM and Rose to specify the callsign of the remote +station and the remote node to match the +.B "callsign entry" +line. If no SSID is specified in the callsign section then the callsign will +be matched with any that has the same callsign and any SSID. Specifying an +SSID causes the callsign to be matched exactly. +.sp 1 +The fifth version is used by NET/ROM and Rose to specify only the address of the +remote node to match the +.B "callsign entry" +line. This entry will mean that all remote users at the given node will +match the entry. +.sp 1 +Comments may be embedded in the configuration file by placing a # in the +first column. +.SH FILES +.LP +/etc/ax25/ax25d.conf +.SH "SEE ALSO" +.BR ax25 (4), +.BR netrom (4), +.BR rose (4), +.BR axports (5), +.BR nrports (5), +.BR rsports (5), +.BR ax25d (8). diff --git a/ax25/axctl.8 b/ax25/axctl.8 new file mode 100644 index 0000000..3189aa8 --- /dev/null +++ b/ax25/axctl.8 @@ -0,0 +1,67 @@ +.TH AXCTL 8 "2 August 1996" Linux "Linux System Managers Manual" +.SH NAME +axctl \- Configure/Kill running AX.25 connections. +.SH SYNOPSIS +.B axctl [-v] port dest src -window|-t1|-t2|-t3|-n2|-idle|-paclen|-kill [parm] +.SH DESCRIPTION +.LP +The +.B axctl +command is designed to be a multi-function command that allows miscellaneous +commands to be issued to the Linux AX.25 protocol layer for existing AX.25 +connections. The connection is uniquely identified via the combination of +port, destination callsign and source callsign, with that information the +kernel is able to change the parameters, or abort the connection. +.LP +Many of the options are similar to those found in +.B axparms +and perform the same function. Only one parameter may be changed on each +invokation of +.B axctl. +.SH OPTIONS +.TP 20 +.BI \-v +Displays the version number. +.TP 20 +.BI "\-window window" +Sets the window size for the AX.25 connection. +.TP 20 +.BI "\-t1 t1\-timeout" +Sets the initial T1 timeout value for the AX.25 connection, the value is given in +seconds. +.TP 20 +.BI "\-t2 t2\-timeout" +Sets the T2 timeout value for the AX.25 connection, the value is given in +seconds. +.TP 20 +.BI "\-t3 t3\-timeout" +Sets the T3 timeout value for the AX.25 connected, the value is given in +seconds. +.TP 20 +.BI "\-n2 n2\-count" +Sets the maximum number of tries for the AX.25 connection. +.TP 20 +.BI "\-idle idle-timeout" +Sets the value for the idle timer for the AX.25 connection, the value is in +minutes. +.TP 20 +.BI "\-paclen paclength" +Sets the maximum packet length that may be transmitted on the AX.25 +connection. +.TP 20 +.BI "\-kill" +Will abort an existing AX.25 connection. +.SH FILES +.LP +/etc/ax25/axports +.SH "SEE ALSO" +.BR call (1), +.BR getsockopt (2), +.BR setsockopt (2), +.BR ax25 (4), +.BR axparms (8), +.BR axports (5). +.SH AUTHORS +.nf +Joerg Reuter DL1BKE <jreuter@poboxes.com> +.fi diff --git a/ax25/axctl.c b/ax25/axctl.c new file mode 100644 index 0000000..84422fd --- /dev/null +++ b/ax25/axctl.c @@ -0,0 +1,92 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <pwd.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> + +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> + +#include <config.h> + +int main(int argc, char **argv) +{ + struct ax25_ctl_struct ax25_ctl; + char *addr; + int s; + + if (argc == 2 && strncmp(argv[1], "-v", 2) == 0) { + printf("axctl: %s\n", VERSION); + return 0; + } + + if (argc < 5) { + fprintf(stderr, "Usage: axctl [-v] port dest src -t1|-t2|-t3|-n2|-paclen|-idle|-window|-maxq|-kill parm\n"); + return 1; + } + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "axctl: no AX.25 port data configured\n"); + return 1; + } + + if ((addr = ax25_config_get_addr(argv[1])) == NULL) { + fprintf(stderr, "axctl: invalid port name - %s\n", argv[1]); + return 1; + } + + if (ax25_aton_entry(addr, (char *)&ax25_ctl.port_addr) == -1) + return 1; + if (ax25_aton_entry(argv[2], (char *)&ax25_ctl.dest_addr) == -1) + return 1; + if (ax25_aton_entry(argv[3], (char *)&ax25_ctl.source_addr) == -1) + return 1; + + if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) { + perror("axctl: socket"); + return 1; + } + + if (strcmp(argv[4], "-kill") == 0) { + ax25_ctl.cmd = AX25_KILL; + ax25_ctl.arg = 0; + } else { + if (argc < 6) { + fprintf(stderr,"axctl: parameter missing\n"); + return 1; + } + ax25_ctl.arg = atoi(argv[5]); + + if (strcmp(argv[4], "-t1") == 0) + ax25_ctl.cmd = AX25_T1; + else if (strcmp(argv[4], "-t2") == 0) + ax25_ctl.cmd = AX25_T2; + else if (strcmp(argv[4], "-t3") == 0) + ax25_ctl.cmd = AX25_T3; + else if (strcmp(argv[4], "-idle") == 0) + ax25_ctl.cmd = AX25_IDLE; + else if (strcmp(argv[4], "-n2") == 0) + ax25_ctl.cmd = AX25_N2; + else if (strcmp(argv[4], "-window") == 0) + ax25_ctl.cmd = AX25_WINDOW; + else if (strcmp(argv[4], "-paclen") == 0) + ax25_ctl.cmd = AX25_PACLEN; + } + + if (ioctl(s, SIOCAX25CTLCON, &ax25_ctl) != 0) { + perror("axctl: SIOAX25CTLCON"); + return 1; + } + + return 0; +} + diff --git a/ax25/axparms.8 b/ax25/axparms.8 new file mode 100644 index 0000000..627adbf --- /dev/null +++ b/ax25/axparms.8 @@ -0,0 +1,119 @@ +.TH AXPARMS 8 "25 July 1997" Linux "Linux System Managers Manual" +.SH NAME +axparms \- Configure AX.25 interfaces. +.SH SYNOPSIS +.B axparms -assoc|-forward|-route|-setcall|-version ... +.SH DESCRIPTION +.LP +The +.B axparms +command is designed to be a multi-function command that allows miscellaneous +commands to be issued to the Linux AX.25 protocol layer. It includes the +functionality of +.B axassociate +and +.B axsetcall +which this command superceedes. The different modes of the command are +chosen by the first argument. Sunsequent arguments depend upon this argument +and so no generalised command format can be given. +.SH "-assoc Argument" +.LP +The format of this option is: +.LP +.nf +.B axparms -assoc <callsign> <username> +.br +.B axparms -assoc <callsign> delete +.br +.B axparms -assoc policy [default|deny] +.br +.B axparms -assoc show +.fi +.LP +This option mainpulates the kernel uid/callsign mapping table, allowing +callsigns to be associated and dis-associated with a user. The +.B policy +option permits the superuser to have all other uid's either default to the +actual port name, or to block traffic. +.LP +At power up the table is blank and the policy is 'default', which is thus +backward compatible. +.SH "-forward Argument" +.LP +Allows the use of many receivers with one transmitter, known as packet +forwarding in many systems. The format of this command is: +.LP +.nf +.B axparms -forward <portfrom> <portto> +.br +.B axparms -forward <portfrom> delete +.fi +.LP +Any packets to be transmitted on port portfrom will be transmitted on port +portto. This will stay in force until the second form of the command is +issued which will remove the association. +.SH "-route Argument" +.LP +This option allows the internal AX.25 routing table to be manipulated. This +table is available for reading in /proc/net/ax25_route, and will be built up +dynamically by stations heard. However it is possible to add, delete and list +entries via this option. +.LP +The formats of this option are: +.LP +.nf +.B axparms -route add <port> <callsign> [<digis>] [-ipmode V|D] +.br +.B axparms -route del <port> <callsign> +.fi +.B axparms -route list +.fi +.LP +Routes added via this command will not be removed from the internal routing +table when they are \(lqold\(rq as normal entries are. The +.B -ipmode +option sets mode vc or mode datagram for this destination. +.LP +If the <callsign> argument is set to \(lqdefault\(rq then this will set the +default route for all outgoing AX.25 connections which will be used when there +is no specific route to the required destination. +.SH "-setcall Argument" +.LP +The format of this option is: +.LP +.B axparms -setcall <serial-device> <callsign> +.LP +This changes the callsign associated with the given serial device in KISS mode. +The change is permanent until the link is downed or another \(lqaxparms +-setcall\(rq is made. +.LP +The interface must already have been attached with +.B kissattach +to use this option. +.SH "-version Argument" +.LP +This option displays the version of the AX.25 utilities that +.B axparms +belongs to. +.SH FILES +.LP +/proc/net/ax25_bpqether +.br +/proc/net/ax25_calls +.br +/etc/ax25/axports +.SH "SEE ALSO" +.BR call (1), +.BR getsockopt (2), +.BR setsockopt (2), +.BR ax25 (4), +.BR axctl (8), +.BR axports (5). +.SH AUTHORS +.nf +Alan Cox GW4PTS <alan@cymru.net> +.br +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> +.br +Joerg Reuter DL1BKE <jreuter@poboxes.com> +.fi diff --git a/ax25/axparms.c b/ax25/axparms.c new file mode 100644 index 0000000..5683d46 --- /dev/null +++ b/ax25/axparms.c @@ -0,0 +1,442 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <pwd.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> + +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <config.h> + +#include "../pathnames.h" + +void usage(void) +{ + fprintf(stderr, "usage: axparms -assoc|-forward|-route|-setcall|-version ...\n"); +} + +void usageassoc(void) +{ + fprintf(stderr, "usage: axparms -assoc show\n"); + fprintf(stderr, "usage: axparms -assoc policy default|deny\n"); + fprintf(stderr, "usage: axparms -assoc [callsign] [username]\n"); + fprintf(stderr, "usage: axparms -assoc [callsign] delete\n"); +} + +void usageforward(void) +{ + fprintf(stderr, "usage: axparms -forward <portfrom> <portto>\n"); + fprintf(stderr, "usage: axparms -forward <portfrom> delete\n"); +} + +void usageroute(void) +{ + fprintf(stderr, "usage: axparms -route add port callsign [digi ...] [-ipmode mode]\n"); + fprintf(stderr, "usage: axparms -route del port callsign\n"); + fprintf(stderr, "usage: axparms -route list\n"); +} + +void usagesetcall(void) +{ + fprintf(stderr, "usage: axparms -setcall interface callsign\n"); +} + +int routes(int s, int argc, char *argv[], ax25_address *callsign) +{ + struct ax25_routes_struct ax25_route; + struct ax25_route_opt_struct ax25_opt; + int i, j; + int ip_mode = ' '; + FILE* fp; + char routebuf[80]; + + if (strcmp(argv[2], "add") == 0) { + ax25_route.port_addr = *callsign; + ax25_route.digi_count = 0; + + if (strcmp(argv[4], "default") == 0) { + ax25_route.dest_addr = null_ax25_address; + } else { + if (ax25_aton_entry(argv[4], (char *)&ax25_route.dest_addr) == -1) + return 1; + } + + for (i = 5, j = 0; i < argc && j < 6; i++) { + if (strncmp(argv[i], "-i", 2) == 0) { + if (++i == argc) { + fprintf(stderr, "axparms: -i must have a parameter\n"); + return 1; + } + switch (*argv[i]) { + case 'd': + case 'D': + ip_mode = 'D'; + break; + case 'v': + case 'V': + ip_mode = 'V'; + break; + default: + ip_mode = ' '; + break; + } + } else { + if (ax25_aton_entry(argv[i], (char *)&ax25_route.digi_addr[j]) == -1) + return 1; + ax25_route.digi_count++; + j++; + } + } + + if (ioctl(s, SIOCADDRT, &ax25_route) != 0) { + perror("axparms: SIOCADDRT"); + return 1; + } + + ax25_opt.port_addr = *callsign; + ax25_opt.dest_addr = ax25_route.dest_addr; + ax25_opt.cmd = AX25_SET_RT_IPMODE; + ax25_opt.arg = ip_mode; + + if (ioctl(s, SIOCAX25OPTRT, &ax25_opt) != 0) { + perror("axparms: SIOCAX25OPTRT"); + return 1; + } + } + + if (strcmp(argv[2], "del") == 0) { + ax25_route.port_addr = *callsign; + ax25_route.digi_count = 0; + + if (strcmp(argv[4], "default") == 0) { + ax25_route.dest_addr = null_ax25_address; + } else { + if (ax25_aton_entry(argv[4], (char *)&ax25_route.dest_addr) == -1) + return 1; + } + + if (ioctl(s, SIOCDELRT, &ax25_route) != 0) { + perror("axparms: SIOCDELRT"); + return 1; + } + } + + if (strcmp(argv[2], "list") == 0) { + if ((fp=fopen(PROC_AX25_ROUTE_FILE,"r")) == NULL) { + fprintf(stderr, "axparms: route: cannot open %s\n", +PROC_AX25_ROUTE_FILE); + return 1; + } + while (fgets(routebuf,80,fp)) + printf(routebuf); + puts(""); + } + + return 0; +} + +int setifcall(int s, char *ifn, char *name) +{ + char call[7]; + struct ifreq ifr; + + if (ax25_aton_entry(name, call) == -1) + return 1; + + strcpy(ifr.ifr_name, ifn); + memcpy(ifr.ifr_hwaddr.sa_data, call, 7); + ifr.ifr_hwaddr.sa_family = AF_AX25; + + if (ioctl(s, SIOCSIFHWADDR, &ifr) != 0) { + perror("axparms: SIOCSIFHWADDR"); + return 1; + } + + return 0; +} + +int associate(int s, int argc, char *argv[]) +{ + char buffer[80], *u, *c; + struct sockaddr_ax25 sax25; + struct passwd *pw; + int opt; + FILE *fp; + + + if (strcmp(argv[2], "show") == 0) { + if (argc < 3) { + usageassoc(); + exit(1); + } + + if ((fp = fopen(PROC_AX25_CALLS_FILE, "r")) == NULL) { + fprintf(stderr, "axparms: associate: cannot open %s\n", PROC_AX25_CALLS_FILE); + return 1; + } + + fgets(buffer, 80, fp); + + printf("Userid Callsign\n"); + + while (fgets(buffer, 80, fp) != NULL) { + u = strtok(buffer, " \t\n"); + c = strtok(NULL, " \t\n"); + if ((pw = getpwuid(atoi(u))) != NULL) + printf("%-10s %s\n", pw->pw_name, c); + } + + fclose(fp); + + return 0; + } + + if (strcmp(argv[2], "policy") == 0) { + if (argc < 4) { + usageassoc(); + exit(1); + } + + if (strcmp(argv[3], "default") == 0) { + opt = AX25_NOUID_DEFAULT; + + if (ioctl(s, SIOCAX25NOUID, &opt) == -1) { + perror("axparms: SIOCAX25NOUID"); + return 1; + } + + return 0; + } + + if (strcmp(argv[3], "deny") == 0) { + opt = AX25_NOUID_BLOCK; + + if (ioctl(s, SIOCAX25NOUID, &opt) == -1) { + perror("axparms: SIOCAX25NOUID"); + return 1; + } + + return 0; + } + + fprintf(stderr, "axparms: associate: 'default' or 'deny' required\n"); + + return 1; + } + + if (argc < 4) { + usageassoc(); + exit(1); + } + + if (ax25_aton_entry(argv[2], (char *)&sax25.sax25_call) == -1) { + fprintf(stderr, "axparms: associate: invalid callsign %s\n", argv[2]); + return 1; + } + + if (strcmp(argv[3], "delete") == 0) { + if (ioctl(s, SIOCAX25DELUID, &sax25) == -1) { + perror("axparms: SIOCAX25DELUID"); + return 1; + } + + return 0; + } + + if ((pw = getpwnam(argv[3])) == NULL) { + fprintf(stderr, "axparms: associate: unknown username %s\n", argv[3]); + return 1; + } + + sax25.sax25_uid = pw->pw_uid; + + if (ioctl(s, SIOCAX25ADDUID, &sax25) == -1) { + perror("axparms: SIOCAX25ADDUID"); + return 1; + } + + return 0; +} + +int forward(int s, int argc, char *argv[]) +{ +#ifdef HAVE_AX25_FWD_STRUCT + struct ax25_fwd_struct ax25_fwd; + char *addr; + + if (argc < 4) { + usageforward(); + exit(1); + } + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "axparms: no AX.25 port data configured\n"); + return 1; + } + + if ((addr = ax25_config_get_addr(argv[2])) == NULL) { + fprintf(stderr, "axparms: invalid port name - %s\n", argv[2]); + return 1; + } + + if (ax25_aton_entry(addr, (char *)&ax25_fwd.port_from) == -1) { + fprintf(stderr, "axparms: invalid port name - %s\n", argv[2]); + return 1; + } + + if (strcmp(argv[3], "delete") == 0) { + if (ioctl(s, SIOCAX25DELFWD, &ax25_fwd) == -1) { + perror("axparms: SIOCAX25DELFWD"); + return 1; + } + + return 0; + } + + if ((addr = ax25_config_get_addr(argv[3])) == NULL) { + fprintf(stderr, "axparms: invalid port name - %s\n", argv[3]); + return 1; + } + + if (ax25_aton_entry(addr, (char *)&ax25_fwd.port_to) == -1) { + fprintf(stderr, "axparms: invalid port name - %s\n", argv[3]); + return 1; + } + + if (ioctl(s, SIOCAX25ADDFWD, &ax25_fwd) == -1) { + perror("axparms: SIOCAX25ADDFWD"); + return 1; + } +#else + fprintf(stderr, "axparms: Not compiled in with forwarding option.\n"); +#endif /* HAVE_AX25_FWD_STRUCT */ + + return 0; +} + +int main(int argc, char **argv) +{ + ax25_address callsign; + int s, n; + char *addr; + + if (argc == 1) { + usage(); + return 1; + } + + if (strncmp(argv[1], "-v", 2) == 0) { + printf("axparms: %s\n", VERSION); + return 0; + } + + if (strncmp(argv[1], "-a", 2) == 0) { + + if (argc < 3) { + usageassoc(); + return 1; + } + + if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) { + perror("axparms: socket"); + return 1; + } + + n = associate(s, argc, argv); + + close(s); + + return n; + } + + if (strncmp(argv[1], "-f", 2) == 0) { + if (argc == 2) { + usageforward(); + return 1; + } + + if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) { + perror("axparms: socket"); + return 1; + } + + n = forward(s, argc, argv); + + close(s); + + return n; + } + + if (strncmp(argv[1], "-r", 2) == 0) { + if (argc < 3 ) { + usageroute(); + return 1; + } + + if (strcmp(argv[2], "add") != 0 && strcmp(argv[2], "del") != 0 && strcmp(argv[2], "list") != 0) { + usageroute(); + return 1; + } + + if (argc < 5 && strcmp(argv[2], "list") != 0) { + usageroute(); + return 1; + } + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "axparms: no AX.25 port data configured\n"); + return 1; + } + + if ((addr = ax25_config_get_addr(argv[3])) == NULL) { + fprintf(stderr, "axparms: invalid port name - %s\n", argv[3]); + return 1; + } + + if (ax25_aton_entry(addr, callsign.ax25_call) == -1) + return 1; + + if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) { + perror("axparms: socket"); + return 1; + } + + n = routes(s, argc, argv, &callsign); + + close(s); + + return n; + } + + if (strncmp(argv[1], "-s", 2) == 0) { + if (argc != 4) { + usagesetcall(); + return 1; + } + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("axparms: socket"); + return 1; + } + + n = setifcall(s, argv[2], argv[3]); + + close(s); + + return n; + } + + usage(); + + return 1; +} diff --git a/ax25/axports.5 b/ax25/axports.5 new file mode 100644 index 0000000..fc61a47 --- /dev/null +++ b/ax25/axports.5 @@ -0,0 +1,62 @@ +.TH AXPORTS 5 "15 October 1996" Linux "Linux Programmer's Manual" +.SH NAME +axports \- AX.25 port configuration file. +.SH DESCRIPTION +.LP +.B Axports +is an ASCII file that contains information about each of the physical AX.25 +ports that are to be used. When dealing with an AX.25 utility such as +.B call, +it takes an optional argument that is the port name. This port name is a +reference to the line within +.B axports, +which has that name as its first argument. The information on each line +contains enough information to bind the command to a particular physical AX.25 +interface, this binding is done by matching the callsign on the line in +.B axports +with the callsign of the port set by +.B kissattach. +.LP +The lines within +.B axports +must either be a comment line, which starts with a # in the first column, or +a port description in the following format, each field being delimited by +white space: +.sp +.RS +name callsign speed paclen window description +.RE +.sp +The field descriptions are: +.sp +.RS +.TP 14 +.B name +is the unique identifier of the port. This is the name given as the port +argument of many of the AX.25 support programs. +.TP 14 +.B callsign +the callsign of the physical interface to bind to. +.TP 14 +.B speed +this is the speed of interface, a value of zero means that no speed will be +set by kissattach(8). +.TP 14 +.B paclen +is the default maximum packet size for this interface. +.TP 14 +.B window +the default window size for this interface. +.TP 14 +.B description +a free format description of this interface, this field extends to the end +of the line. This field may contain spaces. +.RE +.SH FILES +.LP +/etc/ax25/axports +.SH "SEE ALSO" +.BR call (1), +.BR ax25 (4), +.BR axparms (8), +.BR kissattach (8). diff --git a/ax25/axspawn.8 b/ax25/axspawn.8 new file mode 100644 index 0000000..ccb6934 --- /dev/null +++ b/ax25/axspawn.8 @@ -0,0 +1,52 @@ +.TH AXSPAWN 8 "25 August 1996" Linux "Linux System Managers Manual" +.SH NAME +axspawn \- Allow automatic login to a Linux system. +.SH SYNOPSIS +.B axspawn [--wait, -w] +.SH DESCRIPTION +.LP +.B Axspawn +will check if the peer is an AX.25 connect, the callsign a valid Amateur +Radio callsign, strip the SSID, check if UID/GID are valid, allow a +password-less login if the password-entry in /etc/passwd is \(lq+\(rq or +empty; in every other case login will prompt for a password. +.LP +.B Axspawn +can create user accounts automatically. You may specify the user shell, +first and maximum user id, group ID in the config file and (unlike WAMPES) +create a file \(lq/etc/ax25/ax25.profile\(rq which will be copied to +~/.profile. +.SH SECURITY +.LP +Auto accounting is a security problem by definition. Unlike WAMPES, which +creates an empty password field, Axspawn adds an \(lqimpossible\(rq ('+') +password to /etc/passwd. Login gets called with the \(lq-f\(rq option, thus +new users have the chance to login without a password. (I guess this won't +work with the shadow password system). +.LP +Of course +.B axspawn +does callsign checking: Only letters and numbers are allowed, the callsign +must be longer than 4 characters and shorter than 6 characters (without +SSID). There must be at least one digit, and max. two digits within the +call. The SSID must be within the range of 0 and 15. Please drop me a note +if you know a valid Amateur Radio callsign that does not fit this pattern +_and_ can be represented correctly in AX.25. +.SH OPTIONS +.TP 5 +.B -w, --wait +Disables the prompting for a password if the password entry in /etc/passwd +is either a \(lq+\(rq or blank. +.SH FILES +.nf +/etc/passwd +.br +/etc/ax25/ax25.profile +.br +/etc/ax25/axspawn.conf +.fi +.SH "SEE ALSO" +.BR axspawn.conf (5), +.BR ax25d (8). +.SH AUTHOR +Joerg Reuter DL1BKE <jreuter@poboxes.com> diff --git a/ax25/axspawn.c b/ax25/axspawn.c new file mode 100644 index 0000000..88381cf --- /dev/null +++ b/ax25/axspawn.c @@ -0,0 +1,911 @@ +/* + * + * $Id: axspawn.c,v 1.6 1996/08/24 22:33:05 jreuter Exp jreuter $ + * + * axspawn.c - run a program from ax25d. + * + * Copyright (c) 1996 Jörg Reuter DL1BKE (jreuter@poboxes.com) + * + * This program is a hack. + * + * 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. + * + * It might even kill your cat... ;-) + * + * Status: alpha (still...) + * + * usage: change the "default" lines in your /usr/local/etc/ax25d.conf: + * + * default * * * * * 1 root /usr/local/sbin/axspawn axspawn + * + * a line like this would wait for an incoming info frame first. + * + * default * * * * * 1 root /usr/local/sbin/axspawn axspawn --wait + * + * The program will check if the peer is an AX.25 socket, the + * callsign is a valid amateur radio callsign, strip the SSID, + * check if UID/GID are valid, allow a password-less login if the + * password-entry in /etc/passwd is "+" or empty; in every other case + * login will prompt for a password. + * + * Still on my TODO list: a TheNet compatible or MD5 based + * authentication scheme... Won't help you if you changed the "+"-entry + * in /etc/passwd to a valid passord and login with telnet, though. + * A better solution could be a small program called from .profile. + * + * Axspawn can create user accounts automatically. You may specify + * the user shell, first and maximum user id, group ID in the config + * file and (unlike WAMPES) create a file "/usr/local/etc/ax25.profile" + * which will be copied to ~/.profile. + * + * This is an example for the config file: + * + * # this is /usr/local/etc/axspawn.conf + * # + * # allow automatic creation of user accounts + * create yes + * # + * # guest user if above is 'no' or everything else fails. Disable with "no" + * guest ax25 + * # + * # group id or name for autoaccount + * group ax25 + * # + * # first user id to use + * first_uid 400 + * # + * # maximum user id + * max_uid 2000 + * # + * # where to add the home directory for the new user + * home /home/ax25 + * # + * # user's shell + * shell /bin/bash + * # + * # bind user id to callsign for outgoing connects. + * associate yes + * + * SECURITY: + * + * Umm... auto accounting is a security problem by definition. Unlike + * WAMPES, which creates an empty password field, Axspawn adds an + * "impossible" ('+') password to /etc/passwd. Login gets called with + * the "-f" option, thus new users have the chance to login without + * a password. (I guess this won't work with the shadow password system). + * + * The "associate" option has to be used with great care. If a user + * logs on it removes any existing callsign from the translation table + * for this userid and replaces it with the callsign and SSID of the + * user. This will happen with multiple connects (same callsign, + * different SSIDs), too. Unless you want your users to be able + * to call out from your machine disable "associate". + * + * Of course Axspawn does callsign checking: Only letters and numbers + * are allowed, the callsign must be longer than 4 characters and + * shorter than 6 characters (without SSID). There must be at least + * one digit, and max. two digits within the call. The SSID must + * be within the range of 0 and 15. Please drop me a note if you + * know a valid Amateur Radio (sic!) callsign that does not fit this + * pattern _and_ can be represented correctly in AX.25. + * + * It uses the forkpty from libbsd.a (found after analyzing logind) + * which has no prototype in any of my .h files. + * + */ + +/* removed -h <protocol> from login command as it was causing hostname lookups + with new login/libc - Terry, vk2ktj. */ + + +#define QUEUE_DELAY 400 /* 400 msec */ +#define USERPROFILE ".profile" +#define PASSWDFILE "/etc/passwd" + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <strings.h> +#include <ctype.h> +#include <termios.h> +#include <unistd.h> +#include <signal.h> +#include <pwd.h> +#include <grp.h> +#include <utmp.h> +#include <paths.h> +#include <errno.h> +#include <syslog.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/file.h> + +#include <sys/socket.h> + +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> + +#include "../pathnames.h" + +#define MAXLEN strlen("DB0PRA-15") +#define MINLEN strlen("KA9Q") + +#define AX_PACLEN 256 +#define NETROM_PACLEN 236 +#define ROSE_PACLEN 128 + +#define IS_DIGIT(x) ( (x >= '0') && (x <= '9') ) +#define IS_LETTER(x) ( (x >= 'A') && (x <= 'Z') ) + +#define MSG_NOCALL "Sorry, you are not allowed to connect.\n" +#define MSG_CANNOTFORK "Sorry, system is overloaded.\n" +#define MSG_NOPTY "Sorry, all channels in use.\n" +#define MSG_NOTINDBF "Sorry, you are not in my database\n" + +#define EXITDELAY 10 + +char policy_add_user = 1; +char policy_guest = 1; +char policy_associate = 0; + +gid_t user_gid = 400; +char *user_shell = "/bin/bash"; +char *start_home = "/home/funk"; +char *guest = "guest"; +int start_uid = 400; +int end_uid = 65535; +int paclen = ROSE_PACLEN; /* Its the shortest ie safest */ + +struct write_queue { + struct write_queue *next; + char *data; + int len; +}; + +struct write_queue *wqueue_head = NULL; +struct write_queue *wqueue_tail = NULL; +long wqueue_length = 0; + +/* This one is in /usr/lib/libbsd.a, but not in bsd.h and fellows... weird. */ +/* (found in logind.c) */ + +pid_t forkpty(int *, char *, void *, struct winsize *); + +int _write_ax25(const char *s, int len) +{ + int k, m; + char *p; + + p = (char *) malloc(len+1); + + if (p == NULL) + return 0; + + m = 0; + for (k = 0; k < len; k++) + { + if ( (s[k] == '\r') && ((k+1) < len) && (s[k+1] == '\n') ) + continue; + else if (s[k] == '\n') + p[m++] = '\r'; + else + p[m++] = s[k]; + } + + if (m) + write(1, p, m); + + free(p); + return len; +} + +int read_ax25(char *s, int size) +{ + int len = read(0, s, size); + int k; + + for (k = 0; k < len; k++) + if (s[k] == '\r') s[k] = '\n'; + + return len; +} + +/* + * We need to buffer the data from the pipe since bash does + * a fflush() on every output line. We don't want it, it's + * PACKET radio, isn't it? + */ + +void kick_wqueue(int dummy) +{ + char *s, *p; + struct write_queue *buf; + + + if (wqueue_length == 0) + return; + + s = (char *) malloc(wqueue_length); + + p = s; + + while (wqueue_head) + { + buf = wqueue_head; + wqueue_head = buf->next; + + memcpy(p, buf->data, buf->len); + p += buf->len; + free(buf->data); + free(buf); + } + + _write_ax25(s, wqueue_length); + free(s); + wqueue_tail=NULL; + wqueue_length=0; +} + +int write_ax25(const char *s, int len) +{ + struct itimerval itv, oitv; + struct write_queue * buf; + + signal(SIGALRM, SIG_IGN); + + buf = (struct write_queue *) malloc(sizeof(struct write_queue)); + if (buf == NULL) + return 0; + + buf->data = (char *) malloc(len); + if (buf->data == NULL) + return 0; + + memcpy(buf->data, s, len); + buf->len = len; + buf->next = NULL; + + if (wqueue_head == NULL) + { + wqueue_head = buf; + wqueue_tail = buf; + wqueue_length = len; + } else { + wqueue_tail->next = buf; + wqueue_tail = buf; + wqueue_length += len; + } + + if (wqueue_length >= paclen) + { + kick_wqueue(0); + } else { + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 0; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = QUEUE_DELAY; + + setitimer(ITIMER_REAL, &itv, &oitv); + signal(SIGALRM, kick_wqueue); + } + return len; +} + +int get_assoc(struct sockaddr_ax25 *sax25) +{ + FILE *fp; + int uid; + char buf[81]; + + fp = fopen(PROC_AX25_CALLS_FILE, "r"); + if (!fp) return -1; + + fgets(buf, sizeof(buf)-1, fp); + + while(!feof(fp)) + { + if (fscanf(fp, "%d %s", &uid, buf) == 2) + if (sax25->sax25_uid == uid) + { + ax25_aton_entry(buf, (char *) &sax25->sax25_call); + return 0; + } + } + + return -1; +} + + +void cleanup(char *tty) +{ + struct utmp ut, *ut_line; + FILE *fp; + + setutent(); + ut.ut_type = LOGIN_PROCESS; + strncpy(ut.ut_id, tty + 3, sizeof(ut.ut_line)); + ut_line = getutid(&ut); + + if (ut_line != NULL) { + ut_line->ut_type = DEAD_PROCESS; + ut_line->ut_host[0] = '\0'; + ut_line->ut_user[0] = '\0'; + time(&ut_line->ut_time); + pututline(ut_line); + if ((fp = fopen(_PATH_WTMP, "r+")) != NULL) { + fseek(fp, 0L, SEEK_END); + if (fwrite(ut_line, sizeof(ut), 1, fp) != 1) + syslog(LOG_ERR, "Ooops, I think I've just barbecued your wtmp file\n"); + fclose(fp); + } + } + + endutent(); +} + + +/* + * add a new user to /etc/passwd and do some init + */ + +void new_user(char *newuser) +{ + struct passwd pw, *pwp; + uid_t uid; + FILE *fp; + char username[80]; + char homedir[256], userdir[256]; + char buf[4096]; + char subdir[4]; + int cnt; + unsigned char *p, *q; + struct stat fst; + int fd_a, fd_b, fd_l; + + /* + * build path for home directory + */ + + strncpy(subdir, newuser, 3); + subdir[3] = '\0'; + sprintf(username, "%s", newuser); + sprintf(homedir, "%s/%s.../%s", start_home, subdir, newuser); + strcpy(userdir, homedir); + + fd_l = open(LOCK_AXSPAWN_FILE, O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); + flock(fd_l, LOCK_EX); + +retry: + /* + * find first free UID + */ + + for (uid = start_uid; uid < 65535; uid++) + { + pwp = getpwuid(uid); + if (pwp == NULL) + break; + } + + if (uid >= 65535 || uid < start_uid) + return; + + /* + * build directories for home + */ + + p = homedir; + + while (*p == '/') p++; + + chdir("/"); + + while(p) + { + q = strchr(p, '/'); + if (q) + { + *q = '\0'; + q++; + while (*q == '/') q++; + if (*q == 0) q = NULL; + } + + if (stat(p, &fst) < 0) + { + if (errno == ENOENT) + { + mkdir(p, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); + + if (q == NULL) + { + chown(p, uid, user_gid); + chmod(p, S_IRUSR|S_IWUSR|S_IXUSR); + } + } + else + return; + } + + if (chdir(p) < 0) + return; + p = q; + } + + /* + * add the user now + */ + + fp = fopen(PASSWDFILE, "a+"); + if (fp == NULL) + return; + + pw.pw_name = newuser; + pw.pw_passwd = "+"; + pw.pw_uid = uid; + pw.pw_gid = user_gid; + pw.pw_gecos = username; + pw.pw_dir = userdir; + pw.pw_shell = user_shell; + + if (getpwuid(uid) != NULL) goto retry; /* oops?! */ + + if (putpwent(&pw, fp) < 0) + return; + + flock(fd_l, LOCK_UN); + fclose(fp); + + /* + * copy ax25.profile + */ + + fd_a = open(CONF_AXSPAWN_PROF_FILE, O_RDONLY); + + if (fd_a > 0) + { + fd_b = open(USERPROFILE, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IXUSR); + + if (fd_b < 0) + return; + + while ( (cnt = read(fd_a, &buf, sizeof(buf))) > 0 ) + write(fd_b, &buf, cnt); + close(fd_b); + close(fd_a); + chown(USERPROFILE, uid, user_gid); + } +} + +void read_config(void) +{ + FILE *fp = fopen(CONF_AXSPAWN_FILE, "r"); + char buf[512]; + char cmd[40], param[80]; + char *p; + + if (fp == NULL) + return; + + while (!feof(fp)) + { + fgets(buf, sizeof(buf), fp); + p = strchr(buf, '#'); + if (p) *p='\0'; + + if (buf[0] != '\0') + { + sscanf(buf, "%s %s", cmd, param); + + if (!strncmp(cmd, "create", 5)) + { + policy_add_user = (param[0] == 'y'); + } else + if (!strncmp(cmd, "guest", 5)) + { + if (!strcmp(param, "no")) + { + policy_guest = 0; + } else { + policy_guest = 1; + guest = (char *) malloc(strlen(param)+1); + strcpy(guest, param); + } + } else + if (!strncmp(cmd, "group", 5)) + { + user_gid = strtol(param, &p, 0); + if (*p != '\0') + { + struct group * gp = getgrnam(param); + if (gp != NULL) + user_gid = gp->gr_gid; + else + user_gid = 400; + endgrent(); + } + } else + if (!strncmp(cmd, "first", 5)) + { + start_uid = strtol(param, &p, 0); + if (*p != '\0') + start_uid = 400; + } else + if (!strncmp(cmd, "max", 3)) + { + end_uid = strtol(param, &p, 0); + if (*p != '\0') + end_uid = 0; + } else + if (!strncmp(cmd, "home", 4)) + { + start_home = (char *) malloc(strlen(param)+1); + strcpy(start_home, param); + } else + if (!strncmp(cmd, "assoc", 5)) + { + if (!strcmp(param, "yes")) + policy_associate = 1; + else + policy_associate = 0; + } else + if (!strncmp(cmd, "shell", 5)) + { + user_shell = (char *) malloc(strlen(param)+1); + strcpy(user_shell, param); + } else + { + printf("error in config: ->%s %s<-\n", cmd, param); + } + } + } + + fclose(fp); +} + +char ptyslave[20]; +int child_pid; + +void signal_handler(int dummy) +{ + kill(child_pid, SIGHUP); + cleanup(ptyslave+5); + exit(1); +} + +int main(int argc, char **argv) +{ + char call[20], user[20], real_user[20]; + char buf[2048]; + int k, cnt, digits, letters, invalid, ssid, ssidcnt, addrlen; + int fdmaster; + pid_t pid = -1; + char *p; + fd_set fds_read, fds_err; + struct passwd *pw; + int chargc; + char *chargv[20]; + int envc; + char *envp[20]; + char wait_for_tcp; + struct utmp ut_line; + struct winsize win = { 0, 0, 0, 0}; + struct sockaddr_ax25 sax25; + union { + struct full_sockaddr_ax25 fsax25; + struct sockaddr_rose rose; + } sockaddr; + char *protocol; + + digits = letters = invalid = ssid = ssidcnt = 0; + + if (argc > 1 && (!strcmp(argv[1],"-w") || !strcmp(argv[1],"--wait"))) + wait_for_tcp = 1; + else + wait_for_tcp = 0; + + read_config(); + + openlog("axspawn", LOG_PID, LOG_DAEMON); + + if (getuid() != 0) { + printf("permission denied\n"); + syslog(LOG_NOTICE, "user %d tried to run axspawn\n", getuid()); + return 1; + } + + addrlen = sizeof(struct full_sockaddr_ax25); + k = getpeername(0, (struct sockaddr *) &sockaddr, &addrlen); + + if (k < 0) { + syslog(LOG_NOTICE, "getpeername: %m\n"); + return 1; + } + + switch (sockaddr.fsax25.fsa_ax25.sax25_family) { + case AF_AX25: + strcpy(call, ax25_ntoa(&sockaddr.fsax25.fsa_ax25.sax25_call)); + protocol = "AX.25"; + paclen = AX_PACLEN; + break; + + case AF_NETROM: + strcpy(call, ax25_ntoa(&sockaddr.fsax25.fsa_ax25.sax25_call)); + protocol = "NET/ROM"; + paclen = NETROM_PACLEN; + break; + + case AF_ROSE: + strcpy(call, ax25_ntoa(&sockaddr.rose.srose_call)); + protocol = "Rose"; + paclen = ROSE_PACLEN; + break; + + default: + syslog(LOG_NOTICE, "peer is not an AX.25, NET/ROM or Rose socket\n"); + return 1; + } + + for (k = 0; k < strlen(call); k++) + { + if (ssidcnt) + { + if (!IS_DIGIT(call[k])) + invalid++; + else + { + if (ssidcnt > 2) + invalid++; + else if (ssidcnt == 1) + ssid = (int) (call[k] - '0'); + else + { + ssid *= 10; + ssid += (int) (call[k] - '0'); + + if (ssid > 15) invalid++; + } + ssidcnt++; + } + } else + if (IS_DIGIT(call[k])) + { + digits++; + if (k > 3) invalid++; + } else + if (IS_LETTER(call[k])) + letters++; + else + if (call[k] == '-') + { + if (k < MINLEN) + invalid++; + else + ssidcnt++; + } + else + invalid++; + } + + if ( invalid || (k < MINLEN) || (digits > 2) || (digits < 1) ) + { + write_ax25(MSG_NOCALL, sizeof(MSG_NOCALL)); + syslog(LOG_NOTICE, "%s is not an Amateur Radio callsign\n", call); + sleep(EXITDELAY); + return 1; + } + + strcpy(user, call); + strlwr(user); + p = strchr(user, '-'); + if (p) *p = '\0'; + strcpy(real_user, user); + + if (wait_for_tcp) + read_ax25(buf, sizeof(buf)); /* incoming TCP/IP connection? */ + + pw = getpwnam(user); + + if (pw == NULL) + { + if (policy_add_user) + { + new_user(user); + pw = getpwnam(user); + } + + if (pw == NULL && policy_guest) + { + strcpy(real_user,guest); + pw = getpwnam(guest); + + if (! (pw && pw->pw_uid && pw->pw_gid) ) + { + write_ax25(MSG_NOTINDBF, sizeof(MSG_NOTINDBF)); + syslog(LOG_NOTICE, "%s (callsign: %s) not found in /etc/passwd\n", user, call); + sleep(EXITDELAY); + return 1; + } + } + } + + endpwent(); + + if (pw->pw_uid == 0 || pw->pw_gid == 0) + { + write_ax25(MSG_NOCALL, sizeof(MSG_NOCALL)); + syslog(LOG_NOTICE, "root login of %s (callsign: %s) denied\n", user, call); + sleep(EXITDELAY); + return 1; + } + + /* + * associate UID with callsign (or vice versa?) + */ + + if (policy_associate) + { + int fds = socket(AF_AX25, SOCK_SEQPACKET, 0); + if (fds != -1) + { + sax25.sax25_uid = pw->pw_uid; + if (get_assoc(&sax25) != -1) + ioctl(fds, SIOCAX25DELUID, &sax25); + switch (sockaddr.fsax25.fsa_ax25.sax25_family) { + case AF_AX25: + case AF_NETROM: + sax25.sax25_call = sockaddr.fsax25.fsa_ax25.sax25_call; + break; + case AF_ROSE: + sax25.sax25_call = sockaddr.rose.srose_call; + break; + } + ioctl(fds, SIOCAX25ADDUID, &sax25); + close(fds); + } + } + + fcntl(1, F_SETFL, O_NONBLOCK); + + pid = forkpty(&fdmaster, ptyslave, NULL, &win); + + if (pid == 0) + { + struct termios termios; + + memset((char *) &termios, 0, sizeof(termios)); + + ioctl(0, TIOCSCTTY, (char *) 0); + + termios.c_iflag = ICRNL | IXOFF; + termios.c_oflag = OPOST | ONLCR; + termios.c_cflag = CS8 | CREAD | CLOCAL; + termios.c_lflag = ISIG | ICANON; + termios.c_cc[VINTR] = 127; + termios.c_cc[VQUIT] = 28; + termios.c_cc[VERASE] = 8; + termios.c_cc[VKILL] = 24; + termios.c_cc[VEOF] = 4; + cfsetispeed(&termios, B19200); + cfsetospeed(&termios, B19200); + tcsetattr(0, TCSANOW, &termios); + + setutent(); + ut_line.ut_type = LOGIN_PROCESS; + ut_line.ut_pid = getpid(); + strncpy(ut_line.ut_line, ptyslave + 5, sizeof(ut_line.ut_line)); + strncpy(ut_line.ut_id, ptyslave + 8, sizeof(ut_line.ut_id)); + strncpy(ut_line.ut_user, "LOGIN", sizeof(ut_line.ut_user)); + strncpy(ut_line.ut_host, protocol, sizeof(ut_line.ut_host)); + time(&ut_line.ut_time); + ut_line.ut_addr = 0; + pututline(&ut_line); + endutent(); + + chargc = 0; + chargv[chargc++] = "/bin/login"; + chargv[chargc++] = "-p"; + if (!strcmp(pw->pw_passwd, "+")) + chargv[chargc++] = "-f"; + chargv[chargc++] = real_user; + chargv[chargc] = NULL; + + envc = 0; + envp[envc] = (char *) malloc(30); + sprintf(envp[envc++], "AXCALL=%s", call); + envp[envc] = (char *) malloc(30); + sprintf(envp[envc++], "CALL=%s", user); + envp[envc] = (char *) malloc(30); + sprintf(envp[envc++], "PROTOCOL=%s", protocol); + envp[envc] = NULL; + + execve(chargv[0], chargv, envp); + } + else if (pid > 0) + { + child_pid = 0; + signal(SIGHUP, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGQUIT, signal_handler); + + while(1) + { + FD_ZERO(&fds_read); + FD_ZERO(&fds_err); + FD_SET(0, &fds_read); + FD_SET(0, &fds_err); + FD_SET(fdmaster, &fds_read); + FD_SET(fdmaster, &fds_err); + + k = select(fdmaster+1, &fds_read, NULL, &fds_err, NULL); + + if (k > 0) + { + if (FD_ISSET(0, &fds_err)) + { + kill(pid, SIGHUP); + cleanup(ptyslave+5); + return 1; + } + + if (FD_ISSET(fdmaster, &fds_err)) + { + cleanup(ptyslave+5); + return 1; + } + + if (FD_ISSET(0, &fds_read)) + { + cnt = read_ax25(buf, sizeof(buf)); + if (cnt < 0) /* Connection died */ + { + kill(pid, SIGHUP); + cleanup(ptyslave+5); + return 1; + } else + write(fdmaster, buf, cnt); + } + + if (FD_ISSET(fdmaster, &fds_read)) + { + cnt = read(fdmaster, buf, sizeof(buf)); + if (cnt < 0) + { + cleanup(ptyslave+5); + return 1; /* Child died */ + } + write_ax25(buf, cnt); + } + } else + if (k < 0 && errno != EINTR) + { + kill(pid, SIGHUP); /* just in case... */ + cleanup(ptyslave+5); + return 0; + } + } + } + else + { + syslog(LOG_ERR, "cannot fork %m, closing connection to %s\n", call); + write_ax25(MSG_CANNOTFORK, sizeof(MSG_CANNOTFORK)); + sleep(EXITDELAY); + return 1; + } + + sleep(EXITDELAY); + + return 0; +} diff --git a/ax25/axspawn.conf b/ax25/axspawn.conf new file mode 100644 index 0000000..1f0bac4 --- /dev/null +++ b/ax25/axspawn.conf @@ -0,0 +1,25 @@ +# /etc/ax25/axspawn.conf +# +# allow automatic creation of user accounts +create yes +# +# guest user if above is 'no' or everything else fails. Disable with "no" +guest ax25 +# +# group id or name for autoaccount +group ax25 +# +# first user id to use +first_uid 400 +# +# maximum user id +max_uid 2000 +# +# where to add the home directory for the new user +home /home/ax25 +# +# user shell +shell /bin/bash +# +# bind user id to callsign for outgoing connects. +associate no diff --git a/ax25/axspawn.conf.5 b/ax25/axspawn.conf.5 new file mode 100644 index 0000000..416ccdf --- /dev/null +++ b/ax25/axspawn.conf.5 @@ -0,0 +1,75 @@ +.TH AXSPAWN.CONF 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +axspawn.conf \- Control the operation of axspawn. +.SH DESCRIPTION +.LP +The +.B axspawn.conf +file controls the operation of the axspawn(8) program. The operation of the +config file can best be seen in an example: +.LP +.RS +# this is /etc/ax25/axspawn.conf +.br +# +.br +# allow automatic creation of user accounts +.br +create yes +.br +# +.br +# guest user if above is 'no' or everything else +.br +# fails. Disable with "no" +.br +guest ax25 +.br +# +.br +# group id or name for autoaccount +.br +group ax25 +.br +# +.br +# first user id to use +.br +first_uid 400 +.br +# +.br +# maximum user id +.br +max_uid 2000 +.br +# +.br +# where to add the home directory for the new user +.br +home /home/ax25 +.br +# +.br +# user's shell +.br +shell /bin/bash +.br +# +.br +# bind user id to callsign for outgoing connects. +.br +associate yes +.RE +.LP +The \(lqassociate\(rq option has to be used with great care. If a user logs +on it removes any existing callsign from the translation table for this +userid and replaces it with the callsign and SSID of the user. This will +happen with multiple connects (same callsign, different SSIDs), too. Unless +you want your users to be able to call out from your machine disable +\(lqassociate\(rq. +.SH FILES +.LP +/etc/ax25/axspawn.conf +.SH "SEE ALSO" +.BR axspawn (8). diff --git a/ax25/beacon.8 b/ax25/beacon.8 new file mode 100644 index 0000000..9b38db7 --- /dev/null +++ b/ax25/beacon.8 @@ -0,0 +1,51 @@ +.TH BEACON 8 "10 February 1997" Linux "Linux System Managers Manual" +.SH NAME +beacon \- transmit periodic messages on an AX.25 port. +.SH SYNOPSIS +.B beacon [-c <src_call>] [-d <dest_call>] [-l] [-m] [-s] [-t interval] [-v] port \(lqmessage\(rq +.SH DESCRIPTION +.LP +.B Beacon +transmits the message text on an AX.25 port every thirty minutes. The message +is addressed to \(lqIDENT\(rq and is sent using the AX.25 callsign of the port +specified on the command line. Typically the message text will contain +spaces and/or other characters, therefore the message text should be +enclosed in quotes to ensure they are passed to the +.B beacon +program untranslated. +.SH OPTIONS +.TP 16 +.BI \-c +Configure the source callsign for beacons. The default is to use the +interface callsign. +.TP 16 +.BI \-d +Configure the destination callsign for beacons. The default is \(lqIDENT\(rq. +.TP 16 +.BI \-l +Enables the logging of errors to the system log, the default is off. +.TP 16 +.BI \-m +Changes the destination address to \(lqMAIL\(rq and sends the message text +once only. This option overrides any destination callsign given with the \-d option. +.TP 16 +.BI \-s +Sends the message text once only. +.TP 16 +.BI "\-t interval" +The time interval between messages, the interval is given in minutes and the +default is thirty minutes. +.TP 16 +.BI \-v +Display the version. +.SH "SEE ALSO" +.BR ax25 (4), +.BR axports (5). +.SH AUTHORS +.nf +Alan Cox GW4PTS <alan@cymru.net> +.br +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> +.br +David Brooke G6GZH <db@fusk.demon.co.uk> +.fi diff --git a/ax25/beacon.c b/ax25/beacon.c new file mode 100644 index 0000000..c9b989e --- /dev/null +++ b/ax25/beacon.c @@ -0,0 +1,163 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/daemon.h> + +#include <config.h> + +static int logging = FALSE; +static int mail = FALSE; +static int single = FALSE; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct full_sockaddr_ax25 dest; + struct full_sockaddr_ax25 src; + int s, n, dlen, len, interval = 30; + char addr[20], *port, *message, *portcall; + char *srccall = NULL, *destcall = NULL; + + while ((n = getopt(argc, argv, "c:d:lmst:v")) != -1) { + switch (n) { + case 'c': + srccall = optarg; + break; + case 'd': + destcall = optarg; + break; + case 'l': + logging = TRUE; + break; + case 'm': + mail = TRUE; + /* falls through */ + case 's': + single = TRUE; + break; + case 't': + interval = atoi(optarg); + if (interval < 1) { + fprintf(stderr, "beacon: interval must be greater than on minute\n"); + return 1; + } + break; + case 'v': + printf("beacon: %s\n", VERSION); + return 0; + case '?': + case ':': + fprintf(stderr, "usage: beacon [-c <src_call>] [-d <dest_call>] [-l] [-m] [-s] [-t interval] [-v] <port> <message>\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if (optind == argc || optind == argc - 1) { + fprintf(stderr, "usage: beacon [-c <src_call>] [-d <dest_call>] [-l] [-m] [-s] [-t interval] [-v] <port> <message>\n"); + return 1; + } + + port = argv[optind]; + message = argv[optind + 1]; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "beacon: no AX.25 ports defined\n"); + return 1; + } + + if ((portcall = ax25_config_get_addr(port)) == NULL) { + fprintf(stderr, "beacon: invalid AX.25 port setting - %s\n", port); + return 1; + } + + if (mail) + strcpy(addr, "MAIL"); + else if (destcall != NULL) + strcpy(addr, destcall); + else + strcpy(addr, "IDENT"); + + if ((dlen = ax25_aton(addr, &dest)) == -1) { + fprintf(stderr, "beacon: unable to convert callsign '%s'\n", addr); + return 1; + } + + if (srccall != NULL && strcmp(srccall, portcall) != 0) + sprintf(addr, "%s %s", srccall, portcall); + else + strcpy(addr, portcall); + + if ((len = ax25_aton(addr, &src)) == -1) { + fprintf(stderr, "beacon: unable to convert callsign '%s'\n", addr); + return 1; + } + + if (!single) { + if (!daemon_start(FALSE)) { + fprintf(stderr, "beacon: cannot become a daemon\n"); + return 1; + } + } + + if (logging) { + openlog("beacon", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + if ((s = socket(AF_AX25, SOCK_DGRAM, 0)) == -1) { + if (logging) { + syslog(LOG_ERR, "socket: %m"); + closelog(); + } + return 1; + } + + if (bind(s, (struct sockaddr *)&src, len) == -1) { + if (logging) { + syslog(LOG_ERR, "bind: %m"); + closelog(); + } + return 1; + } + + if (sendto(s, message, strlen(message), 0, (struct sockaddr *)&dest, dlen) == -1) { + if (logging) { + syslog(LOG_ERR, "sendto: %m"); + closelog(); + } + return 1; + } + + close(s); + + if (!single) + sleep(interval * 60); + else + break; + } + + return 0; +} diff --git a/ax25/bpqparms.8 b/ax25/bpqparms.8 new file mode 100644 index 0000000..7a8b450 --- /dev/null +++ b/ax25/bpqparms.8 @@ -0,0 +1,37 @@ +.TH BPQPARMS 8 "4 September 1996" Linux "Linux System Managers Manual" +.SH NAME +bpqparms \- Configure BPQ ethernet devices. +.SH SYNOPSIS +.B bpqparms device [-a ethaddr] [-d ethaddr] [-vV] +.SH DESCRIPTION +.LP +.B Bpqparms +allows the setting of the BPQ Ethernet options for a particular device. Each +BPQ Ethernet device appears as a device named bpq0...bpqN which overlays the +original Ethernet device, usually eth0...ethN. This device is an AX.25 +device driver and allows AX.25 frames to be transmitted over an Ethernet to +another machine using the same protocol. The default for the device is to +send and receive BPQ Ethernet packets to the broadcast address. This +program replaces the previous \(lqaxparms -dev\(rq option. +.SH OPTIONS +.TP 15 +.BI "\-a ethaddr" +Allows the setting of which ethernet address will be accepted by the BPQ +Ethernet device. +.TP 15 +.BI "\-d ethaddr" +If specified on its own, will set the destination ethernet address will be +used for transmitting and for receiving of BPQ ethernet packets. An address +of \(lqbroadcast\(rq sets it to the ethernet broadcast address. +.TP 15 +.BI \-v +Displays the version number. +.TP 15 +.BI \-V +The original version messages. +.SH "SEE ALSO" +.BR ax25 (4), +.BR axports (5), +.BR ifconfig (8). +.SH AUTHOR +Joerg Reuter DL1BKE <jreuter@poboxes.com> diff --git a/ax25/bpqparms.c b/ax25/bpqparms.c new file mode 100644 index 0000000..1a88fd6 --- /dev/null +++ b/ax25/bpqparms.c @@ -0,0 +1,146 @@ +/* + bpqparms.c + + Copyright 1996, by Joerg Reuter jreuter@poboxes.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the (modified) GNU General Public License + delivered with the LinuX kernel source. + + 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 find a copy of the GNU General Public License in + /usr/src/linux/COPYING; + +*/ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <termios.h> +#include <string.h> +#include <ctype.h> +#include <sys/ioctl.h> +#include <linux/timer.h> + +#include <sys/socket.h> +#include <net/if.h> +#include <net/ethernet.h> +#include <linux/bpqether.h> /* xlz - dammit, we need this again */ + +#include <config.h> + +#define RCS_ID "$Id:$" + +void usage(void) +{ + fprintf(stderr, "usage : bpqparms dev -d address [-a address]\n"); + fprintf(stderr, "examples: bpqparms bpq0 -d 00:80:AD:1B:05:26\n"); + fprintf(stderr, " bpqparms bpq0 -d broadcast -a 00:80:AD:1B:05:26\n"); + exit(1); +} + +char *Version = "$Revision:$"; + +int get_hwaddr(unsigned char *k, char *s) +{ + unsigned char broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + unsigned int eth[ETH_ALEN]; + int n; + + if (strcmp(s, "default") == 0 || strcmp(s, "broadcast") == 0) { + memcpy(k, broadcast, ETH_ALEN); + } else { + n = sscanf(s, "%x:%x:%x:%x:%x:%x", + ð[0], ð[1], ð[2], ð[3], ð[4], ð[5]); + + if (n < 6) + return 1; + + for (n = 0; n < ETH_ALEN; n++) + k[n] = eth[n]; + } + + return 0; +} + +int main(int argc, char **argv) +{ + int fd; + int cmd, flag; + struct ifreq ifr; + char dev[40]; + struct bpq_ethaddr addr; + + strcpy(dev, argv[1]); + + flag = 0; + + while ((cmd = getopt(argc, argv, "d:a:vVh")) != EOF) { + switch (cmd) { + case 'd': + flag |= 1; + if (get_hwaddr(addr.destination, optarg)) { + fprintf(stderr, "bpqparms: invalid 'destination' address %s\n", optarg); + return 1; + } + break; + + case 'a': + flag |= 2; + if (get_hwaddr(addr.accept, optarg)) { + fprintf(stderr, "bpqparms: invalid 'accept' address %s\n", optarg); + return 1; + } + break; + + case 'V': + printf("bpqparms version %s\n", Version); + printf("Copyright 1996, Jörg Reuter (jreuter@poboxes.com)\n"); + printf("This program is free software; you can redistribute it and/or modify\n"); + printf("it under the terms of the GNU General Public License as published by\n"); + printf("the Free Software Foundation; either version 2 of the License, or\n"); + printf(" (at your option) any later version.\n\n"); + printf("This program is distributed in the hope that it will be useful,\n"); + printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); + return 0; + + case 'v': + printf("bpqparms: %s\n", VERSION); + return(0); + + case 'h': + case ':': + case '?': + usage(); + } + } + + if (!(flag & 0x01) || optind+1 > argc) + usage(); + + strcpy(dev, argv[optind]); + + if ((flag & 0x02) == 0) + memcpy(addr.accept, addr.destination, ETH_ALEN); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + strcpy(ifr.ifr_name, dev); + ifr.ifr_data = (caddr_t) &addr; + + if (ioctl(fd, SIOCSBPQETHADDR, &ifr) < 0) { + perror("bpqparms SIOCSBPQETHADDR"); + close(fd); + return 1; + } + + close(fd); + + return 0; +} diff --git a/ax25/mheard.1 b/ax25/mheard.1 new file mode 100644 index 0000000..b300aaf --- /dev/null +++ b/ax25/mheard.1 @@ -0,0 +1,74 @@ +.TH MHEARD 1 "19 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +mheard \- display AX.25 calls recently heard. +.SH SYNOPSIS +.B mheard [-d cmns] [-n] [-o cfpt] [-v] [port...] +.SH DESCRIPTION +.LP +.B Mheard +displays information about most recently heard AX.25 callsigns, the interface +upon which they were heard, the total packets heard, the time +at which the last one was heard and other information. +.B Mheard +displays different information, in different orders depending on the +settings of the arguments. Information on specific ports can be displayed by +giving the port names as arguments. +.SH OPTIONS +.TP 13 +.BI "\-d cmns" +Sets the information that is displayed for each AX.25 callsign heard. The +different arguments are: +.RS +.TP 5 +.BI c +Display all the information with regard to callsigns, from-callsign, +to-callsign, port name, and any digipeaters that may be in use. +.TP 5 +.BI m +Display miscellaneous information, the from-callsign, port name, no frames +heard, the last type of frames heard, and which different PIDs have been +heard from that station. +.TP 5 +.BI n +Display the default information. This is the from-callsign, port name, no frames +heard and the date and time last heard. +.TP 5 +.BI s +Displays statistics about the station heard, the from-callsign, port name, +no I frames, no S frames, no U frames, time first heard, and time last +heard. +.RE +.TP 13 +.BI \-n +Supress the displaying of titles. +.TP 13 +.BI "\-o cfpt" +Sets the ordering of the information displayed. The meanings of the +different arguments are: +.RS +.TP 5 +.BI c +Sort list by from-callsign. +.TP 5 +.BI f +Sort list by number of frames heard. +.TP 5 +.BI p +Sort list by port name. +.TP 5 +.BI t +Sort list by the time last heard, this is the default. +.RE +.TP 13 +.BI \-v +Display the version. +.SH FILES +.LP +/var/ax25/mheard/mheard.dat +.br +/etc/ax25/axports +.SH "SEE ALSO" +.BR ax25 (4), +.BR mheardd (8). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/ax25/mheard.c b/ax25/mheard.c new file mode 100644 index 0000000..2ab582c --- /dev/null +++ b/ax25/mheard.c @@ -0,0 +1,374 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> +#include <netax25/mheard.h> + +#include <config.h> + +#include "../pathnames.h" + +struct PortRecord { + struct mheard_struct entry; + struct PortRecord *Next; +}; + +static char *types[] = { + "SABM", + "SABME", + "DISC", + "UA", + "DM", + "RR", + "RNR", + "REJ", + "FRMR", + "I", + "UI", + "????"}; + +static struct PortRecord *PortList = NULL; + +static void PrintHeader(int data) +{ + switch (data) { + case 0: + printf("Callsign Port Packets Last Heard\n"); + break; + case 1: + printf("Callsign Port\n"); + break; + case 2: + printf("Callsign Port #I #S #U First Heard Last Heard\n"); + break; + case 3: + printf("Callsign Port Packets Type PIDs\n"); + break; + } +} + +static void PrintPortEntry(struct PortRecord *pr, int data) +{ + char lh[30], fh[30], *call, *s; + char buffer[80]; + int i; + + switch (data) { + case 0: + strcpy(lh, ctime(&pr->entry.last_heard)); + lh[19] = 0; + call = ax25_ntoa(&pr->entry.from_call); + if ((s = strstr(call, "-0")) != NULL) + *s = '\0'; + printf("%-10s %-5s %5d %s\n", + call, pr->entry.portname, pr->entry.count, lh); + break; + case 1: + buffer[0] = '\0'; + call = ax25_ntoa(&pr->entry.from_call); + if ((s = strstr(call, "-0")) != NULL) + *s = '\0'; + strcat(buffer, call); + call = ax25_ntoa(&pr->entry.to_call); + if ((s = strstr(call, "-0")) != NULL) + *s = '\0'; + strcat(buffer, ">"); + strcat(buffer, call); + for (i = 0; i < pr->entry.ndigis && i < 4; i++) { + strcat(buffer, ","); + call = ax25_ntoa(&pr->entry.digis[i]); + if ((s = strstr(call, "-0")) != NULL) + *s = '\0'; + strcat(buffer, call); + } + if (pr->entry.ndigis >= 4) + strcat(buffer, ",..."); + printf("%-70s %-5s\n", + buffer, pr->entry.portname); + break; + case 2: + strcpy(lh, ctime(&pr->entry.last_heard)); + lh[19] = 0; + strcpy(fh, ctime(&pr->entry.first_heard)); + fh[19] = 0; + call = ax25_ntoa(&pr->entry.from_call); + if ((s = strstr(call, "-0")) != NULL) + *s = '\0'; + printf("%-10s %-5s %5d %5d %5d %s %s\n", + call, pr->entry.portname, pr->entry.iframes, pr->entry.sframes, pr->entry.uframes, fh, lh); + break; + case 3: + call = ax25_ntoa(&pr->entry.from_call); + if ((s = strstr(call, "-0")) != NULL) + *s = '\0'; + printf("%-10s %-5s %5d %5s ", + call, pr->entry.portname, pr->entry.count, types[pr->entry.type]); + if (pr->entry.mode & MHEARD_MODE_ARP) + printf(" ARP"); + if (pr->entry.mode & MHEARD_MODE_FLEXNET) + printf(" FlexNet"); + if (pr->entry.mode & MHEARD_MODE_IP_DG) + printf(" IP-DG"); + if (pr->entry.mode & MHEARD_MODE_IP_VC) + printf(" IP-VC"); + if (pr->entry.mode & MHEARD_MODE_NETROM) + printf(" NET/ROM"); + if (pr->entry.mode & MHEARD_MODE_ROSE) + printf(" Rose"); + if (pr->entry.mode & MHEARD_MODE_SEGMENT) + printf(" Segment"); + if (pr->entry.mode & MHEARD_MODE_TEXNET) + printf(" TexNet"); + if (pr->entry.mode & MHEARD_MODE_TEXT) + printf(" Text"); + if (pr->entry.mode & MHEARD_MODE_PSATFT) + printf(" PacsatFT"); + if (pr->entry.mode & MHEARD_MODE_PSATPB) + printf(" PacsatPB"); + if (pr->entry.mode & MHEARD_MODE_UNKNOWN) + printf(" Unknown"); + printf("\n"); + break; + } +} + +static void ListAllPorts(int data) +{ + struct PortRecord *pr; + + for (pr = PortList; pr != NULL; pr = pr->Next) + PrintPortEntry(pr, data); +} + +static void ListOnlyPort(char *name, int data) +{ + struct PortRecord *pr; + + for (pr = PortList; pr != NULL; pr = pr->Next) + if (strcmp(pr->entry.portname, name) == 0) + PrintPortEntry(pr, data); +} + +static void LoadPortData(void) +{ + FILE *fp; + struct PortRecord *pr; + struct mheard_struct mheard; + + if ((fp = fopen(DATA_MHEARD_FILE, "r")) == NULL) { + fprintf(stderr, "mheard: cannot open mheard data file\n"); + exit(1); + } + + while (fread(&mheard, sizeof(struct mheard_struct), 1, fp) == 1) { + pr = malloc(sizeof(struct PortRecord)); + pr->entry = mheard; + pr->Next = PortList; + PortList = pr; + } + + fclose(fp); +} + +static void SortByTime(void) +{ + struct PortRecord *p = PortList; + struct PortRecord *n; + PortList = NULL; + + while (p != NULL) { + struct PortRecord *w = PortList; + + n = p->Next; + + if (w == NULL || p->entry.last_heard > w->entry.last_heard) { + p->Next = w; + PortList = p; + p = n; + continue; + } + + while (w->Next != NULL && p->entry.last_heard <= w->Next->entry.last_heard) + w = w->Next; + + p->Next = w->Next; + w->Next = p; + p = n; + } +} + + +static void SortByPort(void) +{ + struct PortRecord *p = PortList; + struct PortRecord *n; + PortList = NULL; + + while (p != NULL) { + struct PortRecord *w = PortList; + + n = p->Next; + + if (w == NULL || strcmp(p->entry.portname, w->entry.portname) < 0) { + p->Next = w; + PortList = p; + p = n; + continue; + } + + while (w->Next != NULL && strcmp(p->entry.portname, w->Next->entry.portname) >= 0) + w = w->Next; + + p->Next = w->Next; + w->Next = p; + p = n; + } +} + +static void SortByCall(void) +{ + struct PortRecord *p = PortList; + struct PortRecord *n; + PortList = NULL; + + while (p != NULL) { + struct PortRecord *w = PortList; + + n = p->Next; + + if (w == NULL || memcmp(&p->entry.from_call, &w->entry.from_call, sizeof(ax25_address)) < 0) { + p->Next = w; + PortList = p; + p = n; + continue; + } + + while (w->Next != NULL && memcmp(&p->entry.from_call, &w->Next->entry.from_call, sizeof(ax25_address)) >= 0) + w = w->Next; + + p->Next = w->Next; + w->Next = p; + p = n; + } +} + +static void SortByFrame(void) +{ + struct PortRecord *p = PortList; + struct PortRecord *n; + PortList = NULL; + + while (p != NULL) { + struct PortRecord *w = PortList; + + n = p->Next; + + if (w == NULL || p->entry.count > w->entry.count) { + p->Next = w; + PortList = p; + p = n; + continue; + } + + while (w->Next != NULL && p->entry.count <= w->Next->entry.count) + w = w->Next; + + p->Next = w->Next; + w->Next = p; + p = n; + } +} + +int main(int argc, char *argv[]) +{ + int headers = TRUE; + int mode = 0; + int data = 0; + int c; + + while ((c = getopt(argc, argv, "d:no:v")) != -1) { + switch (c) { + case 'd': + switch (*optarg) { + case 'c': + data = 1; + break; + case 'm': + data = 3; + break; + case 'n': + data = 0; + break; + case 's': + data = 2; + break; + default: + fprintf(stderr, "mheard: invalid display type '%s'\n", optarg); + return 1; + } + break; + case 'n': + headers = FALSE; + break; + case 'o': + switch (*optarg) { + case 'c': + mode = 2; + break; + case 'f': + mode = 3; + break; + case 'p': + mode = 1; + break; + case 't': + mode = 0; + break; + default: + fprintf(stderr, "mheard: invalid ordering type '%s'\n", optarg); + return 1; + } + break; + case 'v': + printf("mheard: %s\n", VERSION); + return 0; + case '?': + case ':': + fprintf(stderr, "Usage: %s [-d cmns] [-n] [-o cfpt] [-v] [port ...]\n", argv[0]); + return 1; + } + } + + LoadPortData(); + + switch (mode) { + case 0: SortByTime(); break; + case 1: SortByPort(); break; + case 2: SortByCall(); break; + case 3: SortByFrame(); break; + } + + if (argc == optind) { + if (headers) + PrintHeader(data); + ListAllPorts(data); + } else { + while (argv[optind] != NULL) { + if (headers) { + printf("Port %s:\n", argv[optind]); + PrintHeader(data); + } + ListOnlyPort(argv[optind], data); + optind++; + } + } + + return 0; +} diff --git a/ax25/mheard.dat b/ax25/mheard.dat new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ax25/mheard.dat diff --git a/ax25/mheardd.8 b/ax25/mheardd.8 new file mode 100644 index 0000000..63cda36 --- /dev/null +++ b/ax25/mheardd.8 @@ -0,0 +1,42 @@ +.TH MHEARDD 8 "27 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +mheardd \- collect information about packet activity +.SH SYNOPSIS +.B mheardd [-f] [-l] [-n number] [-v] +.SH DESCRIPTION +.LP +.B Mheardd +is a daemon that collects the statistics about the activity on all the AX.25 +channels that are configured. The list generated is available for viewing by +the +.BR mheard (1) +program. The information collected is a superset of the information normally +collected by similar mheard programs and this is reflected in the options +available for the viewing program. Logging to the system log file may be +enabled which will enable monitoring of pathalogical conditions, for example +invalid frame types and invalid/unknown protocol IDs. +.SH OPTIONS +.TP 10 +.BI \-f +Deletes the existing mheard logging file at program startup, this is not the +default. +.TP 10 +.BI \-l +Enables logging to the system log file. The default is off. +.TP 10 +.BI "\-n number" +Sets the number of entries in the activity list file, the default is 40. The +minimum value allowed is 10 and the maximum is 100. +.TP 10 +.BI \-v +Display the version. +.SH FILES +.LP +/var/ax25/mheard/mheard.dat +.br +/etc/ax25/axports +.SH "SEE ALSO" +.BR mheard (1), +.BR ax25 (4). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/ax25/mheardd.c b/ax25/mheardd.c new file mode 100644 index 0000000..2d98fad --- /dev/null +++ b/ax25/mheardd.c @@ -0,0 +1,436 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <signal.h> +#include <syslog.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <sys/socket.h> +#include <net/ethernet.h> +#include <netinet/in.h> + +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/daemon.h> +#include <netax25/mheard.h> + +#include <config.h> + +#include "../pathnames.h" + +#define KISS_MASK 0x0F +#define KISS_DATA 0x00 + +#define PID_SEGMENT 0x08 +#define PID_ARP 0xCD +#define PID_NETROM 0xCF +#define PID_IP 0xCC +#define PID_ROSE 0x01 +#define PID_TEXNET 0xC3 +#define PID_FLEXNET 0xCE +#define PID_TEXT 0xF0 +#define PID_PSATFT 0xBB +#define PID_PSATPB 0xBD + +#define I 0x00 +#define S 0x01 +#define RR 0x01 +#define RNR 0x05 +#define REJ 0x09 +#define U 0x03 +#define SABM 0x2F +#define SABME 0x6F +#define DISC 0x43 +#define DM 0x0F +#define UA 0x63 +#define FRMR 0x87 +#define UI 0x03 + +#define PF 0x10 +#define EPF 0x01 + +#define MMASK 7 + +#define HDLCAEB 0x01 +#define SSID 0x1E +#define SSSID_SPARE 0x40 +#define ESSID_SPARE 0x20 + +#define ALEN 6 +#define AXLEN 7 + +struct mheard_list_struct { + int in_use; + struct mheard_struct entry; + long position; +}; + +static struct mheard_list_struct *mheard_list; +static int mheard_list_size = 40; +static int logging = FALSE; + +static int ftype(unsigned char *, int *, int); +static struct mheard_list_struct *findentry(ax25_address *, char *); + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +int main(int argc, char **argv) +{ + struct mheard_list_struct *mheard; + unsigned char buffer[1500], *data; + int size, s; + char *port = NULL; + struct sockaddr sa; + int asize; + long position; + int ctlen, type, end, extseq, flush = FALSE; + FILE *fp; + + while ((s = getopt(argc, argv, "fln:v")) != -1) { + switch (s) { + case 'l': + logging = TRUE; + break; + case 'f': + flush = TRUE; + break; + case 'n': + mheard_list_size = atoi(optarg); + if (mheard_list_size < 10 || mheard_list_size > 100) { + fprintf(stderr, "mheardd: list size must be between 10 and 100\n"); + return 1; + } + break; + case 'v': + printf("mheardd: %s\n", VERSION); + return 0; + case ':': + fprintf(stderr, "mheardd: option -n needs an argument\n"); + return 1; + case '?': + fprintf(stderr, "Usage: mheardd [-f] [-l] [-n number] [-v]\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "mheardd: no AX.25 port data configured\n"); + return 1; + } + + if ((mheard_list = calloc(mheard_list_size, sizeof(struct mheard_list_struct))) == NULL) { + fprintf(stderr, "mheardd: cannot allocate memory\n"); + return 1; + } + + if (flush) + unlink(DATA_MHEARD_FILE); + + /* Load an existing heard list */ + if ((fp = fopen(DATA_MHEARD_FILE, "r")) != NULL) { + s = 0; + position = ftell(fp); + + while (fread(buffer, sizeof(struct mheard_struct), 1, fp) == 1 && s < mheard_list_size) { + memcpy(&mheard_list[s].entry, buffer, sizeof(struct mheard_struct)); + mheard_list[s].in_use = TRUE; + mheard_list[s].position = position; + position = ftell(fp); + s++; + } + + fclose(fp); + } else { + if ((fp = fopen(DATA_MHEARD_FILE, "w")) != NULL) + fclose(fp); + } + + if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) { + perror("mheardd: socket"); + return 1; + } + + if (!daemon_start(FALSE)) { + fprintf(stderr, "mheardd: cannot become a daemon\n"); + return 1; + } + + /* Use syslog for error messages rather than perror/fprintf */ + if (logging) { + openlog("mheardd", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + asize = sizeof(sa); + + if ((size = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &asize)) == -1) { + if (logging) { + syslog(LOG_ERR, "recv: %m"); + closelog(); + } + return 1; + } + + if ((port = ax25_config_get_name(sa.sa_data)) == NULL) { + if (logging) + syslog(LOG_WARNING, "unknown port '%s'\n", sa.sa_data); + continue; + } + + data = buffer; + + if ((*data & KISS_MASK) != KISS_DATA) + continue; + + data++; + size--; + + if (size < (AXLEN + AXLEN + 1)) { + if (logging) + syslog(LOG_WARNING, "packet too short\n"); + continue; + } + + mheard = findentry((ax25_address *)(data + AXLEN), port); + + if (!ax25_validate(data + 0) || !ax25_validate(data + AXLEN)) { + if (logging) + syslog(LOG_WARNING, "invalid callsign on port %s\n", port); + continue; + } + + memcpy(&mheard->entry.from_call, data + AXLEN, sizeof(ax25_address)); + memcpy(&mheard->entry.to_call, data + 0, sizeof(ax25_address)); + strcpy(mheard->entry.portname, port); + mheard->entry.ndigis = 0; + + extseq = ((data[AXLEN + ALEN] & SSSID_SPARE) != SSSID_SPARE); + end = (data[AXLEN + ALEN] & HDLCAEB); + + data += (AXLEN + AXLEN); + size -= (AXLEN + AXLEN); + + while (!end) { + memcpy(&mheard->entry.digis[mheard->entry.ndigis], data, sizeof(ax25_address)); + mheard->entry.ndigis++; + + end = (data[ALEN] & HDLCAEB); + + data += AXLEN; + size -= AXLEN; + } + + if (size == 0) { + if (logging) + syslog(LOG_WARNING, "packet too short\n"); + continue; + } + + ctlen = ftype(data, &type, extseq); + + mheard->entry.count++; + + switch (type) { + case SABM: + mheard->entry.type = MHEARD_TYPE_SABM; + mheard->entry.uframes++; + break; + case SABME: + mheard->entry.type = MHEARD_TYPE_SABME; + mheard->entry.uframes++; + break; + case DISC: + mheard->entry.type = MHEARD_TYPE_DISC; + mheard->entry.uframes++; + break; + case UA: + mheard->entry.type = MHEARD_TYPE_UA; + mheard->entry.uframes++; + break; + case DM: + mheard->entry.type = MHEARD_TYPE_DM; + mheard->entry.uframes++; + break; + case RR: + mheard->entry.type = MHEARD_TYPE_RR; + mheard->entry.sframes++; + break; + case RNR: + mheard->entry.type = MHEARD_TYPE_RNR; + mheard->entry.sframes++; + break; + case REJ: + mheard->entry.type = MHEARD_TYPE_REJ; + mheard->entry.sframes++; + break; + case FRMR: + mheard->entry.type = MHEARD_TYPE_FRMR; + mheard->entry.uframes++; + break; + case I: + mheard->entry.type = MHEARD_TYPE_I; + mheard->entry.iframes++; + break; + case UI: + mheard->entry.type = MHEARD_TYPE_UI; + mheard->entry.uframes++; + break; + default: + if (logging) + syslog(LOG_WARNING, "unknown packet type %02X\n", *data); + mheard->entry.type = MHEARD_TYPE_UNKNOWN; + break; + } + + data += ctlen; + size -= ctlen; + + if (type == I || type == UI) { + switch (*data) { + case PID_TEXT: + mheard->entry.mode |= MHEARD_MODE_TEXT; + break; + case PID_SEGMENT: + mheard->entry.mode |= MHEARD_MODE_SEGMENT; + break; + case PID_ARP: + mheard->entry.mode |= MHEARD_MODE_ARP; + break; + case PID_NETROM: + mheard->entry.mode |= MHEARD_MODE_NETROM; + break; + case PID_IP: + mheard->entry.mode |= (type == I) ? MHEARD_MODE_IP_VC : MHEARD_MODE_IP_DG; + break; + case PID_ROSE: + mheard->entry.mode |= MHEARD_MODE_ROSE; + break; + case PID_TEXNET: + mheard->entry.mode |= MHEARD_MODE_TEXNET; + break; + case PID_FLEXNET: + mheard->entry.mode |= MHEARD_MODE_FLEXNET; + break; + case PID_PSATPB: + mheard->entry.mode |= MHEARD_MODE_PSATPB; + break; + case PID_PSATFT: + mheard->entry.mode |= MHEARD_MODE_PSATFT; + break; + default: + if (logging) + syslog(LOG_WARNING, "unknown PID %02X\n", *data); + mheard->entry.mode |= MHEARD_MODE_UNKNOWN; + break; + } + } + + if (mheard->entry.first_heard == 0) + time(&mheard->entry.first_heard); + + time(&mheard->entry.last_heard); + + if ((fp = fopen(DATA_MHEARD_FILE, "r+")) == NULL) { + if (logging) + syslog(LOG_ERR, "cannot open mheard data file\n"); + continue; + } + + if (mheard->position == 0xFFFFFF) { + fseek(fp, 0L, SEEK_END); + mheard->position = ftell(fp); + } + + fseek(fp, mheard->position, SEEK_SET); + + fwrite(&mheard->entry, sizeof(struct mheard_struct), 1, fp); + + fclose(fp); + } +} + +static int ftype(unsigned char *data, int *type, int extseq) +{ + if (extseq) { + if ((*data & 0x01) == 0) { /* An I frame is an I-frame ... */ + *type = I; + return 2; + } + if (*data & 0x02) { + *type = *data & ~PF; + return 1; + } else { + *type = *data; + return 2; + } + } else { + if ((*data & 0x01) == 0) { /* An I frame is an I-frame ... */ + *type = I; + return 1; + } + if (*data & 0x02) { /* U-frames use all except P/F bit for type */ + *type = *data & ~PF; + return 1; + } else { /* S-frames use low order 4 bits for type */ + *type = *data & 0x0F; + return 1; + } + } +} + +static struct mheard_list_struct *findentry(ax25_address *callsign, char *port) +{ + struct mheard_list_struct *oldest = NULL; + int i; + + for (i = 0; i < mheard_list_size; i++) + if (mheard_list[i].in_use && + ax25_cmp(&mheard_list[i].entry.from_call, callsign) == 0 && + strcmp(mheard_list[i].entry.portname, port) == 0) + return mheard_list + i; + + for (i = 0; i < mheard_list_size; i++) { + if (!mheard_list[i].in_use) { + mheard_list[i].in_use = TRUE; + mheard_list[i].position = 0xFFFFFF; + return mheard_list + i; + } + } + + for (i = 0; i < mheard_list_size; i++) { + if (mheard_list[i].in_use) { + if (oldest == NULL) { + oldest = mheard_list + i; + } else { + if (mheard_list[i].entry.last_heard < oldest->entry.last_heard) + oldest = mheard_list + i; + } + } + } + + memset(&oldest->entry, 0x00, sizeof(struct mheard_struct)); + + return oldest; +} diff --git a/ax25/rxecho.8 b/ax25/rxecho.8 new file mode 100644 index 0000000..7a9ed80 --- /dev/null +++ b/ax25/rxecho.8 @@ -0,0 +1,38 @@ +.TH RXECHO 8 "15 October 1996" Linux "Linux System Managers Manual" +.SH NAME +rxecho \- Route AX.25 packets between ports transparently. +.SH SYNOPSIS +.B rxecho [-l] [-v] +.SH DESCRIPTION +.LP +.B Rxecho +copies AX.25 frames between interfaces without altering their contents. The +purpose of this utility is to allow other AX.25 aware programs/computers to +share the same AX.25 ports as the Linux kernel AX.25 code. It could be used +to route packets out onto another serial port to allow another machine +running DOS based programs to share the same radio ports as the Linux +machine, or it could route packets out onto a pseudo-tty to another +application on the same machine. The copying could even be to another +radio port. +.LP +The copying of the packets is controlled by a configuration file +rxecho.conf(5), which can be set up to selectively copy packets. +.SH OPTIONS +.TP 10 +.BI \-l +Enables logging of errors to the system log, the default is off. +.TP 10 +.BI \-v +Display the version. +.SH FILES +.nf +/etc/ax25/axports +.br +/etc/ax25/rxecho.conf +.fi +.SH "SEE ALSO" +.BR axports (5), +.BR rxecho.conf (5), +.BR kissattach (8). +.SH AUTHOR +Tomi Manninen OH2BNS <tpmannin@cc.hut.fi> diff --git a/ax25/rxecho.c b/ax25/rxecho.c new file mode 100644 index 0000000..31334aa --- /dev/null +++ b/ax25/rxecho.c @@ -0,0 +1,376 @@ +/* + * rxecho.c - Copies AX.25 packets from an interface to another interface. + * Reads CONFIGFILE (see below) and uses that information to + * decide what packets should be copied and where. + * + * CONFIGFILE format is: + * + * # this is a comment + * 144 kiss0 oh2bns-1,oh2bns-2 + * kiss0 144 * + * + * This means that packets received on port 144 are copied to port + * kiss0 if they are destined to oh2bns-1 or oh2bns-2. Packets + * from port kiss0 are all copied to port 144. + * + * There may be empty lines and an arbirary amount of white + * space around the tokens but the callsign field must not + * have any spaces in it. There can be up to MAXCALLS call- + * signs in the callsign field (see below). + * + * Copyright (C) 1996 by Tomi Manninen, OH2BNS, <tomi.manninen@hut.fi>. + * + * *** Modified 9/9/96 by Heikki Hannikainen, OH7LZB, <hessu@pspt.fi>: + * + * One port can actually be echoed to multiple ports (with a + * different recipient callsign, of course). The old behaviour was + * to give up on the first matching port, even if the recipient + * callsign didn't match (and the frame wasn't echoed anywhere). + * + * *** + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> +#include <signal.h> +#include <sys/types.h> + +#include <sys/socket.h> +#include <net/ethernet.h> +#include <netinet/in.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/daemon.h> + +#include <config.h> + +#include "../pathnames.h" + +#define MAXCALLS 8 + +struct config { + char from[14]; /* sockaddr.sa_data is 14 bytes */ + char to[14]; + ax25_address calls[MAXCALLS];/* list of calls to echo */ + int ncalls; /* number of calls to echo */ + + struct config *next; +}; + +static int logging = FALSE; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +/* + * Read string "call1,call2,call3,..." into p. + */ +static int read_calls(struct config *p, char *s) +{ + char *cp, *cp1; + + if (p == NULL || s == NULL) + return -1; + + p->ncalls = 0; + + if (strcmp(s, "*") == 0) + return 0; + + cp = s; + + while ((cp1 = strchr(cp, ',')) != NULL && p->ncalls < MAXCALLS) { + *cp1 = 0; + + if (ax25_aton_entry(cp, p->calls[p->ncalls].ax25_call) == -1) + return -1; + + p->ncalls++; + cp = ++cp1; + } + + if (p->ncalls < MAXCALLS) { + if (ax25_aton_entry(cp, p->calls[p->ncalls].ax25_call) == -1) + return -1; + + p->ncalls++; + } + + return p->ncalls; +} + +static struct config *readconfig(void) +{ + FILE *fp; + char line[80], *cp, *dev; + struct config *p, *list = NULL; + + if ((fp = fopen(CONF_RXECHO_FILE, "r")) == NULL) { + fprintf(stderr, "rxecho: cannot open config file\n"); + return NULL; + } + + while (fgets(line, 80, fp) != NULL) { + cp = strtok(line, " \t\r\n"); + + if (cp == NULL || cp[0] == '#') + continue; + + if ((p = calloc(1, sizeof(struct config))) == NULL) { + perror("rxecho: malloc"); + return NULL; + } + + if ((dev = ax25_config_get_dev(cp)) == NULL) { + fprintf(stderr, "rxecho: invalid port name - %s\n", cp); + return NULL; + } + + strcpy(p->from, dev); + + if ((cp = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "rxecho: config file error.\n"); + return NULL; + } + + if ((dev = ax25_config_get_dev(cp)) == NULL) { + fprintf(stderr, "rxecho: invalid port name - %s\n", cp); + return NULL; + } + + strcpy(p->to, dev); + + if (read_calls(p, strtok(NULL, " \t\r\n")) == -1) { + fprintf(stderr, "rxecho: config file error.\n"); + return NULL; + } + + p->next = list; + list = p; + } + + fclose(fp); + + if (list == NULL) + fprintf(stderr, "rxecho: Empty config file!\n"); + + return list; +} + +/* + * Slightly modified from linux/include/net/ax25.h and + * linux/net/ax25/ax25_subr.c: + */ + +#if 0 +#define C_COMMAND 1 +#define C_RESPONSE 2 +#define LAPB_C 0x80 +#endif +#define LAPB_E 0x01 +#define AX25_ADDR_LEN 7 +#define AX25_REPEATED 0x80 + +typedef struct { + ax25_address calls[AX25_MAX_DIGIS]; + unsigned char repeated[AX25_MAX_DIGIS]; + char ndigi; + char lastrepeat; +} ax25_digi; + +/* + * Given an AX.25 address pull of to, from, digi list, and the start of data. + */ +static unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi) +{ + int d = 0; + + if (len < 14) return NULL; + +#if 0 + if (flags != NULL) { + *flags = 0; + + if (buf[6] & LAPB_C) { + *flags = C_COMMAND; + } + + if (buf[13] & LAPB_C) { + *flags = C_RESPONSE; + } + } + + if (dama != NULL) + *dama = ~buf[13] & DAMA_FLAG; +#endif + + /* Copy to, from */ + if (dest != NULL) + memcpy(dest, buf + 0, AX25_ADDR_LEN); + + if (src != NULL) + memcpy(src, buf + 7, AX25_ADDR_LEN); + + buf += 2 * AX25_ADDR_LEN; + len -= 2 * AX25_ADDR_LEN; + + digi->lastrepeat = -1; + digi->ndigi = 0; + + while (!(buf[-1] & LAPB_E)) { + if (d >= AX25_MAX_DIGIS) return NULL; /* Max of 6 digis */ + if (len < 7) return NULL; /* Short packet */ + + if (digi != NULL) { + memcpy(&digi->calls[d], buf, AX25_ADDR_LEN); + digi->ndigi = d + 1; + + if (buf[6] & AX25_REPEATED) { + digi->repeated[d] = 1; + digi->lastrepeat = d; + } else { + digi->repeated[d] = 0; + } + } + + buf += AX25_ADDR_LEN; + len -= AX25_ADDR_LEN; + d++; + } + + return buf; +} + +/* + * Check if frame should be echoed. Return 0 if it should and -1 if not. + */ +static int check_calls(struct config *cfg, unsigned char *buf, int len) +{ + ax25_address dest; + ax25_digi digi; + ax25_address *axp; + int i; + + if ((buf[0] & 0x0F) != 0) + return -1; /* don't echo non-data */ + + if (cfg->ncalls == 0) + return 0; /* copy everything */ + + if (ax25_parse_addr(++buf, --len, NULL, &dest, &digi) == NULL) + return -1; /* invalid ax.25 header */ + + /* + * If there are no digis or all digis are already repeated + * use destination address. Else use first non-repeated digi. + */ + if (digi.ndigi == 0 || digi.ndigi == digi.lastrepeat + 1) + axp = &dest; + else + axp = &digi.calls[digi.lastrepeat + 1]; + + for (i = 0; i < cfg->ncalls; i++) + if (ax25_cmp(&cfg->calls[i], axp) == 0) + return 0; + + return -1; +} + +int main(int argc, char **argv) +{ + struct sockaddr sa; + int s, size, alen; + unsigned char buf[1500]; + struct config *p, *list; + + while ((s = getopt(argc, argv, "lv")) != -1) { + switch (s) { + case 'l': + logging = TRUE; + break; + case 'v': + printf("rxecho: %s\n", VERSION); + return 0; + default: + fprintf(stderr, "usage: rxecho [-l] [-v]\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "rxecho: no AX.25 port data configured\n"); + return 1; + } + + if ((list = readconfig()) == NULL) + return 1; + + if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) { + perror("rxecho: socket:"); + return 1; + } + + if (!daemon_start(FALSE)) { + fprintf(stderr, "rxecho: cannot become a daemon\n"); + close(s); + return 1; + } + + if (logging) { + openlog("rxecho", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + alen = sizeof(sa); + + if ((size = recvfrom(s, buf, 1500, 0, &sa, &alen)) == -1) { + if (logging) { + syslog(LOG_ERR, "recvfrom: %m"); + closelog(); + } + return 1; + } + + for (p = list; p != NULL; p = p->next) + if ((strcmp(p->from, sa.sa_data) == 0) && (check_calls(p, buf, size) == 0)) { + strcpy(sa.sa_data, p->to); + if (sendto(s, buf, size, 0, &sa, alen) == -1) { + if (logging) { + syslog(LOG_ERR, "sendto: %m"); + closelog(); + } + } + } + } +} diff --git a/ax25/rxecho.conf b/ax25/rxecho.conf new file mode 100644 index 0000000..0bb498c --- /dev/null +++ b/ax25/rxecho.conf @@ -0,0 +1,12 @@ +# /etc/ax25/rxecho.conf +# +# This means that packets received on port '1' are copied to port '2' if they +# are destined to oh2bns-1 or oh2bns-2. All packets from port '2' are copied +# to port '1'. +# +# There may be empty lines and an arbirary amount of white space around the +# tokens but the callsign field must not have any spaces in it. There can be +# up to MAXCALLS callsigns in the callsign field. +# +1 2 oh2bns-1,oh2bns-2 +2 1 * diff --git a/ax25/rxecho.conf.5 b/ax25/rxecho.conf.5 new file mode 100644 index 0000000..105c45b --- /dev/null +++ b/ax25/rxecho.conf.5 @@ -0,0 +1,22 @@ +.TH RXECHO.CONF 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +rxecho.conf \- control rxecho AX.25 packet routing. +.SH DESCRIPTION +.LP +.B Rxecho.conf +controls the copying of packets between AX.25 ports performed by the program +rxecho. The format of the configuration file is: + +portin portout * | callsign... + +Each entry in the file represents a one-way packet flow between ports. Any +packet received on portin is copied to portout, if its destination callsign +or the next callsign to digipeat the frame is in the list of callsigns. If +the callsign list is replaced by a \(lq*\(rq then all packets are copied. +The configuration file may contain comments that begin with a #. +.SH FILES +.LP +/etc/ax25/rxecho.conf +.SH "SEE ALSO" +.BR axports (8), +.BR rxecho (8). diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..29a1390 --- /dev/null +++ b/config.h.in @@ -0,0 +1,124 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef gid_t + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME + +/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have the wait3 system call. */ +#undef HAVE_WAIT3 + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef pid_t + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if the `setpgrp' function takes no argument. */ +#undef SETPGRP_VOID + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +#undef TIME_WITH_SYS_TIME + +/* Define if your <sys/time.h> declares struct tm. */ +#undef TM_IN_SYS_TIME + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef uid_t + +/* Define if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +#undef HAVE_AX25_FWD_STRUCT + +#undef HAVE_AX25_IAMDIGI +#undef HAVE_AX25_PIDINCL + +/* Define if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if you have the mkdir function. */ +#undef HAVE_MKDIR + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the socket function. */ +#undef HAVE_SOCKET + +/* Define if you have the strdup function. */ +#undef HAVE_STRDUP + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strspn function. */ +#undef HAVE_STRSPN + +/* Define if you have the strstr function. */ +#undef HAVE_STRSTR + +/* Define if you have the strtol function. */ +#undef HAVE_STRTOL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the uname function. */ +#undef HAVE_UNAME + +/* Define if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the <paths.h> header file. */ +#undef HAVE_PATHS_H + +/* Define if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the <sys/file.h> header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the <sys/ioctl.h> header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the <syslog.h> header file. */ +#undef HAVE_SYSLOG_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the ax25 library (-lax25). */ +#undef HAVE_LIBAX25 + +/* Define if you have the util library (-lutil). */ +#undef HAVE_LIBUTIL + +/* Define if you have the z library (-lz). */ +#undef HAVE_LIBZ + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/configure b/configure new file mode 100755 index 0000000..1e9bf5a --- /dev/null +++ b/configure @@ -0,0 +1,3654 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-x use the X Window System" +ac_help="$ac_help + --with-x use the X Window System" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=ax25/ax25d.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +VERSION=0.0.1 +PACKAGE=ax25-tools +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:563: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:616: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:673: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=$PACKAGE + +VERSION=$VERSION + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <<EOF +#define PACKAGE "$PACKAGE" +EOF + +cat >> confdefs.h <<EOF +#define VERSION "$VERSION" +EOF + + + +missing_dir=`cd $ac_aux_dir && pwd` +echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 +echo "configure:719: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:732: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:745: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:758: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:771: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + + + + + + + +for ac_prog in mawk gawk nawk awk +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:796: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AWK" && break +done + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:828: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:858: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:909: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:941: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 952 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:957: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:983: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:988: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:997: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1016: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1059: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +echo $ac_n "checking for zlibVersion in -lz""... $ac_c" 1>&6 +echo "configure:1113: checking for zlibVersion in -lz" >&5 +ac_lib_var=`echo z'_'zlibVersion | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lz $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1121 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char zlibVersion(); + +int main() { +zlibVersion() +; return 0; } +EOF +if { (eval echo configure:1132: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo z | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lz $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for ax25_config_load_ports in -lax25""... $ac_c" 1>&6 +echo "configure:1160: checking for ax25_config_load_ports in -lax25" >&5 +ac_lib_var=`echo ax25'_'ax25_config_load_ports | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lax25 -lz $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1168 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ax25_config_load_ports(); + +int main() { +ax25_config_load_ports() +; return 0; } +EOF +if { (eval echo configure:1179: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo ax25 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lax25 $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + +echo $ac_n "checking for initscr in -lncurses""... $ac_c" 1>&6 +echo "configure:1208: checking for initscr in -lncurses" >&5 +ac_lib_var=`echo ncurses'_'initscr | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lncurses $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1216 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char initscr(); + +int main() { +initscr() +; return 0; } +EOF +if { (eval echo configure:1227: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + NCURSES_LIB="-lncurses" +else + echo "$ac_t""no" 1>&6 +NCURSES_LIB= +fi + + +echo $ac_n "checking for openpty in -lutil""... $ac_c" 1>&6 +echo "configure:1250: checking for openpty in -lutil" >&5 +ac_lib_var=`echo util'_'openpty | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lutil $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1258 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char openpty(); + +int main() { +openpty() +; return 0; } +EOF +if { (eval echo configure:1269: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo util | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lutil $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1297: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 1312 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1318: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 1329 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1335: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 1346 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1352: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +# If we find X, set shell vars x_includes and x_libraries to the +# paths, otherwise set no_x=yes. +# Uses ac_ vars as temps to allow command line to override cache and checks. +# --without-x overrides everything else, but does not touch the cache. +echo $ac_n "checking for X""... $ac_c" 1>&6 +echo "configure:1381: checking for X" >&5 + +# Check whether --with-x or --without-x was given. +if test "${with_x+set}" = set; then + withval="$with_x" + : +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else +if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=NO ac_x_libraries=NO +rm -fr conftestdir +if mkdir conftestdir; then + cd conftestdir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat > Imakefile <<'EOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case "$ac_im_incroot" in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; + esac + case "$ac_im_usrlibdir" in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; + esac + fi + cd .. + rm -fr conftestdir +fi + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +cat > conftest.$ac_ext <<EOF +#line 1443 "configure" +#include "confdefs.h" +#include <$x_direct_test_include> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1448: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + # We can compile using X headers with no special include directory. +ac_x_includes= +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + # Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done +fi +rm -f conftest* +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1517 "configure" +#include "confdefs.h" + +int main() { +${x_direct_test_function}() +; return 0; } +EOF +if { (eval echo configure:1524: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries= +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \ + /usr/X11/lib \ + /usr/X11R6/lib \ + /usr/X11R5/lib \ + /usr/X11R4/lib \ + \ + /usr/lib/X11 \ + /usr/lib/X11R6 \ + /usr/lib/X11R5 \ + /usr/lib/X11R4 \ + \ + /usr/local/X11/lib \ + /usr/local/X11R6/lib \ + /usr/local/X11R5/lib \ + /usr/local/X11R4/lib \ + \ + /usr/local/lib/X11 \ + /usr/local/lib/X11R6 \ + /usr/local/lib/X11R5 \ + /usr/local/lib/X11R4 \ + \ + /usr/X386/lib \ + /usr/x386/lib \ + /usr/XFree86/lib/X11 \ + \ + /usr/lib \ + /usr/local/lib \ + /usr/unsupported/lib \ + /usr/athena/lib \ + /usr/local/x11r5/lib \ + /usr/lpp/Xamples/lib \ + /lib/usr/lib/X11 \ + \ + /usr/openwin/lib \ + /usr/openwin/share/lib \ + ; \ +do + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f conftest* +fi # $ac_x_libraries = NO + +if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi +fi + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + echo "$ac_t""$have_x" 1>&6 + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6 +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + cat >> confdefs.h <<\EOF +#define X_DISPLAY_MISSING 1 +EOF + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + case "`(uname -sr) 2>/dev/null`" in + "SunOS 5"*) + echo $ac_n "checking whether -R must be followed by a space""... $ac_c" 1>&6 +echo "configure:1630: checking whether -R must be followed by a space" >&5 + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries" + cat > conftest.$ac_ext <<EOF +#line 1633 "configure" +#include "confdefs.h" + +int main() { + +; return 0; } +EOF +if { (eval echo configure:1640: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_R_nospace=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_R_nospace=no +fi +rm -f conftest* + if test $ac_R_nospace = yes; then + echo "$ac_t""no" 1>&6 + X_LIBS="$X_LIBS -R$x_libraries" + else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat > conftest.$ac_ext <<EOF +#line 1656 "configure" +#include "confdefs.h" + +int main() { + +; return 0; } +EOF +if { (eval echo configure:1663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_R_space=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_R_space=no +fi +rm -f conftest* + if test $ac_R_space = yes; then + echo "$ac_t""yes" 1>&6 + X_LIBS="$X_LIBS -R $x_libraries" + else + echo "$ac_t""neither works" 1>&6 + fi + fi + LIBS="$ac_xsave_LIBS" + esac + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And karl@cs.umb.edu says + # the Alpha needs dnet_stub (dnet does not exist). + echo $ac_n "checking for dnet_ntoa in -ldnet""... $ac_c" 1>&6 +echo "configure:1695: checking for dnet_ntoa in -ldnet" >&5 +ac_lib_var=`echo dnet'_'dnet_ntoa | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldnet $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1703 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dnet_ntoa(); + +int main() { +dnet_ntoa() +; return 0; } +EOF +if { (eval echo configure:1714: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + echo $ac_n "checking for dnet_ntoa in -ldnet_stub""... $ac_c" 1>&6 +echo "configure:1736: checking for dnet_ntoa in -ldnet_stub" >&5 +ac_lib_var=`echo dnet_stub'_'dnet_ntoa | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldnet_stub $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1744 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dnet_ntoa(); + +int main() { +dnet_ntoa() +; return 0; } +EOF +if { (eval echo configure:1755: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to dickey@clark.net. + echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 +echo "configure:1784: checking for gethostbyname" >&5 +if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1789 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char gethostbyname(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) +choke me +#else +gethostbyname(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_gethostbyname=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_gethostbyname=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_gethostbyname = no; then + echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 +echo "configure:1833: checking for gethostbyname in -lnsl" >&5 +ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1841 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname(); + +int main() { +gethostbyname() +; return 0; } +EOF +if { (eval echo configure:1852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says simon@lia.di.epfl.ch: it contains + # gethostby* variants that don't use the nameserver (or something). + # -lsocket must be given before -lnsl if both are needed. + # We assume that if connect needs -lnsl, so does gethostbyname. + echo $ac_n "checking for connect""... $ac_c" 1>&6 +echo "configure:1882: checking for connect" >&5 +if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1887 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char connect(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_connect) || defined (__stub___connect) +choke me +#else +connect(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1910: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_connect=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_connect=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_connect = no; then + echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6 +echo "configure:1931: checking for connect in -lsocket" >&5 +ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1939 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect(); + +int main() { +connect() +; return 0; } +EOF +if { (eval echo configure:1950: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX. + echo $ac_n "checking for remove""... $ac_c" 1>&6 +echo "configure:1974: checking for remove" >&5 +if eval "test \"`echo '$''{'ac_cv_func_remove'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1979 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char remove(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char remove(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_remove) || defined (__stub___remove) +choke me +#else +remove(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2002: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_remove=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_remove=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'remove`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_remove = no; then + echo $ac_n "checking for remove in -lposix""... $ac_c" 1>&6 +echo "configure:2023: checking for remove in -lposix" >&5 +ac_lib_var=`echo posix'_'remove | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lposix $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2031 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char remove(); + +int main() { +remove() +; return 0; } +EOF +if { (eval echo configure:2042: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + echo $ac_n "checking for shmat""... $ac_c" 1>&6 +echo "configure:2066: checking for shmat" >&5 +if eval "test \"`echo '$''{'ac_cv_func_shmat'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2071 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shmat(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shmat(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shmat) || defined (__stub___shmat) +choke me +#else +shmat(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2094: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_shmat=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_shmat=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'shmat`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_shmat = no; then + echo $ac_n "checking for shmat in -lipc""... $ac_c" 1>&6 +echo "configure:2115: checking for shmat in -lipc" >&5 +ac_lib_var=`echo ipc'_'shmat | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lipc $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2123 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shmat(); + +int main() { +shmat() +; return 0; } +EOF +if { (eval echo configure:2134: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +else + echo "$ac_t""no" 1>&6 +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS="$LDFLAGS" + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # --interran@uluru.Stanford.EDU, kb@cs.umb.edu. + echo $ac_n "checking for IceConnectionNumber in -lICE""... $ac_c" 1>&6 +echo "configure:2167: checking for IceConnectionNumber in -lICE" >&5 +ac_lib_var=`echo ICE'_'IceConnectionNumber | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2175 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char IceConnectionNumber(); + +int main() { +IceConnectionNumber() +; return 0; } +EOF +if { (eval echo configure:2186: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +else + echo "$ac_t""no" 1>&6 +fi + + LDFLAGS="$ac_save_LDFLAGS" + +fi + + +# If we find X, set shell vars x_includes and x_libraries to the +# paths, otherwise set no_x=yes. +# Uses ac_ vars as temps to allow command line to override cache and checks. +# --without-x overrides everything else, but does not touch the cache. +echo $ac_n "checking for X""... $ac_c" 1>&6 +echo "configure:2216: checking for X" >&5 + +# Check whether --with-x or --without-x was given. +if test "${with_x+set}" = set; then + withval="$with_x" + : +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else +if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=NO ac_x_libraries=NO +rm -fr conftestdir +if mkdir conftestdir; then + cd conftestdir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat > Imakefile <<'EOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case "$ac_im_incroot" in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; + esac + case "$ac_im_usrlibdir" in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; + esac + fi + cd .. + rm -fr conftestdir +fi + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +cat > conftest.$ac_ext <<EOF +#line 2278 "configure" +#include "confdefs.h" +#include <$x_direct_test_include> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2283: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + # We can compile using X headers with no special include directory. +ac_x_includes= +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + # Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done +fi +rm -f conftest* +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2352 "configure" +#include "confdefs.h" + +int main() { +${x_direct_test_function}() +; return 0; } +EOF +if { (eval echo configure:2359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries= +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \ + /usr/X11/lib \ + /usr/X11R6/lib \ + /usr/X11R5/lib \ + /usr/X11R4/lib \ + \ + /usr/lib/X11 \ + /usr/lib/X11R6 \ + /usr/lib/X11R5 \ + /usr/lib/X11R4 \ + \ + /usr/local/X11/lib \ + /usr/local/X11R6/lib \ + /usr/local/X11R5/lib \ + /usr/local/X11R4/lib \ + \ + /usr/local/lib/X11 \ + /usr/local/lib/X11R6 \ + /usr/local/lib/X11R5 \ + /usr/local/lib/X11R4 \ + \ + /usr/X386/lib \ + /usr/x386/lib \ + /usr/XFree86/lib/X11 \ + \ + /usr/lib \ + /usr/local/lib \ + /usr/unsupported/lib \ + /usr/athena/lib \ + /usr/local/x11r5/lib \ + /usr/lpp/Xamples/lib \ + /lib/usr/lib/X11 \ + \ + /usr/openwin/lib \ + /usr/openwin/share/lib \ + ; \ +do + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f conftest* +fi # $ac_x_libraries = NO + +if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi +fi + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + echo "$ac_t""$have_x" 1>&6 + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6 +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:2446: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2451 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2459: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 2476 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 2494 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 2515 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:2526: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 +echo "configure:2550: checking for sys/wait.h that is POSIX.1 compatible" >&5 +if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2555 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/wait.h> +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif +int main() { +int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; +; return 0; } +EOF +if { (eval echo configure:2571: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_sys_wait_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_sys_wait_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 +if test $ac_cv_header_sys_wait_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_WAIT_H 1 +EOF + +fi + +for ac_hdr in fcntl.h limits.h paths.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2595: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2600 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2605: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +cat > conftest.$ac_ext <<EOF +#line 2633 "configure" +#include "confdefs.h" +#include <netax25/ax25.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ax25_fwd_struct" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_AX25_FWD_STRUCT 1 +EOF + +fi +rm -f conftest* + +cat > conftest.$ac_ext <<EOF +#line 2648 "configure" +#include "confdefs.h" +#include <netax25/ax25.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "AX25_IAMDIGI" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_AX25_IAMDIGI 1 +EOF + +fi +rm -f conftest* + +cat > conftest.$ac_ext <<EOF +#line 2663 "configure" +#include "confdefs.h" +#include <netax25/ax25.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "AX25_PIDINCL" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_AX25_PIDINCL 1 +EOF + +fi +rm -f conftest* + + + + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2681: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2686 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2735: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:2756: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2761 "configure" +#include "confdefs.h" +#include <sys/types.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:2790: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2795 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:2823: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2828 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:2837: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:2858: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2863 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <time.h> +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:2871: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:2894: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext <<EOF +#line 2900 "configure" +#include "confdefs.h" +#include <sgtty.h> +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext <<EOF +#line 2918 "configure" +#include "confdefs.h" +#include <termio.h> +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:2940: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <<EOF +#line 2948 "configure" +#include "confdefs.h" + +main() +{ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1); +} + +EOF +if { (eval echo configure:2958: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" + +echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 +echo "configure:2976: checking whether setpgrp takes no argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2984 "configure" +#include "confdefs.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* + * If this system has a BSD-style setpgrp, which takes arguments, exit + * successfully. + */ +main() +{ + if (setpgrp(1,1) == -1) + exit(0); + else + exit(1); +} + +EOF +if { (eval echo configure:3004: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_setpgrp_void=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_setpgrp_void=yes +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6 +if test $ac_cv_func_setpgrp_void = yes; then + cat >> confdefs.h <<\EOF +#define SETPGRP_VOID 1 +EOF + +fi + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:3028: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3033 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <signal.h> +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:3050: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <<EOF +#define RETSIGTYPE $ac_cv_type_signal +EOF + + +echo $ac_n "checking for strftime""... $ac_c" 1>&6 +echo "configure:3069: checking for strftime" >&5 +if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3074 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char strftime(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char strftime(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_strftime) || defined (__stub___strftime) +choke me +#else +strftime(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3097: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_strftime=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_strftime=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STRFTIME 1 +EOF + +else + echo "$ac_t""no" 1>&6 +# strftime is in -lintl on SCO UNIX. +echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6 +echo "configure:3119: checking for strftime in -lintl" >&5 +ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lintl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3127 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char strftime(); + +int main() { +strftime() +; return 0; } +EOF +if { (eval echo configure:3138: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STRFTIME 1 +EOF + +LIBS="-lintl $LIBS" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking for wait3 that fills in rusage""... $ac_c" 1>&6 +echo "configure:3165: checking for wait3 that fills in rusage" >&5 +if eval "test \"`echo '$''{'ac_cv_func_wait3_rusage'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_wait3_rusage=no +else + cat > conftest.$ac_ext <<EOF +#line 3173 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <stdio.h> +/* HP-UX has wait3 but does not fill in rusage at all. */ +main() { + struct rusage r; + int i; + /* Use a field that we can force nonzero -- + voluntary context switches. + For systems like NeXT and OSF/1 that don't set it, + also use the system CPU time. And page faults (I/O) for Linux. */ + r.ru_nvcsw = 0; + r.ru_stime.tv_sec = 0; + r.ru_stime.tv_usec = 0; + r.ru_majflt = r.ru_minflt = 0; + switch (fork()) { + case 0: /* Child. */ + sleep(1); /* Give up the CPU. */ + _exit(0); + case -1: _exit(0); /* What can we do? */ + default: /* Parent. */ + wait3(&i, 0, &r); + sleep(2); /* Avoid "text file busy" from rm on fast HP-UX machines. */ + exit(r.ru_nvcsw == 0 && r.ru_majflt == 0 && r.ru_minflt == 0 + && r.ru_stime.tv_sec == 0 && r.ru_stime.tv_usec == 0); + } +} +EOF +if { (eval echo configure:3204: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_wait3_rusage=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_wait3_rusage=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_wait3_rusage" 1>&6 +if test $ac_cv_func_wait3_rusage = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_WAIT3 1 +EOF + +fi + +for ac_func in gethostname gettimeofday mkdir select socket strdup strerror strspn strstr strtol strtoul uname +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3229: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3234 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3257: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "netrom/Makefile tcpip/Makefile ax25/Makefile Makefile rose/Makefile user_call/Makefile kiss/Makefile hdlcutil/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@AWK@%$AWK%g +s%@CC@%$CC%g +s%@NCURSES_LIB@%$NCURSES_LIB%g +s%@CPP@%$CPP%g +s%@X_CFLAGS@%$X_CFLAGS%g +s%@X_PRE_LIBS@%$X_PRE_LIBS%g +s%@X_LIBS@%$X_LIBS%g +s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g +s%@LIBOBJS@%$LIBOBJS%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"netrom/Makefile tcpip/Makefile ax25/Makefile Makefile rose/Makefile user_call/Makefile kiss/Makefile hdlcutil/Makefile"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="config.h" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + + +EOF +cat >> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..4efad35 --- /dev/null +++ b/configure.in @@ -0,0 +1,58 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(ax25/ax25d.c) + +dnl For automake +VERSION=0.0.1 +PACKAGE=ax25-tools +AM_INIT_AUTOMAKE($PACKAGE,$VERSION) + +AM_CONFIG_HEADER(config.h) + + + +dnl Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_INSTALL + +dnl Checks for libraries. +AC_CHECK_LIB(z, zlibVersion) +dnl AC_SUBST(AX25_LIB) +dnl AC_CHECK_LIB(ax25, ax25_config_load_ports, AX25_LIB="-lax25", AX25_LIB=,-lz) +AC_CHECK_LIB(ax25, ax25_config_load_ports,,,-lz) +AC_SUBST(NCURSES_LIB) +AC_CHECK_LIB(ncurses, initscr,NCURSES_LIB="-lncurses",NCURSES_LIB=) + +AC_CHECK_LIB(util, openpty) +AC_PATH_XTRA + +dnl Checks for header files. +AC_PATH_X +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h limits.h paths.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h) + +dnl Check for ceratin functions in header files +AC_HEADER_EGREP(ax25_fwd_struct, netax25/ax25.h, AC_DEFINE(HAVE_AX25_FWD_STRUCT)) +AC_HEADER_EGREP(AX25_IAMDIGI, netax25/ax25.h, AC_DEFINE(HAVE_AX25_IAMDIGI)) +AC_HEADER_EGREP(AX25_PIDINCL, netax25/ax25.h, AC_DEFINE(HAVE_AX25_PIDINCL)) + + + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_HEADER_TIME +AC_STRUCT_TM + +dnl Checks for library functions. +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_FUNC_SETPGRP +AC_TYPE_SIGNAL +AC_FUNC_STRFTIME +AC_FUNC_WAIT3 +AC_CHECK_FUNCS(gethostname gettimeofday mkdir select socket strdup strerror strspn strstr strtol strtoul uname) + +AC_OUTPUT(netrom/Makefile tcpip/Makefile ax25/Makefile Makefile rose/Makefile user_call/Makefile kiss/Makefile hdlcutil/Makefile) diff --git a/hdlcutil/Makefile.am b/hdlcutil/Makefile.am new file mode 100644 index 0000000..32059d1 --- /dev/null +++ b/hdlcutil/Makefile.am @@ -0,0 +1,31 @@ + +installconf: + +sbin_PROGRAMS = setcrystal sethdlc smmixer smdiag + +man_MANS = sethdlc.8 smdiag.8 smmixer.8 baycom.9 hdlcdrv.9 soundmodem.9 + +setcrystal_SOURCES = \ + setcrystal.c + +sethdlc_SOURCES = \ + sethdlc.c \ + hdrvcomm.c \ + hdrvcomm.h \ + usersmdiag.h + +smmixer_SOURCES = \ + smmixer.c \ + hdrvcomm.c \ + hdrvcomm.h \ + usersmdiag.h + +smdiag_SOURCES = \ + smdiag.c \ + hdrvcomm.c \ + hdrvcomm.h \ + usersmdiag.h + +smdiag_LDADD = \ + $(X_LIBS) \ + -lX11 diff --git a/hdlcutil/Makefile.in b/hdlcutil/Makefile.in new file mode 100644 index 0000000..edf7170 --- /dev/null +++ b/hdlcutil/Makefile.in @@ -0,0 +1,403 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +sbin_PROGRAMS = setcrystal sethdlc smmixer smdiag + +man_MANS = sethdlc.8 smdiag.8 smmixer.8 baycom.9 hdlcdrv.9 soundmodem.9 + +setcrystal_SOURCES = setcrystal.c + + +sethdlc_SOURCES = sethdlc.c hdrvcomm.c hdrvcomm.h usersmdiag.h + + +smmixer_SOURCES = smmixer.c hdrvcomm.c hdrvcomm.h usersmdiag.h + + +smdiag_SOURCES = smdiag.c hdrvcomm.c hdrvcomm.h usersmdiag.h + + +smdiag_LDADD = $(X_LIBS) -lX11 + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +setcrystal_OBJECTS = setcrystal.o +setcrystal_LDADD = $(LDADD) +setcrystal_DEPENDENCIES = +setcrystal_LDFLAGS = +sethdlc_OBJECTS = sethdlc.o hdrvcomm.o +sethdlc_LDADD = $(LDADD) +sethdlc_DEPENDENCIES = +sethdlc_LDFLAGS = +smmixer_OBJECTS = smmixer.o hdrvcomm.o +smmixer_LDADD = $(LDADD) +smmixer_DEPENDENCIES = +smmixer_LDFLAGS = +smdiag_OBJECTS = smdiag.o hdrvcomm.o +smdiag_DEPENDENCIES = +smdiag_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(setcrystal_SOURCES) $(sethdlc_SOURCES) $(smmixer_SOURCES) $(smdiag_SOURCES) +OBJECTS = $(setcrystal_OBJECTS) $(sethdlc_OBJECTS) $(smmixer_OBJECTS) $(smdiag_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps hdlcutil/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +setcrystal: $(setcrystal_OBJECTS) $(setcrystal_DEPENDENCIES) + @rm -f setcrystal + $(LINK) $(setcrystal_LDFLAGS) $(setcrystal_OBJECTS) $(setcrystal_LDADD) $(LIBS) + +sethdlc: $(sethdlc_OBJECTS) $(sethdlc_DEPENDENCIES) + @rm -f sethdlc + $(LINK) $(sethdlc_LDFLAGS) $(sethdlc_OBJECTS) $(sethdlc_LDADD) $(LIBS) + +smmixer: $(smmixer_OBJECTS) $(smmixer_DEPENDENCIES) + @rm -f smmixer + $(LINK) $(smmixer_LDFLAGS) $(smmixer_OBJECTS) $(smmixer_LDADD) $(LIBS) + +smdiag: $(smdiag_OBJECTS) $(smdiag_DEPENDENCIES) + @rm -f smdiag + $(LINK) $(smdiag_LDFLAGS) $(smdiag_OBJECTS) $(smdiag_LDADD) $(LIBS) + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done + +install-man9: + $(mkinstalldirs) $(DESTDIR)$(man9dir) + @list='$(man9_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.9*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man9dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man9dir)/$$inst; \ + done + +uninstall-man9: + @list='$(man9_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.9*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man9dir)/$$inst"; \ + rm -f $(DESTDIR)$(man9dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man8 install-man9 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 uninstall-man9 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = hdlcutil + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +hdrvcomm.o: hdrvcomm.c hdrvcomm.h usersmdiag.h +setcrystal.o: setcrystal.c +sethdlc.o: sethdlc.c hdrvcomm.h +smdiag.o: smdiag.c hdrvcomm.h +smmixer.o: smmixer.c hdrvcomm.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 \ + $(DESTDIR)$(mandir)/man9 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile install-man8 uninstall-man8 \ +install-man9 uninstall-man9 install-man uninstall-man tags \ +mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \ +distdir info-am info dvi-am dvi check check-am installcheck-am \ +installcheck install-exec-am install-exec install-data-am install-data \ +install-am install uninstall-am uninstall all-redirect all-am all \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +installconf: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/hdlcutil/hdrvcomm.c b/hdlcutil/hdrvcomm.c new file mode 100644 index 0000000..55f0f38 --- /dev/null +++ b/hdlcutil/hdrvcomm.c @@ -0,0 +1,663 @@ +/*****************************************************************************/ + +/* + * hdrvcomm.c -- HDLC driver communications. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.1 10.5.97 Started + */ + +/*****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ipc.h> +#include <sys/msg.h> +#include <asm/byteorder.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +/*#include <linux/if.h>*/ +#include <net/if.h> +#include "hdrvcomm.h" +#include "usersmdiag.h" + +#include <linux/hdlcdrv.h> +/* ---------------------------------------------------------------------- */ + +#ifdef HDRVC_KERNEL +static int kernel_mode = 1; +#endif /* HDRVC_KERNEL */ +static char *if_name = "bc0"; +static char *prg_name; +static int fd = -1; +static struct ifreq ifr_h; +static int promisc = 0; +static int msqid = -1; + +/* ---------------------------------------------------------------------- */ + +static void terminate(void) +{ +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if (ioctl(fd, SIOCSIFFLAGS, &ifr_h) < 0) { + perror("ioctl (SIOCSIFFLAGS)"); + exit(1); + } + } +#endif /* HDRVC_KERNEL */ + exit(0); +} + +/* ---------------------------------------------------------------------- */ + +static void terminate_sig(int signal) +{ + printf("signal %i caught\n", signal); + terminate(); +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_recvpacket(char *pkt, int maxlen) +{ + struct ifreq ifr_new; + struct sockaddr from; + int from_len = sizeof(from); + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if (!promisc) { + struct sockaddr sa; + + strcpy(sa.sa_data, if_name); + sa.sa_family = AF_INET; + if (bind(fd, &sa, sizeof(struct sockaddr)) < 0) { + fprintf(stderr, "%s: Error %s (%i) bind failed\n", + prg_name, strerror(errno), errno); + exit(-2); + } + ifr_new = ifr_h; + ifr_new.ifr_flags |= IFF_PROMISC; + if (ioctl(fd, SIOCSIFFLAGS, &ifr_new) < 0) { + perror("ioctl (SIOCSIFFLAGS)"); + exit(1); + } + signal(SIGTERM, terminate_sig); + signal(SIGQUIT, terminate_sig); + if (atexit((void (*)(void))terminate)) { + perror("atexit"); + terminate(); + } + promisc = 1; + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + } + if (!pkt || maxlen < 2) + return 0; + return recvfrom(fd, pkt, maxlen, 0, &from, &from_len); + } +#endif /* HDRVC_KERNEL */ + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_getfd(void) +{ + return fd; +} + +/* ---------------------------------------------------------------------- */ + +char *hdrvc_ifname(void) +{ + return if_name; +} + +/* ---------------------------------------------------------------------- */ + +void hdrvc_args(int *argc, char *argv[], char *def_if) +{ + int ac, i; + + if (def_if) + if_name = def_if; + if (!argc || !argv || (ac = *argc) < 1) + return; + prg_name = argv[0]; + for (i = 1; i < ac-1; i++) { +#ifdef HDRVC_KERNEL + if (!strcmp(argv[i], "-i")) { + kernel_mode = 1; + if_name = argv[i+1]; + ac -= 2; + if (i < ac) + memmove(argv+i, argv+i+2, (ac-i) * sizeof(void *)); + i--; + } else +#endif /* HDRVC_KERNEL */ + if (!strcmp(argv[i], "-u")) { +#ifdef HDRVC_KERNEL + kernel_mode = 0; +#endif /* HDRVC_KERNEL */ + if_name = argv[i+1]; + ac -= 2; + if (i < ac) + memmove(argv+i, argv+i+2, (ac-i) * sizeof(void *)); + i--; + } + } + *argc = ac; +} + +/* ---------------------------------------------------------------------- */ + +void hdrvc_init(void) +{ +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if ((fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_AX25))) < 0) { + fprintf(stderr, "%s: Error %s (%i), cannot open %s\n", prg_name, + strerror(errno), errno, if_name); + exit(-1); + } + strcpy(ifr_h.ifr_name, if_name); + if (ioctl(fd, SIOCGIFFLAGS, &ifr_h) < 0) { + fprintf(stderr, "%s: Error %s (%i), cannot ioctl %s\n", prg_name, + strerror(errno), errno, if_name); + exit(-1); + } + } else +#endif /* HDRVC_KERNEL */ + { + key_t k = ftok(if_name, USERSM_KEY_PROJ); + + if (k == (key_t)-1) { + fprintf(stderr, "%s: Error %s (%i), cannot ftok on %s\n", prg_name, + strerror(errno), errno, if_name); + exit(-1); + } + if ((msqid = msgget(k, 0700)) < 0) { + fprintf(stderr, "%s: Error %s (%i), cannot msgget %d\n", prg_name, + strerror(errno), errno, k); + exit(-1); + } + } +} + +/* ---------------------------------------------------------------------- */ + +extern __inline__ void hdrvc_sendmsg(struct usersmmsg *msg, int len) +{ + if (msgsnd(msqid, (struct msgbuf *)msg, len+sizeof(msg->hdr)-sizeof(long), 0) < 0) { + perror("msgsnd"); + exit(1); + } +} + +extern __inline__ int hdrvc_recvmsg(struct usersmmsg *msg, int maxlen, long type) +{ + int len; + + if ((len = msgrcv(msqid, (struct msgbuf *)msg, maxlen-sizeof(long), type, MSG_NOERROR)) < 0) { + perror("msgrcv"); + exit(1); + } +#if 0 + for (;;) { + if ((len = msgrcv(msqid, (struct msgbuf *)msg, maxlen-sizeof(long), type, IPC_NOWAIT|MSG_NOERROR)) >= 0) + return len+sizeof(long); + if (errno != ENOMSG) { + perror("msgrcv"); + exit(1); + } + usleep(250000); + } +#endif + return len+sizeof(long); +} + +/* ---------------------------------------------------------------------- */ + +#ifdef HDRVC_KERNEL + +int hdrvc_hdlcdrv_ioctl(int cmd, struct hdlcdrv_ioctl *par) +{ + struct ifreq ifr = ifr_h; + + if (!kernel_mode) { + errno = EINVAL; + return -1; + } + ifr.ifr_data = (caddr_t)par; + par->cmd = cmd; + return ioctl(fd, SIOCDEVPRIVATE, &ifr); +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_sm_ioctl(int cmd, struct sm_ioctl *par) +{ + struct ifreq ifr = ifr_h; + + if (!kernel_mode) { + errno = EINVAL; + return -1; + } + ifr.ifr_data = (caddr_t)par; + par->cmd = cmd; + return ioctl(fd, SIOCDEVPRIVATE, &ifr); +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_baycom_ioctl(int cmd, struct baycom_ioctl *par) +{ + struct ifreq ifr = ifr_h; + + if (!kernel_mode) { + errno = EINVAL; + return -1; + } + ifr.ifr_data = (caddr_t)par; + par->cmd = cmd; + return ioctl(fd, SIOCDEVPRIVATE, &ifr); +} + +/* ---------------------------------------------------------------------- */ + +unsigned int hdrvc_get_ifflags(void) +{ + struct ifreq ifr; + + if (kernel_mode) { + memcpy(&ifr, &ifr_h, sizeof(ifr)); + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("ioctl: SIOCGIFFLAGS"); + exit(-1); + } + return ifr.ifr_flags; + } + return IFF_UP | IFF_RUNNING; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_diag(struct sm_diag_data *diag) +{ + struct sm_ioctl smi; + int ret; + struct usersmmsg msg; + + if (!diag) { + errno = EINVAL; + return -1; + } + if (kernel_mode) { + memcpy(&smi.data.diag, diag, sizeof(smi.data.diag)); + ret = hdrvc_sm_ioctl(SMCTL_DIAGNOSE, &smi); + memcpy(diag, &smi.data.diag, sizeof(smi.data.diag)); + return ret; + } + msg.hdr.type = USERSM_CMD_REQ_DIAG; + msg.hdr.channel = 0; + msg.data.diag.mode = diag->mode; + msg.data.diag.flags = diag->flags; + msg.data.diag.samplesperbit = diag->samplesperbit; + msg.data.diag.datalen = diag->datalen; + hdrvc_sendmsg(&msg, sizeof(msg.data.diag)); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DIAG); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.diag) || ret < sizeof(msg.data.diag)+msg.data.diag.datalen*sizeof(short)) { + errno = EIO; + return -1; + } + diag->mode = msg.data.diag.mode; + diag->flags = msg.data.diag.flags; + diag->samplesperbit = msg.data.diag.samplesperbit; + diag->datalen = msg.data.diag.datalen; + memcpy(diag->data, msg.data.diag_out.samples, msg.data.diag.datalen*sizeof(short)); + return 0; +} + +#endif /* HDRVC_KERNEL */ + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_samples(void) +{ + int ret; + struct hdlcdrv_ioctl bi; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETSAMPLES, &bi); + if (ret < 0) + return ret; + return bi.data.bits & 0xff; + } +#endif /* HDRVC_KERNEL */ + errno = EAGAIN; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_bits(void) +{ + int ret; + struct hdlcdrv_ioctl bi; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETBITS, &bi); + if (ret < 0) + return ret; + return bi.data.bits & 0xff; + } +#endif /* HDRVC_KERNEL */ + errno = EAGAIN; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_channel_access_param(struct hdrvc_channel_params *par) +{ + struct hdlcdrv_ioctl hi; + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if ((ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETCHANNELPAR, &hi)) < 0) + return ret; + if (!par) { + errno = EINVAL; + return -1; + } + par->tx_delay = hi.data.cp.tx_delay; + par->tx_tail = hi.data.cp.tx_tail; + par->slottime = hi.data.cp.slottime; + par->ppersist = hi.data.cp.ppersist; + par->fulldup = hi.data.cp.fulldup; + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_CHACCESS_PAR; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_CHACCESS_PAR); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.cp)) { + errno = EIO; + return -1; + } + par->tx_delay = msg.data.cp.tx_delay; + par->tx_tail = msg.data.cp.tx_tail; + par->slottime = msg.data.cp.slottime; + par->ppersist = msg.data.cp.ppersist; + par->fulldup = msg.data.cp.fulldup; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_set_channel_access_param(struct hdrvc_channel_params par) +{ + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct hdlcdrv_ioctl hi; + + hi.data.cp.tx_delay = par.tx_delay; + hi.data.cp.tx_tail = par.tx_tail; + hi.data.cp.slottime = par.slottime; + hi.data.cp.ppersist = par.ppersist; + hi.data.cp.fulldup = par.fulldup; + if ((ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_SETCHANNELPAR, &hi)) < 0) + return ret; + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_SET_CHACCESS_PAR; + msg.hdr.channel = 0; + msg.data.cp.tx_delay = par.tx_delay; + msg.data.cp.tx_tail = par.tx_tail; + msg.data.cp.slottime = par.slottime; + msg.data.cp.ppersist = par.ppersist; + msg.data.cp.fulldup = par.fulldup; + hdrvc_sendmsg(&msg, sizeof(msg.data.cp)); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_calibrate(int calib) +{ + struct hdlcdrv_ioctl bhi; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + bhi.data.calibrate = calib; + return hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_CALIBRATE, &bhi); + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_CALIBRATE; + msg.hdr.channel = 0; + msg.data.calib = calib; + hdrvc_sendmsg(&msg, sizeof(msg.data.calib)); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_channel_state(struct hdrvc_channel_state *st) +{ + struct hdlcdrv_ioctl bhi; + int ret; + struct usersmmsg msg; + + if (!st) { + errno = EINVAL; + return -1; + } +#ifdef HDRVC_KERNEL + if (kernel_mode) { + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETSTAT, &bhi); + if (ret >= 0) { + st->ptt = bhi.data.cs.ptt; + st->dcd = bhi.data.cs.dcd; + st->ptt_keyed = bhi.data.cs.ptt_keyed; + st->tx_packets = bhi.data.cs.tx_packets; + st->tx_errors = bhi.data.cs.tx_errors; + st->rx_packets = bhi.data.cs.rx_packets; + st->rx_errors = bhi.data.cs.rx_errors; + } + return ret; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_CHANNELSTATE; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_CHANNELSTATE); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.cs)) { + errno = EIO; + return -1; + } + st->ptt = msg.data.cs.ptt; + st->dcd = msg.data.cs.dcd; + st->ptt_keyed = msg.data.cs.ptt_keyed; + st->tx_packets = msg.data.cs.tx_packets; + st->tx_errors = msg.data.cs.tx_errors; + st->rx_packets = msg.data.cs.rx_packets; + st->rx_errors = msg.data.cs.rx_errors; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_diag2(unsigned int mode, unsigned int flags, short *data, + unsigned int maxdatalen, unsigned int *samplesperbit) +{ + int ret; + struct usersmmsg msg; + static unsigned int modeconvusersm[4] = { + USERSM_DIAGMODE_OFF, USERSM_DIAGMODE_INPUT, USERSM_DIAGMODE_DEMOD, + USERSM_DIAGMODE_CONSTELLATION + }; + + if (mode > HDRVC_DIAGMODE_CONSTELLATION) { + errno = EINVAL; + return -1; + } +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct sm_ioctl smi; + static unsigned int modeconvsm[4] = { + SM_DIAGMODE_OFF, SM_DIAGMODE_INPUT, SM_DIAGMODE_DEMOD, SM_DIAGMODE_CONSTELLATION + }; + + smi.data.diag.mode = modeconvsm[mode]; + smi.data.diag.flags = (flags & HDRVC_DIAGFLAG_DCDGATE) ? SM_DIAGFLAG_DCDGATE : 0; + smi.data.diag.samplesperbit = 0; + smi.data.diag.datalen = maxdatalen; + smi.data.diag.data = data; + if ((ret = hdrvc_sm_ioctl(SMCTL_DIAGNOSE, &smi)) < 0) + return ret; + if (samplesperbit) + *samplesperbit = smi.data.diag.samplesperbit; + if (smi.data.diag.mode != modeconvsm[mode] || !(smi.data.diag.flags & SM_DIAGFLAG_VALID)) + return 0; + return smi.data.diag.datalen; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_DIAG; + msg.hdr.channel = 0; + msg.data.diag.mode = modeconvusersm[mode]; + msg.data.diag.flags = (flags & HDRVC_DIAGFLAG_DCDGATE) ? USERSM_DIAGFLAG_DCDGATE : 0; + msg.data.diag.samplesperbit = 0; + msg.data.diag.datalen = maxdatalen; + hdrvc_sendmsg(&msg, sizeof(msg.data.diag)); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DIAG); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.diag) || ret < sizeof(msg.data.diag)+msg.data.diag.datalen*sizeof(short)) { + errno = EIO; + return -1; + } + if (samplesperbit) + *samplesperbit = msg.data.diag.samplesperbit; + if (msg.data.diag.mode != modeconvusersm[mode] || !(msg.data.diag.flags & USERSM_DIAGFLAG_VALID)) + return 0; + if (!data || msg.data.diag.datalen <= 0) + return 0; + memcpy(data, msg.data.diag_out.samples, msg.data.diag.datalen*sizeof(short)); + return msg.data.diag.datalen; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_driver_name(char *buf, int bufsz) +{ + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct hdlcdrv_ioctl bhi; + + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_DRIVERNAME, &bhi); + if (ret < 0) + return ret; + strncpy(buf, bhi.data.modename, bufsz); + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_DRVNAME; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DRVNAME); + if (ret < 0) + return ret; + if (ret < 1) { + errno = EIO; + return -1; + } + if (bufsz < ret) + ret = bufsz; + strncpy(buf, msg.data.by, ret); + buf[ret-1] = 0; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_mode_name(char *buf, int bufsz) +{ + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct hdlcdrv_ioctl bhi; + + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETMODE, &bhi); + if (ret < 0) + return ret; + strncpy(buf, bhi.data.modename, bufsz); + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_DRVMODE; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DRVMODE); + if (ret < 0) + return ret; + if (ret < 1) { + errno = EIO; + return -1; + } + if (bufsz < ret) + ret = bufsz; + strncpy(buf, msg.data.by, ret); + buf[ret-1] = 0; + return 0; +} + +/* ---------------------------------------------------------------------- */ diff --git a/hdlcutil/hdrvcomm.h b/hdlcutil/hdrvcomm.h new file mode 100644 index 0000000..ec4be73 --- /dev/null +++ b/hdlcutil/hdrvcomm.h @@ -0,0 +1,109 @@ +/*****************************************************************************/ + +/* + * hdrvcomm.h -- HDLC driver communications. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +/*****************************************************************************/ + +#ifndef _HDRVCOMM_H +#define _HDRVCOMM_H + +/* ---------------------------------------------------------------------- */ + +#undef HDRVC_KERNEL 1 + +/* ---------------------------------------------------------------------- */ + +#ifdef HDRVC_KERNEL +#include <linux/hdlcdrv.h> +#include <linux/soundmodem.h> +#include <linux/baycom.h> +#endif /* HDRVC_KERNEL */ + +/* ---------------------------------------------------------------------- */ + +struct hdrvc_channel_params { + int tx_delay; /* the transmitter keyup delay in 10ms units */ + int tx_tail; /* the transmitter keyoff delay in 10ms units */ + int slottime; /* the slottime in 10ms; usually 10 = 100ms */ + int ppersist; /* the p-persistence 0..255 */ + int fulldup; /* some driver do not support full duplex, setting */ + /* this just makes them send even if DCD is on */ +}; + +struct hdrvc_channel_state { + int ptt; + int dcd; + int ptt_keyed; + unsigned long tx_packets; + unsigned long tx_errors; + unsigned long rx_packets; + unsigned long rx_errors; +}; + +/* ---------------------------------------------------------------------- */ + +/* + * diagnose modes + */ +#define HDRVC_DIAGMODE_OFF 0 +#define HDRVC_DIAGMODE_INPUT 1 +#define HDRVC_DIAGMODE_DEMOD 2 +#define HDRVC_DIAGMODE_CONSTELLATION 3 + +/* + * diagnose flags + */ +#define HDRVC_DIAGFLAG_DCDGATE (1<<0) + + +/* ---------------------------------------------------------------------- */ + +extern int hdrvc_recvpacket(char *pkt, int maxlen); +extern int hdrvc_getfd(void); +extern char *hdrvc_ifname(void); +extern void hdrvc_args(int *argc, char *argv[], char *def_if); +extern void hdrvc_init(void); +extern int hdrvc_get_samples(void); +extern int hdrvc_get_bits(void); +extern int hdrvc_get_channel_access_param(struct hdrvc_channel_params *par); +extern int hdrvc_set_channel_access_param(struct hdrvc_channel_params par); +extern int hdrvc_calibrate(int calib); +extern int hdrvc_get_channel_state(struct hdrvc_channel_state *st); +extern unsigned int hdrvc_get_ifflags(void); +extern int hdrvc_diag2(unsigned int mode, unsigned int flags, short *data, unsigned int maxdatalen, + unsigned int *samplesperbit); +extern int hdrvc_get_driver_name(char *buf, int bufsz); +extern int hdrvc_get_mode_name(char *buf, int bufsz); + +#ifdef HDRVC_KERNEL +extern int hdrvc_hdlcdrv_ioctl(int cmd, struct hdlcdrv_ioctl *par); +extern int hdrvc_sm_ioctl(int cmd, struct sm_ioctl *par); +extern int hdrvc_baycom_ioctl(int cmd, struct baycom_ioctl *par); +extern int hdrvc_diag(struct sm_diag_data *diag); +#endif /* HDRVC_KERNEL */ + +/* ---------------------------------------------------------------------- */ +#endif /* _HDRVCOMM_H */ diff --git a/hdlcutil/setcrystal.c b/hdlcutil/setcrystal.c new file mode 100644 index 0000000..f5181f3 --- /dev/null +++ b/hdlcutil/setcrystal.c @@ -0,0 +1,136 @@ +/*****************************************************************************/ + +/* + * setcrystal.c -- crystal soundcard configuration utility + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +/* --------------------------------------------------------------------- */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <asm/io.h> + +/* --------------------------------------------------------------------- */ + +static const unsigned char crystal_key[32] = { + 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc, + 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2, + 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13, + 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a +}; + +#define KEY_PORT 0x279 +#define CSN 1 /* card select number */ + +/* --------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + int wssbase = 0x534; + int synbase = 0x388; + int sbbase = 0x220; + int irq = 5; + int dma = 1; + int dma2 = 3; + + int i; + + printf("Crystal PnP Soundcard enabler\n" + "(C) 1996 by Thomas Sailer, HB9JNX/AE4WA\n" + "WARNING: This utility is incompatible with OS PnP support!\n" + " Remove it as soon as Linux supports PnP!\n"); + while ((i = getopt(argc, argv, "i:d:c:s:w:f:h")) != EOF) { + switch (i) { + case 'i': + irq = strtoul(optarg, NULL, 0); + break; + case 'd': + dma = strtoul(optarg, NULL, 0); + break; + case 'c': + dma2 = strtoul(optarg, NULL, 0); + break; + case 's': + sbbase = strtoul(optarg, NULL, 0); + break; + case 'w': + wssbase = strtoul(optarg, NULL, 0); + break; + case 'f': + synbase = strtoul(optarg, NULL, 0); + break; + + default: + case ':': + case '?': + case 'h': + fprintf(stderr, "usage: [-w wssio] [-s sbio] " + "[-f synthio] [-i irq] [-d dma] [-c dma2]\n"); + exit(1); + } + } + + if ((i = ioperm(KEY_PORT, 1, 1))) { + perror("ioperm"); + exit(1); + } + /* + * send crystal key + */ + for (i = 0; i < 32; i++) + outb(crystal_key[i], KEY_PORT); + /* + * send config data + */ + outb(0x6, KEY_PORT); + outb(CSN, KEY_PORT); + outb(0x15, KEY_PORT); + outb(0x0, KEY_PORT); /* logical device 0 */ + outb(0x47, KEY_PORT); + outb(wssbase >> 8, KEY_PORT); + outb(wssbase & 0xff, KEY_PORT); + outb(0x48, KEY_PORT); + outb(synbase >> 8, KEY_PORT); + outb(synbase & 0xff, KEY_PORT); + outb(0x42, KEY_PORT); + outb(sbbase >> 8, KEY_PORT); + outb(sbbase & 0xff, KEY_PORT); + outb(0x22, KEY_PORT); + outb(irq, KEY_PORT); + outb(0x2a, KEY_PORT); + outb(dma, KEY_PORT); + outb(0x25, KEY_PORT); + outb(dma2, KEY_PORT); + outb(0x33, KEY_PORT); + outb(0x1, KEY_PORT); /* activate logical device */ + outb(0x79, KEY_PORT); /* activate part */ + + printf("Crystal CS423[26] set to: WSS iobase 0x%x, Synth iobase 0x%x," + " SB iobase 0x%x,\n IRQ %u, DMA %u, DMA2 %u\n", wssbase, + synbase, sbbase, irq, dma, dma2); + exit(0); +} + +/* --------------------------------------------------------------------- */ diff --git a/hdlcutil/sethdlc.c b/hdlcutil/sethdlc.c new file mode 100644 index 0000000..b07c0de --- /dev/null +++ b/hdlcutil/sethdlc.c @@ -0,0 +1,598 @@ +/*****************************************************************************/ + +/* + * sethdlc.c -- kernel HDLC radio modem driver setup utility. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.1 16.10.96 Adapted from setbaycom.c and setsm.c + * 0.2 20.11.96 New mode set/query code + * 0.5 11.05.97 introduced hdrvcomm.h + */ + +/*****************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +/*#include <linux/if.h>*/ +#include <net/if.h> +#include "hdrvcomm.h" + +#include <linux/soundmodem.h> +#include <linux/baycom.h> + +/* ---------------------------------------------------------------------- */ + +static unsigned char trace_stat = 0; +static char *progname; + +/* ---------------------------------------------------------------------- */ + +static void display_packet(unsigned char *bp, unsigned int len) +{ + unsigned char v1=1,cmd=0; + unsigned char i,j; + + if (!bp || !len) + return; + if (len < 8) + return; + if (bp[1] & 1) { + /* + * FlexNet Header Compression + */ + v1 = 0; + cmd = (bp[1] & 2) != 0; + printf("fm ? to "); + i = (bp[2] >> 2) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[2] << 4) | ((bp[3] >> 4) & 0xf)) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[3] << 2) | ((bp[4] >> 6) & 3)) & 0x3f; + if (i) + printf("%c",i+0x20); + i = bp[4] & 0x3f; + if (i) + printf("%c",i+0x20); + i = (bp[5] >> 2) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[5] << 4) | ((bp[6] >> 4) & 0xf)) & 0x3f; + if (i) + printf("%c",i+0x20); + printf("-%u QSO Nr %u", bp[6] & 0xf, (bp[0] << 6) | + (bp[1] >> 2)); + bp += 7; + len -= 7; + } else { + /* + * normal header + */ + if (len < 15) + return; + if ((bp[6] & 0x80) != (bp[13] & 0x80)) { + v1 = 0; + cmd = (bp[6] & 0x80); + } + printf("fm "); + for(i = 7; i < 13; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u to ",(bp[13] >> 1) & 0xf); + for(i = 0; i < 6; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c", bp[i] >> 1); + printf("-%u", (bp[6] >> 1) & 0xf); + bp += 14; + len -= 14; + if ((!(bp[-1] & 1)) && (len >= 7)) + printf(" via "); + while ((!(bp[-1] & 1)) && (len >= 7)) { + for(i = 0; i < 6; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u",(bp[6] >> 1) & 0xf); + bp += 7; + len -= 7; + if ((!(bp[-1] & 1)) && (len >= 7)) + printf(","); + } + } + if(!len) + return; + i = *bp++; + len--; + j = v1 ? ((i & 0x10) ? '!' : ' ') : + ((i & 0x10) ? (cmd ? '+' : '-') : (cmd ? '^' : 'v')); + if (!(i & 1)) { + /* + * Info frame + */ + printf(" I%u%u%c",(i >> 5) & 7,(i >> 1) & 7,j); + } else if (i & 2) { + /* + * U frame + */ + switch (i & (~0x10)) { + case 0x03: + printf(" UI%c",j); + break; + case 0x2f: + printf(" SABM%c",j); + break; + case 0x43: + printf(" DISC%c",j); + break; + case 0x0f: + printf(" DM%c",j); + break; + case 0x63: + printf(" UA%c",j); + break; + case 0x87: + printf(" FRMR%c",j); + break; + default: + printf(" unknown U (0x%x)%c",i & (~0x10),j); + break; + } + } else { + /* + * supervisory + */ + switch (i & 0xf) { + case 0x1: + printf(" RR%u%c",(i >> 5) & 7,j); + break; + case 0x5: + printf(" RNR%u%c",(i >> 5) & 7,j); + break; + case 0x9: + printf(" REJ%u%c",(i >> 5) & 7,j); + break; + default: + printf(" unknown S (0x%x)%u%c", i & 0xf, + (i >> 5) & 7, j); + break; + } + } + if (!len) { + printf("\n"); + return; + } + printf(" pid=%02X\n", *bp++); + len--; + j = 0; + while (len) { + i = *bp++; + if ((i >= 32) && (i < 128)) + printf("%c",i); + else if (i == 13) { + if (j) + printf("\n"); + j = 0; + } else + printf("."); + if (i >= 32) + j = 1; + len--; + } + if (j) + printf("\n"); +} + +/* ---------------------------------------------------------------------- */ + +static void print_bits(int (*bitproc)(void)) +{ + int ret; + int i; + char str[9]; + char *cp; + + for(;;) { + ret = bitproc(); + if (ret < 0) { + if (errno == EAGAIN) + return; + fprintf(stderr, "%s: Error %s (%i), cannot ioctl\n", + progname, strerror(errno), errno); + return; + } + strcpy(cp = str, "00000000"); + for(i = 0; i < 8; i++, cp++, ret >>= 1) + *cp += (ret & 1); + printf("%s", str); + } +} + +/* ---------------------------------------------------------------------- */ + +#ifdef HDRVC_KERNEL + +static void do_set_params(int argc, char **argv) +{ + struct hdlcdrv_ioctl drvname, curm, newm, mlist, curp, newp, mpmask; + char set = 0; + int ret; + int mask; + + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_DRIVERNAME, &drvname); + if (ret < 0) { + perror("ioctl (HDLCDRVCTL_DRIVERNAME)"); + exit(1); + } + printf("driver name: %s\n", drvname.data.drivername); + + mask = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_MODEMPARMASK, &mpmask); + if (mask < 0) + mask = ~0; + + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETMODEMPAR, &curp); + if (ret < 0) { + perror("ioctl (HDLCDRVCTL_GETMODEMPAR)"); + exit(1); + } + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETMODE, &curm); + if (ret < 0) { + perror("ioctl (HDLCDRVCTL_GETMODE)"); + exit(1); + } + newm = curm; + newp = curp; + while (argc >= 2) { + if (!strcasecmp(argv[0], "mode")) { + strncpy(newm.data.modename, argv[1], + sizeof(newm.data.modename)); + set |= 1; + } else if (!strcasecmp(argv[0], "io") && mask & HDLCDRV_PARMASK_IOBASE) { + newp.data.mp.iobase = strtoul(argv[1], NULL, 0); + set |= 2; + } else if (!strcasecmp(argv[0], "irq") && mask & HDLCDRV_PARMASK_IRQ) { + newp.data.mp.irq = strtoul(argv[1], NULL, 0); + set |= 2; + } else if (!strcasecmp(argv[0], "dma") && mask & HDLCDRV_PARMASK_DMA) { + newp.data.mp.dma = strtoul(argv[1], NULL, 0); + set |= 2; + } else if (!strcasecmp(argv[0], "dma2") && mask & HDLCDRV_PARMASK_DMA2) { + newp.data.mp.dma2 = strtoul(argv[1], NULL, 0); + set |= 2; + } else if (!strcasecmp(argv[0], "serio") && mask & HDLCDRV_PARMASK_SERIOBASE) { + newp.data.mp.seriobase = strtol(argv[1], NULL, 0); + set |= 2; + } else if (!strcasecmp(argv[0], "pario") && mask & HDLCDRV_PARMASK_PARIOBASE) { + newp.data.mp.pariobase = strtol(argv[1], NULL, 0); + set |= 2; + } else if (!strcasecmp(argv[0], "midiio") && mask & HDLCDRV_PARMASK_MIDIIOBASE) { + newp.data.mp.midiiobase = strtol(argv[1], NULL, 0); + set |= 2; + } else { + fprintf(stderr, "%s: invalid parameter type '%s', " + "valid: mode%s%s%s%s%s%s%s\n", + progname, argv[0], + (mask & HDLCDRV_PARMASK_IOBASE) ? " io" : "", + (mask & HDLCDRV_PARMASK_IRQ) ? " irq" : "", + (mask & HDLCDRV_PARMASK_DMA) ? " dma" : "", + (mask & HDLCDRV_PARMASK_DMA2) ? " dma2" : "", + (mask & HDLCDRV_PARMASK_SERIOBASE) ? " serio" : "", + (mask & HDLCDRV_PARMASK_PARIOBASE) ? " pario" : "", + (mask & HDLCDRV_PARMASK_MIDIIOBASE) ? " midiio" : ""); + } + argv += 2; + argc -= 2; + } + if (argc >= 1) + fprintf(stderr, "%s: orphaned parameter type '%s', no data\n", + progname, argv[0]); + printf("current parameters: mode %s", curm.data.modename); + if (mask & HDLCDRV_PARMASK_IOBASE) + printf(" io 0x%x", curp.data.mp.iobase); + if (mask & HDLCDRV_PARMASK_IRQ) + printf(" irq %u", curp.data.mp.irq); + if (mask & HDLCDRV_PARMASK_DMA) + printf(" dma %u", curp.data.mp.dma); + if (mask & HDLCDRV_PARMASK_DMA2) + printf(" dma2 %u", curp.data.mp.dma2); + if (mask & HDLCDRV_PARMASK_SERIOBASE) + printf(" serio 0x%x", curp.data.mp.seriobase); + if (mask & HDLCDRV_PARMASK_PARIOBASE) + printf(" pario 0x%x", curp.data.mp.pariobase); + if (mask & HDLCDRV_PARMASK_MIDIIOBASE) + printf(" midiio 0x%x", curp.data.mp.midiiobase); + printf("\n"); + + if (set & 1) + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_SETMODE, &newm); + if (ret < 0) { + perror("ioctl (HDLCDRVCTL_SETMODE)"); + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_MODELIST, &mlist); + if (ret < 0) { + perror("ioctl (HDLCDRVCTL_MODELIST)"); + exit(1); + } + printf("driver supported modes: %s\n", + mlist.data.modename); + exit(1); + } + if (set & 2) { + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_SETMODEMPAR, &newp); + if (ret < 0) { + perror("ioctl (HDLCDRVCTL_SETMODEMPAR)"); + fprintf(stderr, "%s: trying to restore old " + "parameters\n", progname); + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_SETMODEMPAR, &curp); + if (ret < 0) + perror("ioctl (HDLCDRVCTL_SETMODEMPAR)"); + exit(1); + } + } + if (set & 3) { + printf("new parameters: mode %s", newm.data.modename); + if (mask & HDLCDRV_PARMASK_IOBASE) + printf(" io 0x%x", newp.data.mp.iobase); + if (mask & HDLCDRV_PARMASK_IRQ) + printf(" irq %u", newp.data.mp.irq); + if (mask & HDLCDRV_PARMASK_DMA) + printf(" dma %u", newp.data.mp.dma); + if (mask & HDLCDRV_PARMASK_DMA2) + printf(" dma2 %u", newp.data.mp.dma2); + if (mask & HDLCDRV_PARMASK_SERIOBASE) + printf(" serio 0x%x", newp.data.mp.seriobase); + if (mask & HDLCDRV_PARMASK_PARIOBASE) + printf(" pario 0x%x", newp.data.mp.pariobase); + if (mask & HDLCDRV_PARMASK_MIDIIOBASE) + printf(" midiio 0x%x", newp.data.mp.midiiobase); + printf("\n"); + } + exit(0); +} + +#endif /* HDRVC_KERNEL */ + +/* ---------------------------------------------------------------------- */ + +static void display_channel_params(const struct hdrvc_channel_params *par) +{ + printf("TX delay %ums, TX tail %ums, slottime %ums, p-persistence " + " %u/256, %s duplex\n", 10*par->tx_delay, 10*par->tx_tail, + 10*par->slottime, par->ppersist, + par->fulldup ? "Full" : "Half"); +} + +/* ---------------------------------------------------------------------- */ + +static void do_set_channel_params(int argc, char **argv) +{ + struct hdrvc_channel_params par1, par2; + char set = 0; + int ret; + + ret = hdrvc_get_channel_access_param(&par1); + if (ret < 0) { + perror("hdrvc_get_channel_access_param"); + exit(1); + } + par2 = par1; + while (argc > 0) { + if (argc >= 2 && !strcasecmp(argv[0], "txd")) { + par2.tx_delay = strtoul(argv[1], NULL, 0) / 10; + set = 1; + argv += 2; + argc -= 2; + } else if (argc >= 2 && !strcasecmp(argv[0], "txtail")) { + par2.tx_tail = strtoul(argv[1], NULL, 0) / 10; + set = 1; + argv += 2; + argc -= 2; + } else if (argc >= 2 && !strcasecmp(argv[0], "slot")) { + par2.slottime = strtoul(argv[1], NULL, 0) / 10; + set = 1; + argv += 2; + argc -= 2; + } else if (argc >= 2 && !strcasecmp(argv[0], "ppersist")) { + par2.ppersist = strtoul(argv[1], NULL, 0); + set = 1; + argv += 2; + argc -= 2; + } else if (!strcasecmp(argv[0], "half")) { + par2.fulldup = 0; + set = 1; + argv += 1; + argc -= 1; + } else if (!strcasecmp(argv[0], "full")) { + par2.fulldup = 1; + set = 1; + argv += 1; + argc -= 1; + } else { + + argv += 1; + argc -= 1; + } + } + printf("current parameters: "); + display_channel_params(&par1); + if (set) { + ret = hdrvc_set_channel_access_param(par2); + if (ret < 0) { + perror("hdrvc_set_channel_access_param"); + exit(1); + } + printf("new parameters: "); + display_channel_params(&par2); + } + exit(0); +} + +/* ---------------------------------------------------------------------- */ + +static const char *usage_str = +"[-b] [-i] [-d] [-i <baycomif>] [-h] [-c <cal>]\n" +"[-p] [hw <hw>] [type <type>] [io <iobase>] [irq <irq>] [dma <dma>]\n" +" [options <opt>] [serio <serio>] [pario <pario>] [midiio <midiio>]\n" +"[-a] [txd <txdelay>] [txtail <txtail>] [slot <slottime>]\n" +" [ppersist <ppersistence>] [full] [half]\n" +" -a: set or display channel access parameters\n" +" -b: trace demodulated bits\n" +" -s: trace sampled input from tcm3105 (ser12 only)\n" +" -d: trace dcd and ptt status on stdout\n" +" -i: specify the name of the baycom kernel driver interface\n" +" -c: calibrate (i.e. send calibration pattern) for cal seconds\n" +#ifdef HDRVC_KERNEL +" -p: set or display interface parameters\n" +#endif /* HDRVC_KERNEL */ +" -h: this help\n\n"; + +int main(int argc, char *argv[]) +{ + int ret; + fd_set fds_read; + fd_set fds_write; + struct timeval tm; + char getsetparams = 0; + char cal = 0; + int cal_val = 0; + struct sm_ioctl bsi; + struct baycom_ioctl bbi; + struct hdrvc_channel_state chst; + unsigned char pktbuf[2048]; + + progname = *argv; + printf("%s: Version 0.5; (C) 1996-1997 by Thomas Sailer HB9JNX/AE4WA\n", *argv); + hdrvc_args(&argc, argv, "bc0"); + while ((ret = getopt(argc, argv, "bsdhpc:a")) != -1) { + switch (ret) { + case 'b': + trace_stat = 2; + break; + case 's': + trace_stat = 3; + break; + case 'd': + trace_stat = 1; + break; +#ifdef HDRVC_KERNEL + case 'p': + getsetparams = 1; + break; +#endif /* HDRVC_KERNEL */ + case 'a': + getsetparams = 2; + break; + case 'c': + cal = 1; + cal_val = strtoul(optarg, NULL, 0); + break; + default: + printf("usage: %s %s", *argv, usage_str); + exit(-1); + } + } + hdrvc_init(); + if (getsetparams == 1) { +#ifdef HDRVC_KERNEL + do_set_params(argc - optind, argv+optind); +#endif /* HDRVC_KERNEL */ + exit(0); + } + if (getsetparams == 2) { + do_set_channel_params(argc - optind, argv+optind); + exit(0); + } + if (cal) { + ret = hdrvc_calibrate(cal_val); + if (ret < 0) { + perror("hdrvc_calibrate"); + exit(1); + } + fprintf(stdout, "%s: calibrating for %i seconds\n", *argv, + cal_val); + exit(0); + } + for (;;) { + while ((ret = hdrvc_recvpacket(pktbuf, sizeof(pktbuf))) > 1) + display_packet(pktbuf+1, ret-1); + switch (trace_stat) { + case 1: + ret = hdrvc_get_channel_state(&chst); + if (ret < 0) + perror("hdrvc_get_channel_state"); + printf("%c%c rx: %lu tx: %lu rxerr: %lu txerr: %lu", + chst.dcd ? 'D' : '-', chst.ptt ? 'P' : '-', + chst.rx_packets, chst.tx_packets, chst.rx_errors, + chst.tx_errors); +#ifdef HDRVC_KERNEL + if (hdrvc_sm_ioctl(SMCTL_GETDEBUG, &bsi) >= 0) { + printf(" intrate: %u modcyc: %u " + "demodcyc: %u dmares: %u", + bsi.data.dbg.int_rate, + bsi.data.dbg.mod_cycles, + bsi.data.dbg.demod_cycles, + bsi.data.dbg.dma_residue); + } + if (hdrvc_baycom_ioctl(BAYCOMCTL_GETDEBUG, &bbi) >= 0) { + printf(" dbg1: %lu dbg2: %lu dbg3: %li", + bbi.data.dbg.debug1, bbi.data.dbg.debug2, + bbi.data.dbg.debug3); + } +#endif /* HDRVC_KERNEL */ + printf("\n"); + break; + case 2: + print_bits(hdrvc_get_bits); + printf("\n"); + break; + case 3: + print_bits(hdrvc_get_samples); + printf("\n"); + break; + default: + break; + } + tm.tv_usec = 500000L; + tm.tv_sec = 0L; + if (hdrvc_getfd() >= 0) { + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_SET(hdrvc_getfd(), &fds_read); + ret = select(hdrvc_getfd()+1, &fds_read, &fds_write, NULL, &tm); + } else + ret = select(0, NULL, NULL, NULL, &tm); + if (ret < 0) { + fprintf(stderr, "%s: Error %s (%i) in select\n", *argv, + strerror(errno), errno); + exit(-2); + } + } +} + +/* ---------------------------------------------------------------------- */ diff --git a/hdlcutil/smdiag.c b/hdlcutil/smdiag.c new file mode 100644 index 0000000..d8a20f8 --- /dev/null +++ b/hdlcutil/smdiag.c @@ -0,0 +1,434 @@ +/*****************************************************************************/ + +/* + * smdiag.c -- kernel soundcard radio modem driver diagnostics utility. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.1 26.06.96 Started + * 0.2 11.05.97 introduced hdrvcomm.h + */ + +/*****************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#include <net/if.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "hdrvcomm.h" + +#include <linux/soundmodem.h> + +/* ---------------------------------------------------------------------- */ + +static char *progname; +static Display *display = NULL; +static Window window; +static Pixmap pixmap; +static unsigned long col_zeroline; +static unsigned long col_background; +static unsigned long col_trace; +static GC gr_context; +static int xmul; + +/* ---------------------------------------------------------------------- */ + +static int x_error_handler(Display *disp, XErrorEvent *evt) +{ + char err_buf[256], mesg[256], number[256]; + char *mtype = "XlibMessage"; + + XGetErrorText(disp, evt->error_code, err_buf, sizeof(err_buf)); + fprintf(stderr, "X Error: %s\n", err_buf); + XGetErrorDatabaseText(disp, mtype, "MajorCode", "Request Major code %d", + mesg, sizeof(mesg)); + fprintf(stderr, mesg, evt->request_code); + sprintf(number, "%d", evt->request_code); + XGetErrorDatabaseText(disp, "XRequest", number, "", err_buf, + sizeof(err_buf)); + fprintf(stderr, " (%s)\n", err_buf); + abort(); +} + +/* ---------------------------------------------------------------------- */ + +#define WIDTH 512 +#define HEIGHT (constell ? 512 : 256) + +static int openwindow(char *disp, int constell, int samplesperbit) +{ + XSetWindowAttributes attr; + XGCValues gr_values; + XColor color, dummy; + XSizeHints sizehints; + + if (!(display = XOpenDisplay(NULL))) + return -1; + XSetErrorHandler(x_error_handler); + XAllocNamedColor(display, DefaultColormap(display, 0), "red", + &color, &dummy); + col_zeroline = color.pixel; + col_background = WhitePixel(display, 0); + col_trace = BlackPixel(display, 0); + attr.background_pixel = col_background; + if (!(window = XCreateWindow(display, XRootWindow(display, 0), + 200, 200, WIDTH, HEIGHT, 5, + DefaultDepth(display, 0), + InputOutput, DefaultVisual(display, 0), + CWBackPixel, &attr))) { + fprintf(stderr, "smdiag: unable to open X window\n"); + exit(1); + } + if (!(pixmap = XCreatePixmap(display, window, WIDTH, HEIGHT, + DefaultDepth(display, 0)))) { + fprintf(stderr, "smdiag: unable to open offscreen pixmap\n"); + exit(1); + } + xmul = WIDTH / (2*(samplesperbit > 0 ? samplesperbit : 1)); + XSelectInput(display, window, KeyPressMask | StructureNotifyMask + | ExposureMask) ; + XAllocNamedColor(display, DefaultColormap(display, 0), "red", + &color, &dummy); + gr_values.foreground = col_trace; + gr_values.line_width = 1; + gr_values.line_style = LineSolid; + gr_context = XCreateGC(display, window, GCForeground | GCLineWidth | + GCLineStyle, &gr_values); + XStoreName(display, window, "diagnostics"); + /* + * Do not allow the window to be resized + */ + memset(&sizehints, 0, sizeof(sizehints)); + sizehints.min_width = sizehints.max_width = WIDTH; + sizehints.min_height = sizehints.max_height = HEIGHT; + sizehints.flags = PMinSize | PMaxSize; + XSetWMNormalHints(display, window, &sizehints); + XMapWindow(display, window); + XSynchronize(display, 1); + return 0; +} + +#undef WIDTH +#undef HEIGHT + +/* ---------------------------------------------------------------------- */ + +static void closewindow(void) +{ + if (!display) + return; + XDestroyWindow(display, window); + XCloseDisplay(display); + display = NULL; +} + +/* ---------------------------------------------------------------------- */ + +#define XCOORD(x) ((x) * xm) +#define YCOORD(y) ((SHRT_MAX - (int)(y)) * winattrs.height / USHRT_MAX) + +static void drawdata(short *data, int len, int replace, int xm) +{ + int cnt; + GC gc; + XGCValues gcv; + XWindowAttributes winattrs; + + if (!display || !pixmap) + return; + XGetWindowAttributes(display, window, &winattrs); + gcv.line_width = 1; + gcv.line_style = LineSolid; + gc = XCreateGC(display, pixmap, GCLineWidth | GCLineStyle, &gcv); + XSetState(display, gc, col_background, col_background, GXcopy, + AllPlanes); + if (replace) + XFillRectangle(display, pixmap, gc, 0, 0, + winattrs.width, winattrs.height); + else + XCopyArea(display, window, pixmap, gr_context, 0, 0, + winattrs.width, winattrs.height, 0, 0); + XSetForeground(display, gc, col_trace); + for (cnt = 0; cnt < len-1; cnt++) + XDrawLine(display, pixmap, gc, XCOORD(cnt), YCOORD(data[cnt]), + XCOORD(cnt+1), YCOORD(data[cnt+1])); + XSetForeground(display, gc, col_zeroline); + XDrawLine(display, pixmap, gc, 0, YCOORD(0), winattrs.width, + YCOORD(0)); + XCopyArea(display, pixmap, window, gr_context, 0, 0, winattrs.width, + winattrs.height, 0, 0); + XFreeGC(display, gc); + XSync(display, 0); +} + +#undef XCOORD +#undef YCOORD + +/* ---------------------------------------------------------------------- */ + +#define XCOORD(x) ((SHRT_MAX - (int)(x)) * winattrs.width / USHRT_MAX) +#define YCOORD(y) ((SHRT_MAX - (int)(y)) * winattrs.height / USHRT_MAX) + +static void drawconstell(short *data, int len) +{ + int cnt; + GC gc; + XGCValues gcv; + XWindowAttributes winattrs; + + if (!display || !pixmap) + return; + XGetWindowAttributes(display, window, &winattrs); + gcv.line_width = 1; + gcv.line_style = LineSolid; + gc = XCreateGC(display, pixmap, GCLineWidth | GCLineStyle, &gcv); + XSetState(display, gc, col_background, col_background, GXcopy, + AllPlanes); + XCopyArea(display, window, pixmap, gr_context, 0, 0, + winattrs.width, winattrs.height, 0, 0); + XSetForeground(display, gc, col_trace); + for (cnt = 0; cnt < len-1; cnt += 2) + XDrawPoint(display, pixmap, gc, + XCOORD(data[cnt]), YCOORD(data[cnt+1])); + XSetForeground(display, gc, col_zeroline); + XDrawLine(display, pixmap, gc, 0, YCOORD(0), winattrs.width, YCOORD(0)); + XDrawLine(display, pixmap, gc, XCOORD(0), 0, XCOORD(0), winattrs.height); + XCopyArea(display, pixmap, window, gr_context, 0, 0, winattrs.width, + winattrs.height, 0, 0); + XFreeGC(display, gc); + XSync(display, 0); +} + +#undef XCOORD +#undef YCOORD + +/* ---------------------------------------------------------------------- */ + +static void clearwindow(void) +{ + XWindowAttributes winattrs; + GC gc; + XGCValues gcv; + + if (!display || !pixmap) + return; + XGetWindowAttributes(display, window, &winattrs); + gcv.line_width = 1; + gcv.line_style = LineSolid; + gc = XCreateGC(display, pixmap, GCLineWidth | GCLineStyle, &gcv); + XSetState(display, gc, col_background, col_background, GXcopy, + AllPlanes); + XFillRectangle(display, pixmap, gc, 0, 0, + winattrs.width, winattrs.height); + XSetForeground(display, gc, col_zeroline); + XClearArea(display, window, 0, 0, 0, 0, False); + XCopyArea(display, pixmap, window, gr_context, 0, 0, winattrs.width, + winattrs.height, 0, 0); + XFreeGC(display, gc); +} + +/* ---------------------------------------------------------------------- */ + +static Bool predicate(Display *display, XEvent *event, char *arg) +{ + return True; +} + +/* ---------------------------------------------------------------------- */ + +static char *getkey(void) +{ + XWindowAttributes winattrs; + XEvent evt; + static char kbuf[32]; + int i; + + if (!display) + return NULL; + XSync(display, 0); + while (XCheckIfEvent(display, &evt, predicate, NULL)) { + switch (evt.type) { + case KeyPress: + i = XLookupString((XKeyEvent *)&evt, kbuf, sizeof(kbuf)-1, + NULL, NULL); + if (!i) + return NULL; + kbuf[i] = 0; + return kbuf; + case DestroyNotify: + XCloseDisplay(display); + display = NULL; + return NULL; + case Expose: + XGetWindowAttributes(display, window, &winattrs); + XCopyArea(display, pixmap, window, gr_context, 0, 0, + winattrs.width, winattrs.height, 0, 0); + break; + default: + break; + } + } + return NULL; +} + +/* ---------------------------------------------------------------------- */ + +static void printmode(unsigned int mode, unsigned int trigger) +{ + printf("Source: %s%s\n", (mode == SM_DIAGMODE_DEMOD) ? + "demodulator (eye diagram)" : "input (oscilloscope)", + (trigger & SM_DIAGFLAG_DCDGATE) ? " gated with DCD" : ""); +} + +/* ---------------------------------------------------------------------- */ + +static const char *usage_str = +"[-d display] [-i smif] [-c] [-e]\n" +" -d: display host\n" +" -i: specify the name of the baycom kernel driver interface\n" +" -c: toggle carrier trigger\n" +" -e: eye diagram mode\n\n" +" -p: constellation plot\n\n"; + +int main(int argc, char *argv[]) +{ + char *disp = NULL; + unsigned int mode = HDRVC_DIAGMODE_INPUT; + unsigned int trigger = 0; + unsigned int ifflags; + short data[256]; + char *cp; + int ret; + unsigned int samplesperbit; + + progname = *argv; + printf("%s: Version 0.2; (C) 1996-1997 by Thomas Sailer HB9JNX/AE4WA\n", *argv); + hdrvc_args(&argc, argv, "sm0"); + while ((ret = getopt(argc, argv, "d:ecp")) != -1) { + switch (ret) { + case 'd': + disp = optarg; + break; + case 'e': + mode = HDRVC_DIAGMODE_DEMOD; + trigger = HDRVC_DIAGFLAG_DCDGATE; + break; + case 'c': + trigger ^= HDRVC_DIAGFLAG_DCDGATE; + break; + case 'p': + mode = HDRVC_DIAGMODE_CONSTELLATION; + break; + default: + printf("usage: %s %s", *argv, usage_str); + exit(-1); + } + } + hdrvc_init(); +#ifdef HDRVC_KERNEL + ifflags = hdrvc_get_ifflags(); + if (!(ifflags & IFF_UP)) { + fprintf(stderr, "interface %s down\n", hdrvc_ifname()); + exit(1); + } + if (!(ifflags & IFF_RUNNING)) { + fprintf(stderr, "interface %s not running\n", hdrvc_ifname()); + exit(1); + } +#endif /* HDRVC_KERNEL */ + printmode(mode, trigger); + for (;;) { + if ((ret = hdrvc_diag2(mode, trigger, data, sizeof(data) / sizeof(short), + &samplesperbit)) < 0) { + perror("hdrvc_diag2"); + exit(1); + } + if (ret > 0) { + if (!display) { + openwindow(disp, mode == HDRVC_DIAGMODE_CONSTELLATION, + samplesperbit); + clearwindow(); + } + if (mode == SM_DIAGMODE_CONSTELLATION) + drawconstell(data, ret); + else + drawdata(data, ret, mode == HDRVC_DIAGMODE_INPUT, + mode == HDRVC_DIAGMODE_INPUT ? 5:xmul); + } else + usleep(100000L); + if (display) { + if ((cp = getkey())) { + for (; *cp; cp++) { + printf("char pressed: '%c'\n", *cp); + switch (*cp) { + case 'c': + case 'C': + clearwindow(); + printmode(mode, trigger); + break; + case 'q': + case 'Q': + closewindow(); + break; + case 'i': + case 'I': + if (mode == HDRVC_DIAGMODE_CONSTELLATION) + break; + mode = HDRVC_DIAGMODE_INPUT; + clearwindow(); + printmode(mode, trigger); + break; + case 'e': + case 'E': + if (mode == HDRVC_DIAGMODE_CONSTELLATION) + break; + mode = HDRVC_DIAGMODE_DEMOD; + clearwindow(); + printmode(mode, trigger); + break; + case 'd': + case 'D': + trigger ^= HDRVC_DIAGFLAG_DCDGATE; + clearwindow(); + printmode(mode, trigger); + break; + } + } + } + if (!display) + exit(0); + } + } +} + +/* ---------------------------------------------------------------------- */ diff --git a/hdlcutil/smmixer.c b/hdlcutil/smmixer.c new file mode 100644 index 0000000..3cfc7e7 --- /dev/null +++ b/hdlcutil/smmixer.c @@ -0,0 +1,781 @@ +/*****************************************************************************/ + +/* + * smmixer.c -- kernel soundcard radio modem driver mixer utility. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.1 26.06.96 Started + * 0.2 11.05.97 introduced hdrvcomm.h + */ + +/*****************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <net/if.h> +#include "hdrvcomm.h" + +#include <linux/soundmodem.h> +/* ---------------------------------------------------------------------- */ + +static char *progname; +static unsigned int mixdevice; + +/* ---------------------------------------------------------------------- */ + +static int do_mix_ioctl(int cmd, struct sm_mixer_data *mixdat) +{ + struct sm_ioctl par; + int i; + + par.cmd = cmd; + par.data.mix = *mixdat; +#ifdef HDRVC_KERNEL + i = hdrvc_sm_ioctl(cmd, &par); +#endif + *mixdat = par.data.mix; + return i; +} + +/* ---------------------------------------------------------------------- */ + +static unsigned char get_mixer_reg(unsigned char addr) +{ + int i; + struct sm_mixer_data mixdat; + + mixdat.reg = addr; + if ((i = do_mix_ioctl(SMCTL_GETMIXER, &mixdat)) < 0) { + perror("do_mix_ioctl: SMCTL_GETMIXER"); + exit(1); + } + if (!i) + fprintf(stderr, "warning: mixer device %u register %u not " + "accessible for reading!\n", mixdat.mixer_type, + addr); + if (mixdat.mixer_type != mixdevice) { + fprintf(stderr, "error: mixer type changed !?\n"); + exit(2); + } + return mixdat.data; +} + +/* ---------------------------------------------------------------------- */ + +static void set_mixer_reg(unsigned char addr, unsigned char data) +{ + struct sm_mixer_data mixdat; + + mixdat.reg = addr; + mixdat.data = data; + mixdat.mixer_type = mixdevice; + if (do_mix_ioctl(SMCTL_SETMIXER, &mixdat) < 0) { + perror("do_mix_ioctl: SMCTL_SETMIXER"); + exit(1); + } +} + +/* ---------------------------------------------------------------------- */ + +static void display_mixer_ad1848(void) +{ + static const char *src[4] = { "Line", "Aux1", "Mic", "Dac" }; + unsigned char data; + + data = get_mixer_reg(0); + printf("Left input: Source: %-4s Gain: %3ddB\n", src[(data>>6)&3], + (((data & 0xe0) == 0xa0) ? 20 : 0) + (data & 0xf) * 3 / 2); + data = get_mixer_reg(1); + printf("Right input: Source: %-4s Gain: %3ddB\n", src[(data>>6)&3], + (((data & 0xe0) == 0xa0) ? 20 : 0) + (data & 0xf) * 3 / 2); + data = get_mixer_reg(2); + if (!(data & 0x80)) + printf("Left Aux1 mixing: Gain: %3ddB\n", + (8 - (int)(data & 0x1f)) * 3 / 2); + data = get_mixer_reg(3); + if (!(data & 0x80)) + printf("Right Aux1 mixing: Gain: %3ddB\n", + (8 - (int)(data & 0x1f)) * 3 / 2); + data = get_mixer_reg(4); + if (!(data & 0x80)) + printf("Left Aux2 mixing: Gain: %3ddB\n", + (8 - (int)(data & 0x1f)) * 3 / 2); + data = get_mixer_reg(5); + if (!(data & 0x80)) + printf("Right Aux2 mixing: Gain: %3ddB\n", + (8 - (int)(data & 0x1f)) * 3 / 2); + data = get_mixer_reg(6); + if (data & 0x80) + printf("Left output: muted\n"); + else + printf("Left output: Gain: %3ddB\n", + ((int)(data & 0x3f)) * (-3) / 2); + data = get_mixer_reg(7); + if (data & 0x80) + printf("Right output: muted\n"); + else + printf("Right output: Gain: %3ddB\n", + ((int)(data & 0x3f)) * (-3) / 2); + data = get_mixer_reg(13); + if (data & 1) + printf("Digital mix: Gain: %3ddB\n", + ((int)((data >> 2) & 0x3f)) * (-3) / 2); +} + +/* ---------------------------------------------------------------------- */ + +static void display_mixer_cs423x(void) +{ + unsigned char data; + + display_mixer_ad1848(); + data = get_mixer_reg(26); + printf("Mono: %s%s%s Gain: %3ddB\n", + (data & 0x80) ? "input muted, " : "", + (data & 0x40) ? "output muted, " : "", + (data & 0x20) ? "bypass, " : "", + (int)(data & 0xf) * (-3)); + data = get_mixer_reg(27); + if (data & 0x80) + printf("Left output: muted\n"); + else + printf("Left output: Gain: %3ddB\n", + ((int)(data & 0xf)) * (-2)); + data = get_mixer_reg(29); + if (data & 0x80) + printf("Right output: muted\n"); + else + printf("Right output: Gain: %3ddB\n", + ((int)(data & 0xf)) * (-2)); + +} + +/* ---------------------------------------------------------------------- */ + +static void display_mixer_ct1335(void) +{ + unsigned char data; + + data = get_mixer_reg(0x2); + printf("Master volume: %3ddB\n", + (((int)((data >> 1) & 7)) - 7) * 46 / 7); + data = get_mixer_reg(0xa); + printf("Voice volume: %3ddB\n", + (((int)((data >> 1) & 3)) - 3) * 46 / 3); + data = get_mixer_reg(0x6); + printf("MIDI volume: %3ddB\n", + (((int)((data >> 1) & 7)) - 7) * 46 / 7); + data = get_mixer_reg(0x8); + printf("CD volume: %3ddB\n", + (((int)((data >> 1) & 7)) - 7) * 46 / 7); +} + +/* ---------------------------------------------------------------------- */ + +static void display_mixer_ct1345(void) +{ + static const char *src[4] = { "Mic", "CD", "Mic", "Line" }; + unsigned char data, data2; + + data = get_mixer_reg(0xc); + data2 = get_mixer_reg(0xe); + printf("Input source: %s\n", src[(data >> 1) & 3]); + if (!(data & data2 & 0x20)) { + printf("Filter: Low pass %s kHz: ", (data & 0x8) ? + "8.8" : "3.2"); + if (data & 0x20) + printf("output\n"); + else + printf("input%s\n", (data2 & 0x20) ? "" : ", output"); + } + if (data2 & 2) + printf("stereo\n"); + + data = get_mixer_reg(0x22); + printf("Master volume: Left: %3ddB Right: %3ddB\n", + (((int)((data >> 5) & 7)) - 7) * 46 / 7, + (((int)((data >> 1) & 7)) - 7) * 46 / 7); + data = get_mixer_reg(0x4); + printf("Voice volume: Left: %3ddB Right: %3ddB\n", + (((int)((data >> 5) & 7)) - 7) * 46 / 7, + (((int)((data >> 1) & 7)) - 7) * 46 / 7); + data = get_mixer_reg(0x26); + printf("MIDI volume: Left: %3ddB Right: %3ddB\n", + (((int)((data >> 5) & 7)) - 7) * 46 / 7, + (((int)((data >> 1) & 7)) - 7) * 46 / 7); + data = get_mixer_reg(0x28); + printf("CD volume: Left: %3ddB Right: %3ddB\n", + (((int)((data >> 5) & 7)) - 7) * 46 / 7, + (((int)((data >> 1) & 7)) - 7) * 46 / 7); + data = get_mixer_reg(0x2e); + printf("Line volume: Left: %3ddB Right: %3ddB\n", + (((int)((data >> 5) & 7)) - 7) * 46 / 7, + (((int)((data >> 1) & 7)) - 7) * 46 / 7); + data = get_mixer_reg(0x0a); + printf("Mic mixing volume: %3ddB\n", + (((int)((data >> 1) & 3)) - 3) * 46 / 3); +} + +/* ---------------------------------------------------------------------- */ + +static void display_mixer_ct1745(void) +{ + unsigned char data, data2; + + printf("Master volume: Left: %3ddB Right: %3ddB\n", + ((int)((get_mixer_reg(0x30) >> 3) & 0x1f) - 31) * 2, + ((int)((get_mixer_reg(0x31) >> 3) & 0x1f) - 31) * 2); + printf("Voice volume: Left: %3ddB Right: %3ddB\n", + ((int)((get_mixer_reg(0x32) >> 3) & 0x1f) - 31) * 2, + ((int)((get_mixer_reg(0x33) >> 3) & 0x1f) - 31) * 2); + printf("MIDI volume: Left: %3ddB Right: %3ddB\n", + ((int)((get_mixer_reg(0x34) >> 3) & 0x1f) - 31) * 2, + ((int)((get_mixer_reg(0x35) >> 3) & 0x1f) - 31) * 2); + printf("CD volume: Left: %3ddB Right: %3ddB\n", + ((int)((get_mixer_reg(0x36) >> 3) & 0x1f) - 31) * 2, + ((int)((get_mixer_reg(0x37) >> 3) & 0x1f) - 31) * 2); + printf("Line volume: Left: %3ddB Right: %3ddB\n", + ((int)((get_mixer_reg(0x38) >> 3) & 0x1f) - 31) * 2, + ((int)((get_mixer_reg(0x39) >> 3) & 0x1f) - 31) * 2); + printf("Mic volume: %3ddB\n", + ((int)((get_mixer_reg(0x3a) >> 3) & 0x1f) - 31) * 2); + printf("PC speaker volume: %3ddB\n", + ((int)((get_mixer_reg(0x3b) >> 6) & 0x3) - 3) * 6); + printf("Mic gain: %s\n", + (get_mixer_reg(0x43) & 1) ? "fixed 20dB" : "AGC"); + printf("Output gain: Left: %3ddB Right: %3ddB\n", + ((int)((get_mixer_reg(0x41) >> 6) & 3)) * 6, + ((int)((get_mixer_reg(0x42) >> 6) & 3)) * 6); + printf("Input gain: Left: %3ddB Right: %3ddB\n", + ((int)((get_mixer_reg(0x3f) >> 6) & 3)) * 6, + ((int)((get_mixer_reg(0x40) >> 6) & 3)) * 6); + data = (get_mixer_reg(0x44) >> 4) & 0xf; + if (data > 7) + data--; + data2 = (get_mixer_reg(0x45) >> 4) & 0xf; + if (data2 > 7) + data2--; + printf("Treble: Left: %3ddB Right: %3ddB\n", + ((int)data - 7) * 2, ((int)data2 - 7) * 2); + data = (get_mixer_reg(0x46) >> 4) & 0xf; + if (data > 7) + data--; + data2 = (get_mixer_reg(0x47) >> 4) & 0xf; + if (data2 > 7) + data2--; + printf("Bass: Left: %3ddB Right: %3ddB\n", + ((int)data - 7) * 2, ((int)data2 - 7) * 2); + data = get_mixer_reg(0x3c); + printf("Output sources left: PCSpeaker Voice.L%s%s%s\n", + (data & 1) ? " Mic" : "", (data & 4) ? " CD.L" : "", + (data & 0x10) ? " Line.L" : ""); + printf("Output sources right: PCSpeaker Voice.R%s%s%s\n", + (data & 1) ? " Mic" : "", (data & 2) ? " CD.R" : "", + (data & 8) ? " Line.R" : ""); + data = get_mixer_reg(0x3d); + printf("Input sources left: %s%s%s%s%s%s%s\n", + (data & 1) ? " Mic" : "", (data & 2) ? " CD.R" : "", + (data & 4) ? " CD.L" : "", (data & 8) ? " Line.R" : "", + (data & 0x10) ? " Line.L" : "", (data & 0x20) ? " Midi.R" : "", + (data & 0x40) ? " Midi.L" : ""); + data = get_mixer_reg(0x3e); + printf("Input sources right: %s%s%s%s%s%s%s\n", + (data & 1) ? " Mic" : "", (data & 2) ? " CD.R" : "", + (data & 4) ? " CD.L" : "", (data & 8) ? " Line.R" : "", + (data & 0x10) ? " Line.L" : "", (data & 0x20) ? " Midi.R" : "", + (data & 0x40) ? " Midi.L" : ""); +} + +/* ---------------------------------------------------------------------- */ + +static int parse_ad_src(const char *cp) +{ + if (!strcasecmp(cp, "line")) + return 0; + if (!strcasecmp(cp, "aux1")) + return 1; + if (!strcasecmp(cp, "mic")) + return 2; + if (!strcasecmp(cp, "dac")) + return 3; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +static int set_mixer_ad1848(int argc, char *argv[]) +{ + unsigned int mask = 0; + int olvll = 0, olvlr = 0; + int isrcl = 0, isrcr = 0; + int ilvll = 0, ilvlr = 0; + unsigned int data; + + for (; argc >= 1; argc--, argv++) { + if (!strncasecmp(argv[0], "ol=", 3)) { + olvll = strtol(argv[0]+3, NULL, 0); + mask |= 1; + if (olvll < -46 || olvll > 0) { + fprintf(stderr, "output level out of range " + "-100..0dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "or=", 3)) { + olvlr = strtol(argv[0]+3, NULL, 0); + mask |= 2; + if (olvlr < -46 || olvlr > 0) { + fprintf(stderr, "output level out of range " + "-100..0dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "o=", 2)) { + olvll = olvlr = strtol(argv[0]+2, NULL, 0); + mask |= 3; + if (olvll < -46 || olvll > 0) { + fprintf(stderr, "output level out of range " + "-100..0dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "il=", 3)) { + ilvll = strtol(argv[0]+3, NULL, 0); + mask |= 4; + if (ilvll < 0 || ilvll > 43) { + fprintf(stderr, "input gain out of range " + "0..43dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "ir=", 3)) { + ilvlr = strtol(argv[0]+3, NULL, 0); + mask |= 8; + if (ilvll < 0 || ilvll > 43) { + fprintf(stderr, "input gain out of range " + "0..43dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "i=", 2)) { + ilvll = ilvlr = strtol(argv[0]+2, NULL, 0); + mask |= 12; + if (ilvll < 0 || ilvll > 43) { + fprintf(stderr, "input gain out of range " + "0..43dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "sl=", 3)) { + mask |= 16; + if ((isrcl = parse_ad_src(argv[0]+3)) < 0) { + fprintf(stderr, "invalid input source, must " + "be either line, aux1, mic or dac\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "sr=", 3)) { + mask |= 32; + if ((isrcr = parse_ad_src(argv[0]+3)) < 0) { + fprintf(stderr, "invalid input source, must " + "be either line, aux1, mic or dac\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "s=", 2)) { + mask |= 48; + if ((isrcl = isrcr = parse_ad_src(argv[0]+2)) < 0) { + fprintf(stderr, "invalid input source, must " + "be either line, aux1, mic or dac\n"); + return -1; + } + } else { + fprintf(stderr, "invalid parameter \"%s\"\n", argv[0]); + return -1; + } + } + data = get_mixer_reg(0x00); + if (mask & 4) { + data &= 0xc0; + if (ilvll > 23) { + data |= 0x20; + ilvll -= 20; + } + data |= ilvll * 2 / 3; + } + if (mask & 16) + data = (data & 0x3f) | (isrcl << 6); + if ((data & 0xc0) != 0x80) + data &= ~0x20; + set_mixer_reg(0x00, data); + data = get_mixer_reg(0x01); + if (mask & 8) { + data &= 0xc0; + if (ilvlr > 23) { + data |= 0x20; + ilvlr -= 20; + } + data |= ilvlr * 2 / 3; + } + if (mask & 32) + data = (data & 0x3f) | (isrcr << 6); + if ((data & 0xc0) != 0x80) + data &= ~0x20; + set_mixer_reg(0x01, data); + set_mixer_reg(0x02, 0x80); + set_mixer_reg(0x03, 0x80); + set_mixer_reg(0x04, 0x80); + set_mixer_reg(0x05, 0x80); + if (mask & 1) { + if (olvll < -95) + set_mixer_reg(0x06, 0x80); + else + set_mixer_reg(0x06, (olvll * (-2) / 3)); + } + if (mask & 2) { + if (olvlr < -95) + set_mixer_reg(0x07, 0x80); + else + set_mixer_reg(0x07, (olvlr * (-2) / 3)); + } + set_mixer_reg(0x0d, 0x00); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int set_mixer_ct1335(int argc, char *argv[]) +{ + unsigned int mask = 0; + int olvl = 0; + + for (; argc >= 1; argc--, argv++) { + if (!strncasecmp(argv[0], "o=", 2)) { + olvl = strtol(argv[0]+2, NULL, 0); + mask |= 1; + if (olvl < -46 || olvl > 0) { + fprintf(stderr, "output level out of range " + "-46..0dB\n"); + return -1; + } + } else { + fprintf(stderr, "invalid parameter \"%s\"\n", argv[0]); + return -1; + } + } + if (mask & 1) + set_mixer_reg(0x02, (((olvl * 7 / 46) + 7) << 1)); + set_mixer_reg(0x06, 0x00); + set_mixer_reg(0x08, 0x00); + set_mixer_reg(0x0a, 0x06); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int set_mixer_ct1345(int argc, char *argv[]) +{ + unsigned int mask = 0; + int olvll = 0, olvlr = 0; + int isrc = 0; + unsigned int data; + + for (; argc >= 1; argc--, argv++) { + if (!strncasecmp(argv[0], "ol=", 3)) { + olvll = strtol(argv[0]+3, NULL, 0); + mask |= 1; + if (olvll < -46 || olvll > 0) { + fprintf(stderr, "output level out of range " + "-46..0dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "or=", 3)) { + olvlr = strtol(argv[0]+3, NULL, 0); + mask |= 2; + if (olvlr < -46 || olvlr > 0) { + fprintf(stderr, "output level out of range " + "-46..0dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "o=", 2)) { + olvll = olvlr = strtol(argv[0]+2, NULL, 0); + mask |= 3; + if (olvll < -46 || olvll > 0) { + fprintf(stderr, "output level out of range " + "-46..0dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "s=", 2)) { + mask |= 4; + if (!strcasecmp(argv[0]+2, "mic")) + isrc = 0; + else if (!strcasecmp(argv[0]+2, "cd")) + isrc = 1; + else if (!strcasecmp(argv[0]+2, "line")) + isrc = 3; + else { + fprintf(stderr, "invalid input source, must " + "be either mic, cd or line\n"); + return -1; + } + } else { + fprintf(stderr, "invalid parameter \"%s\"\n", argv[0]); + return -1; + } + } + set_mixer_reg(0x04, 0xee); + set_mixer_reg(0x0a, 0x00); + if (mask & 4) + data = (isrc & 3) << 1; + else + data = get_mixer_reg(0x0c) & 0x06; + set_mixer_reg(0x0c, data | 0x20); + set_mixer_reg(0x0e, 0x20); + data = get_mixer_reg(0x22); + if (mask & 1) + data = (data & 0x0f) | (((olvll * 7 / 46) + 7) << 5); + if (mask & 2) + data = (data & 0xf0) | (((olvlr * 7 / 46) + 7) << 1); + set_mixer_reg(0x22, data); + set_mixer_reg(0x26, 0x00); + set_mixer_reg(0x28, 0x00); + set_mixer_reg(0x2e, 0x00); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int set_mixer_ct1745(int argc, char *argv[]) +{ + unsigned int mask = 0; + int olvll = 0, olvlr = 0; + int ilvll = 0, ilvlr = 0; + unsigned int insrc = 0; + unsigned int data; + + for (; argc >= 1; argc--, argv++) { + if (!strncasecmp(argv[0], "ol=", 3)) { + olvll = strtol(argv[0]+3, NULL, 0); + mask |= 1; + if (olvll < -62 || olvll > 18) { + fprintf(stderr, "output level out of range " + "-62..18dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "or=", 3)) { + olvlr = strtol(argv[0]+3, NULL, 0); + mask |= 2; + if (olvlr < -62 || olvlr > 18) { + fprintf(stderr, "output level out of range " + "-62..18dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "o=", 2)) { + olvll = olvlr = strtol(argv[0]+2, NULL, 0); + mask |= 3; + if (olvll < -62 || olvll > 18) { + fprintf(stderr, "output level out of range " + "-62..18dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "il=", 3)) { + ilvll = strtol(argv[0]+3, NULL, 0); + mask |= 4; + if (ilvll < -62 || ilvll > 18) { + fprintf(stderr, "input gain out of range " + "-62..18dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "ir=", 3)) { + ilvlr = strtol(argv[0]+3, NULL, 0); + mask |= 8; + if (ilvll < -62 || ilvll > 18) { + fprintf(stderr, "input gain out of range " + "-62..18dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "i=", 2)) { + ilvll = ilvlr = strtol(argv[0]+2, NULL, 0); + mask |= 12; + if (ilvll < -62 || ilvll > 18) { + fprintf(stderr, "input gain out of range " + "-62..18dB\n"); + return -1; + } + } else if (!strncasecmp(argv[0], "s=", 2)) { + mask |= 16; + if (!strcasecmp(argv[0]+2, "mic")) + insrc |= 1; + else if (!strcasecmp(argv[0]+2, "cd.r")) + insrc |= 2; + else if (!strcasecmp(argv[0]+2, "cd.l")) + insrc |= 4; + else if (!strcasecmp(argv[0]+2, "cd")) + insrc |= 6; + else if (!strcasecmp(argv[0]+2, "line.r")) + insrc |= 0x08; + else if (!strcasecmp(argv[0]+2, "line.l")) + insrc |= 0x10; + else if (!strcasecmp(argv[0]+2, "line")) + insrc |= 0x18; + else if (!strcasecmp(argv[0]+2, "midi.r")) + insrc |= 0x20; + else if (!strcasecmp(argv[0]+2, "midi.l")) + insrc |= 0x40; + else if (!strcasecmp(argv[0]+2, "midi")) + insrc |= 0x60; + else { + fprintf(stderr, "invalid input source, must " + "be either line, cd, mic or midi\n"); + return -1; + } + } else { + fprintf(stderr, "invalid parameter \"%s\"\n", argv[0]); + return -1; + } + } + if (mask & 3) { + set_mixer_reg(0x3c, 0); /* output src: only voice and pcspk */ + set_mixer_reg(0x44, 4<<4); /* treble.l: -6dB */ + set_mixer_reg(0x45, 4<<4); /* treble.r: -6dB */ + set_mixer_reg(0x46, 6<<4); /* bass.l: -2dB */ + set_mixer_reg(0x47, 6<<4); /* bass.r: -2dB */ + set_mixer_reg(0x3b, 0); /* PC speaker vol -18dB */ + } + if (mask & 12) + set_mixer_reg(0x43, 1); /* mic: agc off, fixed 20dB gain */ + if (mask & 1) { + data = 0; + while (olvll > 0) { + olvll -= 6; + data += 0x40; + } + set_mixer_reg(0x41, data); /* output gain */ + set_mixer_reg(0x30, 0xf8); /* master vol */ + set_mixer_reg(0x32, (olvll / 2 + 31) << 3); /* voice vol */ + } + if (mask & 2) { + data = 0; + while (olvlr > 0) { + olvlr -= 6; + data += 0x40; + } + set_mixer_reg(0x42, data); /* output gain */ + set_mixer_reg(0x31, 0xf8); /* master vol */ + set_mixer_reg(0x33, (olvlr / 2 + 31) << 3); /* voice vol */ + } + if (mask & 4) { + data = 0; + while (ilvll > 0) { + ilvll -= 6; + data += 0x40; + } + set_mixer_reg(0x3f, data); /* input gain */ + data = (ilvll / 2 + 31) << 3; + set_mixer_reg(0x34, data); /* midi vol */ + set_mixer_reg(0x36, data); /* cd vol */ + set_mixer_reg(0x38, data); /* line vol */ + set_mixer_reg(0x3a, data); /* mic vol */ + } + if (mask & 8) { + data = 0; + while (ilvlr > 0) { + ilvlr -= 6; + data += 0x40; + } + set_mixer_reg(0x40, data); /* input gain */ + data = (ilvlr / 2 + 31) << 3; + set_mixer_reg(0x35, data); /* midi vol */ + set_mixer_reg(0x37, data); /* cd vol */ + set_mixer_reg(0x39, data); /* line vol */ + set_mixer_reg(0x3a, data); /* mic vol */ + } + if (mask & 16) { + set_mixer_reg(0x3d, insrc); /* input sources */ + set_mixer_reg(0x3e, insrc); /* input sources */ + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static const char *usage_str = +"[-i smif]\n\n"; + +int main(int argc, char *argv[]) +{ + int c; + struct sm_mixer_data mixdat; + + progname = *argv; + printf("%s: Version 0.2; (C) 1996-1997 by Thomas Sailer HB9JNX/AE4WA\n", *argv); + hdrvc_args(&argc, argv, "sm0"); + while ((c = getopt(argc, argv, "")) != -1) { + switch (c) { + default: + printf("usage: %s %s", *argv, usage_str); + exit(-1); + } + } + hdrvc_init(); + mixdat.reg = 0; + if (do_mix_ioctl(SMCTL_GETMIXER, &mixdat) < 0) { + perror("do_mix_ioctl: SMCTL_GETMIXER"); + exit(1); + } + mixdevice = mixdat.mixer_type; + switch (mixdevice) { + case SM_MIXER_INVALID: + printf("invalid mixer device\n"); + exit(1); + case SM_MIXER_AD1848: + if (optind < argc) + set_mixer_ad1848(argc - optind, argv + optind); + display_mixer_ad1848(); + break; + case SM_MIXER_CRYSTAL: + if (optind < argc) + set_mixer_ad1848(argc - optind, argv + optind); + display_mixer_cs423x(); + break; + case SM_MIXER_CT1335: + if (optind < argc) + set_mixer_ct1335(argc - optind, argv + optind); + display_mixer_ct1335(); + break; + case SM_MIXER_CT1345: + if (optind < argc) + set_mixer_ct1345(argc - optind, argv + optind); + display_mixer_ct1345(); + break; + case SM_MIXER_CT1745: + if (optind < argc) + set_mixer_ct1745(argc - optind, argv + optind); + display_mixer_ct1745(); + break; + default: + printf("unknown mixer device %d\n", mixdevice); + exit(1); + } + exit(0); +} + +/* ---------------------------------------------------------------------- */ diff --git a/hdlcutil/usersmdiag.h b/hdlcutil/usersmdiag.h new file mode 100644 index 0000000..5335002 --- /dev/null +++ b/hdlcutil/usersmdiag.h @@ -0,0 +1,118 @@ +/*****************************************************************************/ + +/* + * usersmdiag.h -- Diagnostics interface. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Swiss Federal Institute of Technology (ETH), Electronics Lab + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * This is the Linux realtime sound output driver + */ + +/*****************************************************************************/ + +#ifndef _USERSMDIAG_H +#define _USERSMDIAG_H + +/* --------------------------------------------------------------------- */ + +#define USERSM_KEY_PROJ '0' + +/* --------------------------------------------------------------------- */ + +#define USERSM_CMD_REQ_CHACCESS_PAR 0x00020 +#define USERSM_CMD_ACK_CHACCESS_PAR 0x10021 +#define USERSM_CMD_SET_CHACCESS_PAR 0x00022 + +#define USERSM_CMD_CALIBRATE 0x00030 +#define USERSM_CMD_REQ_CHANNELSTATE 0x00031 +#define USERSM_CMD_ACK_CHANNELSTATE 0x10032 + +#define USERSM_CMD_REQ_DIAG 0x00040 +#define USERSM_CMD_ACK_DIAG 0x10041 + +#define USERSM_CMD_REQ_DRVNAME 0x00050 +#define USERSM_CMD_ACK_DRVNAME 0x10051 +#define USERSM_CMD_REQ_DRVMODE 0x00052 +#define USERSM_CMD_ACK_DRVMODE 0x10053 + +/* + * diagnose modes; same as in <linux/soundmodem.h> + */ +#define USERSM_DIAGMODE_OFF 0 +#define USERSM_DIAGMODE_INPUT 1 +#define USERSM_DIAGMODE_DEMOD 2 +#define USERSM_DIAGMODE_CONSTELLATION 3 + +/* + * diagnose flags; same as in <linux/soundmodem.h> + */ +#define USERSM_DIAGFLAG_DCDGATE (1<<0) +#define USERSM_DIAGFLAG_VALID (1<<1) + +/* --------------------------------------------------------------------- */ + +#define DIAGDATALEN 64 + +/* --------------------------------------------------------------------- */ + +struct usersmmsg { + struct usersm_hdr { + long type; + unsigned int channel; + } hdr; + union { + struct usersm_chaccess_par { + int tx_delay; /* the transmitter keyup delay in 10ms units */ + int tx_tail; /* the transmitter keyoff delay in 10ms units */ + int slottime; /* the slottime in 10ms; usually 10 = 100ms */ + int ppersist; /* the p-persistence 0..255 */ + int fulldup; /* some driver do not support full duplex, setting */ + /* this just makes them send even if DCD is on */ + } cp; + + int calib; + + struct usersm_channel_state { + int ptt; + int dcd; + int ptt_keyed; + unsigned long tx_packets; + unsigned long tx_errors; + unsigned long rx_packets; + unsigned long rx_errors; + } cs; + + struct usersm_diag { + unsigned int mode; + unsigned int flags; + unsigned int samplesperbit; + unsigned int datalen; + } diag; + + struct usersm_diag_out { + struct usersm_diag diag; + short samples[DIAGDATALEN]; + } diag_out; + + unsigned char by[0]; + } data; +}; + +/* --------------------------------------------------------------------- */ +#endif /* _USERSMDIAG_H */ diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/kiss/Makefile.am b/kiss/Makefile.am new file mode 100644 index 0000000..7a130da --- /dev/null +++ b/kiss/Makefile.am @@ -0,0 +1,8 @@ + +installconf: + +sbin_PROGRAMS = kissattach kissnetd kissparms mkiss net2kiss + +man_MANS = kissattach.8 kissnetd.8 kissparms.8 mkiss.8 net2kiss.8 + + diff --git a/kiss/Makefile.in b/kiss/Makefile.in new file mode 100644 index 0000000..883ef04 --- /dev/null +++ b/kiss/Makefile.in @@ -0,0 +1,367 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +sbin_PROGRAMS = kissattach kissnetd kissparms mkiss net2kiss + +man_MANS = kissattach.8 kissnetd.8 kissparms.8 mkiss.8 net2kiss.8 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +kissattach_SOURCES = kissattach.c +kissattach_OBJECTS = kissattach.o +kissattach_LDADD = $(LDADD) +kissattach_DEPENDENCIES = +kissattach_LDFLAGS = +kissnetd_SOURCES = kissnetd.c +kissnetd_OBJECTS = kissnetd.o +kissnetd_LDADD = $(LDADD) +kissnetd_DEPENDENCIES = +kissnetd_LDFLAGS = +kissparms_SOURCES = kissparms.c +kissparms_OBJECTS = kissparms.o +kissparms_LDADD = $(LDADD) +kissparms_DEPENDENCIES = +kissparms_LDFLAGS = +mkiss_SOURCES = mkiss.c +mkiss_OBJECTS = mkiss.o +mkiss_LDADD = $(LDADD) +mkiss_DEPENDENCIES = +mkiss_LDFLAGS = +net2kiss_SOURCES = net2kiss.c +net2kiss_OBJECTS = net2kiss.o +net2kiss_LDADD = $(LDADD) +net2kiss_DEPENDENCIES = +net2kiss_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man8dir = $(mandir)/man8 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = kissattach.c kissnetd.c kissparms.c mkiss.c net2kiss.c +OBJECTS = kissattach.o kissnetd.o kissparms.o mkiss.o net2kiss.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps kiss/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +kissattach: $(kissattach_OBJECTS) $(kissattach_DEPENDENCIES) + @rm -f kissattach + $(LINK) $(kissattach_LDFLAGS) $(kissattach_OBJECTS) $(kissattach_LDADD) $(LIBS) + +kissnetd: $(kissnetd_OBJECTS) $(kissnetd_DEPENDENCIES) + @rm -f kissnetd + $(LINK) $(kissnetd_LDFLAGS) $(kissnetd_OBJECTS) $(kissnetd_LDADD) $(LIBS) + +kissparms: $(kissparms_OBJECTS) $(kissparms_DEPENDENCIES) + @rm -f kissparms + $(LINK) $(kissparms_LDFLAGS) $(kissparms_OBJECTS) $(kissparms_LDADD) $(LIBS) + +mkiss: $(mkiss_OBJECTS) $(mkiss_DEPENDENCIES) + @rm -f mkiss + $(LINK) $(mkiss_LDFLAGS) $(mkiss_OBJECTS) $(mkiss_LDADD) $(LIBS) + +net2kiss: $(net2kiss_OBJECTS) $(net2kiss_DEPENDENCIES) + @rm -f net2kiss + $(LINK) $(net2kiss_LDFLAGS) $(net2kiss_OBJECTS) $(net2kiss_LDADD) $(LIBS) + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = kiss + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +kissattach.o: kissattach.c ../config.h ../pathnames.h +kissnetd.o: kissnetd.c +kissparms.o: kissparms.c ../config.h +mkiss.o: mkiss.c ../config.h +net2kiss.o: net2kiss.c + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile install-man8 uninstall-man8 \ +install-man uninstall-man tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +installconf: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/kiss/kissattach.c b/kiss/kissattach.c new file mode 100644 index 0000000..149c2bd --- /dev/null +++ b/kiss/kissattach.c @@ -0,0 +1,289 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <netdb.h> +#include <syslog.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/daemon.h> +#include <netax25/axlib.h> +#include <netax25/ttyutils.h> + +#include <config.h> + +#include "../pathnames.h" + +static char *callsign; +static int speed = 0; +static int mtu = 0; +static int logging = FALSE; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +static int readconfig(char *port) +{ + FILE *fp; + char buffer[90], *s; + int n = 0; + + if ((fp = fopen(CONF_AXPORTS_FILE, "r")) == NULL) { + fprintf(stderr, "kissattach: cannot open axports file\n"); + return FALSE; + } + + while (fgets(buffer, 90, fp) != NULL) { + n++; + + if ((s = strchr(buffer, '\n')) != NULL) + *s = '\0'; + + if (strlen(buffer) > 0 && *buffer == '#') + continue; + + if ((s = strtok(buffer, " \t\r\n")) == NULL) { + fprintf(stderr, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + if (strcmp(s, port) != 0) + continue; + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + callsign = strdup(s); + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + speed = atoi(s); + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + if (mtu == 0) { + if ((mtu = atoi(s)) <= 0) { + fprintf(stderr, "kissattach: invalid paclen setting\n"); + return FALSE; + } + } + + fclose(fp); + + return TRUE; + } + + fclose(fp); + + fprintf(stderr, "kissattach: cannot find port %s in axports\n", port); + + return FALSE; +} + + +static int setifcall(int fd, char *name) +{ + char call[7]; + + if (ax25_aton_entry(name, call) == -1) + return FALSE; + + if (ioctl(fd, SIOCSIFHWADDR, call) != 0) { + close(fd); + perror("kissattach: SIOCSIFHWADDR"); + return FALSE; + } + + return TRUE; +} + + +static int startiface(char *dev, struct hostent *hp) +{ + struct ifreq ifr; + int fd; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("kissattach: socket"); + return FALSE; + } + + strcpy(ifr.ifr_name, dev); + + if (hp != NULL) { + ifr.ifr_addr.sa_family = AF_INET; + + ifr.ifr_addr.sa_data[0] = 0; + ifr.ifr_addr.sa_data[1] = 0; + ifr.ifr_addr.sa_data[2] = hp->h_addr_list[0][0]; + ifr.ifr_addr.sa_data[3] = hp->h_addr_list[0][1]; + ifr.ifr_addr.sa_data[4] = hp->h_addr_list[0][2]; + ifr.ifr_addr.sa_data[5] = hp->h_addr_list[0][3]; + ifr.ifr_addr.sa_data[6] = 0; + + if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) { + perror("kissattach: SIOCSIFADDR"); + return FALSE; + } + } + + ifr.ifr_mtu = mtu; + + if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) { + perror("kissattach: SIOCSIFMTU"); + return FALSE; + } + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("kissattach: SIOCGIFFLAGS"); + return FALSE; + } + + ifr.ifr_flags &= IFF_NOARP; + ifr.ifr_flags |= IFF_UP; + ifr.ifr_flags |= IFF_RUNNING; + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { + perror("kissattach: SIOCSIFFLAGS"); + return FALSE; + } + + close(fd); + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + int fd; + int disc = N_AX25; + char dev[64]; + int v = 4; + struct hostent *hp = NULL; + + while ((fd = getopt(argc, argv, "i:lm:v")) != -1) { + switch (fd) { + case 'i': + if ((hp = gethostbyname(optarg)) == NULL) { + fprintf(stderr, "kissattach: invalid internet name/address - %s\n", optarg); + return 1; + } + break; + case 'l': + logging = TRUE; + break; + case 'm': + if ((mtu = atoi(optarg)) <= 0) { + fprintf(stderr, "kissattach: invalid mtu size - %s\n", optarg); + return 1; + } + break; + case 'v': + printf("kissattach: %s\n", VERSION); + return 0; + case ':': + case '?': + fprintf(stderr, "usage: kissattach [-i inetaddr] [-l] [-m mtu] [-v] ttyinterface port\n"); + return 1; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "usage: kissattach [-i inetaddr] [-l] [-m mtu] [-v] ttyinterface port\n"); + return 1; + } + + if (tty_is_locked(argv[optind])) { + fprintf(stderr, "kissattach: device %s already in use\n", argv[optind]); + return 1; + } + + if (!readconfig(argv[optind + 1])) + return 1; + + if ((fd = open(argv[optind], O_RDONLY | O_NONBLOCK)) == -1) { + perror("kissattach: open"); + return 1; + } + + if (speed != 0 && !tty_speed(fd, speed)) + return 1; + + if (ioctl(fd, TIOCSETD, &disc) == -1) { + perror("kissattach: TIOCSETD"); + return 1; + } + + if (ioctl(fd, SIOCGIFNAME, dev) == -1) { + perror("kissattach: SIOCGIFNAME"); + return 1; + } + + if (!setifcall(fd, callsign)) + return 1; + + /* Now set the encapsulation */ + if (ioctl(fd, SIOCSIFENCAP, &v) == -1) { + perror("kissattach: SIOCSIFENCAP"); + return 1; + } + + if (!startiface(dev, hp)) + return 1; + + printf("AX.25 port %s bound to device %s\n", argv[optind + 1], dev); + + if (logging) { + openlog("kissattach", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "AX.25 port %s bound to device %s\n", argv[optind + 1], dev); + } + + signal(SIGHUP, SIG_IGN); + signal(SIGTERM, terminate); + + /* + * Become a daemon if we can. + */ + if (!daemon_start(FALSE)) { + fprintf(stderr, "kissattach: cannot become a daemon\n"); + return 1; + } + + if (!tty_lock(argv[optind])) + return 1; + + while (1) + sleep(10000); + + /* NOT REACHED */ + return 0; +} diff --git a/kiss/kissnetd.c b/kiss/kissnetd.c new file mode 100644 index 0000000..ff38779 --- /dev/null +++ b/kiss/kissnetd.c @@ -0,0 +1,257 @@ +/* + * kissnetd.c : Simple kiss broadcast daemon between several + * pseudo-tty devices. + * Each kiss frame received on one pty is broadcasted + * to each other one. + * + * ATEPRA FPAC/Linux Project + * + * F1OAT 960804 - Frederic RIBLE + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <assert.h> +#include <fcntl.h> +#include <strings.h> +#include <errno.h> +#include <syslog.h> +#include <time.h> + +static char *Version = "1.5"; +static int VerboseMode = 0; +static int MaxFrameSize = 512; + +#define REOPEN_TIMEOUT 30 /* try tio reopen every 10 s */ + +struct PortDescriptor { + char Name[80]; + int Fd; + unsigned char *FrameBuffer; + int BufferIndex; + time_t TimeLastOpen; +}; + +static struct PortDescriptor *PortList[FD_SETSIZE]; +static int NbPort = 0; + +static void Usage(void) +{ + fprintf(stderr, "\nUsage : kissnetd [-v] [-f size] /dev/pty?? [/dev/pty??]*\n"); + fprintf(stderr, " -v : Verbose mode, trace on stdout\n"); + fprintf(stderr, " -f size : Set max frame size to size bytes (default 512)\n"); + exit(1); +} + +static void Banner(int Small) +{ + if (Small) { + printf("kissnetd V %s by Frederic RIBLE F1OAT - ATEPRA FPAC/Linux Project\n", Version); + } + else { + printf("****************************************\n"); + printf("* Network broadcast between kiss ports *\n"); + printf("* ATEPRA FPAC/Linux Project *\n"); + printf("****************************************\n"); + printf("* kissnetd Version %-4s *\n", Version); + printf("* by Frederic RIBLE F1OAT *\n"); + printf("****************************************\n"); + } +} + +static void NewPort(char *Name) +{ + struct PortDescriptor *MyPort; + + if (VerboseMode) { + printf("Opening port %s\n", Name); + } + + if (NbPort == FD_SETSIZE) { + fprintf(stderr, "Cannot handle %s : too many ports\n", Name); + exit(1); + } + + MyPort = calloc(sizeof(struct PortDescriptor), 1); + if (MyPort) MyPort->FrameBuffer = calloc(sizeof (unsigned char), MaxFrameSize); + if (!MyPort || !MyPort->FrameBuffer) { + perror("cannot allocate port descriptor"); + exit(1); + } + + strncpy(MyPort->Name, Name, sizeof(MyPort->Name)); + MyPort->Fd = -1; + MyPort->FrameBuffer[0] = 0xC0; + MyPort->BufferIndex = 1; + PortList[NbPort++] = MyPort; +} + +static void ReopenPort(int PortNumber) +{ + char MyString[80]; + + PortList[PortNumber]->TimeLastOpen = time(NULL); + + if (VerboseMode) { + printf("Reopening port %d\n", PortNumber); + } + + syslog(LOG_WARNING, "kissnetd : Opening port %s\n", PortList[PortNumber]->Name); + + PortList[PortNumber]->Fd = open(PortList[PortNumber]->Name, O_RDWR | O_NONBLOCK); + if (PortList[PortNumber]->Fd < 0) { + syslog(LOG_WARNING, "kissnetd : Error opening port %s : %s\n", + PortList[PortNumber]->Name, sys_errlist[errno]); + if (VerboseMode) { + sprintf(MyString, "cannot reopen %s", PortList[PortNumber]->Name); + perror(MyString); + } + } +} + +static void TickReopen(void) +{ + int i; + time_t CurrentTime = time(NULL); + + for (i=0; i<NbPort; i++) { + if (PortList[i]->Fd >= 0) continue; + if ( (CurrentTime - PortList[i]->TimeLastOpen) > REOPEN_TIMEOUT ) ReopenPort(i); + } +} + +static void Broadcast(int InputPort) +{ + int i; + int rc; + + /* Broadcast only info frames */ + + if (PortList[InputPort]->FrameBuffer[1] != 0x00) return; + + for (i=0; i<NbPort; i++) { + if (i == InputPort) continue; + if (PortList[i]->Fd < 0) continue; + rc = write(PortList[i]->Fd, + PortList[InputPort]->FrameBuffer, + PortList[InputPort]->BufferIndex); + if (VerboseMode) { + printf("Sending %d bytes on port %d : rc=%d\n", + PortList[InputPort]->BufferIndex, + i, rc); + } + } +} + +static void ProcessInput(int PortNumber) +{ + static unsigned char MyBuffer[2048]; + int Length; + int i; + struct PortDescriptor *MyPort = PortList[PortNumber]; + + Length = read(MyPort->Fd, MyBuffer, sizeof(MyBuffer)); + if (VerboseMode) { + printf("Read port %d : rc=%d\n", PortNumber, Length); + } + if (!Length) return; + if (Length < 0) { + syslog(LOG_WARNING, "kissnetd : Error reading port %s : %s\n", + PortList[PortNumber]->Name, sys_errlist[errno]); + if (VerboseMode) perror("read"); + close(MyPort->Fd); + MyPort->Fd = -1; + return; + } + for (i=0; i<Length; i++) { + if (MyPort->BufferIndex == MaxFrameSize) { + if (MyBuffer[i] == 0xC0) { + if (VerboseMode) printf("Drop frame too long\n"); + MyPort->BufferIndex = 1; + } + } + else { + MyPort->FrameBuffer[MyPort->BufferIndex++] = MyBuffer[i]; + if (MyBuffer[i] == 0xC0) { + Broadcast(PortNumber); + MyPort->BufferIndex = 1; + } + } + } +} + +static void ProcessPortList(void) +{ + static fd_set MyFdSet; + int i, rc; + struct timeval Timeout; + + Timeout.tv_sec = 1; + Timeout.tv_usec = 0; + + FD_ZERO(&MyFdSet); + for (i=0; i<NbPort; i++) { + if (PortList[i]->Fd >= 0) FD_SET(PortList[i]->Fd, &MyFdSet); + } + rc = select(FD_SETSIZE, &MyFdSet, NULL, NULL, &Timeout); + + if (VerboseMode) printf("select : rc=%d\n", rc); + if (!rc ) TickReopen(); + + if (rc > 0) { + for (i=0; i<NbPort && rc; i++) { + if (PortList[i]->Fd < 0) continue; + if (FD_ISSET(PortList[i]->Fd, &MyFdSet)) { + ProcessInput(i); + rc--; + } + } + } +} + +static void ProcessArgv(char *argv[]) +{ + char *Opt; + int ArgvIndex = 0; + + while (argv[ArgvIndex]) { + if (argv[ArgvIndex][0] != '-') { + NewPort(argv[ArgvIndex++]); + continue; + } + for (Opt = &argv[ArgvIndex++][1]; *Opt; Opt++) { + switch (*Opt) { + case 'v': + VerboseMode = 1; + break; + case 'f': + MaxFrameSize = atoi(argv[ArgvIndex++]); + break; + default: + fprintf(stderr, "Invalid option %c\n", *Opt); + Usage(); + break; + } + } + + } +} + + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + Banner(0); + Usage(); + } + else { + Banner(1); + } + + ProcessArgv(argv+1); + while (1) ProcessPortList(); + return 0; +} diff --git a/kiss/kissparms.c b/kiss/kissparms.c new file mode 100644 index 0000000..0a1a101 --- /dev/null +++ b/kiss/kissparms.c @@ -0,0 +1,221 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <net/if.h> +#include <net/ethernet.h> + +#include <netax25/ax25.h> +#include <netax25/axconfig.h> + +#include <config.h> + +#define PARAM_TXDELAY 1 +#define PARAM_PERSIST 2 +#define PARAM_SLOTTIME 3 +#define PARAM_TXTAIL 4 +#define PARAM_FULLDUP 5 +#define PARAM_HARDWARE 6 +#define PARAM_FECLEVEL 8 +#define PARAM_RETURN 255 + +#define USAGE "usage: kissparms -p <port> [-f y|n] [-h hw] [-l txtail] \ + [-r pers ] [-s slot] [-t txd] [-e feclevel] [-v] [-x]\n" + +int main(int argc, char *argv[]) +{ + unsigned char buffer[2]; + struct sockaddr sa; + int proto = ETH_P_AX25; + int txdelay = -1; + int txtail = -1; + int persist = -1; + int slottime = -1; + int fulldup = -1; + int hardware = -1; + int feclevel = -1; + int kissoff = 0; + int buflen, s; + char *port = NULL; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "kissparms: no AX.25 ports configured\n"); + return 1; + } + + while ((s = getopt(argc, argv, "e:f:h:l:p:r:s:t:vx")) != -1) { + switch (s) { + case 'e': + feclevel = atoi(optarg); + if (feclevel < 0 || feclevel > 3) { + fprintf(stderr, "kissparms: invalid FEC level value\n"); + return 1; + } + break; + + case 'f': + if (*optarg != 'y' && *optarg != 'n') { + fprintf(stderr, "kissparms: invalid full duplex setting\n"); + return 1; + } + fulldup = *optarg == 'y'; + break; + + case 'l': + txtail = atoi(optarg) / 10; + if (txtail < 0 || txtail > 255) { + fprintf(stderr, "kissparms: invalid txtail value\n"); + return 1; + } + break; + + + case 'h': + hardware = atoi(optarg); + if (hardware < 0 || hardware > 255) { + fprintf(stderr, "kissparms: invalid hardware value\n"); + return 1; + } + break; + + case 'p': + port = optarg; + if (ax25_config_get_addr(port) == NULL) { + fprintf(stderr, "kissparms: invalid port name - %s\n", port); + return 1; + } + break; + + case 'r': + persist = atoi(optarg); + if (persist < 0 || persist > 255) { + fprintf(stderr, "kissparms: invalid persist value\n"); + return 1; + } + break; + + case 's': + slottime = atoi(optarg) / 10; + if (slottime < 0 || slottime > 255) { + fprintf(stderr, "kissparms: invalid slottime value\n"); + return 1; + } + break; + + case 't': + txdelay = atoi(optarg) / 10; + if (txdelay < 0 || txdelay > 255) { + fprintf(stderr, "kissparms: invalid txdelay value\n"); + return 1; + } + break; + + case 'v': + printf("kissparms: %s\n", VERSION); + return 0; + + case 'x': + kissoff = 1; + break; + + case ':': + case '?': + fprintf(stderr, USAGE); + return 1; + } + } + + if (port == NULL) { + fprintf(stderr, USAGE); + return 1; + } + + if ((s = socket(AF_INET, SOCK_PACKET, htons(proto))) < 0) { + perror("kissparms: socket"); + return 1; + } + + strcpy(sa.sa_data, ax25_config_get_dev(port)); + + if (kissoff) { + buffer[0] = PARAM_RETURN; + buflen = 1; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } else { + if (txdelay != -1) { + buffer[0] = PARAM_TXDELAY; + buffer[1] = txdelay; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (txtail != -1) { + buffer[0] = PARAM_TXTAIL; + buffer[1] = txtail; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (persist != -1) { + buffer[0] = PARAM_PERSIST; + buffer[1] = persist; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (slottime != -1) { + buffer[0] = PARAM_SLOTTIME; + buffer[1] = slottime; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (fulldup != -1) { + buffer[0] = PARAM_FULLDUP; + buffer[1] = fulldup; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (hardware != -1) { + buffer[0] = PARAM_HARDWARE; + buffer[1] = hardware; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + + if (feclevel != -1) { + buffer[0] = PARAM_FECLEVEL; + buffer[1] = feclevel; + + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + } + + close(s); + + return 0; +} diff --git a/kiss/mkiss.c b/kiss/mkiss.c new file mode 100644 index 0000000..8621ce4 --- /dev/null +++ b/kiss/mkiss.c @@ -0,0 +1,512 @@ +/* + * mkiss.c + * Fake out AX.25 code into supporting dual port TNCS by routing serial + * port data to/from two pseudo ttys. + * + * Version 1.03 + * + * N0BEL + * Kevin Uhlir + * kevinu@flochart.com + * + * 1.01 12/30/95 Ron Curry - Fixed FD_STATE bug where FD_STATE was being used for + * three state machines causing spurious writes to wrong TNC port. FD_STATE is + * now used for real serial port, FD0_STATE for first psuedo tty, and FD1_STATE + * for second psuedo tty. This was an easy fix but a MAJOR bug. + * + * 1.02 3/1/96 Jonathan Naylor - Make hardware handshaking default to off. + * Allowed for true multiplexing of the data from the two pseudo ttys. + * Numerous formatting changes. + * + * 1.03 4/20/96 Tomi Manninen - Rewrote KISS en/decapsulation (much of the + * code taken from linux/drivers/net/slip.c). Added support for all the 16 + * possible kiss ports and G8BPQ-style checksumming on ttyinterface. Now + * mkiss also sends a statistic report to stderr if a SIGUSR1 is sent to it. + * + * 1.04 25/5/96 Jonathan Naylor - Added check for UUCP style tty lock files. + * As they are now supported by kissattach as well. + * + * 1.05 20/8/96 Jonathan Naylor - Convert to becoming a daemon and added + * system logging. + * + * 1.06 23/11/96 Tomi Manninen - Added simple support for polled kiss. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <syslog.h> + +#include <netax25/ttyutils.h> +#include <netax25/daemon.h> + +#include <config.h> + +#define SIZE 4096 + +#define FEND 0300 /* Frame End (0xC0) */ +#define FESC 0333 /* Frame Escape (0xDB) */ +#define TFEND 0334 /* Transposed Frame End (0xDC) */ +#define TFESC 0335 /* Transposed Frame Escape (0xDD) */ + +#define POLL 0x0E + +/* + * Keep these off the stack. + */ +static unsigned char ibuf[SIZE]; /* buffer for input operations */ +static unsigned char obuf[SIZE]; /* buffer for kiss_tx() */ + +static int crc_errors = 0; +static int invalid_ports = 0; +static int return_polls = 0; + +static char *usage_string = "usage: mkiss [-p] [-c] [-h] [-l] [-s speed] [-v] ttyinterface pty ...\n"; + +static int dump_report = FALSE; + +static int logging = FALSE; +static int crcflag = FALSE; +static int hwflag = FALSE; +static int pollflag = FALSE; + +struct iface +{ + char *name; /* Interface name (/dev/???) */ + int fd; /* File descriptor */ + int escaped; /* FESC received? */ + unsigned char crc; /* Incoming frame crc */ + unsigned char obuf[SIZE]; /* TX buffer */ + unsigned char *optr; /* Next byte to transmit */ + unsigned int errors; /* KISS protocol error count */ + unsigned int nondata; /* Non-data frames rx count */ + unsigned int rxpackets; /* RX frames count */ + unsigned int txpackets; /* TX frames count */ + unsigned long rxbytes; /* RX bytes count */ + unsigned long txbytes; /* TX bytes count */ +}; + +static int poll(int fd, int ports) +{ + char buffer[3]; + static int port = 0; + + buffer[0] = FEND; + buffer[1] = POLL | (port << 4); + buffer[2] = FEND; + if (write(fd, buffer, 3) == -1) { + perror("mkiss: poll: write"); + return 1; + } + if (++port >= ports) + port = 0; + return 0; +} + +static int kiss_tx(int fd, int port, unsigned char *s, int len, int usecrc) +{ + unsigned char *ptr = obuf; + unsigned char c; + unsigned char crc = 0; + int first = TRUE; + + /* Non-data frames don't get a checksum byte */ + if ((s[0] & 0x0F) != 0) + usecrc = FALSE; + + /* Allow for checksum byte */ + if (usecrc) + len++; + + /* + * Send an initial FEND character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = FEND; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + c = *s++; + if (first) { /* Control byte */ + c = (c & 0x0F) | (port << 4); + first = FALSE; + } + if (usecrc) { + if (len == 0) /* Now past user data... */ + c = crc; /* ...time to encode cksum */ + else + crc ^= c; /* Adjust checksum */ + } + switch (c) { + case FEND: + *ptr++ = FESC; + *ptr++ = TFEND; + break; + case FESC: + *ptr++ = FESC; + *ptr++ = TFESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = FEND; + return write(fd, obuf, ptr - obuf); +} + +static int kiss_rx(struct iface *ifp, unsigned char c, int usecrc) +{ + int len; + + switch (c) { + case FEND: + len = ifp->optr - ifp->obuf; + if (len != 0 && ifp->escaped) { /* protocol error... */ + len = 0; /* ...drop frame */ + ifp->errors++; + } + if (len != 0 && (ifp->obuf[0] & 0x0F) != 0) { + /* + * Non-data frames don't have checksum. + */ + usecrc = 0; + if ((ifp->obuf[0] & 0x0F) == POLL) { + len = 0; /* drop returned polls */ + return_polls++; + } else + ifp->nondata++; + } + if (len != 0 && usecrc) { + if (ifp->crc != 0) { /* checksum failed... */ + len = 0; /* ...drop frame */ + crc_errors++; + } else + len--; /* delete checksum byte */ + } + if (len != 0) { + ifp->rxpackets++; + ifp->rxbytes += len; + } + /* + * Clean up. + */ + ifp->optr = ifp->obuf; + ifp->crc = 0; + ifp->escaped = FALSE; + return len; + case FESC: + ifp->escaped = TRUE; + return 0; + case TFESC: + if (ifp->escaped) { + ifp->escaped = FALSE; + c = FESC; + } + break; + case TFEND: + if (ifp->escaped) { + ifp->escaped = FALSE; + c = FEND; + } + break; + default: + if (ifp->escaped) { /* protocol error... */ + ifp->escaped = FALSE; + ifp->errors++; + } + break; + } + *ifp->optr++ = c; + if (usecrc) + ifp->crc ^= c; + return 0; +} + +static void sigterm_handler(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +static void sigusr1_handler(int sig) +{ + signal(SIGUSR1, sigusr1_handler); + dump_report = TRUE; +} + +static void report(struct iface *tty, struct iface **pty, int numptys) +{ + int i; + long t; + + time(&t); + syslog(LOG_INFO, "version %s.", VERSION); + syslog(LOG_INFO, "Status report at %s", ctime(&t)); + syslog(LOG_INFO, "Hardware handshaking %sabled.", + hwflag ? "en" : "dis"); + syslog(LOG_INFO, "G8BPQ checksumming %sabled.", + crcflag ? "en" : "dis"); + syslog(LOG_INFO, "polling %sabled.", + pollflag ? "en" : "dis"); + syslog(LOG_INFO, "ttyinterface is %s (fd=%d)", tty->name, tty->fd); + for (i = 0; i < numptys; i++) + syslog(LOG_INFO, "pty%d is %s (fd=%d)", i, pty[i]->name, + pty[i]->fd); + syslog(LOG_INFO, "Checksum errors: %d", crc_errors); + syslog(LOG_INFO, "Invalid ports: %d", invalid_ports); + syslog(LOG_INFO, "Returned polls: %d", return_polls); + syslog(LOG_INFO, "Interface TX frames TX bytes RX frames RX bytes Errors"); + syslog(LOG_INFO, "%-11s %-9u %-9lu %-9u %-9lu %u", + tty->name, + tty->txpackets, tty->txbytes, + tty->rxpackets, tty->rxbytes, + tty->errors); + for (i = 0; i < numptys; i++) { + syslog(LOG_INFO, "%-11s %-9u %-9lu %-9u %-9lu %u", + pty[i]->name, + pty[i]->txpackets, pty[i]->txbytes, + pty[i]->rxpackets, pty[i]->rxbytes, + pty[i]->errors); + } + return; +} + +int main(int argc, char *argv[]) +{ + struct iface *pty[16]; + struct iface *tty; + unsigned char *icp; + int topfd; + fd_set readfd; + struct timeval timeout; + int retval, numptys, i, size, len; + int speed = -1; + + while ((size = getopt(argc, argv, "chlps:v")) != -1) { + switch (size) { + case 'c': + crcflag = TRUE; + break; + case 'h': + hwflag = TRUE; + break; + case 'l': + logging = TRUE; + break; + case 'p': + pollflag = TRUE; + break; + case 's': + speed = atoi(optarg); + break; + case 'v': + printf("mkiss: %s\n", VERSION); + return 1; + case ':': + case '?': + fprintf(stderr, usage_string); + return 1; + } + } + + if ((argc - optind) < 2) { + fprintf(stderr, usage_string); + return 1; + } + if ((numptys = argc - optind - 1) > 16) { + fprintf(stderr, "mkiss: max 16 pty interfaces allowed.\n"); + return 1; + } + + /* + * Check for lock files before opening any TTYs + */ + if (tty_is_locked(argv[optind])) { + fprintf(stderr, "mkiss: tty %s is locked by another process\n", argv[optind]); + return 1; + } + for (i = 0; i < numptys; i++) { + if (tty_is_locked(argv[optind + i + 1])) { + fprintf(stderr, "mkiss: tty %s is locked by another process\n", argv[optind + i + 1]); + return 1; + } + } + + /* + * Open and configure the tty interface. Open() is + * non-blocking so it won't block regardless of the modem + * status lines. + */ + if ((tty = calloc(1, sizeof(struct iface))) == NULL) { + perror("mkiss: malloc"); + return 1; + } + + if ((tty->fd = open(argv[optind], O_RDWR | O_NDELAY)) == -1) { + perror("mkiss: open"); + return 1; + } + + tty->name = argv[optind]; + tty_raw(tty->fd, hwflag); + if (speed != -1) tty_speed(tty->fd, speed); + tty->optr = tty->obuf; + topfd = tty->fd; + /* + * Make it block again... + */ + fcntl(tty->fd, F_SETFL, 0); + + /* + * Open and configure the pty interfaces + */ + for (i = 0; i < numptys; i++) { + if ((pty[i] = calloc(1, sizeof(struct iface))) == NULL) { + perror("mkiss: malloc"); + return 1; + } + if ((pty[i]->fd = open(argv[optind + i + 1], O_RDWR)) == -1) { + perror("mkiss: open"); + return 1; + } + pty[i]->name = argv[optind + i + 1]; + tty_raw(pty[i]->fd, FALSE); + pty[i]->optr = pty[i]->obuf; + topfd = (pty[i]->fd > topfd) ? pty[i]->fd : topfd; + } + + /* + * Now all the ports are open, lock them. + */ + tty_lock(argv[optind]); + for (i = 0; i < numptys; i++) + tty_lock(argv[optind + i + 1]); + + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, sigusr1_handler); + signal(SIGTERM, sigterm_handler); + + if (!daemon_start(FALSE)) { + fprintf(stderr, "mkiss: cannot become a daemon\n"); + return 1; + } + + if (logging) { + openlog("mkiss", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + /* + * Loop until an error occurs on a read. + */ + while (TRUE) { + FD_ZERO(&readfd); + FD_SET(tty->fd, &readfd); + for (i = 0; i < numptys; i++) + FD_SET(pty[i]->fd, &readfd); + + if (pollflag) { + timeout.tv_sec = 1; + timeout.tv_usec = 0; + } + + errno = 0; + retval = select(topfd + 1, &readfd, NULL, NULL, pollflag ? &timeout : NULL); + + if (retval == -1) { + if (dump_report) { + if (logging) + report(tty, pty, numptys); + dump_report = FALSE; + continue; + } else { + perror("mkiss: select"); + continue; + } + } + + /* + * Timer expired. + */ + if (retval == 0 && pollflag) { + poll(tty->fd, numptys); + continue; + } + + /* + * A character has arrived on the ttyinterface. + */ + if (FD_ISSET(tty->fd, &readfd)) { + if ((size = read(tty->fd, ibuf, SIZE)) < 0 && errno != EINTR) { + if (logging) + syslog(LOG_ERR, "tty->fd: %m"); + break; + } + for (icp = ibuf; size > 0; size--, icp++) { + if ((len = kiss_rx(tty, *icp, crcflag)) != 0) { + if ((i = (*tty->obuf & 0xF0) >> 4) < numptys) { + kiss_tx(pty[i]->fd, 0, tty->obuf, len, FALSE); + pty[i]->txpackets++; + pty[i]->txbytes += len; + } else + invalid_ports++; + if (pollflag) + poll(tty->fd, numptys); + } + } + } + + for (i = 0; i < numptys; i++) { + /* + * A character has arrived on pty[i]. + */ + if (FD_ISSET(pty[i]->fd, &readfd)) { + if ((size = read(pty[i]->fd, ibuf, SIZE)) < 0 && errno != EINTR) { + if (logging) + syslog(LOG_ERR, "pty[%d]->fd: %m\n", i); + goto end; + } + for (icp = ibuf; size > 0; size--, icp++) { + if ((len = kiss_rx(pty[i], *icp, FALSE)) != 0) { + kiss_tx(tty->fd, i, pty[i]->obuf, len, crcflag); + tty->txpackets++; + tty->txbytes += len; + } + } + } + } + } + + end: + if (logging) + closelog(); + + close(tty->fd); + free(tty); + + for (i = 0; i < numptys; i++) { + close(pty[i]->fd); + free(pty[i]); + } + + return 1; +} diff --git a/kiss/net2kiss.c b/kiss/net2kiss.c new file mode 100644 index 0000000..19a7385 --- /dev/null +++ b/kiss/net2kiss.c @@ -0,0 +1,643 @@ +/*****************************************************************************/ + +/* + * net2kiss.c - convert a network interface to KISS data stream + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.1 18.09.96 Started + */ + +/*****************************************************************************/ + +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <asm/byteorder.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <grp.h> +#include <string.h> +#include <termios.h> + +#include <sys/socket.h> +#include <net/if.h> +#include <net/ethernet.h> + +/* --------------------------------------------------------------------- */ + +static int fdif, fdpty; +static struct ifreq ifr; +static char *progname; +static int verbose = 0; + +/* --------------------------------------------------------------------- */ + +static void die(char *func) +{ + fprintf(stderr, "%s: %s (%i)%s%s\n", progname, strerror(errno), + errno, func ? " in " : "", func ? func : ""); + exit(-1); +} + +/* --------------------------------------------------------------------- */ + +static void display_packet(unsigned char *bp, unsigned int len) +{ + unsigned char v1=1,cmd=0; + unsigned char i,j; + + if (!bp || !len) + return; + if (len < 8) + return; + if (bp[1] & 1) { + /* + * FlexNet Header Compression + */ + v1 = 0; + cmd = (bp[1] & 2) != 0; + printf("fm ? to "); + i = (bp[2] >> 2) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[2] << 4) | ((bp[3] >> 4) & 0xf)) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[3] << 2) | ((bp[4] >> 6) & 3)) & 0x3f; + if (i) + printf("%c",i+0x20); + i = bp[4] & 0x3f; + if (i) + printf("%c",i+0x20); + i = (bp[5] >> 2) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[5] << 4) | ((bp[6] >> 4) & 0xf)) & 0x3f; + if (i) + printf("%c",i+0x20); + printf("-%u QSO Nr %u", bp[6] & 0xf, (bp[0] << 6) | + (bp[1] >> 2)); + bp += 7; + len -= 7; + } else { + /* + * normal header + */ + if (len < 15) + return; + if ((bp[6] & 0x80) != (bp[13] & 0x80)) { + v1 = 0; + cmd = (bp[6] & 0x80); + } + printf("fm "); + for(i = 7; i < 13; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u to ",(bp[13] >> 1) & 0xf); + for(i = 0; i < 6; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u",(bp[6] >> 1) & 0xf); + bp += 14; + len -= 14; + if ((!(bp[-1] & 1)) && (len >= 7)) printf(" via "); + while ((!(bp[-1] & 1)) && (len >= 7)) { + for(i = 0; i < 6; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u",(bp[6] >> 1) & 0xf); + bp += 7; + len -= 7; + if ((!(bp[-1] & 1)) && (len >= 7)) + printf(","); + } + } + if(!len) + return; + i = *bp++; + len--; + j = v1 ? ((i & 0x10) ? '!' : ' ') : + ((i & 0x10) ? (cmd ? '+' : '-') : (cmd ? '^' : 'v')); + if (!(i & 1)) { + /* + * Info frame + */ + printf(" I%u%u%c",(i >> 5) & 7,(i >> 1) & 7,j); + } else if (i & 2) { + /* + * U frame + */ + switch (i & (~0x10)) { + case 0x03: + printf(" UI%c",j); + break; + case 0x2f: + printf(" SABM%c",j); + break; + case 0x43: + printf(" DISC%c",j); + break; + case 0x0f: + printf(" DM%c",j); + break; + case 0x63: + printf(" UA%c",j); + break; + case 0x87: + printf(" FRMR%c",j); + break; + default: + printf(" unknown U (0x%x)%c",i & (~0x10),j); + break; + } + } else { + /* + * supervisory + */ + switch (i & 0xf) { + case 0x1: + printf(" RR%u%c",(i >> 5) & 7,j); + break; + case 0x5: + printf(" RNR%u%c",(i >> 5) & 7,j); + break; + case 0x9: + printf(" REJ%u%c",(i >> 5) & 7,j); + break; + default: + printf(" unknown S (0x%x)%u%c", i & 0xf, + (i >> 5) & 7, j); + break; + } + } + if (!len) { + printf("\n"); + return; + } + printf(" pid=%02X\n", *bp++); + len--; + j = 0; + while (len) { + i = *bp++; + if ((i >= 32) && (i < 128)) + printf("%c",i); + else if (i == 13) { + if (j) + printf("\n"); + j = 0; + } else + printf("."); + if (i >= 32) + j = 1; + len--; + } + if (j) + printf("\n"); +} + +/* ---------------------------------------------------------------------- */ + +static int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + char line[] = "/dev/ptyXX"; + const char *cp1, *cp2; + int master, slave; + struct group *gr = getgrnam("tty"); + + for (cp1 = "pqrstuvwxyzPQRST"; *cp1; cp1++) { + line[8] = *cp1; + for (cp2 = "0123456789abcdef"; *cp2; cp2++) { + line[9] = *cp2; + if ((master = open(line, O_RDWR, 0)) == -1) { + if (errno == ENOENT) + return (-1); /* out of ptys */ + } else { + line[5] = 't'; + (void) chown(line, getuid(), + gr ? gr->gr_gid : -1); + (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); +#if 0 + (void) revoke(line); +#endif + if ((slave = open(line, O_RDWR, 0)) != -1) { + *amaster = master; + *aslave = slave; + if (name) + strcpy(name, line); + if (termp) + (void) tcsetattr(slave, + TCSAFLUSH, + termp); + if (winp) + (void) ioctl(slave, + TIOCSWINSZ, + (char *)winp); + return 0; + } + (void) close(master); + line[5] = 'p'; + } + } + } + errno = ENOENT; /* out of ptys */ + return (-1); +} + +/* ---------------------------------------------------------------------- */ + +static void restore_ifflags(int signum) +{ + if (ioctl(fdif, SIOCSIFFLAGS, &ifr) < 0) + die("ioctl SIOCSIFFLAGS"); + close(fdif); + close(fdpty); + exit(0); +} + +/* --------------------------------------------------------------------- */ + +#define KISS_FEND ((unsigned char)0300) +#define KISS_FESC ((unsigned char)0333) +#define KISS_TFEND ((unsigned char)0334) +#define KISS_TFESC ((unsigned char)0335) + +#define KISS_CMD_DATA 0 +#define KISS_CMD_TXDELAY 1 +#define KISS_CMD_PPERSIST 2 +#define KISS_CMD_SLOTTIME 3 +#define KISS_CMD_TXTAIL 4 +#define KISS_CMD_FULLDUP 5 + +#define KISS_HUNT 0 +#define KISS_RX 1 +#define KISS_ESCAPED 2 + +/* --------------------------------------------------------------------- */ + +static void kiss_overflow(void) +{ + if (verbose) + printf("KISS: packet overflow\n"); +} + +static void kiss_bad_escape(void) +{ + if (verbose) + printf("KISS: bad escape sequence\n"); +} + +static void display_kiss_packet(char *pfx, unsigned char *pkt, + unsigned int pktlen) +{ + if (!verbose) + return; + switch (*pkt) { + case KISS_CMD_DATA: + printf("%s: ", pfx); + display_packet(pkt+1, pktlen-1); + break; + + case KISS_CMD_TXDELAY: + printf("%s: txdelay = %dms\n", pfx, (int)pkt[1] * 10); + break; + + case KISS_CMD_PPERSIST: + printf("%s: p persistence = %d\n", pfx, pkt[1]); + break; + + case KISS_CMD_SLOTTIME: + printf("%s: slottime = %dms\n", pfx, (int)pkt[1] * 10); + break; + + case KISS_CMD_TXTAIL: + printf("%s: txtail = %dms\n", pfx, (int)pkt[1] * 10); + break; + + case KISS_CMD_FULLDUP: + printf("%s: %sduplex\n", pfx, pkt[1] ? "full" : "half"); + break; + + default: + printf("%s: unknown frame type 0x%02x, length %d\n", pfx, + *pkt, pktlen); + } +} + +static void kiss_packet(int fdif, char *addr, + unsigned char *pkt, unsigned int pktlen) +{ + struct sockaddr to; + int i; + + if (pktlen < 2) + return; + display_kiss_packet("KISS", pkt, pktlen); + strncpy(to.sa_data, addr, sizeof(to.sa_data)); + i = sendto(fdif, pkt, pktlen, 0, &to, sizeof(to)); + if (i >= 0) + return; + if (errno == EMSGSIZE) { + if (verbose) + printf("sendto: %s: packet (size %d) too " + "long\n", addr, pktlen-1); + return; + } + if (errno == EWOULDBLOCK) { + if (verbose) + printf("sendto: %s: busy\n", addr); + return; + } + die("sendto"); + return; +} + +/* --------------------------------------------------------------------- */ + +static int doio(int fdif, int fdpty, char *ifaddr) +{ + unsigned char ibuf[2048]; + unsigned char *bp; + unsigned char pktbuf[2048]; + unsigned char *pktptr = pktbuf; + unsigned char pktstate = KISS_HUNT; + unsigned char obuf[16384]; + unsigned int ob_wp = 0, ob_rp = 0, ob_wpx; + int i; + fd_set rmask, wmask; + struct sockaddr from; + int from_len; + +#define ADD_CHAR(c) \ + obuf[ob_wpx] = c; \ + ob_wpx = (ob_wpx + 1) % sizeof(obuf); \ + if (ob_wpx == ob_rp) goto kissencerr; + +#define ADD_KISSCHAR(c) \ + if (((c) & 0xff) == KISS_FEND) \ + { ADD_CHAR(KISS_FESC); ADD_CHAR(KISS_TFEND); } \ + else if (((c) & 0xff) == KISS_FESC) \ + { ADD_CHAR(KISS_FESC); ADD_CHAR(KISS_TFESC); } \ + else { ADD_CHAR(c); } + + for (;;) { + FD_ZERO(&rmask); + FD_ZERO(&wmask); + FD_SET(fdif, &rmask); + FD_SET(fdpty, &rmask); + if (ob_rp != ob_wp) + FD_SET(fdpty, &wmask); + i = select((fdif > fdpty) ? fdif+1 : fdpty+1, &rmask, &wmask, + NULL, NULL); + if (i < 0) + die("select"); + if (FD_ISSET(fdpty, &wmask)) { + if (ob_rp > ob_wp) + i = write(fdpty, obuf+ob_rp, + sizeof(obuf)-ob_rp); + else + i = write(fdpty, obuf+ob_rp, ob_wp - ob_rp); + if (i < 0) + die("write"); + ob_rp = (ob_rp + i) % sizeof(obuf); + } + if (FD_ISSET(fdpty, &rmask)) { + i = read(fdpty, bp = ibuf, sizeof(ibuf)); + if (i < 0) { + if (errno != EIO) + die("read"); + return 0; + } + for (; i > 0; i--, bp++) { + switch (pktstate) { + default: + case KISS_HUNT: + if (*bp != KISS_FEND) + break; + pktptr = pktbuf; + pktstate = KISS_RX; + break; + + case KISS_RX: + if (*bp == KISS_FESC) { + pktstate = KISS_ESCAPED; + break; + } + if (*bp == KISS_FEND) { + kiss_packet(fdif, ifaddr, + pktbuf, + pktptr - pktbuf); + pktptr = pktbuf; + break; + } + if (pktptr >= pktbuf+sizeof(pktbuf)) { + kiss_overflow(); + pktstate = KISS_HUNT; + break; + } + *pktptr++ = *bp; + break; + + case KISS_ESCAPED: + if (pktptr >= pktbuf+sizeof(pktbuf)) { + kiss_overflow(); + pktstate = KISS_HUNT; + break; + } + if (*bp == KISS_TFESC) + *pktptr++ = KISS_FESC; + else if (*bp == KISS_TFEND) + *pktptr++ = KISS_FEND; + else { + kiss_bad_escape(); + pktstate = KISS_HUNT; + break; + } + pktstate = KISS_RX; + break; + } + } + } + if (FD_ISSET(fdif, &rmask)) { + from_len = sizeof(from); + i = recvfrom(fdif, bp = ibuf, sizeof(ibuf), 0, &from, + &from_len); + if (i < 0) { + if (errno == EWOULDBLOCK) + continue; + die("recvfrom"); + } + if (verbose) + display_kiss_packet(from.sa_data, ibuf, i); + ob_wpx = ob_wp; + ADD_CHAR(KISS_FEND); + for (; i > 0; i--, bp++) { + ADD_KISSCHAR(*bp); + } + ADD_CHAR(KISS_FEND); + ob_wp = ob_wpx; + } + continue; + kissencerr: + if (verbose) + printf("KISS: Encoder out of memory\n"); + } +#undef ADD_CHAR +#undef ADD_KISSCHAR +} + +/* --------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + struct ifreq ifr_new; + struct sockaddr sa; + char *name_iface = "bc0"; + char *name_pname = NULL; + char slavename[32]; + char *master_name; + struct termios termios; + int c; + int errflg = 0; + int symlnk = 0; + int symlnkforce = 0; + short if_newflags = 0; + int proto = htons(ETH_P_AX25); + + progname = argv[0]; + while ((c = getopt(argc, argv, "sfzvai:")) != EOF) { + switch (c) { + case 's': + symlnk = 1; + break; + case 'f': + symlnkforce = 1; + break; + case 'i': + name_iface = optarg; + break; + case 'z': + if_newflags |= IFF_PROMISC; + break; + case 'v': + verbose++; + break; + case 'a': + proto = htons(ETH_P_ALL); + break; + default: + errflg++; + break; + } + } + if (argc > optind) + name_pname = argv[optind]; + else + errflg++; + if (errflg) { + fprintf(stderr, "usage: %s [-s] [-f] [-i iface] " + "[-z] [-v] ptyname\n", progname); + exit(1); + } + if (symlnk) { + int fdtty; + + if (openpty(&fdpty, &fdtty, slavename, NULL, NULL)) { + fprintf(stderr, "%s: out of pseudoterminals\n", + progname); + exit(1); + } + close(fdtty); + fcntl(fdpty, F_SETFL, fcntl(fdpty, F_GETFL, 0) | O_NONBLOCK); + if (symlnkforce) + unlink(name_pname); + if (symlink(slavename, name_pname)) + perror("symlink"); + slavename[5] = 'p'; + master_name = slavename; + } else { + if ((fdpty = open(name_pname, + O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { + fprintf(stderr, "%s: cannot open \"%s\"\n", progname, + name_pname); + exit(1); + } + master_name = name_pname; + } + if ((fdif = socket(PF_INET, SOCK_PACKET, proto)) < 0) + die("socket"); + strcpy(sa.sa_data, name_iface); + sa.sa_family = AF_INET; + if (bind(fdif, &sa, sizeof(struct sockaddr)) < 0) + die("bind"); + strcpy(ifr.ifr_name, name_iface); + if (ioctl(fdif, SIOCGIFFLAGS, &ifr) < 0) + die("ioctl SIOCGIFFLAGS"); + ifr_new = ifr; + ifr_new.ifr_flags |= if_newflags; + if (ioctl(fdif, SIOCSIFFLAGS, &ifr_new) < 0) + die("ioctl SIOCSIFFLAGS"); + signal(SIGHUP, restore_ifflags); + signal(SIGINT, restore_ifflags); + signal(SIGTERM, restore_ifflags); + signal(SIGQUIT, restore_ifflags); + signal(SIGUSR1, restore_ifflags); + signal(SIGUSR2, restore_ifflags); + + for (;;) { + if (tcgetattr(fdpty, &termios)) + die("tcgetattr"); + termios.c_iflag = IGNBRK; + termios.c_oflag = 0; + termios.c_lflag = 0; + termios.c_cflag &= ~(CSIZE|CSTOPB|PARENB|HUPCL|CRTSCTS); + termios.c_cflag |= CS8|CREAD|CLOCAL; + if (tcsetattr(fdpty, TCSANOW, &termios)) + die("tsgetattr"); + if (doio(fdif, fdpty, name_iface)) + break; + /* + * try to reopen master + */ + if (verbose) + printf("reopening master tty: %s\n", master_name); + close(fdpty); + if ((fdpty = open(master_name, + O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { + fprintf(stderr, "%s: cannot reopen \"%s\"\n", progname, + master_name); + exit(1); + } + } + + restore_ifflags(0); + exit(0); +} + +/* --------------------------------------------------------------------- */ @@ -0,0 +1,190 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996. + +# 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, 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., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..4f58503 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/netrom/Makefile.am b/netrom/Makefile.am new file mode 100644 index 0000000..03f0c0d --- /dev/null +++ b/netrom/Makefile.am @@ -0,0 +1,26 @@ + +etcfiles = nrbroadcast nrports +etcdir = $(sysconfdir)/ax25 + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + + +sbin_PROGRAMS = netromd nodesave nrattach nrparms nrsdrv + +man_MANS = netrom.4 nrports.5 nrbroadcast.5 netromd.8 nodesave.8 \ + nrattach.8 nrparms.8 nrsdrv.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +netromd_SOURCES = \ + netromd.c \ + netromd.h \ + netromr.c \ + netromt.c + + diff --git a/netrom/Makefile.in b/netrom/Makefile.in new file mode 100644 index 0000000..80c3c9c --- /dev/null +++ b/netrom/Makefile.in @@ -0,0 +1,452 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +etcfiles = nrbroadcast nrports +etcdir = $(sysconfdir)/ax25 + +sbin_PROGRAMS = netromd nodesave nrattach nrparms nrsdrv + +man_MANS = netrom.4 nrports.5 nrbroadcast.5 netromd.8 nodesave.8 nrattach.8 nrparms.8 nrsdrv.8 + + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +netromd_SOURCES = netromd.c netromd.h netromr.c netromt.c + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +netromd_OBJECTS = netromd.o netromr.o netromt.o +netromd_LDADD = $(LDADD) +netromd_DEPENDENCIES = +netromd_LDFLAGS = +nodesave_SOURCES = nodesave.c +nodesave_OBJECTS = nodesave.o +nodesave_LDADD = $(LDADD) +nodesave_DEPENDENCIES = +nodesave_LDFLAGS = +nrattach_SOURCES = nrattach.c +nrattach_OBJECTS = nrattach.o +nrattach_LDADD = $(LDADD) +nrattach_DEPENDENCIES = +nrattach_LDFLAGS = +nrparms_SOURCES = nrparms.c +nrparms_OBJECTS = nrparms.o +nrparms_LDADD = $(LDADD) +nrparms_DEPENDENCIES = +nrparms_LDFLAGS = +nrsdrv_SOURCES = nrsdrv.c +nrsdrv_OBJECTS = nrsdrv.o +nrsdrv_LDADD = $(LDADD) +nrsdrv_DEPENDENCIES = +nrsdrv_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man8dir = $(mandir)/man8 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(netromd_SOURCES) nodesave.c nrattach.c nrparms.c nrsdrv.c +OBJECTS = $(netromd_OBJECTS) nodesave.o nrattach.o nrparms.o nrsdrv.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps netrom/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +netromd: $(netromd_OBJECTS) $(netromd_DEPENDENCIES) + @rm -f netromd + $(LINK) $(netromd_LDFLAGS) $(netromd_OBJECTS) $(netromd_LDADD) $(LIBS) + +nodesave: $(nodesave_OBJECTS) $(nodesave_DEPENDENCIES) + @rm -f nodesave + $(LINK) $(nodesave_LDFLAGS) $(nodesave_OBJECTS) $(nodesave_LDADD) $(LIBS) + +nrattach: $(nrattach_OBJECTS) $(nrattach_DEPENDENCIES) + @rm -f nrattach + $(LINK) $(nrattach_LDFLAGS) $(nrattach_OBJECTS) $(nrattach_LDADD) $(LIBS) + +nrparms: $(nrparms_OBJECTS) $(nrparms_DEPENDENCIES) + @rm -f nrparms + $(LINK) $(nrparms_LDFLAGS) $(nrparms_OBJECTS) $(nrparms_LDADD) $(LIBS) + +nrsdrv: $(nrsdrv_OBJECTS) $(nrsdrv_DEPENDENCIES) + @rm -f nrsdrv + $(LINK) $(nrsdrv_LDFLAGS) $(nrsdrv_OBJECTS) $(nrsdrv_LDADD) $(LIBS) + +install-man4: + $(mkinstalldirs) $(DESTDIR)$(man4dir) + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man4dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man4dir)/$$inst; \ + done + +uninstall-man4: + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man4dir)/$$inst"; \ + rm -f $(DESTDIR)$(man4dir)/$$inst; \ + done + +install-man5: + $(mkinstalldirs) $(DESTDIR)$(man5dir) + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \ + done + +uninstall-man5: + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \ + rm -f $(DESTDIR)$(man5dir)/$$inst; \ + done + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man4 install-man5 install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man4 uninstall-man5 uninstall-man8 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = netrom + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +netromd.o: netromd.c ../config.h ../pathnames.h netromd.h +netromr.o: netromr.c ../pathnames.h netromd.h +netromt.o: netromt.c ../pathnames.h netromd.h +nodesave.o: nodesave.c +nrattach.o: nrattach.c ../config.h ../pathnames.h +nrparms.o: nrparms.c ../config.h +nrsdrv.o: nrsdrv.c ../config.h ../pathnames.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man4 \ + $(DESTDIR)$(mandir)/man5 $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile install-man4 uninstall-man4 \ +install-man5 uninstall-man5 install-man8 uninstall-man8 install-man \ +uninstall-man tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/netrom/netrom.4 b/netrom/netrom.4 new file mode 100644 index 0000000..67b159a --- /dev/null +++ b/netrom/netrom.4 @@ -0,0 +1,51 @@ +.TH NETROM 4 "25 July 1996" Linux "Linux Programmer's Manual" +.SH NAME +AF_NETROM \- NET/ROM amateur packet radio protocol family +.SH DESCRIPTION +.LP +.B NET/ROM +is a protocol used extensively by radio amateurs. The Linux +NET/ROM protocol family permits access to these protocols via +the standard networking +.B socket +metaphor. +.LP +The NET/ROM protocol layer only supports connected mode. IP traffic may be +stacked on top of NET/ROM frames using a non-standard extension to the +NET/ROM protocol. +.LP +The only mode of operation is connected mode which is the mode used for a +socket of type SOCK_SEQPACKET (stream sockets are not available in NET/ROM). +This requires that the user ensures output data is suitably packetised, and +that input data is read a packet at a time into a buffer of suitable size. +.LP +NET/ROM addresses consist of 6 ascii characters and a number called the +SSID. These are encoded into a sockaddr_ax25 structure which is provided to +the relevant system calls. +.LP +NET/ROM has some unusual properties. Notably in a multi-user system an AX.25 +address is often associated with a user, and some users may not have such an +association. a set of ioctl calls are provided to manage an association +table. +.LP +NET/ROM supports the following socket options for SOL_NETROM. NETROM_T1 is +the T1 timer in 1/10ths of a second, NETROM_T2 is the T2 timer in 1/10ths of +a second. NETROM_N2, the retry counter is also configurable. There is no 'infinite +retry' option supported however. It is possible for an application +to request that the NET/ROM layer return the NET/ROM header as well as the +application data, this is done via the NETROM_HDRINCL socket option. +.SH "SEE ALSO" +.BR call (1), +.BR socket (2), +.BR setsockopt(2), +.BR getsockopt(2), +.BR nrbroadcast (5), +.BR nrports (5), +.BR netromd (8), +.BR noderest (8), +.BR nodesave (8), +.BR nrctl (8), +.BR nrparms (8). +.LP +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/netrom/netromd.8 b/netrom/netromd.8 new file mode 100644 index 0000000..ef1860e --- /dev/null +++ b/netrom/netromd.8 @@ -0,0 +1,97 @@ +.TH NETROMD 8 "20 August 1996" Linux "Linux System Managers Manual" +.SH NAME +netromd \- Send and receive NET/ROM routing messages +.SH SYNOPSIS +.B netromd [-c] [-d] [-i] [-l] [-p pause] [-q quality] [-t interval] [-v] +.SH DESCRIPTION +.LP +For a NET/ROM based network to operate correctly, a periodic broadcast of +routing information needs to occur. Typically this occurs once every hour on +every port which is expected to carry NET/ROM traffic. The purpose of +.B netromd +is to send and receive NET/ROM routing broadcasts. To operate correctly a +set of parameters that corresponds to each AX.25 port needs to be passed to +the program. This information is encoded in a configuration file, by default +which is /etc/ax25/nrbroadcast with each line representing one +port, see the manual page for +.BR nrbroadcast (5). +.LP +To cut down the length of these routing broadcasts, only the information +about the highest quality neighbour for a particular node is transmitted. +The transmission is also limited to those node that have a certain minimum +value in their obsolesence count, this value is decremented every time a +routing broadcast is transmitted, and is refreshed by receiving a routing +broadcast which contains that particular node. +.LP +The value of the default quality is traditionally assigned a value that +represents the quality of the radio links on that port. A higher number +representing better radio links with 255 (the maximum) reserved for wire +connections. The practise in the UK is to set the default quality to a low +value, typically 10, and manually set up the trusted neighbouring nodes in +the neighbour list manually. The worst quality for auto-updates value is a +way to filter out low quality (ie distant) nodes. +.LP +The verbose flag may be either 0 or 1, representing no and yes. By +specifying no, the program will only generate a routing message containing +information about the node on which it is running, by specifying the yes +option, all the information in the nodes routing tables will be transmitted. +The quality advertised for the other node callsigns on this machine may be +set using the \-q option. +.LP +Between each transmission +.B netromd +pauses for five seconds (default) in order to avoid flooding the channels +that it must broadcast on. The value of this delay is settable with the \-p +option. +.SH OPTIONS +.TP 16 +.BI \-c +Forces strict compliance to Software 2000 specifications. At present this +only determines how node mnemonics with lower case characters will be handled. +With compliance enabled mixed case node mnemonics will be ignored. The default +is to accept node mnemonics of mixed case. +.TP 16 +.BI \-d +Switches on debugging messages, the default is off. Logging must be enabled +for them to be output. +.TP 16 +.BI \-i +Transmit a routing broadcast immediately, the default is to wait for the +time interval to elapse before transmitting the first routing broadcast. +.TP 16 +.BI \-l +Enables logging of errors and debug messages to the system log. The default +is off. +.TP 16 +.BI "\-p pause" +Sets the delay between transmissions of individual routing broadcast +packets. The default is five seconds. +.TP 16 +.BI "\-q quality" +Sets the quality of the subsidiary nodes relative to the main node. The +default is 255. +.TP 16 +.BI "\-t interval" +The time interval between routing broadcasts, in minutes. The default is 60 +minutes. +.TP 16 +.BI \-v +Display the version. +.SH FILES +.nf +/proc/net/nr_neigh +.br +/proc/net/nr_nodes +.br +/etc/ax25/axports +.br +/etc/ax25/nrbroadcast +.fi +.SH "SEE ALSO" +.BR ax25 (4), +.BR axports (5), +.BR nrbroadcast (5), +.BR netrom (4), +.BR nrparms (8). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/netrom/netromd.c b/netrom/netromd.c new file mode 100644 index 0000000..fa80c9b --- /dev/null +++ b/netrom/netromd.c @@ -0,0 +1,254 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#include <sys/socket.h> +#include <netinet/in.h> + +#include <net/if.h> +#include <net/ethernet.h> +#include <netax25/ax25.h> +#include <netrom/netrom.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/daemon.h> +#include <netax25/nrconfig.h> + +#include <config.h> + +#include "../pathnames.h" +#include "netromd.h" + +struct port_struct port_list[20]; + +int port_count = FALSE; +int compliant = FALSE; +int debug = FALSE; +int logging = FALSE; + +ax25_address my_call; +ax25_address node_call; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +static int bcast_config_load_ports(void) +{ + char buffer[255], port[32], *s; + FILE *fp; + + if ((fp = fopen(CONF_NETROMD_FILE, "r")) == NULL) { + fprintf(stderr, "netromd: cannot open config file\n"); + return -1; + } + + while (fgets(buffer, 255, fp) != NULL) { + if ((s = strchr(buffer, '\n')) != NULL) + *s = '\0'; + + if (strlen(buffer) == 0 || buffer[0] == '#') + continue; + + if (sscanf(buffer, "%s %d %d %d %d", + port, + &port_list[port_count].minimum_obs, + &port_list[port_count].default_qual, + &port_list[port_count].worst_qual, + &port_list[port_count].verbose) == -1) { + fprintf(stderr, "netromd: unable to parse: %s", buffer); + return -1; + } + + if (ax25_config_get_addr(port) == NULL) { + fprintf(stderr, "netromd: invalid port name - %s\n", port); + return -1; + } + + port_list[port_count].port = strdup(port); + port_list[port_count].device = strdup(ax25_config_get_dev(port_list[port_count].port)); + + if (port_list[port_count].minimum_obs < 0 || port_list[port_count].minimum_obs > 6) { + fprintf(stderr, "netromd: invalid minimum obsolescence\n"); + return -1; + } + + if (port_list[port_count].default_qual < 0 || port_list[port_count].default_qual > 255) { + fprintf(stderr, "netromd: invalid default quality\n"); + return -1; + } + + if (port_list[port_count].worst_qual < 0 || port_list[port_count].worst_qual > 255) { + fprintf(stderr, "netromd: invalid worst quality\n"); + return -1; + } + + if (port_list[port_count].verbose != 0 && port_list[port_count].verbose != 1) { + fprintf(stderr, "netromd: invalid verbose setting\n"); + return -1; + } + + port_count++; + } + + fclose(fp); + + if (port_count == 0) + return -1; + + return 0; +} + +int main(int argc, char **argv) +{ + unsigned char buffer[512]; + int size, s, i; + struct sockaddr sa; + int asize; + struct timeval timeout; + time_t timenow, timelast; + int interval = 3600; + int localval = 255; + int pause = 5; + fd_set fdset; + + time(&timelast); + + while ((i = getopt(argc, argv, "cdilp:q:t:v")) != -1) { + switch (i) { + case 'c': + compliant = TRUE; + break; + case 'd': + debug = TRUE; + break; + case 'i': + timelast = 0; + break; + case 'l': + logging = TRUE; + break; + case 'p': + pause = atoi(optarg); + if (pause < 1 || pause > 120) { + fprintf(stderr, "netromd: invalid pause value\n"); + return 1; + } + break; + case 'q': + localval = atoi(optarg); + if (localval < 10 || localval > 255) { + fprintf(stderr, "netromd: invalid local quality\n"); + return 1; + } + break; + case 't': + interval = atoi(optarg) * 60; + if (interval < 60 || interval > 7200) { + fprintf(stderr, "netromd: invalid time interval\n"); + return 1; + } + break; + case 'v': + printf("netromd: %s\n", VERSION); + return 0; + case '?': + case ':': + fprintf(stderr, "usage: netromd [-d] [-i] [-l] [-q quality] [-t interval] [-v]\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "netromd: no AX.25 ports defined\n"); + return 1; + } + + if (nr_config_load_ports() == 0) { + fprintf(stderr, "netromd: no NET/ROM ports defined\n"); + return 1; + } + + if (bcast_config_load_ports() == -1) { + fprintf(stderr, "netromd: no NET/ROM broadcast ports defined\n"); + return 1; + } + + ax25_aton_entry(nr_config_get_addr(NULL), (char *)&my_call); + ax25_aton_entry("NODES", (char *)&node_call); + + if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) { + perror("netromd: socket"); + return 1; + } + + if (!daemon_start(TRUE)) { + fprintf(stderr, "netromd: cannot become a daemon\n"); + return 1; + } + + if (logging) { + openlog("netromd", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + FD_ZERO(&fdset); + FD_SET(s, &fdset); + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + if (select(s + 1, &fdset, NULL, NULL, &timeout) == -1) + continue; /* Signal received ? */ + + if (FD_ISSET(s, &fdset)) { + asize = sizeof(sa); + + if ((size = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &asize)) == -1) { + if (logging) { + syslog(LOG_ERR, "recvfrom: %m"); + closelog(); + } + return 1; + } + + if (ax25_cmp((ax25_address *)(buffer + 1), &node_call) == 0 && + ax25_cmp((ax25_address *)(buffer + 8), &my_call) != 0 && + buffer[16] == NETROM_PID && buffer[17] == NODES_SIG) { + for (i = 0; i < port_count; i++) { + if (strcmp(port_list[i].device, sa.sa_data) == 0) { + if (debug && logging) + syslog(LOG_DEBUG, "receiving NODES broadcast on port %s from %s\n", port_list[i].port, ax25_ntoa((ax25_address *)(buffer + 8))); + receive_nodes(buffer + 18, size - 18, (ax25_address *)(buffer + 8), i); + break; + } + } + } + } + + time(&timenow); + + if ((timenow - timelast) > interval) { + timelast = timenow; + transmit_nodes(localval, pause); + } + } +} diff --git a/netrom/netromd.h b/netrom/netromd.h new file mode 100644 index 0000000..3007b02 --- /dev/null +++ b/netrom/netromd.h @@ -0,0 +1,41 @@ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define NETROM_PID 0xCF + +#define NODES_SIG 0xFF + +#define CALLSIGN_LEN 7 +#define MNEMONIC_LEN 6 +#define QUALITY_LEN 1 + +#define NODES_PACLEN 256 +#define ROUTE_LEN (CALLSIGN_LEN+MNEMONIC_LEN+CALLSIGN_LEN+QUALITY_LEN) + +struct port_struct { + char *device; + char *port; + int minimum_obs; + int default_qual; + int worst_qual; + int verbose; +}; + +extern struct port_struct port_list[]; + +extern int port_count; +extern int debug; +extern int logging; + +extern ax25_address my_call; +extern ax25_address node_call; + +/* In netromt.c */ +extern void transmit_nodes(int, int); + +/* In netromr.c */ +extern void receive_nodes(unsigned char *, int, ax25_address *, int); diff --git a/netrom/netromr.c b/netrom/netromr.c new file mode 100644 index 0000000..eafd225 --- /dev/null +++ b/netrom/netromr.c @@ -0,0 +1,164 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <net/if.h> +#include <net/ethernet.h> + +#include <netax25/ax25.h> +#include <netrom/netrom.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> +#include "../pathnames.h" + +#include "netromd.h" + +extern int compliant; + +static int validmnemonic(char *mnemonic) +{ + if (compliant) { + if (strspn(mnemonic, "#_&-/ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") == strlen(mnemonic)) + return TRUE; + } else { + if (strspn(mnemonic, "#_&-/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") == strlen(mnemonic)) + return TRUE; + } + + return FALSE; +} + +void receive_nodes(unsigned char *buffer, int length, ax25_address *neighbour, int index) +{ + struct nr_route_struct nr_node; + char neigh_buffer[90], *portcall, *p; + FILE *fp; + int s; + int quality, obs_count, qual, lock; + char *addr, *callsign, *device; + + nr_node.type = NETROM_NODE; + /*nr_node.ndigis = 0;*/ + + sprintf(neigh_buffer, "%s/obsolescence_count_initialiser", PROC_NR_SYSCTL_DIR); + + if ((fp = fopen(neigh_buffer, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromr: cannot open %s\n", neigh_buffer); + return; + } + + fgets(neigh_buffer, 90, fp); + + obs_count = atoi(neigh_buffer); + + fclose(fp); + + if ((s = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + if (logging) + syslog(LOG_ERR, "netromr: socket: %m"); + return; + } + + if ((fp = fopen(PROC_NR_NEIGH_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromr: cannot open %s\n", PROC_NR_NEIGH_FILE); + close(s); + return; + } + + fgets(neigh_buffer, 90, fp); + + portcall = ax25_ntoa(neighbour); + + quality = port_list[index].default_qual; + + while (fgets(neigh_buffer, 90, fp) != NULL) { + addr = strtok(neigh_buffer, " "); + callsign = strtok(NULL, " "); + device = strtok(NULL, " "); + qual = atoi(strtok(NULL, " ")); + lock = atoi(strtok(NULL, " ")); + + if (strcmp(callsign, portcall) == 0 && + strcmp(device, port_list[index].device) == 0 && + lock == 1) { + quality = qual; + break; + } + } + + fclose(fp); + + nr_node.callsign = *neighbour; + memcpy(nr_node.mnemonic, buffer, MNEMONIC_LEN); + nr_node.mnemonic[MNEMONIC_LEN] = '\0'; + + if ((p = strchr(nr_node.mnemonic, ' ')) != NULL) + *p = '\0'; + + if (!validmnemonic(nr_node.mnemonic)) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route, invalid mnemonic - %s\n", nr_node.mnemonic); + } else { + nr_node.neighbour = *neighbour; + strcpy(nr_node.device, port_list[index].device); + nr_node.quality = quality; + nr_node.obs_count = obs_count; + + if (ioctl(s, SIOCADDRT, &nr_node) == -1) { + if (logging) + syslog(LOG_ERR, "netromr: SIOCADDRT: %m"); + close(s); + return; + } + } + + buffer += MNEMONIC_LEN; + length -= MNEMONIC_LEN; + + while (length >= ROUTE_LEN) { + /* + * Ensure that a) the route is not via me, and + * b) it is better than my minimum acceptable quality + */ + if (ax25_cmp(&my_call, (ax25_address *)(buffer + 13)) != 0 && + buffer[20] > port_list[index].worst_qual) { + memcpy(&nr_node.callsign, buffer + 0, CALLSIGN_LEN); + memcpy(nr_node.mnemonic, buffer + 7, MNEMONIC_LEN); + nr_node.mnemonic[MNEMONIC_LEN] = '\0'; + + if ((p = strchr(nr_node.mnemonic, ' ')) != NULL) + *p = '\0'; + + if (!validmnemonic(nr_node.mnemonic)) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route, invalid mnemonic - %s\n", nr_node.mnemonic); + } else { + nr_node.neighbour = *neighbour; + strcpy(nr_node.device, port_list[index].device); + nr_node.quality = ((quality * buffer[20]) + 128) / 256; + nr_node.obs_count = obs_count; + + if (ioctl(s, SIOCADDRT, &nr_node) == -1) { + if (logging) + syslog(LOG_ERR, "netromr: SIOCADDRT: %m"); + close(s); + return; + } + } + } + + buffer += ROUTE_LEN; + length -= ROUTE_LEN; + } + + close(s); +} diff --git a/netrom/netromt.c b/netrom/netromt.c new file mode 100644 index 0000000..d22caf1 --- /dev/null +++ b/netrom/netromt.c @@ -0,0 +1,268 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <syslog.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrom/netrom.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/nrconfig.h> + +#include "../pathnames.h" +#include "netromd.h" + +static int build_header(unsigned char *message) +{ + message[0] = NODES_SIG; + + strcpy(message + 1, nr_config_get_alias(NULL)); + strncat(message + 1, " ", MNEMONIC_LEN - strlen(message + 1)); + + return 7; +} + +static void build_mine(int s, struct full_sockaddr_ax25 *dest, int dlen, int localval, int pause) +{ + unsigned char message[100]; + char buffer[255], *port, *p; + FILE *fp; + int len; + + len = build_header(message); + + if ((fp = fopen(CONF_NRPORTS_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: cannot open nrports file\n"); + return; + } + + while (fgets(buffer, 255, fp) != NULL) { + if ((p = strchr(buffer, '\n')) != NULL) + *p = '\0'; + + if (strlen(buffer) == 0 || buffer[0] == '#') + continue; + + port = strtok(buffer, " \t"); + + if (nr_config_get_addr(port) == NULL) + continue; + + if (strcmp(nr_config_get_addr(port), nr_config_get_addr(NULL)) == 0) + continue; + + if (ax25_aton_entry(nr_config_get_addr(port), message + len) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: invalid callsign in nrports\n"); + fclose(fp); + return; + } + len += CALLSIGN_LEN; + + strcpy(message + len, nr_config_get_alias(port)); + strncat(message + len, " ", MNEMONIC_LEN - strlen(message + len)); + len += MNEMONIC_LEN; + + ax25_aton_entry(nr_config_get_addr(NULL), message + len); + len += CALLSIGN_LEN; + + message[len] = localval; + len += QUALITY_LEN; + } + + fclose(fp); + + if (sendto(s, message, len, 0, (struct sockaddr *)dest, dlen) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: sendto: %m"); + } + + sleep(pause); +} + +static void build_others(int s, int min_obs, struct full_sockaddr_ax25 *dest, int dlen, int port, int pause) +{ + unsigned char message[300]; + FILE *fpnodes, *fpneigh; + char nodes_buffer[90]; + char neigh_buffer[90]; + char *callsign, *mnemonic, *neighbour; + int which, number, quality, neigh_no, obs_count; + int olen, len; + + if ((fpnodes = fopen(PROC_NR_NODES_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: cannot open %s\n", PROC_NR_NODES_FILE); + return; + } + + if ((fpneigh = fopen(PROC_NR_NEIGH_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: cannot open %s\n", PROC_NR_NEIGH_FILE); + fclose(fpnodes); + return; + } + + fgets(nodes_buffer, 90, fpnodes); + + do { + len = olen = build_header(message); + + while (fgets(nodes_buffer, 90, fpnodes) != NULL) { + callsign = strtok(nodes_buffer, " "); + mnemonic = strtok(NULL, " "); + which = atoi(strtok(NULL, " ")); + number = atoi(strtok(NULL, " ")); + quality = atoi(strtok(NULL, " ")); + obs_count = atoi(strtok(NULL, " ")); + neigh_no = atoi(strtok(NULL, " ")); + neighbour = NULL; + + if (obs_count < min_obs || quality == 0) continue; + + /* "Blank" mnemonic */ + if (strcmp(mnemonic, "*") == 0) + mnemonic = ""; + + fseek(fpneigh, 0L, SEEK_SET); + + fgets(neigh_buffer, 90, fpneigh); + + while (fgets(neigh_buffer, 90, fpneigh) != NULL) { + if (atoi(strtok(neigh_buffer, " ")) == neigh_no) { + neighbour = strtok(NULL, " "); + break; + } + } + + if (neighbour == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: corruption in nodes/neighbour matching\n"); + continue; + } + + if (ax25_aton_entry(callsign, message + len) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: invalid callsign '%s' in /proc/net/nr_nodes\n", callsign); + continue; + } + len += CALLSIGN_LEN; + + strcpy(message + len, mnemonic); + strncat(message + len, " ", MNEMONIC_LEN - strlen(message + len)); + len += MNEMONIC_LEN; + + if (ax25_aton_entry(neighbour, message + len) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: invalid callsign '%s' in /proc/net/nr_neigh\n", neighbour); + len -= (CALLSIGN_LEN + MNEMONIC_LEN); + continue; + } + len += CALLSIGN_LEN; + + message[len] = quality; + len += QUALITY_LEN; + + /* No room for another entry? */ + if (len + ROUTE_LEN > NODES_PACLEN) + break; + } + + /* Only send it if there is more that just the header */ + if (len > olen) { + if (sendto(s, message, len, 0, (struct sockaddr *)dest, dlen) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: sendto: %m"); + } + + sleep(pause); + } + + /* If the packet was not full then we are done */ + } while (len + ROUTE_LEN > NODES_PACLEN); + + fclose(fpnodes); + fclose(fpneigh); +} + +void transmit_nodes(int localval, int pause) +{ + struct full_sockaddr_ax25 dest; + struct full_sockaddr_ax25 src; + int s, dlen, slen; + char path[25], *addr; + int i; + + switch (fork()) { + case 0: + break; + case -1: + if (logging) + syslog(LOG_ERR, "netromt: fork: %m\n"); + return; + default: + return; + } + + dlen = ax25_aton("NODES", &dest); + + for (i = 0; i < port_count; i++) { + + addr = ax25_config_get_addr(port_list[i].port); + + if (addr == NULL) continue; + + if (debug && logging) + syslog(LOG_DEBUG, "transmitting NODES broadcast on port %s\n", port_list[i].port); + + sprintf(path, "%s %s", nr_config_get_addr(NULL), addr); + + ax25_aton(path, &src); + slen = sizeof(struct full_sockaddr_ax25); + + if ((s = socket(AF_AX25, SOCK_DGRAM, NETROM_PID)) < 0) { + if (logging) + syslog(LOG_ERR, "netromt: socket: %m"); + continue; + } + + if (bind(s, (struct sockaddr *)&src, slen) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: bind: %m"); + close(s); + continue; + } + + build_mine(s, &dest, dlen, localval, pause); + + if (port_list[i].verbose) + build_others(s, port_list[i].minimum_obs, &dest, dlen, i, pause); + + close(s); + } + + if ((s = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + if (logging) + syslog(LOG_ERR, "netromt: socket: %m"); + exit(1); + } + + if (ioctl(s, SIOCNRDECOBS, &i) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: SIOCNRDECOBS: %m"); + exit(1); + } + + close(s); + + exit(0); +} diff --git a/netrom/nodesave.8 b/netrom/nodesave.8 new file mode 100644 index 0000000..626778b --- /dev/null +++ b/netrom/nodesave.8 @@ -0,0 +1,31 @@ +.TH NODESAVE 8 "21 May 1996" Linux "Linux System Managers Manual" +.SH NAME +nodesave \- Saves NET/ROM routing information +.SH SYNOPSIS +.B nodesave [filename] +.SH DESCRIPTION +.LP +.B Nodesave +saves the contents of the /proc filesystem entries for the NET/ROM routing +tables. The output of the program is in the form of a Bourne shell script +that calls nrparms(8) to recreate the NET/ROM routing information. If no +filename is given on the command line, the program writes the script to +stdout. +.LP +Typically +.B nodesave +would be used when taking a system off-air so that the NET/ROM routing may +be quickly restored when the system is brought back on-line. +.SH FILES +.nf +/proc/net/nr_neigh +.br +/proc/net/nr_nodes +.fi +.SH "SEE ALSO" +.BR netrom (4), +.BR netromd (8), +.BR nrparms (8). +.LP +.SH AUTHOR +Tomi Manninen OH2BNS <tpmannin@cc.hut.fi> diff --git a/netrom/nodesave.c b/netrom/nodesave.c new file mode 100644 index 0000000..3eab61b --- /dev/null +++ b/netrom/nodesave.c @@ -0,0 +1,101 @@ +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <netax25/ax25.h> + +#include <netax25/axconfig.h> + +#include <netax25/procutils.h> + +int main(int argc, char **argv) +{ + FILE *fp = stdout; + struct proc_nr_nodes *nodes, *nop; + struct proc_nr_neigh *neighs, *nep; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "nodesave: no AX.25 port data configured\n"); + return 1; + } + + if (argc > 1) { + if ((fp = fopen(argv[1], "w")) == NULL) { + fprintf(stderr, "nodesave: cannot open file %s\n", argv[1]); + return 1; + } + } + + if ((neighs = read_proc_nr_neigh()) == NULL && errno != 0) { + perror("nodesave: read_proc_nr_neigh"); + fclose(fp); + return 1; + } + + if ((nodes = read_proc_nr_nodes()) == NULL && errno != 0) { + perror("nodesave: read_proc_nr_nodes"); + free_proc_nr_neigh(neighs); + fclose(fp); + return 1; + } + + fprintf(fp, "#! /bin/sh\n#\n# Locked routes:\n#\n"); + + for (nep = neighs; nep != NULL; nep = nep->next) { + if (nep->lock) { + fprintf(fp, "nrparms -routes \"%s\" %s + %d\n", + ax25_config_get_name(nep->dev), + nep->call, + nep->qual); + } + } + + fprintf(fp, "#\n# Nodes:\n#\n"); + + for (nop = nodes; nop != NULL; nop = nop->next) { + if ((nep = find_neigh(nop->addr1, neighs)) != NULL) { + fprintf(fp, "nrparms -nodes %s + \"%s\" %d %d \"%s\" %s\n", + nop->call, + nop->alias, + nop->qual1, + nop->obs1, + ax25_config_get_name(nep->dev), + nep->call); + } + + if (nop->n > 1 && (nep = find_neigh(nop->addr2, neighs)) != NULL) { + fprintf(fp, "nrparms -nodes %s + \"%s\" %d %d \"%s\" %s\n", + nop->call, + nop->alias, + nop->qual2, + nop->obs2, + ax25_config_get_name(nep->dev), + nep->call); + } + + if (nop->n > 2 && (nep = find_neigh(nop->addr3, neighs)) != NULL) { + fprintf(fp, "nrparms -nodes %s + \"%s\" %d %d \"%s\" %s\n", + nop->call, + nop->alias, + nop->qual3, + nop->obs3, + ax25_config_get_name(nep->dev), + nep->call); + } + } + + free_proc_nr_neigh(neighs); + free_proc_nr_nodes(nodes); + + fclose(fp); + + if (argc > 1) { + chmod(argv[1], S_IEXEC); + } + + return 0; +} diff --git a/netrom/nrattach.8 b/netrom/nrattach.8 new file mode 100644 index 0000000..692e3f2 --- /dev/null +++ b/netrom/nrattach.8 @@ -0,0 +1,39 @@ +.TH NRATTACH 8 "21 May 1996" Linux "Linux System Managers Manual" +.SH NAME +nrattach \- Start a NET/ROM interface +.SH SYNOPSIS +.B nrattach [-i inetaddr] [-m mtu] [-v] port +.SH DESCRIPTION +.LP +.B Nrattach +takes many of the parameters for the port from the nrports(5) file. The +paclen parameter is used for the device mtu unless overridden by a value on +the command line. The port argument is the name of a port as given in the +nrports(5) file. +.LP +.B Nrattach +tries to find the first free NET/ROM device in the system. The devices +checked are nr0, nr1, nr2 and nr3 in that order. If no free NET/ROM device +is available an error is generated and the program terminates. +.SH OPTIONS +.TP 16 +.BI "\-i inetaddr" +Set the internet address of the interface. This address may either be a +dotted decimal address or a host name. +.TP 16 +.BI "\-m mtu" +Sets the mtu of the interface. If this value is not given then the value is +taken from the paclen parameter in nrports. +.TP 16 +.BI \-v +Display the version. +.SH "SEE ALSO" +.BR netrom (4), +.BR nrparms (4), +.BR nrports (5), +.BR ifconfig (8). +.SH BUGS +The program can be run many times with the same arguments creating many +instances of the same attributes on different devices. Not a good idea. +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/netrom/nrattach.c b/netrom/nrattach.c new file mode 100644 index 0000000..aee0936 --- /dev/null +++ b/netrom/nrattach.c @@ -0,0 +1,240 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <netdb.h> + +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <net/if.h> +#include <net/if_arp.h> + +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> + +#include <config.h> + +#include "../pathnames.h" + +char *callsign; +int mtu = 0; + +int readconfig(char *port) +{ + FILE *fp; + char buffer[90], *s; + int n = 0; + + if ((fp = fopen(CONF_NRPORTS_FILE, "r")) == NULL) { + fprintf(stderr, "nrattach: cannot open nrports file\n"); + return FALSE; + } + + while (fgets(buffer, 90, fp) != NULL) { + n++; + + if ((s = strchr(buffer, '\n')) != NULL) + *s = '\0'; + + if (strlen(buffer) > 0 && *buffer == '#') + continue; + + if ((s = strtok(buffer, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + if (strcmp(s, port) != 0) + continue; + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + callsign = strdup(s); + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + if (mtu == 0) { + if ((mtu = atoi(s)) <= 0) { + fprintf(stderr, "nrattach: invalid paclen setting\n"); + return FALSE; + } + } + + fclose(fp); + + return TRUE; + } + + fclose(fp); + + fprintf(stderr, "nrattach: cannot find port %s in nrports\n", port); + + return FALSE; +} + +int getfreedev(char *dev) +{ + struct ifreq ifr; + int fd; + int i; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("nrattach: socket"); + return FALSE; + } + + for (i = 0; i < 4; i++) { + sprintf(dev, "nr%d", i); + strcpy(ifr.ifr_name, dev); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("nrattach: SIOCGIFFLAGS"); + return FALSE; + } + + if (!(ifr.ifr_flags & IFF_UP)) { + close(fd); + return TRUE; + } + } + + close(fd); + + return FALSE; +} + +int startiface(char *dev, struct hostent *hp) +{ + struct ifreq ifr; + char call[7]; + int fd; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("nrattach: socket"); + return FALSE; + } + + strcpy(ifr.ifr_name, dev); + + if (hp != NULL) { + ifr.ifr_addr.sa_family = AF_INET; + + ifr.ifr_addr.sa_data[0] = 0; + ifr.ifr_addr.sa_data[1] = 0; + ifr.ifr_addr.sa_data[2] = hp->h_addr_list[0][0]; + ifr.ifr_addr.sa_data[3] = hp->h_addr_list[0][1]; + ifr.ifr_addr.sa_data[4] = hp->h_addr_list[0][2]; + ifr.ifr_addr.sa_data[5] = hp->h_addr_list[0][3]; + ifr.ifr_addr.sa_data[6] = 0; + + if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) { + perror("nrattach: SIOCSIFADDR"); + return FALSE; + } + } + + if (ax25_aton_entry(callsign, call) == -1) + return FALSE; + + ifr.ifr_hwaddr.sa_family = ARPHRD_NETROM; + memcpy(ifr.ifr_hwaddr.sa_data, call, 7); + + if (ioctl(fd, SIOCSIFHWADDR, &ifr) != 0) { + perror("nrattach: SIOCSIFHWADDR"); + return FALSE; + } + + ifr.ifr_mtu = mtu; + + if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) { + perror("nrattach: SIOCSIFMTU"); + return FALSE; + } + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("nrattach: SIOCGIFFLAGS"); + return FALSE; + } + + ifr.ifr_flags &= IFF_NOARP; + ifr.ifr_flags |= IFF_UP; + ifr.ifr_flags |= IFF_RUNNING; + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { + perror("nrattach: SIOCSIFFLAGS"); + return FALSE; + } + + close(fd); + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + int fd; + char dev[64]; + struct hostent *hp = NULL; + + while ((fd = getopt(argc, argv, "i:m:v")) != -1) { + switch (fd) { + case 'i': + if ((hp = gethostbyname(optarg)) == NULL) { + fprintf(stderr, "nrattach: invalid internet name/address - %s\n", optarg); + return 1; + } + break; + case 'm': + if ((mtu = atoi(optarg)) <= 0) { + fprintf(stderr, "nrattach: invalid mtu size - %s\n", optarg); + return 1; + } + break; + case 'v': + printf("nrattach: %s\n", VERSION); + return 0; + case ':': + case '?': + fprintf(stderr, "usage: nrattach [-i inetaddr] [-m mtu] [-v] port\n"); + return 1; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "usage: nrattach [-i inetaddr] [-m mtu] [-v] port\n"); + return 1; + } + + if (!readconfig(argv[optind])) + return 1; + + if (!getfreedev(dev)) { + fprintf(stderr, "nrattach: cannot find free NET/ROM device\n"); + return 1; + } + + if (!startiface(dev, hp)) + return 1; + + printf("NET/ROM port %s bound to device %s\n", argv[optind], dev); + + return 0; +} diff --git a/netrom/nrbroadcast b/netrom/nrbroadcast new file mode 100644 index 0000000..8584b22 --- /dev/null +++ b/netrom/nrbroadcast @@ -0,0 +1,8 @@ +# /etc/ax25/nrbroadcast +# +# The format of this file is: +# +# ax25_name min_obs def_qual worst_qual verbose +# +1 5 192 100 0 +2 5 255 100 1 diff --git a/netrom/nrbroadcast.5 b/netrom/nrbroadcast.5 new file mode 100644 index 0000000..7258bc7 --- /dev/null +++ b/netrom/nrbroadcast.5 @@ -0,0 +1,49 @@ +.TH NRBROADCAST 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +nrbroadcast \- NET/ROM routing broadcast configuration file. +.SH DESCRIPTION +.LP +.B Nrbroadcast +is an ASCII file that contains information about each of the physical AX.25 +ports that are to have NET/ROM routing broadcasts transmitted from them. +.LP +Each line has the following format, each field being delimited by white space: +.sp +.RS +port minobs defqual worstqual verbose +.RE +.sp +The field descriptions are: +.sp +.RS +.TP 14 +.B port +the port name of the AX.25 port to broadcast on. +.TP +.B minobs +this is the minimum obsolescence count of a routing table entry to be +broadcast on this port. +.TP +.B defqual +this is the default quality of an incoming routing broadcast from an unknown +neighbour. +.TP +.B worstqual +this is the worst quality node received from a routing broadcast that will +be added to our routing table. +.TP +.B verbose +whether the routes to all of my nodes in my routing table, or just the nodes +resident on my machine are to be broadcast. +.RE +.SH FILES +.LP +/etc/ax25/nrbroadcast +.br +/etc/ax25/axports +.SH "SEE ALSO" +.BR call (1), +.BR netrom (4), +.BR axports (5), +.BR netromd (8), +.BR nrparms (8). diff --git a/netrom/nrparms.8 b/netrom/nrparms.8 new file mode 100644 index 0000000..38d3dd8 --- /dev/null +++ b/netrom/nrparms.8 @@ -0,0 +1,76 @@ +.TH NRPARMS 8 "25 January 1997" Linux "Linux System Managers Manual" +.SH NAME +nrparms \- Configure the NET/ROM interface. +.SH SYNOPSIS +.B nrparms -nodes node +|- ident quality count port neighbour [digicall...] +.LP +.B nrparms -routes port nodecall [digicall...] +|- quality +.LP +.B nrparms -version +.SH DESCRIPTION +.LP +This program is used to manipulate the routing tables of the NET/ROM network +layer, or to get and set many of the network and transport layer parameters +for the NET/ROM protocol. The program has three basic modes of operation, +node setting, neighbour setting and general parameter setting. The syntax +for the node and neighbour setting is taken from the original NET/ROM manual +and is therefore not very UNIXy but should be familiar to those familiar +with NET/ROMs or TheNet. +.LP +To set up a new route to a NET/ROM node in the routing tables you must use +the nodes option. All of the parameters are needed to add the node. It is +probably best to illustrate with an example: +.LP +.B nrparms -nodes GB7BPQ + NMCLUS 120 6 vhf G8ROU-3 +.LP +This creates a new route to a distant node with the callsign GB7BPQ and the +alias NMCLUS, it has a quality of 120 (out of 255) and has an obsolescence +count of six and packets for that node should be sent on the AX.25 port named +vhf to my immediate neighbour G8ROU-3. The callsigns of the node and the +neighbour may be the same. For example to set up the node G8ROU-3 which is +also my immediate neighbour, I would use: +.LP +.B nrparms -nodes G8ROU-3 + MATLCK 200 6 vhf G8ROU-3 +.LP +If the ident of the remote node is not known, it is possible to add a +node with a blank ident. To do this an ident of '*' must be entered on +the command line. Because of the command line expansion that shells do, the * +must be escaped by enclosing it in quotes. +.LP +It is also possible to remove a route to a distant node with the same +command except that the + is replaced by a -. The other parameters must also +be present. If the node has not other routes then the node will be deleted, +and the neighbour node that the connections go via may also be deleted if no +other node route uses it, and it is not a locked neighbour entry. +.LP +When setting up a new node, a new neighbour entry may also be created. This +will have a default value. For that neighbour to be meaningful in the +automatic routing process, it must have a more reasonable entry in the +neighbours list. To do this the routes option of the command must be used. +An example: +.LP +.B nrparms -routes ax0 G8ROU-3 + 120 +.LP +This will create (or update) the neighbour entry for G8ROU-3 with a quality +of 120 and it will be locked, it will not create a node entry for the +neighbour. This quality will be used by the +.BR netromd (8) +program when calculating route qualities via this neighbour. Normally once a +neighbour has zero node routes going via it, it will be deleted. Locking a +neighbour prevents the deletion from occurring. To unlock a neighbour entry, +the same command is used but with the + replaced by a -. +.SH FILES +.LP +/etc/ax25/axports +.br +/etc/ax25/nrports +.SH "SEE ALSO" +.BR call (1), +.BR netrom (4), +.BR nrports (5), +.BR axparms (8), +.BR netromd (8), +.BR nrctl (8), +.BR nrparms (8). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/netrom/nrparms.c b/netrom/nrparms.c new file mode 100644 index 0000000..7e89ff9 --- /dev/null +++ b/netrom/nrparms.c @@ -0,0 +1,239 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrom/netrom.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/nrconfig.h> + +#include <config.h> + +char nodes_usage[] = "usage: nrparms -nodes nodecall +|- ident quality count port neighbour [digicall...]\n"; +char routes_usage[] = "usage: nrparms -routes port nodecall [digicall...] +|- pathquality\n"; + +void nodes(int s, char *nodecall, char *op, char *ident, int quality, int count, char *port, char *neighbour, char *digis[]) +{ + struct nr_route_struct nr_node; + char *p, *q, *dev; + int i; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "nrparms: nodes: no AX.25 ports configured\n"); + exit(1); + } + + nr_node.type = NETROM_NODE; + /*nr_node.ndigis = 0;*/ + + if (op[0] != '+' && op[0] != '-') { + fprintf(stderr, "nrparms: nodes: invalid operation %s\n", op); + close(s); + exit(1); + } + + if (quality < 1 || quality > 255) { + fprintf(stderr, "nrparms: nodes: invalid quality %d\n", quality); + close(s); + exit(1); + } + + if (count < 1 || count > 6) { + fprintf(stderr, "nrparms: nodes: invalid obs count %d\n", count); + close(s); + exit(1); + } + + if (ax25_aton_entry(nodecall, nr_node.callsign.ax25_call) != 0) { + fprintf(stderr, "nrparms: nodes: invalid callsign %s\n", nodecall); + close(s); + exit(1); + } + + if (strlen(ident) > 7) { + fprintf(stderr, "nrparms: nodes: invalid length of mnemonic %s\n", ident); + close(s); + exit(1); + } + + if (strcmp(ident, "*") != 0) { + for (p = ident, q = nr_node.mnemonic; *p != '\0'; p++, q++) + *q = toupper(*p); + *q = '\0'; + + if (strspn(nr_node.mnemonic, "&#-_/ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") != strlen(nr_node.mnemonic)) { + fprintf(stderr, "nrparms: nodes: invalid ident %s\n", ident); + close(s); + exit(1); + } + } else { + strcpy(nr_node.mnemonic, ""); + } + + if (ax25_aton_entry(neighbour, nr_node.neighbour.ax25_call) != 0) { + fprintf(stderr, "nrparms: nodes: invalid callsign %s\n", neighbour); + close(s); + exit(1); + } + /* + for (i = 0; i < AX25_MAX_DIGIS && digis[i] != NULL; i++) { + if (ax25_aton_entry(digis[i], nr_node.digipeaters[i].ax25_call) != 0) { + fprintf(stderr, "nrparms: invalid callsign %s\n", digis[i]); + close(s); + exit(1); + } + nr_node.ndigis++; + } */ + + if ((dev = ax25_config_get_dev(port)) == NULL) { + fprintf(stderr, "nrparms: nodes: invalid port name - %s\n", port); + close(s); + exit(1); + } + + strcpy(nr_node.device, dev); + + nr_node.quality = quality; + nr_node.obs_count = count; + + if (op[0] == '+') { + if (ioctl(s, SIOCADDRT, &nr_node) == -1) { + perror("nrparms: SIOCADDRT"); + close(s); + exit(1); + } + } else { + if (ioctl(s, SIOCDELRT, &nr_node) == -1) { + perror("nrparms: SIOCDELRT"); + close(s); + exit(1); + } + } +} + +void routes(int s, char *port, char *nodecall, char *rest[]) +{ + struct nr_route_struct nr_neigh; + char *dev, *op; + int i, quality; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "nrparms: routes: no AX.25 ports configured\n"); + exit(1); + } + + nr_neigh.type = NETROM_NEIGH; + /*nr_neigh.ndigis = 0; + + for (i = 0; i < AX25_MAX_DIGIS && rest[i][0] != '-' && rest[i][0] != '+'; i++) { + if (ax25_aton_entry(rest[i], nr_neigh.digipeaters[i].ax25_call) != 0) { + fprintf(stderr, "nrparms: routes: invalid callsign %s\n", rest[i]); + close(s); + exit(1); + } + nr_neigh.ndigis++; + } + */ + + op = rest[i + 0]; + quality = atoi(rest[i + 1]); + + if (op[0] != '+' && op[0] != '-') { + fprintf(stderr, "nrparms: routes: invalid operation %s\n", op); + close(s); + exit(1); + } + + if (quality < 1 || quality > 255) { + fprintf(stderr, "nrparms: routes: invalid quality %d\n", quality); + close(s); + exit(1); + } + + if ((dev = ax25_config_get_dev(port)) == NULL) { + fprintf(stderr, "nrparms: routes: invalid port name - %s\n", port); + close(s); + exit(1); + } + + strcpy(nr_neigh.device, dev); + + if (ax25_aton_entry(nodecall, nr_neigh.callsign.ax25_call) != 0) { + fprintf(stderr, "nrparms: routes: invalid callsign %s\n", nodecall); + close(s); + exit(1); + } + + nr_neigh.quality = quality; + + if (op[0] == '+') { + if (ioctl(s, SIOCADDRT, &nr_neigh) == -1) { + perror("nrparms: SIOCADDRT"); + close(s); + exit(1); + } + } else { + if (ioctl(s, SIOCDELRT, &nr_neigh) == -1) { + perror("nrparms: SIOCDELRT"); + close(s); + exit(1); + } + } +} + +int main(int argc, char *argv[]) +{ + int s; + + if (argc == 1) { + fprintf(stderr, "usage: nrparms -nodes|-routes|-version ...\n"); + return 1; + } + + if (strncmp(argv[1], "-v", 2) == 0) { + printf("nrparms: %s\n", VERSION); + return 0; + } + + if ((s = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + perror("nrparms: socket"); + return 1; + } + + if (strncmp(argv[1], "-n", 2) == 0) { + if (argc < 9) { + fprintf(stderr, nodes_usage); + close(s); + return 1; + } + nodes(s, argv[2], argv[3], argv[4], atoi(argv[5]), atoi(argv[6]), argv[7], argv[8], argv + 9); + close(s); + return 0; + } + + if (strncmp(argv[1], "-r", 2) == 0) { + if (argc < 6) { + fprintf(stderr, routes_usage); + close(s); + return 1; + } + routes(s, argv[2], argv[3], argv + 4); + close(s); + return 0; + } + + fprintf(stderr, "usage: nrparms -nodes|-routes|-version ...\n"); + + close(s); + + return 1; +} diff --git a/netrom/nrports b/netrom/nrports new file mode 100644 index 0000000..4faa359 --- /dev/null +++ b/netrom/nrports @@ -0,0 +1,7 @@ +# /etc/ax25/nrports +# +# The format of this file is: +# +# name callsign alias paclen description +# +netrom OH2BNS-10 #LNODE 235 Switch Port diff --git a/netrom/nrports.5 b/netrom/nrports.5 new file mode 100644 index 0000000..3449113 --- /dev/null +++ b/netrom/nrports.5 @@ -0,0 +1,56 @@ +.TH NRPORTS 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +nrports \- NET/ROM port configuration file. +.SH DESCRIPTION +.LP +.B Nrports +is an ASCII file that contains information about each of the NET/ROM +ports that are to be used. When dealing with an NET/ROM utility such as +.B call, +it takes an optional argument that is the port name. This port name is a +reference to the line within +.B nrports, +which has the same name. The information on each line contains +enough information to bind the command to a particular NET/ROM +interface, this binding is done by matching the callsign on the line in +.B nrports +with the callsign of the port set by +.B ifconfig. +.LP +The +.B nrports +file may contain comments that begin with a # in the first column, or a port +description in the following format, each field being delimited by white space: +.sp +.RS +name callsign alias paclen description +.RE +.sp +The field descriptions are: +.sp +.RS +.TP 14 +.B name +this is the unique NET/ROM port identifier. +.TP 14 +.B callsign +the callsign of the NET/ROM interface to bind to. +.TP 14 +.B alias +this is the alias of the NET/ROM port. +.TP 14 +.B paclen +is the default packet size for this interface. +.TP 14 +.B description +a free format description of this interface, this field extends to the end +of the line. It may contain spaces. +.RE +.SH FILES +.LP +/etc/ax25/nrports +.SH "SEE ALSO" +.BR call (1), +.BR netrom (4), +.BR ifconfig (8), +.BR nrparms (8). diff --git a/netrom/nrsdrv.8 b/netrom/nrsdrv.8 new file mode 100644 index 0000000..fb27562 --- /dev/null +++ b/netrom/nrsdrv.8 @@ -0,0 +1,44 @@ +.TH NRSDRV 8 "22 December 1996" Linux "Linux System Managers Manual" +.SH NAME +nrsdrv \- KISS to NET/ROM serial converter +.SH SYNOPSIS +.B nrsdrv [-f] [-l] [-s speed] [-v] kissdev nrsdev +.SH DESCRIPTION +.LP +.B Nrsdrv +is a program designed to convert from the KISS protocol to the NET/ROM +serial protocol used by real NET/ROM's and TheNet's. The protocols are +fairly similar, although the NET/ROM serial protocol does include a one byte +checksum which KISS does not. +.sp 1 +Typically +.B nrsdrv +will be attached to one end of a pseudo-tty of which the other end has been +attached to a KISS capable program. The NET/ROM device will probably be a +real serial port attached to a TNC or a Hexipus. The full specification of +the NET/ROM serial protocol can be found in the original Software 2000 +documentation that accompanied NET/ROMs. +.SH OPTIONS +.TP 10 +.BI \-f +Flow control enabled for use with a Hexipus, the default is disabled. +See the file hexipus.txt in the source distribution for wiring details. + +.TP 10 +.BI \-l +Log messages to the system log, the default is not to. +.TP 10 +.BI "\-s speed" +Sets the speed of both interfaces. If no value is specified then no speed +will be set. +.TP 10 +.BI \-v +Display the version. +.SH BUGS +None known. +.SH "SEE ALSO" +.BR kill (1), +.BR stty (1), +.BR ax25 (4). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/netrom/nrsdrv.c b/netrom/nrsdrv.c new file mode 100644 index 0000000..92b3d6a --- /dev/null +++ b/netrom/nrsdrv.c @@ -0,0 +1,457 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <netdb.h> +#include <syslog.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <netax25/daemon.h> +#include <netax25/ttyutils.h> + +#include <config.h> + +#include "../pathnames.h" + +static int kissfd, nrsfd; +static int logging = FALSE; +static int debugging = FALSE; +static int flowcontrol = FALSE; +static char *kissdev, *nrsdev; + +#define NUL 000 +#define STX 002 +#define ETX 003 +#define DLE 020 + +#define NRS_WAIT 0 +#define NRS_DATA 1 +#define NRS_ESCAPE 2 +#define NRS_CKSUM 3 +static int nrs_state = NRS_WAIT; + +static unsigned char nrs_cksum = 0; + +static unsigned char nrs_rxbuffer[512]; +static int nrs_rxcount = 0; + +#define FEND 0300 +#define FESC 0333 +#define FESCEND 0334 +#define FESCESC 0335 + +#define KISS_WAIT 0 +#define KISS_CTRL 1 +#define KISS_DATA 2 +#define KISS_ESCAPE 3 +static int kiss_state = KISS_WAIT; + +static unsigned char kiss_rxbuffer[512]; +static int kiss_rxcount = 0; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + tty_unlock(kissdev); + tty_unlock(nrsdev); + + exit(0); +} + +static void key_rts(int fd) +{ + int status; + + if (!flowcontrol) + return; + + /* Wait for CTS to be low */ + while (1) { + /* Get CTS status */ + if (ioctl(fd, TIOCMGET, &status) < 0) { + syslog(LOG_INFO|LOG_ERR, "TIOCMGET failed: flowcontrol disabled (%m)\n"); + flowcontrol = 0; + return; + } + if (status & TIOCM_CTS) { + if (debugging) { + fprintf(stderr,"CTS high: waiting\n"); + } + ioctl(fd, TIOCMIWAIT, &status); + } else { + break; + } + } + + if (debugging) { + fprintf(stderr,"CTS low: keying RTS\n"); + } + status |= TIOCM_RTS | TIOCM_DTR; + if (ioctl(fd, TIOCMSET, &status) < 0) { + syslog(LOG_INFO|LOG_ERR, "TIOCMGET failed: flowcontrol disabled (%m)\n"); + flowcontrol = 0; + } +} + +static void unkey_rts(int fd) +{ + int status; + + if (!flowcontrol) + return; + + if (debugging) { + fprintf(stderr,"Transmission finished: unkeying RTS\n"); + } + ioctl(fd, TIOCMGET, &status); + status &= ~TIOCM_RTS; + status |= TIOCM_DTR; + if (ioctl(fd, TIOCMSET, &status) < 0) { + syslog(LOG_INFO|LOG_ERR, "TIOCMGET failed: flowcontrol disabled (%m)\n"); + flowcontrol = 0; + } +} + +static void nrs_esc(unsigned char *s, int len) +{ + static unsigned char buffer[512]; + unsigned char *ptr = buffer; + unsigned char csum = 0; + unsigned char c; + + *ptr++ = STX; + + while (len-- > 0) { + switch (c = *s++) { + case STX: + case ETX: + case DLE: + *ptr++ = DLE; + /* Fall through */ + default: + *ptr++ = c; + break; + } + + csum += c; + } + + *ptr++ = ETX; + *ptr++ = csum; + *ptr++ = NUL; + *ptr++ = NUL; + + key_rts(nrsfd); + write(nrsfd, buffer, ptr - buffer); + unkey_rts(nrsfd); +} + +static void kiss_esc(unsigned char *s, int len) +{ + static unsigned char buffer[512]; + unsigned char *ptr = buffer; + unsigned char c; + + *ptr++ = FEND; + *ptr++ = 0x00; /* KISS DATA */ + + while (len-- > 0) { + switch (c = *s++) { + case FESC: + *ptr++ = FESC; + *ptr++ = FESCESC; + break; + case FEND: + *ptr++ = FESC; + *ptr++ = FESCEND; + break; + default: + *ptr++ = c; + break; + } + } + + *ptr++ = FEND; + + write(kissfd, buffer, ptr - buffer); +} + +static void nrs_unesc(unsigned char *buffer, int len) +{ + int i; + + for (i = 0; i < len; i++) { + switch (nrs_state) { + case NRS_WAIT: + if (buffer[i] == STX) { + nrs_state = NRS_DATA; + nrs_rxcount = 0; + nrs_cksum = 0; + } + break; + + case NRS_DATA: + switch (buffer[i]) { + case STX: /* !! */ + nrs_rxcount = 0; + nrs_cksum = 0; + break; + case DLE: + nrs_state = NRS_ESCAPE; + break; + case ETX: + nrs_state = NRS_CKSUM; + break; + default: + if (nrs_rxcount < 512) { + nrs_cksum += buffer[i]; + nrs_rxbuffer[nrs_rxcount++] = buffer[i]; + } + break; + } + break; + + case NRS_ESCAPE: + nrs_state = NRS_DATA; + if (nrs_rxcount < 512) { + nrs_cksum += buffer[i]; + nrs_rxbuffer[nrs_rxcount++] = buffer[i]; + } + break; + + case NRS_CKSUM: + if (buffer[i] == nrs_cksum) + kiss_esc(nrs_rxbuffer, nrs_rxcount); + nrs_state = NRS_WAIT; + nrs_cksum = 0; + nrs_rxcount = 0; + break; + } + } +} + +static void kiss_unesc(unsigned char *buffer, int len) +{ + int i; + + for (i = 0; i < len; i++) { + switch (kiss_state) { + case KISS_WAIT: + if (buffer[i] == FEND) { + kiss_state = KISS_CTRL; + kiss_rxcount = 0; + } + break; + + case KISS_CTRL: + if ((buffer[i] & 0x0F) == 0x00) { + kiss_state = KISS_DATA; + kiss_rxcount = 0; + } else { + kiss_state = KISS_WAIT; + kiss_rxcount = 0; + } + break; + + case KISS_DATA: + switch (buffer[i]) { + case FEND: + if (kiss_rxcount > 2) + nrs_esc(kiss_rxbuffer, kiss_rxcount); + kiss_state = KISS_WAIT; + kiss_rxcount = 0; + break; + case FESC: + kiss_state = KISS_ESCAPE; + break; + default: + if (kiss_rxcount < 512) + kiss_rxbuffer[kiss_rxcount++] = buffer[i]; + break; + } + break; + + case KISS_ESCAPE: + kiss_state = KISS_DATA; + switch (buffer[i]) { + case FESCESC: + if (kiss_rxcount < 512) + kiss_rxbuffer[kiss_rxcount++] = FESC; + break; + case FESCEND: + if (kiss_rxcount < 512) + kiss_rxbuffer[kiss_rxcount++] = FEND; + break; + } + break; + } + } +} + +int main(int argc, char *argv[]) +{ + static char buffer[512]; + unsigned int speed = 0; + fd_set read_fd; + int c, n; + + while ((c = getopt(argc, argv, "dfls:v")) != -1) { + switch (c) { + case 'd': + debugging = TRUE; + break; + case 'f': + flowcontrol = TRUE; + break; + case 'l': + logging = TRUE; + break; + case 's': + if ((speed = atoi(optarg)) <= 0) { + fprintf(stderr, "nrsdrv: invalid speed %s\n", optarg); + return 1; + } + break; + case 'v': + printf("kissattach: %s\n", VERSION); + return 0; + case ':': + case '?': + fprintf(stderr, "usage: nrsdrv [-f] [-l] [-s speed] [-v] kisstty nrstty\n"); + return 1; + } + } + + if (debugging) { + fprintf(stderr,"Flow control %s\n", + flowcontrol ? "enabled" : "disabled"); + } + + if ((argc - optind) != 2) { + fprintf(stderr, "usage: nrsdrv [-f] [-l] [-s speed] [-v] kisstty nrstty\n"); + return 1; + } + + kissdev = argv[optind + 0]; + nrsdev = argv[optind + 1]; + + if (tty_is_locked(kissdev)) { + fprintf(stderr, "nrsdrv: device %s already in use\n", argv[optind]); + return 1; + } + + if (tty_is_locked(nrsdev)) { + fprintf(stderr, "nrsdrv: device %s already in use\n", argv[optind + 1]); + return 1; + } + + if ((kissfd = open(kissdev, O_RDWR)) == -1) { + perror("nrsdrv: open kiss device"); + return 1; + } + + if ((nrsfd = open(nrsdev, O_RDWR)) == -1) { + perror("nrsdrv: open nrs device"); + return 1; + } + + tty_lock(kissdev); + tty_lock(nrsdev); + + if (!tty_raw(kissfd, FALSE)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (!tty_raw(nrsfd, FALSE)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (speed != 0 && !tty_speed(kissfd, speed)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (speed != 0 && !tty_speed(nrsfd, speed)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (logging) { + openlog("nrsdrv", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "KISS device %s connected to NRS device %s\n", argv[optind + 0], argv[optind + 1]); + } + + signal(SIGHUP, SIG_IGN); + signal(SIGTERM, terminate); + + /* + * Become a daemon if we can. + */ + if (!daemon_start(FALSE)) { + fprintf(stderr, "nrsdrv: cannot become a daemon\n"); + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (flowcontrol) { + unkey_rts(nrsfd); + } + + c = ((kissfd > nrsfd) ? kissfd : nrsfd) + 1; + + for (;;) { + FD_ZERO(&read_fd); + + FD_SET(kissfd, &read_fd); + FD_SET(nrsfd, &read_fd); + + n = select(c, &read_fd, NULL, NULL, NULL); + + if (FD_ISSET(kissfd, &read_fd)) { + if ((n = read(kissfd, buffer, 512)) <= 0) { + if (logging) { + syslog(LOG_INFO, "terminating on KISS device closure\n"); + closelog(); + } + break; + } + kiss_unesc(buffer, n); + } + + if (FD_ISSET(nrsfd, &read_fd)) { + if ((n = read(nrsfd, buffer, 512)) <= 0) { + if (logging) { + syslog(LOG_INFO, "terminating on NRS device closure\n"); + closelog(); + } + break; + } + nrs_unesc(buffer, n); + } + } + + tty_unlock(kissdev); + tty_unlock(nrsdev); + + return 0; +} diff --git a/rose/Makefile.am b/rose/Makefile.am new file mode 100644 index 0000000..3cbb2c8 --- /dev/null +++ b/rose/Makefile.am @@ -0,0 +1,19 @@ + +etcfiles = rsports +etcdir = $(sysconfdir)/ax25 + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + +sbin_PROGRAMS = rsattach rsdwnlnk rsmemsiz rsparms rsuplnk + +sbin_SCRIPTS = rsusers.sh + + +man_MANS = rose.4 rsports.5 rsattach.8 rsparms.8 rsdwnlnk.8 rsuplnk.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) diff --git a/rose/Makefile.in b/rose/Makefile.in new file mode 100644 index 0000000..0ded273 --- /dev/null +++ b/rose/Makefile.in @@ -0,0 +1,471 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +etcfiles = rsports +etcdir = $(sysconfdir)/ax25 + +sbin_PROGRAMS = rsattach rsdwnlnk rsmemsiz rsparms rsuplnk + +sbin_SCRIPTS = rsusers.sh + +man_MANS = rose.4 rsports.5 rsattach.8 rsparms.8 rsdwnlnk.8 rsuplnk.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +rsattach_SOURCES = rsattach.c +rsattach_OBJECTS = rsattach.o +rsattach_LDADD = $(LDADD) +rsattach_DEPENDENCIES = +rsattach_LDFLAGS = +rsdwnlnk_SOURCES = rsdwnlnk.c +rsdwnlnk_OBJECTS = rsdwnlnk.o +rsdwnlnk_LDADD = $(LDADD) +rsdwnlnk_DEPENDENCIES = +rsdwnlnk_LDFLAGS = +rsmemsiz_SOURCES = rsmemsiz.c +rsmemsiz_OBJECTS = rsmemsiz.o +rsmemsiz_LDADD = $(LDADD) +rsmemsiz_DEPENDENCIES = +rsmemsiz_LDFLAGS = +rsparms_SOURCES = rsparms.c +rsparms_OBJECTS = rsparms.o +rsparms_LDADD = $(LDADD) +rsparms_DEPENDENCIES = +rsparms_LDFLAGS = +rsuplnk_SOURCES = rsuplnk.c +rsuplnk_OBJECTS = rsuplnk.o +rsuplnk_LDADD = $(LDADD) +rsuplnk_DEPENDENCIES = +rsuplnk_LDFLAGS = +SCRIPTS = $(sbin_SCRIPTS) + +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man8dir = $(mandir)/man8 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = rsattach.c rsdwnlnk.c rsmemsiz.c rsparms.c rsuplnk.c +OBJECTS = rsattach.o rsdwnlnk.o rsmemsiz.o rsparms.o rsuplnk.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps rose/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +rsattach: $(rsattach_OBJECTS) $(rsattach_DEPENDENCIES) + @rm -f rsattach + $(LINK) $(rsattach_LDFLAGS) $(rsattach_OBJECTS) $(rsattach_LDADD) $(LIBS) + +rsdwnlnk: $(rsdwnlnk_OBJECTS) $(rsdwnlnk_DEPENDENCIES) + @rm -f rsdwnlnk + $(LINK) $(rsdwnlnk_LDFLAGS) $(rsdwnlnk_OBJECTS) $(rsdwnlnk_LDADD) $(LIBS) + +rsmemsiz: $(rsmemsiz_OBJECTS) $(rsmemsiz_DEPENDENCIES) + @rm -f rsmemsiz + $(LINK) $(rsmemsiz_LDFLAGS) $(rsmemsiz_OBJECTS) $(rsmemsiz_LDADD) $(LIBS) + +rsparms: $(rsparms_OBJECTS) $(rsparms_DEPENDENCIES) + @rm -f rsparms + $(LINK) $(rsparms_LDFLAGS) $(rsparms_OBJECTS) $(rsparms_LDADD) $(LIBS) + +rsuplnk: $(rsuplnk_OBJECTS) $(rsuplnk_DEPENDENCIES) + @rm -f rsuplnk + $(LINK) $(rsuplnk_LDFLAGS) $(rsuplnk_OBJECTS) $(rsuplnk_LDADD) $(LIBS) + +install-sbinSCRIPTS: $(sbin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_SCRIPTS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_SCRIPT) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \ + else if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; fi; \ + done + +uninstall-sbinSCRIPTS: + @$(NORMAL_UNINSTALL) + list='$(sbin_SCRIPTS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \ + done + +install-man4: + $(mkinstalldirs) $(DESTDIR)$(man4dir) + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man4dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man4dir)/$$inst; \ + done + +uninstall-man4: + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man4dir)/$$inst"; \ + rm -f $(DESTDIR)$(man4dir)/$$inst; \ + done + +install-man5: + $(mkinstalldirs) $(DESTDIR)$(man5dir) + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \ + done + +uninstall-man5: + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \ + rm -f $(DESTDIR)$(man5dir)/$$inst; \ + done + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man4 install-man5 install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man4 uninstall-man5 uninstall-man8 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = rose + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +rsattach.o: rsattach.c ../config.h ../pathnames.h +rsdwnlnk.o: rsdwnlnk.c ../config.h +rsmemsiz.o: rsmemsiz.c +rsparms.o: rsparms.c ../config.h ../pathnames.h +rsuplnk.o: rsuplnk.c ../config.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS install-sbinSCRIPTS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS uninstall-sbinSCRIPTS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sbindir) \ + $(DESTDIR)$(mandir)/man4 $(DESTDIR)$(mandir)/man5 \ + $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile uninstall-sbinSCRIPTS \ +install-sbinSCRIPTS install-man4 uninstall-man4 install-man5 \ +uninstall-man5 install-man8 uninstall-man8 install-man uninstall-man \ +tags mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \ +distdir info-am info dvi-am dvi check check-am installcheck-am \ +installcheck install-exec-am install-exec install-data-am install-data \ +install-am install uninstall-am uninstall all-redirect all-am all \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/rose/rose.4 b/rose/rose.4 new file mode 100644 index 0000000..e02d3a4 --- /dev/null +++ b/rose/rose.4 @@ -0,0 +1,44 @@ +.TH ROSE 4 "27 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +AF_ROSE \- Rose amateur packet radio protocol family +.SH DESCRIPTION +.LP +.B Rose +is a protocol used extensively by radio amateurs. The Linux +Rose protocol family permits access to these protocols via +the standard networking +.B socket +metaphor. +.LP +The Rose protocol layer only supports connected mode. +.LP +The only mode of operation is connected mode which is the mode used for a +socket of type SOCK_SEQPACKET (stream sockets are not available in Rose). +This requires that the user ensures output data is suitably packetised, and +that input data is read a packet at a time into a buffer of suitable size. +.LP +Rose addresses consist of 10 digits. These are encoded into a sockaddr_rose +structure which is provided to the relevant system calls. +.LP +Rose has some unusual properties. Notably in a multi-user system an AX.25 +address is often associated with a user, and some users may not have such an +association. a set of ioctl calls are provided to manage an association +table. +.LP +Rose supports the following socket options for SOL_ROSE. ROSE_T1 is the +T11/T21 timer in 1/10ths of a second, ROSE_T2 is the T12/T22 timer in +1/10ths of a second. ROSE_T3, is the T13/T23 timer in 1/10ths of a second. +It is possible for an application to request that the Rose layer return +the Rose header as well as the application data, this is done via the +ROSE_HDRINCL socket option. +.SH "SEE ALSO" +.BR call (1), +.BR socket (2), +.BR setsockopt(2), +.BR getsockopt(2), +.BR rsports (5), +.BR rsctl (8), +.BR rsparms (8). +.LP +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/rose/rsattach.8 b/rose/rsattach.8 new file mode 100644 index 0000000..1a67769 --- /dev/null +++ b/rose/rsattach.8 @@ -0,0 +1,33 @@ +.TH RSATTACH 8 "27 August 1996" Linux "Linux System Managers Manual" +.SH NAME +rsattach \- Start a Rose interface +.SH SYNOPSIS +.B rsattach [-i inetaddr] [-v] port +.SH DESCRIPTION +.LP +.B Rsattach +takes many of the parameters for the port from the rsports(5) file. The port +argument is the name of a port as given in the rsports(5) file. +.LP +.B Rsattach +tries to find the free Rose device in the system. The device name checked is +rose0. If no free Rose device is available an error is generated and the +program terminates. +.SH OPTIONS +.TP 16 +.BI "\-i inetaddr" +Set the internet address of the interface. This address may either be a +dotted decimal address or a host name. +.TP 16 +.BI \-v +Display the version. +.SH "SEE ALSO" +.BR rose (4), +.BR rsparms (4), +.BR rsports (5), +.BR ifconfig (8). +.SH BUGS +The program can be run many times with the same arguments creating many +instances of the same attributes on different devices. Not a good idea. +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/rose/rsattach.c b/rose/rsattach.c new file mode 100644 index 0000000..3d98858 --- /dev/null +++ b/rose/rsattach.c @@ -0,0 +1,219 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <netdb.h> + +#include <sys/ioctl.h> + +#include <sys/socket.h> +/* #include <linux/netdevice.h> */ +#include <net/if.h> +#include <net/if_arp.h> +/* #include <linux/sockios.h> */ + +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> + +#include <config.h> + +#include "../pathnames.h" + +char *address; +int mtu = 128; + +int readconfig(char *port) +{ + FILE *fp; + char buffer[90], *s; + int n = 0; + + if ((fp = fopen(CONF_RSPORTS_FILE, "r")) == NULL) { + fprintf(stderr, "rsattach: cannot open rsports file\n"); + return FALSE; + } + + while (fgets(buffer, 90, fp) != NULL) { + n++; + + if ((s = strchr(buffer, '\n')) != NULL) + *s = '\0'; + + if (strlen(buffer) > 0 && *buffer == '#') + continue; + + if ((s = strtok(buffer, " \t\r\n")) == NULL) { + fprintf(stderr, "rsattach: unable to parse line %d of the rsports file\n", n); + return FALSE; + } + + if (strcmp(s, port) != 0) + continue; + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "rsattach: unable to parse line %d of the rsports file\n", n); + return FALSE; + } + + address = strdup(s); + + fclose(fp); + + return TRUE; + } + + fclose(fp); + + fprintf(stderr, "rsattach: cannot find port %s in rsports\n", port); + + return FALSE; +} + +int getfreedev(char *dev) +{ + struct ifreq ifr; + int fd; + int i; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("rsattach: socket"); + return FALSE; + } + + for (i = 0; i < 6; i++) { + sprintf(dev, "rose%d", i); + strcpy(ifr.ifr_name, dev); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("rsattach: SIOCGIFFLAGS"); + return FALSE; + } + + if (!(ifr.ifr_flags & IFF_UP)) { + close(fd); + return TRUE; + } + } + + close(fd); + + return FALSE; +} + +int startiface(char *dev, struct hostent *hp) +{ + struct ifreq ifr; + char addr[5]; + int fd; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("rsattach: socket"); + return FALSE; + } + + strcpy(ifr.ifr_name, dev); + + if (hp != NULL) { + ifr.ifr_addr.sa_family = AF_INET; + + ifr.ifr_addr.sa_data[0] = 0; + ifr.ifr_addr.sa_data[1] = 0; + ifr.ifr_addr.sa_data[2] = hp->h_addr_list[0][0]; + ifr.ifr_addr.sa_data[3] = hp->h_addr_list[0][1]; + ifr.ifr_addr.sa_data[4] = hp->h_addr_list[0][2]; + ifr.ifr_addr.sa_data[5] = hp->h_addr_list[0][3]; + ifr.ifr_addr.sa_data[6] = 0; + + if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) { + perror("rsattach: SIOCSIFADDR"); + return FALSE; + } + } + + if (rose_aton(address, addr) == -1) + return FALSE; + + ifr.ifr_hwaddr.sa_family = ARPHRD_ROSE; + memcpy(ifr.ifr_hwaddr.sa_data, addr, 5); + + if (ioctl(fd, SIOCSIFHWADDR, &ifr) != 0) { + perror("rsattach: SIOCSIFHWADDR"); + return FALSE; + } + + ifr.ifr_mtu = mtu; + + if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) { + perror("rsattach: SIOCSIFMTU"); + return FALSE; + } + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("rsattach: SIOCGIFFLAGS"); + return FALSE; + } + + ifr.ifr_flags &= IFF_NOARP; + ifr.ifr_flags |= IFF_UP; + ifr.ifr_flags |= IFF_RUNNING; + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { + perror("rsattach: SIOCSIFFLAGS"); + return FALSE; + } + + close(fd); + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + int fd; + char dev[64]; + struct hostent *hp = NULL; + + while ((fd = getopt(argc, argv, "i:m:v")) != -1) { + switch (fd) { + case 'i': + if ((hp = gethostbyname(optarg)) == NULL) { + fprintf(stderr, "rsattach: invalid internet name/address - %s\n", optarg); + return 1; + } + break; + case 'v': + printf("rsattach: %s\n", VERSION); + return 0; + case ':': + case '?': + fprintf(stderr, "usage: rsattach [-i inetaddr] [-v] port\n"); + return 1; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "usage: rsattach [-i inetaddr] [-v] port\n"); + return 1; + } + + if (!readconfig(argv[optind])) + return 1; + + if (!getfreedev(dev)) { + fprintf(stderr, "rsattach: cannot find free Rose device\n"); + return 1; + } + + if (!startiface(dev, hp)) + return 1; + + printf("Rose port %s bound to device %s\n", argv[optind], dev); + + return 0; +} diff --git a/rose/rsdwnlnk.8 b/rose/rsdwnlnk.8 new file mode 100644 index 0000000..f0d4c2d --- /dev/null +++ b/rose/rsdwnlnk.8 @@ -0,0 +1,58 @@ +.TH RSDWNLNK 8 "29 April 1997" Linux "Linux Programmer's Manual" +.SH NAME +rsdwnlnk \- User exit from the ROSE network. +.SH SYNOPSIS +.B rsdwnlnk <port> <call> +.SH DESCRIPTION +.LP +The +.B rdwnplnk +program allows a user to leave the ROSE network using the standard +pseudo-digipeating method. Recent Linux kernels are aware of this form of +operation and the +.B ax25d +program can create such connections. The normal mode of operation of a +ROSE switch is to have one ROSE address (ie port) per physical AX.25 port. +Therefore ROSE users coming in on a given ROSE port will come out of the +associated AX.25 port. +.LP +To use +.B rsdwnlnk +you need an entry in +.B ax25d.conf +to listen for incoming ROSE connections to any callsigns that are not +matched by the more specific ROSE entries. In the example below, I will be +listening for ROSE connections on my ROSE port rs144, the exiting AX.25 +connection will be via the associated AX.25 port, 144, using the callsign +KE4GAJ-10. Please note that the callsign should be on the same line as the +rest of the command, it may be wrapped onto the next line on your screen. +.LP +# +.br +{* VIA rs144} +.br +NOCALL * * * * * * L +.br +default * * * * * * - root /usr/sbin/rsdwnlnk rsdwnlnk 144 KE4GAJ-10 +.br +# +.LP +There would typically be one +.B rsdwnlnk +per ROSE port. The associated program for entering a ROSE network is +.B rsuplnk. +.LP +All errors generated by +.B rsdwnlnk +are written to the system debug log file. +.SH FILES +.br +/etc/ax25/axports +.SH "SEE ALSO" +.BR rose (4), +.BR ax25d.conf (5), +.BR ax25d (8), +.BR rsuplnk (8), +.BR rose_call (8). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/rose/rsdwnlnk.c b/rose/rsdwnlnk.c new file mode 100644 index 0000000..5729d99 --- /dev/null +++ b/rose/rsdwnlnk.c @@ -0,0 +1,272 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <syslog.h> + +#include <sys/time.h> +#include <sys/types.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> + +#include <config.h> + +#define AX25_HBIT 0x80 + +void alarm_handler(int sig) +{ +} + +int main(int argc, char **argv) +{ + unsigned char buffer[512], *addr; + fd_set read_fd; + int n = 0, s, addrlen, yes = 1; + struct full_sockaddr_ax25 axbind, axconnect; + struct sockaddr_rose rosesock, rosepeer; + + openlog("rsdwnlnk", LOG_PID, LOG_DAEMON); + + /* + * Arguments should be "rsdwnlnk ax25port ax25call" + */ + if (argc != 3) { + syslog(LOG_ERR, "invalid number of parameters\n"); + closelog(); + return 1; + } + + if (ax25_config_load_ports() == 0) { + syslog(LOG_ERR, "problem with axports file\n"); + closelog(); + return 1; + } + + addrlen = sizeof(struct sockaddr_rose); + + if (getsockname(STDIN_FILENO, (struct sockaddr *)&rosesock, &addrlen) == -1) { + syslog(LOG_ERR, "cannot getsockname - %s\n", strerror(errno)); + closelog(); + return 1; + } + + addrlen = sizeof(struct sockaddr_rose); + + if (getpeername(STDIN_FILENO, (struct sockaddr *)&rosepeer, &addrlen) == -1) { + syslog(LOG_ERR, "cannot getpeername - %s\n", strerror(errno)); + closelog(); + return 1; + } + + if (setsockopt(STDIN_FILENO, SOL_ROSE, ROSE_QBITINCL, &yes, sizeof(yes)) == -1) { + syslog(LOG_ERR, "cannot setsockopt(ROSE_QBITINCL) - %s\n", strerror(errno)); + closelog(); + return 1; + } + + /* + * Parse the passed values for correctness. + */ + axbind.fsa_ax25.sax25_family = AF_AX25; + axbind.fsa_ax25.sax25_ndigis = 1; + axbind.fsa_ax25.sax25_call = rosepeer.srose_call; + + if ((addr = ax25_config_get_addr(argv[1])) == NULL) { + syslog(LOG_ERR, "invalid AX.25 port name - %s\n", argv[1]); + closelog(); + return 1; + } + + if (ax25_aton_entry(addr, axbind.fsa_digipeater[0].ax25_call) == -1) { + syslog(LOG_ERR, "invalid AX.25 port callsign - %s\n", argv[1]); + closelog(); + return 1; + } + + axconnect.fsa_ax25.sax25_family = AF_AX25; + axconnect.fsa_ax25.sax25_call = rosesock.srose_call; + + /* + * The path at the far end has a digi in it. + */ + if (rosepeer.srose_ndigis == 1) { + axconnect.fsa_digipeater[n] = rosepeer.srose_digi; + axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT; + n++; + } + + /* + * Incoming call has a different DNIC + */ + if (memcmp(rosepeer.srose_addr.rose_addr, rosesock.srose_addr.rose_addr, 2) != 0) { + addr = rose_ntoa(&rosepeer.srose_addr); + addr[4] = '\0'; + if (ax25_aton_entry(addr, axconnect.fsa_digipeater[n].ax25_call) == -1) { + syslog(LOG_ERR, "invalid callsign - %s\n", addr); + closelog(); + return 1; + } + axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT; + n++; + } + + /* + * Put the remote address sans DNIC into the digi chain. + */ + addr = rose_ntoa(&rosepeer.srose_addr); + if (ax25_aton_entry(addr + 4, axconnect.fsa_digipeater[n].ax25_call) == -1) { + syslog(LOG_ERR, "invalid callsign - %s\n", addr + 4); + closelog(); + return 1; + } + axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT; + n++; + + /* + * And my local ROSE callsign. + */ + if (ax25_aton_entry(argv[2], axconnect.fsa_digipeater[n].ax25_call) == -1) { + syslog(LOG_ERR, "invalid callsign - %s\n", argv[2]); + closelog(); + return 1; + } + axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT; + n++; + + /* + * A digi has been specified for this end. + */ + if (rosesock.srose_ndigis == 1) { + axconnect.fsa_digipeater[n] = rosesock.srose_digi; + n++; + } + + axconnect.fsa_ax25.sax25_ndigis = n; + + addrlen = sizeof(struct full_sockaddr_ax25); + + /* + * Open the socket into the kernel. + */ + if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) { + syslog(LOG_ERR, "cannot open AX.25 socket, %s\n", strerror(errno)); + closelog(); + return 1; + } +#ifdef HAVE_AX25_IAMDIGI + if (setsockopt(s, SOL_AX25, AX25_IAMDIGI, &yes, sizeof(yes)) == -1) { + syslog(LOG_ERR, "cannot setsockopt(AX25_IAMDIGI), %s\n", strerror(errno)); + close(s); + closelog(); + return 1; + } +#endif /* HAVE_AX25_IAMDIGI */ +#ifdef HAVE_AX25_PIDINCL + if (setsockopt(s, SOL_AX25, AX25_PIDINCL, &yes, sizeof(yes)) == -1) { + syslog(LOG_ERR, "cannot setsockopt(AX25_PIDINCL), %s\n", strerror(errno)); + close(s); + closelog(); + return 1; + } +#endif /* HAVE_AX25_PIDINCL */ + /* + * Set our AX.25 callsign and AX.25 port callsign accordingly. + */ + if (bind(s, (struct sockaddr *)&axbind, addrlen) != 0) { + syslog(LOG_ERR, "cannot bind AX.25 socket, %s\n", strerror(errno)); + close(s); + closelog(); + return 1; + } + + /* + * If no response in 60 seconds, go away. + */ + alarm(60); + + signal(SIGALRM, alarm_handler); + + /* + * Lets try and connect to the far end. + */ + if (connect(s, (struct sockaddr *)&axconnect, addrlen) != 0) { + switch (errno) { + case ECONNREFUSED: + strcpy(buffer, "*** Connection refused\r"); + break; + case ENETUNREACH: + strcpy(buffer, "*** No known route\r"); + break; + case EINTR: + strcpy(buffer, "*** Connection timed out\r"); + break; + default: + sprintf(buffer, "ERROR: cannot connect to AX.25 callsign, %s\r", strerror(errno)); + break; + } + + close(s); + + write(STDOUT_FILENO, buffer, strlen(buffer)); + + sleep(20); + + return 0; + } + + /* + * We got there. + */ + alarm(0); + + strcpy(buffer, "*** Connected\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + + /* + * Loop until one end of the connection goes away. + */ + for (;;) { + FD_ZERO(&read_fd); + FD_SET(STDIN_FILENO, &read_fd); + FD_SET(s, &read_fd); + + select(s + 1, &read_fd, NULL, NULL, NULL); + + if (FD_ISSET(s, &read_fd)) { + if ((n = read(s, buffer + 2, 512)) == -1) + break; + if (buffer[2] == 0xF0) { + buffer[2] = 0; + write(STDOUT_FILENO, buffer + 2, n); + } else { + buffer[0] = 1; /* Set Q Bit on */ + buffer[1] = 0x7F; /* Q Bit escape */ + write(STDOUT_FILENO, buffer, n + 2); + } + } + + if (FD_ISSET(STDIN_FILENO, &read_fd)) { + if ((n = read(STDIN_FILENO, buffer, 512)) == -1) { + close(s); + break; + } + if (buffer[0] == 0) { /* Q Bit not set */ + buffer[0] = 0xF0; + write(s, buffer, n); + } else { + /* Lose the leading 0x7F */ + write(s, buffer + 2, n - 2); + } + } + } + + closelog(); + + return 0; +} diff --git a/rose/rsmemsiz.c b/rose/rsmemsiz.c new file mode 100644 index 0000000..6c1cec9 --- /dev/null +++ b/rose/rsmemsiz.c @@ -0,0 +1,204 @@ +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <time.h> +#include <sys/utsname.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +enum meminfo_row { meminfo_main = 0, + meminfo_swap }; + +enum meminfo_col { meminfo_total = 0, meminfo_used, meminfo_free, + meminfo_shared, meminfo_buffers, meminfo_cached +}; + +unsigned read_total_main(void); + +/* + * This code is slightly modified from the procps package. + */ + +#define UPTIME_FILE "/proc/uptime" +#define LOADAVG_FILE "/proc/loadavg" +#define MEMINFO_FILE "/proc/meminfo" + +static char buf[300]; + +/* This macro opens FILE only if necessary and seeks to 0 so that successive + calls to the functions are more efficient. It also reads the current + contents of the file into the global buf. +*/ +#define FILE_TO_BUF(FILE) { \ + static int n, fd = -1; \ + if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) { \ + fprintf(stdout, "ERROR: file %s, %s\r", FILE, strerror(errno)); \ + close(fd); \ + return 0; \ + } \ + lseek(fd, 0L, SEEK_SET); \ + if ((n = read(fd, buf, sizeof buf - 1)) < 0) { \ + fprintf(stdout, "ERROR: file %s, %s\r", FILE, strerror(errno)); \ + close(fd); \ + fd = -1; \ + return 0; \ + } \ + buf[n] = '\0'; \ +} + +#define SET_IF_DESIRED(x,y) if (x) *(x) = (y) /* evals 'x' twice */ + +int uptime(double *uptime_secs, double *idle_secs) { + double up=0, idle=0; + + FILE_TO_BUF(UPTIME_FILE) + if (sscanf(buf, "%lf %lf", &up, &idle) < 2) { + fprintf(stdout, "ERROR: Bad data in %s\r", UPTIME_FILE); + return 0; + } + SET_IF_DESIRED(uptime_secs, up); + SET_IF_DESIRED(idle_secs, idle); + return up; /* assume never be zero seconds in practice */ +} + +int loadavg(double *av1, double *av5, double *av15) { + double avg_1=0, avg_5=0, avg_15=0; + + FILE_TO_BUF(LOADAVG_FILE) + if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) { + fprintf(stdout, "ERROR: Bad data in %s\r", LOADAVG_FILE); + return 0; + } + SET_IF_DESIRED(av1, avg_1); + SET_IF_DESIRED(av5, avg_5); + SET_IF_DESIRED(av15, avg_15); + return 1; +} + +/* The following /proc/meminfo parsing routine assumes the following format: + [ <label> ... ] # header lines + [ <label> ] <num> [ <num> ... ] # table rows + [ repeats of above line ] + + Any lines with fewer <num>s than <label>s get trailing <num>s set to zero. + The return value is a NULL terminated unsigned** which is the table of + numbers without labels. Convenient enumeration constants for the major and + minor dimensions are available in the header file. Note that this version + requires that labels do not contain digits. It is readily extensible to + labels which do not *begin* with digits, though. +*/ + +#define MAX_ROW 3 /* these are a little liberal for flexibility */ +#define MAX_COL 7 + +unsigned** meminfo(void) { + static unsigned *row[MAX_ROW + 1]; /* row pointers */ + static unsigned num[MAX_ROW * MAX_COL]; /* number storage */ + char *p; + int i, j, k, l; + + FILE_TO_BUF(MEMINFO_FILE) + if (!row[0]) /* init ptrs 1st time through */ + for (i=0; i < MAX_ROW; i++) /* std column major order: */ + row[i] = num + MAX_COL*i; /* A[i][j] = A + COLS*i + j */ + p = buf; + for (i=0; i < MAX_ROW; i++) /* zero unassigned fields */ + for (j=0; j < MAX_COL; j++) + row[i][j] = 0; + for (i=0; i < MAX_ROW && *p; i++) { /* loop over rows */ + while(*p && !isdigit(*p)) p++; /* skip chars until a digit */ + for (j=0; j < MAX_COL && *p; j++) { /* scanf column-by-column */ + l = sscanf(p, "%u%n", row[i] + j, &k); + p += k; /* step over used buffer */ + if (*p == '\n' || l < 1) /* end of line/buffer */ + break; + } + } +/* row[i+1] = NULL; terminate the row list, currently unnecessary */ + return row; /* NULL return ==> error */ +} + + +/* + * by Heikki Hannikainen <hessu@pspt.fi> + * The following was mostly learnt from the procps package and the + * gnu sh-utils (mainly uname). + */ + +int main(int argc, char **argv) +{ + int upminutes, uphours, updays; + double uptime_secs, idle_secs; + double av[3]; + unsigned **mem; + char *p; + struct utsname name; + time_t t; + + fprintf(stdout, "Linux/ROSE 001. System parameters\r"); + + time(&t); + p = ctime(&t); + p[24] = '\r'; + fprintf(stdout, "System time: %s", p); + + if (uname(&name) == -1) + fprintf(stdout, "Cannot get system name\r"); + else { + fprintf(stdout, "Hostname: %s\r", name.nodename); + fprintf(stdout, "Operating system: %s %s (%s)\r", name.sysname, + name.release, name.machine); + } + + /* read and calculate the amount of uptime and format it nicely */ + uptime(&uptime_secs, &idle_secs); + updays = (int) uptime_secs / (60*60*24); + upminutes = (int) uptime_secs / 60; + uphours = upminutes / 60; + uphours = uphours % 24; + upminutes = upminutes % 60; + fprintf(stdout, "Uptime: "); + + if (updays) + fprintf(stdout, "%d day%s, ", updays, (updays != 1) ? "s" : ""); + + if (uphours) + fprintf(stdout, "%d hour%s ", uphours, (uphours != 1) ? "s" : ""); + fprintf(stdout, "%d minute%s\r", upminutes, (upminutes != 1) ? "s" : ""); + + loadavg(&av[0], &av[1], &av[2]); + fprintf(stdout, "Load average: %.2f, %.2f, %.2f\r", av[0], av[1], av[2]); + + if (!(mem = meminfo()) || mem[meminfo_main][meminfo_total] == 0) { + /* cannot normalize mem usage */ + fprintf(stdout, "Cannot get memory information!\r"); + } else { + fprintf(stdout, "Memory: %5d KB available, %5d KB used, %5d KB free\r", + mem[meminfo_main][meminfo_total] >> 10, + (mem[meminfo_main][meminfo_used] - + mem[meminfo_main][meminfo_buffers] - + mem[meminfo_total][meminfo_cached]) >> 10, + (mem[meminfo_main][meminfo_free] + + mem[meminfo_main][meminfo_buffers] + + mem[meminfo_total][meminfo_cached]) >> 10); + + fprintf(stdout, "Swap: %5d KB available, %5d KB used, %5d KB free\r", + mem[meminfo_swap][meminfo_total] >> 10, + mem[meminfo_swap][meminfo_used] >> 10, + mem[meminfo_swap][meminfo_free] >> 10); + } + + fprintf(stdout, "\r"); + fflush(stdout); + + while (1) { + if (read(STDIN_FILENO, av, 3) <= 0) + break; + } + + return 0; +} diff --git a/rose/rsparms.8 b/rose/rsparms.8 new file mode 100644 index 0000000..aeadc20 --- /dev/null +++ b/rose/rsparms.8 @@ -0,0 +1,64 @@ +.TH RSPARMS 8 "25 July 1997" Linux "Linux System Managers Manual" +.SH NAME +rsparms \- Configure the Rose interface. +.SH SYNOPSIS +.B rsparms -nodes add|del address[/mask] port neigh [digis...] +.LP +.B rsparms -nodes list +.LP +.B rsparms -call <callsign>|none +.LP +.B rsparms -version +.SH DESCRIPTION +.LP +This program is used to manipulate the routing tables of the Rose network +layer. To set up a new route to a Rose node in the routing tables you must +use the nodes option. All of the parameters are needed to add the node. It +is probably best to illustrate with an example: +.LP +.B rsparms -nodes add 2080192303 144 F1OAT-11 +.LP +This creates a new route to a distant node with the address 2080192303 and +the packets for that node should be sent on AX.25 port 144 to my immediate +neighbour F1OAT-11 without going through any digi-praters. For +example to set up the same node but via a digi-peater I would use: +.LP +.B rsparms -nodes add 2080192303 144 F1OAT-11 F6PRA-9 +.LP +It is also possible to remove a route to a distant node with the same +command except that the \(lqadd\(rq is replaced by a \(lqdel\(rq. The other +parameters must also be present. If the node has no other routes then the +node will be deleted, and the neighbour node that the connections go via may +also be deleted if no other node route uses it. +.LP +You may list the configured Rose routes using the following syntax: +.LP +.B rsparms -nodes list +.LP +This program may also be used to set up a common AX.25 level 2 callsign that +will be used for the ROSE node. By default no special level 2 callsign is +set, but setting it will replace any existing level 2 callsign and register +another one. Setting the callsign to \(lqnone\(rq will remove the level 2 +callsign. For example: +.LP +.B rsparms -call VK2KTJ-10 +.LP +would set the callsign used by Rose internode traffic to VK2KTJ-10. +.SH OPTIONS +.TP 10 +.BI \-version +Display the version information. +.SH FILES +.LP +/etc/ax25/axports +.br +/etc/ax25/rsports +.SH "SEE ALSO" +.BR call (1), +.BR rose (4), +.BR axports (5), +.BR rsports (5), +.BR rsctl (8), +.BR rsparms (8). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/rose/rsparms.c b/rose/rsparms.c new file mode 100644 index 0000000..86e0935 --- /dev/null +++ b/rose/rsparms.c @@ -0,0 +1,256 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/rsconfig.h> + +#include <config.h> + +#include "../pathnames.h" + +char nodes_usage[] = "usage: rsparms -node add|del nodeaddr[/mask] port neighbour [digis...]\n rsparms -node list\n"; + +/* print the Rose neighbour whose number is supplied */ +void printnb(char *neigh) +{ + FILE* fp; + char addr[10], callsign[10], port[10], digi[10]; + char buff[80]; + int args; + + if ((fp=fopen(PROC_RS_NEIGH_FILE,"r"))==NULL) { + fprintf(stderr,"rsparms: Couldn't open %s file\n",PROC_RS_NEIGH_FILE); + exit(1); + } + + while(fgets(buff, 80, fp)) { + addr[0]=(char)NULL; callsign[0]=(char)NULL; + port[0]=(char)NULL; digi[0]=(char)NULL; + + args=sscanf(buff,"%9s %9s %9s %*s %*s %*s %*s %*s %*s %9s",addr,callsign,port,digi); + + if (args==4) { /* We have a digi */ + if (strcmp(addr,neigh)==0) + printf("%-6s %-9s via %-9s",port,callsign,digi); + } else + if (args==3) { /* No digi */ + if (strcmp(addr,neigh)==0) + printf("%-6s %-9s",port,callsign); + } + } + fclose(fp); +} + +void nodes(int s, int argc, char *argv[]) +{ + struct rose_route_struct rs_node; + char *dev; + char *mask; + char nodeaddr[11]; + int i, n; + + FILE *fn; + char address[12], rmask[5], neigh1[10], neigh2[10], neigh3[10]; + char buff[80]; + int args; + + if (argc < 3) { + fprintf(stderr, nodes_usage); + exit(1); + } + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "rsparms: nodes: no AX.25 ports configured\n"); + exit(1); + } + + if (argv[2][0] != 'a' && argv[2][0] != 'd' && argv[2][0] != 'l') { + fprintf(stderr, "rsparms: nodes: invalid operation %s\n", argv[2]); + close(s); + exit(1); + } + + if (argv[2][0] == 'l') { + if ((fn=fopen(PROC_RS_NODES_FILE,"r"))==NULL) { + fprintf(stderr,"rsparms: Couldn't open %s file\n",PROC_RS_NODES_FILE); + exit(1); + } + + while(fgets(buff,80,fn)) { + args=sscanf(buff,"%10s %4s %*s %9s %9s %9s",address, rmask, neigh1, neigh2, neigh3); + if (strcmp(address,"address")==0) + continue; + + if (args>2) { + printf("%10s/%4s -> ",address,rmask); + printnb(neigh1); + putchar('\n'); + } + if (args>3) { + printf("%15s -> ",""); + printnb(neigh2); + putchar('\n'); + } + if (args>4) { + printf("%15s -> ",""); + printnb(neigh3); + putchar('\n'); + } + } + exit(0); + } + + if (argc < 6) { + fprintf(stderr, nodes_usage); + exit(1); + } + + if ((mask = strchr(argv[3], '/')) != NULL) { + *mask= (char)NULL; + mask++; + + if (sscanf(mask, "%hd", &rs_node.mask) != 1) { + fprintf(stderr, "rsparms: nodes: no mask supplied!\n"); + close(s); + exit(1); + } + + if (rs_node.mask > 10) { + fprintf(stderr, "rsparms: nodes: invalid mask size: %s\n", mask);; + close(s); + exit(1); + } + } else { + rs_node.mask = 10; + } + + /* Make all non significant digits equal to zero */ + strcpy(nodeaddr, argv[3]); + + for (i = rs_node.mask; i < 10; i++) + nodeaddr[i] = '0'; + + nodeaddr[i] = '\0'; + + if (rose_aton(nodeaddr, rs_node.address.rose_addr) != 0) { + fprintf(stderr, "rsparms: nodes: invalid address %s\n", nodeaddr); + close(s); + exit(1); + } + + if ((dev = ax25_config_get_dev(argv[4])) == NULL) { + fprintf(stderr, "rsparms: nodes: invalid port name - %s\n", argv[4]); + close(s); + exit(1); + } + + strcpy(rs_node.device, dev); + + if (ax25_aton_entry(argv[5], rs_node.neighbour.ax25_call) != 0) { + fprintf(stderr, "rsparms: nodes: invalid callsign %s\n", argv[5]); + close(s); + exit(1); + } + + for (i = 6, n = 0; i < argc && n < AX25_MAX_DIGIS; i++, n++) { + if (ax25_aton_entry(argv[i], rs_node.digipeaters[n].ax25_call) != 0) { + fprintf(stderr, "rsparms: nodes: invalid callsign %s\n", argv[i]); + close(s); + exit(1); + } + } + + rs_node.ndigis = n; + + if (argv[2][0] == 'a') { + if (ioctl(s, SIOCADDRT, &rs_node) == -1) { + perror("rsparms: SIOCADDRT"); + close(s); + exit(1); + } + } else { + if (ioctl(s, SIOCDELRT, &rs_node) == -1) { + perror("rsparms: SIOCDELRT"); + close(s); + exit(1); + } + } +} + + + + +int main(int argc, char *argv[]) +{ + ax25_address rose_call; + int s = 0; + + if (argc == 1) { + fprintf(stderr, "usage: rsparms -call|-nodes|-version ...\n"); + return 1; + } + + if (strncmp(argv[1], "-v", 2) == 0) { + printf("rsparms: %s\n", VERSION); + return 0; + } + + if (strncmp(argv[1], "-c", 2) == 0) { + if (argc < 3) { + fprintf(stderr, "usage: rsparms -call <callsign>|none\n"); + return 1; + } + + if (strcmp(argv[2], "none") != 0) { + if (ax25_aton_entry(argv[2], rose_call.ax25_call) == -1) { + fprintf(stderr, "rsparms: invalid callsign %s\n", argv[2]); + return 1; + } + } else { + rose_call = null_ax25_address; + } + + if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) { + perror("rsparms: socket"); + return 1; + } + + if (ioctl(s, SIOCRSL2CALL, &rose_call) == -1) { + perror("rsparms: ioctl"); + close(s); + return 1; + } + + close(s); + + return 0; + } + + if (strncmp(argv[1], "-n", 2) == 0) { + + if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) { + perror("rsparms: socket"); + return 1; + } + nodes(s, argc, argv); + close(s); + return 0; + } + + fprintf(stderr, "usage: rsparms -call|-nodes|-version ...\n"); + + close(s); + + return 1; +} diff --git a/rose/rsports b/rose/rsports new file mode 100644 index 0000000..8be51a0 --- /dev/null +++ b/rose/rsports @@ -0,0 +1,7 @@ +# /etc/ax25/rsports +# +# The format of this file is: +# +# name address description +# +rose 2080192203 Rose port diff --git a/rose/rsports.5 b/rose/rsports.5 new file mode 100644 index 0000000..44ce54e --- /dev/null +++ b/rose/rsports.5 @@ -0,0 +1,52 @@ +.TH RSPORTS 5 "27 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +rsports \- Rose port configuration file. +.SH DESCRIPTION +.LP +.B Rsports +is an ASCII file that contains information about each of the Rose +ports that are to be used. When dealing with a Rose utility such as +.B call, +it takes an optional argument that is the port name. This port name is a +reference to the line within +.B rsports, +which has the same name. The information on each line contains +enough information to bind the command to a particular Rose +interface, this binding is done by matching the address on the line in +.B rsports +with the address of the port set by +.B ifconfig +or +.B rsattach. +.LP +The +.B rsports +file may contain comments that begin with a # in the first column, or a port +description in the following format, each field being delimited by white space: +.sp +.RS +name address description +.RE +.sp +The field descriptions are: +.sp +.RS +.TP 14 +.B name +this is the unique Rose port identifier. +.TP 14 +.B address +the address of the Rose interface to bind to. +.TP 14 +.B description +a free format description of this interface, this field extends to the end +of the line. It may contain spaces. +.RE +.SH FILES +.LP +/etc/ax25/rsports +.SH "SEE ALSO" +.BR call (1), +.BR rose (4), +.BR ifconfig (8), +.BR rsparms (8). diff --git a/rose/rsuplnk.8 b/rose/rsuplnk.8 new file mode 100644 index 0000000..b9a65f1 --- /dev/null +++ b/rose/rsuplnk.8 @@ -0,0 +1,63 @@ +.TH RSUPLNK 8 "29 April 1997" Linux "Linux Programmer's Manual" +.SH NAME +rsuplnk \- User entry into the ROSE network. +.SH SYNOPSIS +.B rsuplnk [-q] <port> +.SH DESCRIPTION +.LP +The +.B rsuplnk +program allows a user to gain entry into the ROSE network using the standard +pseudo-digipeating method. Recent Linux kernels are aware of this form +of operation and the +.B ax25d +program can listen for such connections. The normal mode of operation of a +ROSE switch is to have one ROSE address (ie port) per physical AX.25 port. +Therefore ROSE users coming in on a given AX.25 port will appear as if they +come from the associated ROSE port. This is the reason for the need for a +ROSE port as an argument. +.LP +To use +.B rsuplnk +you need an entry in +.B ax25d.conf +to listen for incoming connections. In the example below, I will be +listening for ROSE connections on my AX.25 port 144 using the callsign +KE4GAJ-10 and the ROSE port associated with the AX.25 port is rs144. +.LP +# +.br +[KE4GAJ-10* VIA 144] +.br +NOCALL * * * * * * L +.br +default * * * * * * - root /usr/sbin/rsuplnk rsuplnk rs144 +.br +# +.LP +There would typically be one +.B rsuplnk +per user access AX.25 port. The associated program for exiting a ROSE +network is +.B rsdwnlnk. +.LP +All errors generated by +.B rsuplnk +are written to the system debug log file. +.SH OPTIONS +.TP 8 +.BI \-q +Supresses the messages generated by +.B rsuplnk +when making the connection. +.SH FILES +.br +/etc/ax25/rsports +.SH "SEE ALSO" +.BR rose (4), +.BR ax25d.conf (5), +.BR ax25d (8), +.BR rsdwnlnk (8), +.BR rose_call (8). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/rose/rsuplnk.c b/rose/rsuplnk.c new file mode 100644 index 0000000..a024e20 --- /dev/null +++ b/rose/rsuplnk.c @@ -0,0 +1,288 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <syslog.h> + +#include <sys/time.h> +#include <sys/types.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/rsconfig.h> + +#include <config.h> + +void alarm_handler(int sig) +{ +} + +int main(int argc, char **argv) +{ + unsigned char buffer[512], *addr, *p; + char rose_address[11]; + fd_set read_fd; + int n, s, dnicindex = -1, addrindex = -1; + int addrlen, yes = 1, verbose = 1; + struct sockaddr_rose rosebind, roseconnect; + struct full_sockaddr_ax25 ax25sock, ax25peer; + + openlog("rsuplnk", LOG_PID, LOG_DAEMON); + + /* + * Arguments should be "rsuplnk [-q] roseport" + */ + if (argc > 2 && strcmp(argv[1], "-q") == 0) { + verbose = 0; + --argc; + ++argv; + } + + if (argc != 2) { + syslog(LOG_ERR, "invalid number of parameters\n"); + closelog(); + return 1; + } + + if (rs_config_load_ports() == 0) { + syslog(LOG_ERR, "problem with rsports file\n"); + closelog(); + return 1; + } + + addrlen = sizeof(struct full_sockaddr_ax25); + + if (getsockname(STDIN_FILENO, (struct sockaddr *)&ax25sock, &addrlen) == -1) { + syslog(LOG_ERR, "cannot getsockname, %s\n", strerror(errno)); + closelog(); + return 1; + } + + addrlen = sizeof(struct full_sockaddr_ax25); + + if (getpeername(STDIN_FILENO, (struct sockaddr *)&ax25peer, &addrlen) == -1) { + syslog(LOG_ERR, "cannot getpeername, %s\n", strerror(errno)); + closelog(); + return 1; + } +#ifdef HAVE_AX25_PIDINCL + if (setsockopt(STDIN_FILENO, SOL_AX25, AX25_PIDINCL, &yes, sizeof(yes)) == -1) { + syslog(LOG_ERR, "cannot setsockopt(AX25_PIDINCL) - %s\n", strerror(errno)); + closelog(); + return 1; + } +#endif /* HAVE_AX25_PIDINCL */ + roseconnect.srose_family = rosebind.srose_family = AF_ROSE; + roseconnect.srose_ndigis = rosebind.srose_ndigis = 0; + addrlen = sizeof(struct sockaddr_rose); + + if ((addr = rs_config_get_addr(argv[1])) == NULL) { + syslog(LOG_ERR, "invalid Rose port name - %s\n", argv[1]); + closelog(); + return 1; + } + + if (rose_aton(addr, rosebind.srose_addr.rose_addr) == -1) { + syslog(LOG_ERR, "invalid ROSE port address - %s\n", argv[1]); + closelog(); + return 1; + } + + /* + * Copy our DNIC in as default. + */ + memset(rose_address, 0x00, 11); + memcpy(rose_address, addr, 4); + + for (n = 0; n < ax25peer.fsa_ax25.sax25_ndigis; n++) { + addr = ax25_ntoa(&ax25peer.fsa_digipeater[n]); + + if (strspn(addr, "0123456789-") == strlen(addr)) { + if ((p = strchr(addr, '-')) != NULL) + *p = '\0'; + switch (strlen(addr)) { + case 4: + memcpy(rose_address + 0, addr, 4); + dnicindex = n; + break; + case 6: + memcpy(rose_address + 4, addr, 6); + addrindex = n; + break; + default: + break; + } + } + } + + /* + * The user didn't give an address. + */ + if (addrindex == -1) { + strcpy(buffer, "*** No ROSE address given\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + sleep(20); + closelog(); + return 1; + } + + if (rose_aton(rose_address, roseconnect.srose_addr.rose_addr) == -1) { + syslog(LOG_ERR, "invalid Rose address - %s\n", argv[4]); + closelog(); + return 1; + } + + rosebind.srose_call = ax25peer.fsa_ax25.sax25_call; + + roseconnect.srose_call = ax25sock.fsa_ax25.sax25_call; + + /* + * A far end digipeater was specified. + */ + if (addrindex > 0) { + roseconnect.srose_ndigis = 1; + roseconnect.srose_digi = ax25peer.fsa_digipeater[addrindex - 1]; + } + + /* + * Check for a local digipeater. + */ + if (dnicindex != -1) { + if (ax25peer.fsa_ax25.sax25_ndigis - dnicindex > 2) { + rosebind.srose_ndigis = 1; + rosebind.srose_digi = ax25peer.fsa_digipeater[dnicindex + 2]; + } + } else { + if (ax25peer.fsa_ax25.sax25_ndigis - addrindex > 2) { + rosebind.srose_ndigis = 1; + rosebind.srose_digi = ax25peer.fsa_digipeater[addrindex + 2]; + } + } + + /* + * Open the socket into the kernel. + */ + if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) { + syslog(LOG_ERR, "cannot open ROSE socket, %s\n", strerror(errno)); + closelog(); + return 1; + } + + /* + * Set our AX.25 callsign and Rose address accordingly. + */ + if (bind(s, (struct sockaddr *)&rosebind, addrlen) != 0) { + syslog(LOG_ERR, "cannot bind ROSE socket, %s\n", strerror(errno)); + closelog(); + close(s); + return 1; + } + + if (setsockopt(s, SOL_ROSE, ROSE_QBITINCL, &yes, sizeof(yes)) == -1) { + syslog(LOG_ERR, "cannot setsockopt(ROSE_QBITINCL) - %s\n", strerror(errno)); + closelog(); + close(s); + return 1; + } + + if (verbose) { + strcpy(buffer, "*** Connection in progress\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + } + + /* + * If no response in 5 minutes, go away. + */ + alarm(300); + + signal(SIGALRM, alarm_handler); + + /* + * Lets try and connect to the far end. + */ + if (connect(s, (struct sockaddr *)&roseconnect, addrlen) != 0) { + switch (errno) { + case ECONNREFUSED: + strcpy(buffer, "*** Disconnected - 0100 - Number Busy\r"); + break; + case ENETUNREACH: + strcpy(buffer, "*** Disconnected - 0D00 - Not Obtainable\r"); + break; + case EINTR: + strcpy(buffer, "*** Disconnected - 3900 - Ship Absent\r"); + break; + default: + sprintf(buffer, "*** Disconnected - %d - %s\r", errno, strerror(errno)); + break; + } + + close(s); + + if (verbose) { + write(STDOUT_FILENO, buffer, strlen(buffer)); + sleep(20); + } + + return 0; + } + + /* + * We got there. + */ + alarm(0); + + if (verbose) { + strcpy(buffer, "*** Connected\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + } + + /* + * Loop until one end of the connection goes away. + */ + for (;;) { + FD_ZERO(&read_fd); + FD_SET(STDIN_FILENO, &read_fd); + FD_SET(s, &read_fd); + + select(s + 1, &read_fd, NULL, NULL, NULL); + + if (FD_ISSET(s, &read_fd)) { + if ((n = read(s, buffer, 512)) == -1) { + strcpy(buffer, "\r*** Disconnected - 0000 - DTE Originated\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + break; + } + if (buffer[0] == 0) { /* Q Bit not set */ + buffer[0] = 0xF0; + write(STDOUT_FILENO, buffer, n); + } else { + /* Lose the leading 0x7F */ + write(STDOUT_FILENO, buffer + 2, n - 2); + } + } + + if (FD_ISSET(STDIN_FILENO, &read_fd)) { + if ((n = read(STDIN_FILENO, buffer + 2, 512)) == -1) { + close(s); + break; + } + if (buffer[2] == 0xF0) { + buffer[2] = 0; + write(s, buffer + 2, n); + } else { + buffer[0] = 1; /* Set Q bit on */ + buffer[1] = 0x7F; /* PID Escape */ + write(s, buffer, n + 2); + } + } + } + + closelog(); + + return 0; +} diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/tcpip/Makefile.am b/tcpip/Makefile.am new file mode 100644 index 0000000..d047ac5 --- /dev/null +++ b/tcpip/Makefile.am @@ -0,0 +1,23 @@ + +etcfiles = rip98.conf ttylinkd.conf +etcdir = $(sysconfdir)/ax25 + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + +sbin_PROGRAMS = rip98d ttylinkd + +man_MANS = rip98.conf.5 rip98d.8 ttylinkd.conf.5 ttylinkd.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +rip98d_SOURCES = \ + rip98d.c \ + rip98r.c \ + rip98t.c \ + rip98d.h + diff --git a/tcpip/Makefile.in b/tcpip/Makefile.in new file mode 100644 index 0000000..90da959 --- /dev/null +++ b/tcpip/Makefile.in @@ -0,0 +1,386 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +etcfiles = rip98.conf ttylinkd.conf +etcdir = $(sysconfdir)/ax25 + +sbin_PROGRAMS = rip98d ttylinkd + +man_MANS = rip98.conf.5 rip98d.8 ttylinkd.conf.5 ttylinkd.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +rip98d_SOURCES = rip98d.c rip98r.c rip98t.c rip98d.h + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +rip98d_OBJECTS = rip98d.o rip98r.o rip98t.o +rip98d_LDADD = $(LDADD) +rip98d_DEPENDENCIES = +rip98d_LDFLAGS = +ttylinkd_SOURCES = ttylinkd.c +ttylinkd_OBJECTS = ttylinkd.o +ttylinkd_LDADD = $(LDADD) +ttylinkd_DEPENDENCIES = +ttylinkd_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man5dir = $(mandir)/man5 +man8dir = $(mandir)/man8 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(rip98d_SOURCES) ttylinkd.c +OBJECTS = $(rip98d_OBJECTS) ttylinkd.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps tcpip/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +rip98d: $(rip98d_OBJECTS) $(rip98d_DEPENDENCIES) + @rm -f rip98d + $(LINK) $(rip98d_LDFLAGS) $(rip98d_OBJECTS) $(rip98d_LDADD) $(LIBS) + +ttylinkd: $(ttylinkd_OBJECTS) $(ttylinkd_DEPENDENCIES) + @rm -f ttylinkd + $(LINK) $(ttylinkd_LDFLAGS) $(ttylinkd_OBJECTS) $(ttylinkd_LDADD) $(LIBS) + +install-man5: + $(mkinstalldirs) $(DESTDIR)$(man5dir) + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \ + done + +uninstall-man5: + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \ + rm -f $(DESTDIR)$(man5dir)/$$inst; \ + done + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man5 install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man5 uninstall-man8 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = tcpip + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +rip98d.o: rip98d.c ../config.h ../pathnames.h rip98d.h +rip98r.o: rip98r.c rip98d.h +rip98t.o: rip98t.c rip98d.h +ttylinkd.o: ttylinkd.c ../pathnames.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man5 \ + $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile install-man5 uninstall-man5 \ +install-man8 uninstall-man8 install-man uninstall-man tags \ +mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \ +distdir info-am info dvi-am dvi check check-am installcheck-am \ +installcheck install-exec-am install-exec install-data-am install-data \ +install-am install uninstall-am uninstall all-redirect all-am all \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tcpip/rip98.conf b/tcpip/rip98.conf new file mode 100644 index 0000000..3574d56 --- /dev/null +++ b/tcpip/rip98.conf @@ -0,0 +1 @@ +44.131.4.7 diff --git a/tcpip/rip98.conf.5 b/tcpip/rip98.conf.5 new file mode 100644 index 0000000..7e2d3a4 --- /dev/null +++ b/tcpip/rip98.conf.5 @@ -0,0 +1,19 @@ +.TH RIP98.CONF 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +rip98.conf \- control RIP98 routing messages. +.SH DESCRIPTION +.LP +.B Rip98.conf +controls the transmission of RIP98 routing messages. RIP98 is not a +broadcast protocol but instead is transmitted individually to each other +known RIP98 capable system. The list of these systems is kept in the RIP98 +configuration file as a list of host names or IP numbers that are to be +transmitted to, and messages received from. +.SH FILES +.LP +/etc/ax25/rip98.conf +.SH "SEE ALSO" +.BR arp (8), +.BR ifconfig (8), +.BR rip98d (8), +.BR route (8). diff --git a/tcpip/rip98d.8 b/tcpip/rip98d.8 new file mode 100644 index 0000000..0ee12dc --- /dev/null +++ b/tcpip/rip98d.8 @@ -0,0 +1,59 @@ +.TH RIP98D 8 "20 August 1996" Linux "Linux System Managers Manual" +.SH NAME +rip98d \- Send and receive RIP98 routing messages +.SH SYNOPSIS +.B rip98d [-d] [-l] [-r] [-t interval] [-v] +.SH DESCRIPTION +.LP +The RIP98 routing protocol was devised by John Wiseman G8BPQ as an +alternative to both traditional RIP and RSPF for use in an RF environment. +Its main advantage is that each routing element only takes six bytes and is +therefore much more efficient in terms of bandwidth than other routing +protocols. +.LP +In operation +.B rip98d +that each neighbour that also uses RIP98 must be listed. RIP98 is not a +broadcast protocol and each neighbour is individually contacted. Any +incoming RIP98 message is also validated against this list. The list of +neighbours is held in /etc/ax25/rip98.conf, and each line is +either the name or the dotted decimal IP address of the neighbour. +.LP +The time interval between RIP98 transmissions is set to one hour by default +but other intervals can be set with the \-t option. The routes advertised +and received can be restricted by the \-r option which only allows +processing of ampr.org addresses. At present +.B rip98d +is under development and any feedback on its operation would be welcome. +.SH OPTIONS +.TP 16 +.BI \-d +Set debugging on. Information is only output if the logging option is also +enabled. +.TP 16 +.BI \-l +Enable logging to the system log, the default is off. +.TP 16 +.BI \-r +Restricts the transmitting and receiving of routes to ampr.org (44.x.x.x) +addresses only. +.TP 16 +.BI "\-t interval" +The time interval between routing broadcasts, in minutes. The default is 60 +minutes. +.TP 16 +.BI \-v +Display the version. +.SH FILES +.nf +/proc/net/route +.br +/etc/ax25/rip98.conf +.fi +.SH "SEE ALSO" +.BR rip98.conf (5), +.BR arp (8), +.BR ifconfig (8), +.BR route (8). +.SH AUTHOR +Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk> diff --git a/tcpip/rip98d.c b/tcpip/rip98d.c new file mode 100644 index 0000000..78851cd --- /dev/null +++ b/tcpip/rip98d.c @@ -0,0 +1,360 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <netdb.h> +#include <syslog.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <net/route.h> + +#include <netax25/daemon.h> + +#include <config.h> + +#include "../pathnames.h" +#include "rip98d.h" + +struct dest_struct dest_list[50]; + +int dest_count = 0; + +int debug = FALSE; +int restrict = FALSE; +int logging = FALSE; + +struct route_struct *first_route = NULL; + +static struct mask_struct { + unsigned long int mask; + unsigned int bits; +} mask_table[] = { + {0xFFFFFFFF, 32}, + {0xFFFFFFFE, 31}, + {0xFFFFFFFC, 30}, + {0xFFFFFFF8, 29}, + {0xFFFFFFF0, 28}, + {0xFFFFFFE0, 27}, + {0xFFFFFFC0, 26}, + {0xFFFFFF80, 25}, + {0xFFFFFF00, 24}, + {0xFFFFFE00, 23}, + {0xFFFFFC00, 22}, + {0xFFFFF800, 21}, + {0xFFFFF000, 20}, + {0xFFFFE000, 19}, + {0xFFFFC000, 18}, + {0xFFFF8000, 17}, + {0xFFFF0000, 16}, + {0xFFFE0000, 15}, + {0xFFFC0000, 14}, + {0xFFF80000, 13}, + {0xFFF00000, 12}, + {0xFFE00000, 11}, + {0xFFC00000, 10}, + {0xFF800000, 9}, + {0xFF000000, 8}, + {0xFE000000, 7}, + {0xFC000000, 6}, + {0xF8000000, 5}, + {0xF0000000, 4}, + {0xE0000000, 3}, + {0xC0000000, 2}, + {0x80000000, 1}, + {0x00000000, 0}, +}; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +unsigned int mask2bits(unsigned long int mask) +{ + struct mask_struct *t; + + for (t = mask_table; t->mask != 0; t++) + if (mask == t->mask) + return t->bits; + + return 0; +} + +unsigned long int bits2mask(unsigned int bits) +{ + struct mask_struct *t; + + for (t = mask_table; t->mask != 0; t++) + if (bits == t->bits) + return htonl(t->mask); + + return 0; +} + +static unsigned long int hex2intrev(char *buffer) +{ + unsigned long int result = 0L; + + if (buffer[0] >= 'A') + result += (buffer[0] - 'A' + 10) * 16; + else + result += (buffer[0] - '0') * 16; + + if (buffer[1] >= 'A') + result += buffer[1] - 'A' + 10; + else + result += buffer[1] - '0'; + + if (buffer[2] >= 'A') + result += (buffer[2] - 'A' + 10) * 16 * 16 * 16; + else + result += (buffer[2] - '0') * 16 * 16 * 16; + + if (buffer[3] >= 'A') + result += (buffer[3] - 'A' + 10) * 16 * 16; + else + result += (buffer[3] - '0') * 16 * 16; + + if (buffer[4] >= 'A') + result += (buffer[4] - 'A' + 10) * 16 * 16 * 16 * 16 * 16; + else + result += (buffer[4] - '0') * 16 * 16 * 16 * 16 * 16; + + if (buffer[5] >= 'A') + result += (buffer[5] - 'A' + 10) * 16 * 16 * 16 * 16; + else + result += (buffer[5] - '0') * 16 * 16 * 16 * 16; + + if (buffer[6] >= 'A') + result += (buffer[6] - 'A' + 10) * 16 * 16 * 16 * 16 * 16 * 16 * 16; + else + result += (buffer[6] - '0') * 16 * 16 * 16 * 16 * 16 * 16 * 16; + + if (buffer[7] >= 'A') + result += (buffer[7] - 'A' + 10) * 16 * 16 * 16 * 16 * 16 * 16; + else + result += (buffer[7] - '0') * 16 * 16 * 16 * 16 * 16 * 16; + + return result; +} + +static int read_routes(void) +{ + struct route_struct *route, *temp; + char buffer[1023], iface[16], net_addr[64], gate_addr[64], mask_addr[64]; + int n, iflags, refcnt, use, metric, mss, window; + struct in_addr address; + unsigned long int netmask; + unsigned long int network; + FILE *fp; + + if (first_route != NULL) { + route = first_route; + + while (route != NULL) { + temp = route->next; + free(route); + route = temp; + } + + first_route = NULL; + } + + if ((fp = fopen(PROC_IP_ROUTE_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "error cannot open %s\n", PROC_IP_ROUTE_FILE); + return FALSE; + } + + while (fgets(buffer, 1023, fp) != NULL) { + n = sscanf(buffer, "%s %s %s %X %d %d %d %s %d %d\n", + iface, net_addr, gate_addr, &iflags, &refcnt, &use, + &metric, mask_addr, &mss, &window); + + if (n != 10) + continue; + + address.s_addr = htonl(hex2intrev(net_addr)); + netmask = mask2bits(hex2intrev(mask_addr)); + + network = inet_netof(address); + + if (network == 0 || network == 127) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route to %s/%ld - should not be propogated\n", inet_ntoa(address), netmask); + continue; + } + + if (restrict) { + if (inet_netof(address) != 44) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route to %s/%ld - not ampr.org\n", inet_ntoa(address), netmask); + continue; + } + } + + if ((route = malloc(sizeof(struct route_struct))) == NULL) { + if (logging) + syslog(LOG_ERR, "out of memory !\n"); + return FALSE; + } + + route->addr = address; + route->bits = netmask; + route->metric = metric; + route->action = (iflags & RTF_DYNAMIC) ? ORIG_ROUTE : FIXED_ROUTE; + + route->next = first_route; + first_route = route; + } + + fclose(fp); + + return TRUE; +} + +static int load_dests(void) +{ + struct hostent *host; + char buffer[255], *s; + FILE *fp; + + if ((fp = fopen(CONF_RIP98D_FILE, "r")) == NULL) { + fprintf(stderr, "rip98d: cannot open config file\n"); + return FALSE; + } + + while (fgets(buffer, 255, fp) != NULL) { + if ((s = strchr(buffer, '\n')) != NULL) *s = '\0'; + + if ((host = gethostbyname(buffer)) == NULL) { + fprintf(stderr, "rip98d: cannot resolve name %s\n", buffer); + fclose(fp); + return FALSE; + } + + bcopy(host->h_addr, (char *)&dest_list[dest_count].dest_addr, host->h_length); + dest_count++; + } + + fclose(fp); + + if (dest_count == 0) + return FALSE; + + return TRUE; +} + +int main(int argc, char **argv) +{ + int s, i; + struct sockaddr_in loc_addr; + struct timeval timeout; + time_t timenow, timelast = 0; + int interval = 3600; + fd_set fdset; + + if (!load_dests()) { + fprintf(stderr, "rip98d: no destination routers defined\n"); + return 1; + } + + while ((i = getopt(argc, argv, "dlrt:v")) != -1) { + switch (i) { + case 'd': + debug = TRUE; + break; + case 'l': + logging = TRUE; + break; + case 'r': + restrict = TRUE; + break; + case 't': + interval = atoi(optarg) * 60; + if (interval < 60 || interval > 7200) { + fprintf(stderr, "rip98d: invalid time interval\n"); + return 1; + } + break; + case 'v': + printf("rip98d: %s\n", VERSION); + return 0; + case ':': + fprintf(stderr, "rip98d: invalid time interval\n"); + return 1; + case '?': + fprintf(stderr, "usage: rip98d [-d] [-l] [-r] [-t interval] [-v]\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("rip98d: socket"); + return 1; + } + + bzero((char *)&loc_addr, sizeof(loc_addr)); + loc_addr.sin_family = AF_INET; + loc_addr.sin_addr.s_addr = htonl(INADDR_ANY); + loc_addr.sin_port = htons(RIP_PORT); + + if (bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) { + perror("rip98d: bind"); + close(s); + return 1; + } + + if (!daemon_start(FALSE)) { + fprintf(stderr, "rip98d: cannot become a daemon\n"); + close(s); + return 1; + } + + if (logging) { + openlog("rip98d", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + FD_ZERO(&fdset); + FD_SET(s, &fdset); + + timeout.tv_sec = 60; + timeout.tv_usec = 0; + + select(s + 1, &fdset, NULL, NULL, &timeout); + + if (!read_routes()) { + if (logging) + closelog(); + return 1; + } + + if (FD_ISSET(s, &fdset)) + receive_routes(s); + + time(&timenow); + + if ((timenow - timelast) > interval) { + timelast = timenow; + if (first_route != NULL) + transmit_routes(s); + } + } +} diff --git a/tcpip/rip98d.h b/tcpip/rip98d.h new file mode 100644 index 0000000..fb00a7d --- /dev/null +++ b/tcpip/rip98d.h @@ -0,0 +1,58 @@ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define RIP_PORT 520 + +#define RIPCMD_REQUEST 1 +#define RIPCMD_RESPONSE 2 + +#define RIP98_INFINITY 16 + +#define RIP_VERSION_98 98 + +#define RIP_AF_INET 2 + +#define RIP98_HEADER 4 +#define RIP98_ENTRY 6 + +#define RIP98_MAX_FRAME 30 + +struct route_struct { + struct route_struct *next; + struct in_addr addr; + int bits; + int metric; +#define ORIG_ROUTE 0 +#define FIXED_ROUTE 1 +#define NEW_ROUTE 2 +#define DEL_ROUTE 3 + int action; +}; + +extern struct route_struct *first_route; + +struct dest_struct { + struct in_addr dest_addr; +}; + +extern struct dest_struct dest_list[]; + +extern int dest_count; + +extern int debug; +extern int restrict; +extern int logging; + +/* In rip98d.c */ +extern unsigned int mask2bits(unsigned long int); +extern unsigned long int bits2mask(unsigned int); + +/* In rip98t.c */ +extern void transmit_routes(int); + +/* In rip98r.c */ +extern void receive_routes(int); diff --git a/tcpip/rip98r.c b/tcpip/rip98r.c new file mode 100644 index 0000000..765e786 --- /dev/null +++ b/tcpip/rip98r.c @@ -0,0 +1,255 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <net/route.h> + + +#include "rip98d.h" + +#define UNMATCH_ROUTE 0 +#define NO_ROUTE 1 +#define REPLACE_ROUTE 2 +#define ADDITIONAL_ROUTE 3 + +static int cmp_route(struct route_struct *route, struct in_addr addr, int bits, int metric) +{ + unsigned long int old_mask, new_mask; + unsigned long int old_addr, new_addr; + + old_mask = ntohl(bits2mask(route->bits)); + new_mask = ntohl(bits2mask(bits)); + + old_addr = route->addr.s_addr; + new_addr = addr.s_addr; + + if (bits < route->bits) { + new_addr = ntohl(new_addr) & new_mask; + old_addr = ntohl(old_addr) & new_mask; + } else { + new_addr = ntohl(new_addr) & old_mask; + old_addr = ntohl(old_addr) & old_mask; + } + + if (route->action == DEL_ROUTE || route->action == NEW_ROUTE) + return UNMATCH_ROUTE; + + if (old_addr != new_addr) + return UNMATCH_ROUTE; + + if (route->metric <= metric) + return NO_ROUTE; + + if (debug && logging) { + syslog(LOG_DEBUG, "comparing old: %s/%d to\n", inet_ntoa(route->addr), route->bits); + syslog(LOG_DEBUG, " new: %s/%d\n", inet_ntoa(addr), bits); + } + + if (route->bits <= bits) { + if (route->action == ORIG_ROUTE) { + if (debug && logging) + syslog(LOG_DEBUG, " better route, replacing existing route\n"); + return REPLACE_ROUTE; + } else { + if (debug && logging) + syslog(LOG_DEBUG, " better route, adding additional route\n"); + return ADDITIONAL_ROUTE; + } + } else { + if (debug && logging) + syslog(LOG_DEBUG, " better route, adding additional route\n"); + return ADDITIONAL_ROUTE; + } +} + +void receive_routes(int s) +{ + unsigned char message[500], *p; + struct sockaddr_in rem_addr; + struct in_addr addr; + struct route_struct *route, *new; + struct sockaddr_in trg; + struct rtentry rt; + unsigned long int netmask; + unsigned long int network; + int bits, metric; + int size, found, matched; + int mess_len; + int i; + + size = sizeof(struct sockaddr_in); + + mess_len = recvfrom(s, message, 500, 0, (struct sockaddr *)&rem_addr, &size); + + if (message[0] != RIPCMD_RESPONSE || message[1] != RIP_VERSION_98) { + if (debug && logging) { + syslog(LOG_DEBUG, "invalid RIP98 header received\n"); + syslog(LOG_DEBUG, " cmd: %d vers: %d\n", message[0], message[1]); + } + return; + } + + for (found = FALSE, i = 0; i < dest_count; i++) { + if (rem_addr.sin_addr.s_addr == dest_list[i].dest_addr.s_addr) { + found = TRUE; + break; + } + } + + if (!found) { + if (debug && logging) + syslog(LOG_DEBUG, "RIP98 message from unknown address %s\n", inet_ntoa(rem_addr.sin_addr)); + return; + } + + if (debug && logging) + syslog(LOG_DEBUG, "RIP98 message received from %s\n", inet_ntoa(rem_addr.sin_addr)); + + for (p = message + RIP98_HEADER; p < message + mess_len; p += RIP98_ENTRY) { + bcopy((char *)p, (char *)&addr, sizeof(addr)); + bits = p[4]; + metric = p[5]; + + network = inet_netof(addr); + + if (network == 0 || network == 127) { + if (debug && logging) + syslog(LOG_DEBUG, " route to %s/%d metric %d - rejected\n", inet_ntoa(addr), bits, metric); + continue; + } + + if (restrict) { + if (network != 44) { + if (debug && logging) + syslog(LOG_DEBUG, " route to %s/%d metric %d - rejected\n", inet_ntoa(addr), bits, metric); + continue; + } + } + + if (debug && logging) + syslog(LOG_DEBUG, " route to %s/%d metric %d\n", inet_ntoa(addr), bits, metric); + + metric++; + + if (metric > RIP98_INFINITY) + metric = RIP98_INFINITY; + + found = FALSE; + matched = FALSE; + + for (route = first_route; route != NULL; route = route->next) { + + switch (cmp_route(route, addr, bits, metric)) { + + case NO_ROUTE: + matched = TRUE; + break; + + case REPLACE_ROUTE: + route->action = DEL_ROUTE; + + case ADDITIONAL_ROUTE: + if (!found) { + if ((new = malloc(sizeof(struct route_struct))) == NULL) { + if (logging) + syslog(LOG_ERR, "out of memory\n"); + return; + } + + new->addr = addr; + new->bits = bits; + new->metric = metric; + new->action = NEW_ROUTE; + + new->next = first_route; + first_route = new; + + found = TRUE; + } + + matched = TRUE; + break; + + default: + break; + } + } + + if (!matched) { + if ((new = malloc(sizeof(struct route_struct))) == NULL) { + if (logging) + syslog(LOG_ERR, "out of memory\n"); + return; + } + + new->addr = addr; + new->bits = bits; + new->metric = metric; + new->action = NEW_ROUTE; + + new->next = first_route; + first_route = new; + } + } + + for (route = first_route; route != NULL; route = route->next) { + if (route->action == DEL_ROUTE) { + bzero((char *)&rt, sizeof(rt)); + + trg.sin_family = AF_INET; + trg.sin_addr = route->addr; + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_dst, sizeof(struct sockaddr)); + + if (ioctl(s, SIOCDELRT, &rt) < 0) { + if (logging) + syslog(LOG_ERR, "SIOCDELRT: %m"); + } + } + } + + for (route = first_route; route != NULL; route = route->next) { + if (route->action == NEW_ROUTE) { + bzero((char *)&rt, sizeof(rt)); + + trg.sin_family = AF_INET; + trg.sin_addr = route->addr; + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_dst, sizeof(struct sockaddr)); + + rt.rt_flags = RTF_UP | RTF_GATEWAY | RTF_DYNAMIC; + + if (route->bits == 32) { + rt.rt_flags |= RTF_HOST; + } else { + netmask = bits2mask(route->bits); + + trg.sin_family = AF_INET; + bcopy((char *)&netmask, (char *)&trg.sin_addr, sizeof(struct in_addr)); + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_genmask, sizeof(struct sockaddr)); + } + + rt.rt_metric = route->metric; + + trg.sin_family = AF_INET; + trg.sin_addr = rem_addr.sin_addr; + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_gateway, sizeof(struct sockaddr)); + + if (ioctl(s, SIOCADDRT, &rt) < 0) { + if (logging) + syslog(LOG_ERR, "SIOCADDRT: %m"); + } + } + } +} diff --git a/tcpip/rip98t.c b/tcpip/rip98t.c new file mode 100644 index 0000000..c227fc4 --- /dev/null +++ b/tcpip/rip98t.c @@ -0,0 +1,76 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <netinet/in.h> + +#include <arpa/inet.h> + +#include "rip98d.h" + +static int build_header(unsigned char *message) +{ + message[0] = RIPCMD_RESPONSE; + message[1] = RIP_VERSION_98; + + message[2] = 0; + message[3] = 0; + + return RIP98_HEADER; +} + + +void transmit_routes(int s) +{ + unsigned char message[500]; + struct route_struct *route; + struct sockaddr_in rem_addr; + int mess_len; + int size; + int i; + + size = sizeof(struct sockaddr_in); + + for (i = 0; i < dest_count; i++) { + + if (debug && logging) + syslog(LOG_DEBUG, "transmit_routes: sending routing message to %s\n", inet_ntoa(dest_list[i].dest_addr)); + + bzero((char *)&rem_addr, sizeof(rem_addr)); + rem_addr.sin_family = AF_INET; + rem_addr.sin_addr = dest_list[i].dest_addr; + rem_addr.sin_port = htons(RIP_PORT); + + route = first_route; + + while (route != NULL) { + + mess_len = build_header(message); + + while (mess_len < 184 && route != NULL) { + if (route->action != DEL_ROUTE) { + bcopy((char *)&route->addr, message + mess_len + 0, sizeof(struct in_addr)); + message[mess_len + 4] = route->bits; + message[mess_len + 5] = route->metric; + + mess_len += RIP98_ENTRY; + } + + route = route->next; + } + + if (mess_len > RIP98_HEADER) { + if (sendto(s, message, mess_len, 0, (struct sockaddr *)&rem_addr, size) < 0) { + if (logging) + syslog(LOG_ERR, "sendto: %m"); + } + } + } + } +} diff --git a/tcpip/ttylinkd.8 b/tcpip/ttylinkd.8 new file mode 100644 index 0000000..7b2379f --- /dev/null +++ b/tcpip/ttylinkd.8 @@ -0,0 +1,53 @@ +.TH TTYLINKD 8 "5 March 1997" Linux "Linux System Managers Manual" +.SH NAME +ttylinkd \- TTYlink daemon for AX.25, NET/ROM, ROSE and IP. +.SH SYNOPSIS +.B ttylinkd [-hv] [-c callsign] [-f file] +.SH DESCRIPTION +.LP +.B ttylinkd +is a simple daemon that allows incoming ttylink calls to be routed through +to Linux's normal talkd(8) +system and provides a pipe between the two. +.LP +.B ttylinkd +is usually setup to be spawned from ax25d(8) or inetd(8) +but can, since version 0.03, be used on the command line, although +talk(1) is a much better idea for interactive users. +.LP +Use splitscreen(1) +for outgoing ttylink sessions. +.SH OPTIONS +.TP 10 +.BI \-v +Display the version. +.TP 10 +.BI \-h +Display some help and information on it. +.TP 10 +.BI "\-c callsign" +Disable callsign checking and use the given callsign for a name for this +end of the link. +.TP 10 +.BI "\-f file" +Use <file> for the configuration file, instead of the default +/etc/ax25/ttylinkd.conf +.SH FILES +.LP +/etc/ax25/ttylinkd.conf the configuration file for ttylinkd +.SH "SEE ALSO" +.BR talk (1), +.BR splitscreen (1), +.BR ttylinkd.conf (5), +.BR ax25d (8), +.BR inetd (8), +.BR talkd (8). +.SH BUGS +.LP +There is still some need for some checking of who is still logged on. +.LP +The daemon may hang if you disconnect from it strangely. +.LP +There is no real way of working out what is going on with talkd. +.SH AUTHOR +Craig Small VK2XLZ <csmall@gonzo.triode.net.au> diff --git a/tcpip/ttylinkd.c b/tcpip/ttylinkd.c new file mode 100644 index 0000000..e185c7e --- /dev/null +++ b/tcpip/ttylinkd.c @@ -0,0 +1,719 @@ +/* + * ttylinkd: A ttylink daemon using the ntalkd protocol. + * Copyright (C) 1996,1197 Craig Small (csmall@gonzo.triode.net.au) + * + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge. MA 02139, USA. + */ + /* + * Versions: + * 13/01/96 cs Original Version + * 29/01/96 cs Added AX.25 proper support, thanks Tomi OH2BNS!! + * 27/01/97 cs Added support for stdin/stdout. + * 04/03/97 cs Added config file, no more defines. + * 09/03/97 tjd Enhanced to allow specifying user@hostname.wherever. + * rather than be confined to localhost. + */ +#include <ctype.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#define osockaddr sockaddr +#include <protocols/talkd.h> + +#include <syslog.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> + +#include "../pathnames.h" + + +static char version[] = "ttylink daemon (Version 0.05, 9 March 1997) ready.\n"; + +#define SYSOP_USER "root" + +/* TTY control characters from the sysop's talk screen */ +char erasec; +char killc; +char werasec; + +/* Users address family */ +int userfamily; + +#define ADDR_SIZE 256 +char sysop_addr[ADDR_SIZE]; +char *sysop_user=NULL, *sysop_host=NULL; +char config_file[128]; + +int send_control(int skt, struct in_addr addr, CTL_MSG msg, CTL_RESPONSE *resp); +void alarm_handle(int i); +void do_talk(int skt); +void read_config_file(int dummy); + +/*static char *Commands[] = { + "leaving invitation", + "look-up", + "delete", + "announce" }; +*/ +static char *Responses[] = { + "success", + "sysop not logged on", + "failed for unknown reason", + "sysop's machine unknown", + "permission denied", + "unknown request", + "bad version", + "bad address", + "bad control address" }; + + +int main(int argc, char *argv[]) +{ + struct sockaddr_in sin, ctl_sin; + struct in_addr my_addr, rem_addr; + int ctl_skt, skt, new_skt; + int length; + CTL_RESPONSE resp; + CTL_MSG msg; + struct protoent *ppe; + struct hostent *phe, *rhe=NULL; + char hostname[256]; + int local_id, remote_id; + char buf[256]; + char user[NAME_SIZE]; + struct sockaddr sa; + int sa_len, i; + struct sockaddr_in *peer_sin=NULL; + struct sockaddr_ax25 *peer_sax; + struct sockaddr_rose *peer_srose; + + /* Open up the system logger */ + openlog(argv[0], LOG_PID, LOG_DAEMON); + + write(STDOUT_FILENO, version, strlen(version)); + + /* Work out who is calling us */ + userfamily = AF_UNSPEC; + bzero(user, NAME_SIZE); + strcpy(sysop_addr, SYSOP_USER); + strcpy(config_file, CONF_TTYLINKD_FILE); + for(i=1 ; i < argc ; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'v': + return 0; + break; + case 'h': + printf("ttylinkd comes with ABSOLUTELY NO WARRANY, see the file COPYING\n"); + printf("This is free software, and you are welcome to redistribute it\n"); + printf("under the terms of the GNU General Public License.\n\n"); + printf("Usage: %s [-hv] [-c <callsign>] [-f <config_file>]\n", argv[0]); + return 0; + break; + case 'f': + if (i+2 > argc) + { + printf("The -f flag needs a parameter.\n"); + return 0; + break; + } + strncpy(config_file, argv[++i], 127); + break; + case 'c': + if ( i+2 > argc) + { + printf("The -c flag need a parameter.\n"); + return 0; + break; + } + strncpy(user, argv[++i], NAME_SIZE); + break; + default: + fprintf(stderr, "%s: Unknown flag, type %s -h for help\n", argv[0], argv[0]); + return -1; + break; + } /*switch */ + } /* - */ + } /* for */ + if (user[0] == '\0') + { + sa_len = sizeof(sa); + if (getpeername(STDOUT_FILENO, &sa, &sa_len) < 0) + { + fprintf(stderr, "%s: getpeername() failed, you must specify a callsign in stdin mode.\n", argv[0]); + syslog(LOG_CRIT | LOG_DAEMON, "main(): getpeername() failed."); + return 0; + } else { + userfamily = sa.sa_family; + switch(sa.sa_family) { + case AF_INET: + peer_sin = (struct sockaddr_in*)&sa; + write(STDOUT_FILENO, buf, strlen(buf)); + sprintf(buf, "Please enter your callsign: "); + write(STDOUT_FILENO, buf, strlen(buf)); + fflush(stdout); + if (fgets(user, NAME_SIZE-1, stdin) == NULL) + return 0; + for (i = 0; user[i] != '\0' && user[i] != '\n' && user[i] != '\r'; i++) + ; + user[i] = '\0'; + if (strlen(user) < 1) + return 0; + userfamily = AF_INET; + break; + case AF_AX25: + case AF_NETROM: + peer_sax = (struct sockaddr_ax25*)&sa; + for(i=0 ; i < 6 ; i++) + { + user[i] = tolower(((peer_sax->sax25_call.ax25_call[i]) >>1)&0x7f); + if (user[i] == ' ') + break; + } + user[i] = '\0'; + break; + case AF_ROSE: + peer_srose = (struct sockaddr_rose*)&sa; + for(i=0 ; i < 6 ; i++) + { + user[i] = tolower(((peer_srose->srose_call.ax25_call[i]) >>1)&0x7f); + if (user[i] == ' ') + break; + } + user[i] = '\0'; + break; + default: + syslog(LOG_DAEMON | LOG_CRIT, "Unsupported address family."); + exit(1); + } + + } + } /* argc */ + + /* Read the configuration file to find the System Operator. */ + read_config_file(0); + /* ... and parse it into user@host */ + sysop_user=strtok(sysop_addr,"@"); + sysop_host=strtok(NULL,"@"); + + if ((ppe = getprotobyname("udp")) == 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "Cannot find udp protocol entry."); + exit(1); + } + + /* Obtain our local hostname */ + gethostname(hostname,256); + + /* Get the remote address, or use ours if remote isn't specified */ + if (sysop_host) + { + if ((rhe = gethostbyname(sysop_host)) == NULL) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): gethostbyname failed."); + exit(1); + } + } + else + { + if ((rhe = gethostbyname(hostname)) == NULL) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): gethostbyname failed."); + exit(1); + } + } + bcopy(rhe->h_addr, (char*)&rem_addr, rhe->h_length); + + /* Get our local address */ + if ((phe = gethostbyname(hostname)) == NULL) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): gethostbyname failed."); + exit(1); + } + bcopy(phe->h_addr, (char*)&my_addr, phe->h_length); + + /* Create local data socket */ + bzero((char*)&sin, sizeof(sin)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(0); + bcopy(phe->h_addr, (char*)&sin.sin_addr, phe->h_length); + + if ((skt = socket(PF_INET, SOCK_STREAM, 0)) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): socket() failed."); + exit(1); + } + + if (bind( skt, (struct sockaddr*)&sin, sizeof(sin)) != 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): bind() failed."); + exit(1); + } + + length = sizeof(sin); + if (getsockname(skt, (struct sockaddr*)&sin, &length) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): getsockname() failed."); + exit(1); + } + + /* Create local control socket */ + bzero((char*)&ctl_sin, sizeof(ctl_sin)); + + ctl_sin.sin_family = AF_INET; + bcopy(phe->h_addr, (char*)&ctl_sin.sin_addr, phe->h_length); + ctl_sin.sin_port = htons(0); + + if ((ctl_skt = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): socket() while attempting to create control socket."); + close(skt); + exit(1); + } + + if (bind(ctl_skt, (struct sockaddr*)&ctl_sin, sizeof(ctl_sin)) != 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): Error when trying to bind() control socket."); + close(skt); + exit(1); + } + + length = sizeof(ctl_sin); + if (getsockname(ctl_skt, (struct sockaddr*)&ctl_sin, &length) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT,"main(): Error when trying to getsockname() for control socket."); + close(skt); + close(ctl_skt); + exit(1); + } + + /* Start talking to the talk daemon */ + bzero((char*)&msg, sizeof(msg)); + msg.vers = TALK_VERSION; + msg.id_num = htonl(0); + msg.addr.sa_family = ntohs(AF_INET); + msg.ctl_addr = *(struct sockaddr*)&ctl_sin; + msg.ctl_addr = *(struct sockaddr*)&ctl_sin; + msg.ctl_addr.sa_family = ntohs(AF_INET); + msg.pid = htonl(getpid()); + strncpy(msg.l_name, user, NAME_SIZE-1); + strncpy(msg.r_name, sysop_user, NAME_SIZE-1); + + + /* Now look for an invite */ + msg.type = LOOK_UP; + (void) send_control(ctl_skt, rem_addr, msg, &resp); + + /* The person not there? Send an announce and wake him up */ + msg.type = ANNOUNCE; + msg.addr = *(struct sockaddr*)&sin; + msg.addr.sa_family = htons(AF_INET); + msg.id_num = -1; + i = send_control(ctl_skt, rem_addr, msg, &resp); + if ( i != SUCCESS) + { + if (i > BADCTLADDR) + printf("Cannot talk to sysop errno=%d.\n",i); + else + printf("Cannot talk to sysop, reason: %s.\n",Responses[i]); + + close(skt); + close(ctl_skt); + return 0; + } + /* Update the ID number so that we both know what we're talking about. */ + remote_id = resp.id_num; + + /* Get the TCP port ready for a connection */ + if (listen(skt, 5) != 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): Error when trying to listen() on socket."); + exit(1); + } + + /* Now we have to make an invitation for the other user */ + msg.type = LEAVE_INVITE; + if (send_control(ctl_skt, my_addr, msg, &resp) != SUCCESS) + { + printf("Problem with leaving an invitation\n"); + syslog(LOG_DAEMON | LOG_CRIT, "main(): Cannot leave invititation."); + close(skt); + close(ctl_skt); + return 0; + } + local_id = resp.id_num; + + sprintf(buf, "Paging sysop.\n"); + write(STDOUT_FILENO, buf, strlen(buf)); + + /* Wait for the sysop to connect to us */ + signal(SIGALRM, alarm_handle); + alarm(30); + + if ((new_skt = accept(skt, 0, 0)) < 0) + { + if (errno == EINTR) + { + /* Delete invitations from both daemons */ + msg.type = DELETE; + msg.id_num = htonl(local_id); + send_control(ctl_skt, my_addr, msg, &resp); + msg.id_num = htonl(remote_id); + send_control(ctl_skt, rem_addr, msg, &resp); + + close(skt); + close(ctl_skt); + return 0; + } + syslog(LOG_DAEMON | LOG_WARNING, "main(): accept() failed. (%m)"); + } + alarm(0); + signal(SIGALRM, SIG_DFL); + + close(skt); + skt = new_skt; + + /* Delete invitations from both daemons */ + msg.type = DELETE; + msg.id_num = htonl(local_id); + send_control(ctl_skt, my_addr, msg, &resp); + msg.id_num = htonl(remote_id); + send_control(ctl_skt, rem_addr, msg, &resp); + + sprintf(buf, "Sysop has responded.\n"); + write(STDOUT_FILENO, buf, strlen(buf)); + + /* + * A little thing that they don't mention anywhere is the fact that the + * first three characters on a connection are used to work out to erase, + * kill and word erase characters. Nice to know eh? + */ + /* We send ours first, but then again we get data in cooked form, so + * we don't use this. */ + buf[0] = '\0'; + buf[1] = '\0'; + buf[2] = '\0'; + if (write(skt, buf, 3) != 3) + { + printf("Connnection lost\n"); + close(skt); + close(ctl_skt); + return 0; + } + /* Get their character stuff */ + if (read(skt, buf, 3) != 3) + { + printf("Connection lost\n"); + close(skt); + close(ctl_skt); + return 0; + } + erasec = buf[0]; + killc = buf[1]; + werasec = buf[2]; + + /* Tell the sysop who this person is */ + if (sa.sa_family == AF_AX25) + { + sprintf(buf, "Incoming ttylink from %s.\n", user); + write(skt, buf, strlen(buf)); + } + if (sa.sa_family == AF_INET) + { + sprintf(buf, "Incoming ttylink from %s@%s.\n", user, inet_ntoa(peer_sin->sin_addr)); + write(skt, buf, strlen(buf)); + } + + + do_talk(skt); + + close(skt); + close(ctl_skt); + return 0; +} + +/* + * Used to send control messages to our friendly local talk daemon + */ +int send_control(int skt, struct in_addr addr, CTL_MSG msg, CTL_RESPONSE *resp) +{ + fd_set fdvar; + struct timeval timeout; + struct sockaddr_in sin; + static int talk_port = 0; + struct servent *pse; + + /* Look up talk port once only */ + if (talk_port == 0) + { + if ((pse = getservbyname("ntalk", "udp")) == NULL) + { + perror("getservbyname, assuming 518"); + talk_port = 518; + } else { + talk_port = pse->s_port; + } + } + + /* Create the socket address */ + bzero((char*)&sin, sizeof(sin)); + sin.sin_addr = addr; + sin.sin_family = AF_INET; + sin.sin_port = talk_port; + + if (sendto(skt, (char*)&msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin)) != sizeof(msg)) + { + syslog(LOG_DAEMON | LOG_ERR, "send_control(): sendto failed (%m)."); + return -1; + } + + /* Wait for reply */ + FD_ZERO(&fdvar); + FD_SET(skt, &fdvar); + timeout.tv_sec = RING_WAIT; + timeout.tv_usec = 0; + + if (select(32, &fdvar, NULL, NULL, &timeout) < 0) + syslog(LOG_DAEMON | LOG_ERR, "send_control(): select failed. (%m)"); + + /* + * The server is ignoring us, see ya later + */ + if (!(FD_ISSET(skt, &fdvar))) + { + printf("Talk server not responding after %d seconds, aborting.\n", RING_WAIT); + return -1; + } + + /* Get the message */ + if(recv(skt, resp, sizeof(resp),0) ==0) + syslog(LOG_DAEMON | LOG_ERR, "send_control(): recv failed. (%m)"); + + return resp->answer; +} + +/* Used to process the data from the sysop */ +int send_sysop_data(char *buf, int len) +{ + static char outbuf[82]; + static char *bptr = outbuf; + int i; + + for(i = 0; i < len; i++) + { + /* Check for erase character */ + if (buf[i] == erasec) + { + if (bptr > outbuf) + bptr--; + continue; + } + + /* Check for kill character */ + if (buf[i] == killc) + { + bptr = outbuf; + continue; + } + + /* Check for word-erase character */ + if (buf[i] == werasec) + { + while( (bptr > outbuf) && (*bptr != ' ') ) + bptr--; + continue; + } + + /* Check for newline character */ + if (buf[i] == '\n') + { + if ( (userfamily == AF_AX25) || (userfamily == AF_NETROM) || (userfamily == AF_ROSE) ) + { + *bptr = '\r'; + bptr++; + } else { + *bptr = '\r'; + bptr++; + *bptr = '\n'; + bptr++; + } + } else { + *bptr = buf[i]; + bptr++; + } + + /* Check for carriage return, which means send it */ + /* We also send if we have more than 80 characters */ + if (buf[i] == '\n' || (bptr - outbuf) > 80 ) + { + if (write(STDOUT_FILENO, outbuf, (bptr - outbuf) ) != (bptr - outbuf) ) + { + return -1; + } + bptr = outbuf; + } + } /* for */ + return 0; +} + +/* Used to process the data from the user - len must not exceed 256 */ +int send_user_data(int skt, char *buf, int len) +{ + char outbuf[256]; + char *bptr = outbuf; + int i; + + for(i = 0; i < len; i++) + { + if (buf[i] == '\r') + { + if (userfamily == AF_INET) + { + *bptr = '\n'; + bptr++; + /* + * check if this is a <CR><LF> or a <CR><NUL> + * and skip the <LF> or <NUL>. + */ + if (buf[i + 1] == '\n' || buf[i + 1] == '\0') + { + i++; + } + } else + { + *bptr = '\n'; + bptr++; + } + continue; + } + *bptr = buf[i]; + bptr++; + } /* for */ + + if (write(skt, outbuf, bptr - outbuf) != bptr - outbuf) + { + return -1; + } + return 0; +} + + +/* The main talking loop */ +void do_talk(int skt) +{ + fd_set fdvar; + char inbuf[256], outbuf[256]; + struct timeval timeout; + int i; + + + while(1) + { + FD_ZERO(&fdvar); + FD_SET(skt, &fdvar); + FD_SET(STDIN_FILENO, &fdvar); + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + if (select(32, &fdvar, NULL, NULL, &timeout) == 0) + { + if (ioctl(STDIN_FILENO, FIONREAD, (struct sgttyb *)&i) < 0) + return; + if (ioctl(skt, FIONREAD, (struct sgttyb*)&i) < 0) + return; + } + + if (FD_ISSET(skt, &fdvar)) + { + if ((i = read(skt, inbuf, 256)) <= 0) + { + strcpy(inbuf,"Sysop closed connection.\n"); + write(STDOUT_FILENO, inbuf, strlen(inbuf)); + return; + } + if (send_sysop_data(inbuf, i) < 0) + { + strcpy(outbuf, "User closed connection.\n"); + (void) write(skt, outbuf, strlen(outbuf)); + return; + } + } + if (FD_ISSET(STDIN_FILENO, &fdvar)) + { + if ((i = read(STDIN_FILENO, outbuf, 256)) <= 0) + { + strcpy(outbuf, "User closed connection.\n"); + (void) write(skt, outbuf, strlen(outbuf)); + return; + } + if (send_user_data(skt, outbuf, i) < 0) + { + strcpy(inbuf,"Sysop closed connection.\n"); + write(STDOUT_FILENO, inbuf, strlen(inbuf)); + return; + } + } + } +} + +void alarm_handle(int i) +{ + char buf[256]; + + strcpy(buf, "Sysop not responding.\n"); + write(STDOUT_FILENO, buf, strlen(buf)); +} + +void read_config_file(int dummy) +{ + char buf[128]; + char param[20], value[108]; + FILE *fp; + + if ( (fp = fopen(config_file, "r")) == NULL) { + syslog(LOG_DAEMON | LOG_ERR, "Cannot find configuration file: %s (%m)\n",config_file); + return; + } + /* Reset any variables here */ + + while ( fgets(buf, 128, fp) != NULL) { + if ( buf[0] == '#') + continue; + if (sscanf(buf, "%[^=]%*c%[^\n]", param, value) == 2) { + /* A big wierdo switch */ + if (strcasecmp(param, "sysop") == 0) { + strncpy(sysop_addr, value, ADDR_SIZE); + } + } + } /* while */ + fclose(fp); + signal(SIGHUP, read_config_file); +} diff --git a/tcpip/ttylinkd.conf b/tcpip/ttylinkd.conf new file mode 100644 index 0000000..ae65749 --- /dev/null +++ b/tcpip/ttylinkd.conf @@ -0,0 +1,10 @@ +# /etc/ax25/ttylinkd.conf : config file for ttylinkd(8) +# +# We just have one line, who gets the incoming ttylink calls. +# +# sysop=user@hostname.domain.name +# or: +# sysop=user +# +sysop=root + diff --git a/tcpip/ttylinkd.conf.5 b/tcpip/ttylinkd.conf.5 new file mode 100644 index 0000000..ecba3a1 --- /dev/null +++ b/tcpip/ttylinkd.conf.5 @@ -0,0 +1,22 @@ +.TH TTYLINKD.CONF 5 "9 March 1997" Linux "Linux Programmer's Manual" +.SH NAME +ttylinkd.conf \- ttylinkd configuration file. +.SH DESCRIPTION +.LP +.B ttylinkd.conf +allows the super user to determine certain parameters with ttylinkd(8). +Current there is only one field, with the view of not extending this further +(ttylinkd is about a resourceful as it is going to get). +.SH PARAMETERS +.TP 10 +.B # +Any line beginning with the hash (#) symbol is a comment and wille be ignored. +.TP 10 +.B "sysop=<user>[@hostname.domain.name]" +The login <user> will be attempted to be contacted with ttylinkd(8) is +launched. If you do not supply a hostname then the local host will be assumed. +.SH SEE ALSO +.BR ttylinkd (8). +.SH AUTHOR +Craig Small VK2XLZ <csmall@gonzo.triode.net.au> + diff --git a/user_call/Makefile.am b/user_call/Makefile.am new file mode 100644 index 0000000..5aedbd3 --- /dev/null +++ b/user_call/Makefile.am @@ -0,0 +1,10 @@ + +installconf: + + +sbin_PROGRAMS = ax25_call netrom_call rose_call + +man_MANS = ax25_call.8 netrom_call.8 rose_call.8 + +DATA_EXTRA = $(man_MANS) + diff --git a/user_call/Makefile.in b/user_call/Makefile.in new file mode 100644 index 0000000..232f104 --- /dev/null +++ b/user_call/Makefile.in @@ -0,0 +1,349 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +sbin_PROGRAMS = ax25_call netrom_call rose_call + +man_MANS = ax25_call.8 netrom_call.8 rose_call.8 + +DATA_EXTRA = $(man_MANS) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +ax25_call_SOURCES = ax25_call.c +ax25_call_OBJECTS = ax25_call.o +ax25_call_LDADD = $(LDADD) +ax25_call_DEPENDENCIES = +ax25_call_LDFLAGS = +netrom_call_SOURCES = netrom_call.c +netrom_call_OBJECTS = netrom_call.o +netrom_call_LDADD = $(LDADD) +netrom_call_DEPENDENCIES = +netrom_call_LDFLAGS = +rose_call_SOURCES = rose_call.c +rose_call_OBJECTS = rose_call.o +rose_call_LDADD = $(LDADD) +rose_call_DEPENDENCIES = +rose_call_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man8dir = $(mandir)/man8 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = ax25_call.c netrom_call.c rose_call.c +OBJECTS = ax25_call.o netrom_call.o rose_call.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps user_call/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +ax25_call: $(ax25_call_OBJECTS) $(ax25_call_DEPENDENCIES) + @rm -f ax25_call + $(LINK) $(ax25_call_LDFLAGS) $(ax25_call_OBJECTS) $(ax25_call_LDADD) $(LIBS) + +netrom_call: $(netrom_call_OBJECTS) $(netrom_call_DEPENDENCIES) + @rm -f netrom_call + $(LINK) $(netrom_call_LDFLAGS) $(netrom_call_OBJECTS) $(netrom_call_LDADD) $(LIBS) + +rose_call: $(rose_call_OBJECTS) $(rose_call_DEPENDENCIES) + @rm -f rose_call + $(LINK) $(rose_call_LDFLAGS) $(rose_call_OBJECTS) $(rose_call_LDADD) $(LIBS) + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = user_call + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +ax25_call.o: ax25_call.c +netrom_call.o: netrom_call.c +rose_call.o: rose_call.c + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile install-man8 uninstall-man8 \ +install-man uninstall-man tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +installconf: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/user_call/README b/user_call/README new file mode 100644 index 0000000..beee347 --- /dev/null +++ b/user_call/README @@ -0,0 +1,59 @@ +This is the first version of the user_call utilities. They are little +program,s to allow users of ax25d and the node to initiate outgoing AX.25, +NET/ROM and Rose connections. They are very powerful program because it can +pretend to be someone else, so be careful ! + +My testing has been within the confined of the node, but the comments here +apply equally well to use via ax25d. + +Ax25_call takes at least three parameters: + +ax25_call <port> <my callsign> <remote callsign> [<digipeaters> ...] + +Netrom_call takes three parameters: + +netrom_call <port> <my callsign> <remote address> + +Rose_call takes four parameters: + +rose_call <port> <my callsign> <remote callsign> <remote Rose address> + +The <port> is the name of a local AX.25, NET/ROM or Rose port as defined in +the axports, nrports or rsports files respectively. <my callsign> is the +callsign that this connection appears to have come from, ie the local +*user*. It has nothing to do with your AX.25 port callsign. + +Ax25_call must have at least the callsign of the remote user and a set of +optional digipeaters. + +The <remote address> for netrom_call may be of two forms, either the remote +node callsign, or a combination of the remote node alias and remote node +callsign seperated by a ':'. Netrom_call only connects to the remote +callisgn, the full address is sent to the local user for information. + +The <remote callsign> for rose_call is the "service" at the remote Rose +node, ie USERS or any other valid AX.25 callsign, <remote Rose address> is +the ten-digit Rose address of the remote node. + +To start any of these from within the node, you will need to add a line like +the following to the /etc/ax25/node.conf file, this example uses rose_call: + +ExtCmd BBS 0 root /usr/sbin/rose_call rose_call rose %S k4dpz 3100352392 + +This assumes that rose_call is installed in /usr/sbin which is the default. +This will create a new command "BBS" for the node, which when typed will +connect the user to the callsign K4DPZ at remote Rose node 3100352392. The +callsign of the local user is where the %S appears in the line, it is +substituted by node for the users callsign. See node.conf(5) for more +details of the syntax. + +Setting up these programs via ax25d is also quite simple and is similar +conceptually to the example above. + +All of these programs generates errors that are received by the local user, +so if there are any problems then the local user will be able to quote the +message to you. + +Give them a whirl and let me know how you go. + +Jonathan diff --git a/user_call/ax25_call.c b/user_call/ax25_call.c new file mode 100644 index 0000000..aaa47ce --- /dev/null +++ b/user_call/ax25_call.c @@ -0,0 +1,156 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> + +#include <sys/time.h> +#include <sys/types.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> +#include <netax25/axconfig.h> + +void alarm_handler(int sig) +{ +} + +void err(char *message) +{ + write(STDOUT_FILENO, message, strlen(message)); + exit(1); +} + +int main(int argc, char **argv) +{ + char buffer[512], *addr; + fd_set read_fd; + int n, s, addrlen = sizeof(struct full_sockaddr_ax25); + struct full_sockaddr_ax25 axbind, axconnect; + + /* + * Arguments should be "ax25_call port mycall remcall [digis ...]" + */ + if (argc < 4) { + strcpy(buffer, "ERROR: invalid number of parameters\r"); + err(buffer); + } + + if (ax25_config_load_ports() == 0) { + strcpy(buffer, "ERROR: problem with axports file\r"); + err(buffer); + } + + /* + * Parse the passed values for correctness. + */ + axconnect.fsa_ax25.sax25_family = axbind.fsa_ax25.sax25_family = AF_AX25; + axbind.fsa_ax25.sax25_ndigis = 1; + + if ((addr = ax25_config_get_addr(argv[1])) == NULL) { + sprintf(buffer, "ERROR: invalid AX.25 port name - %s\r", argv[1]); + err(buffer); + } + + if (ax25_aton_entry(addr, axbind.fsa_digipeater[0].ax25_call) == -1) { + sprintf(buffer, "ERROR: invalid AX.25 port callsign - %s\r", argv[1]); + err(buffer); + } + + if (ax25_aton_entry(argv[2], axbind.fsa_ax25.sax25_call.ax25_call) == -1) { + sprintf(buffer, "ERROR: invalid callsign - %s\r", argv[2]); + err(buffer); + } + + if (ax25_aton_arglist(argv + 3, &axconnect) == -1) { + sprintf(buffer, "ERROR: invalid destination callsign or digipeater\r"); + err(buffer); + } + + /* + * Open the socket into the kernel. + */ + if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) { + sprintf(buffer, "ERROR: cannot open AX.25 socket, %s\r", strerror(errno)); + err(buffer); + } + + /* + * Set our AX.25 callsign and AX.25 port callsign accordingly. + */ + if (bind(s, (struct sockaddr *)&axbind, addrlen) != 0) { + sprintf(buffer, "ERROR: cannot bind AX.25 socket, %s\r", strerror(errno)); + err(buffer); + } + + sprintf(buffer, "Connecting to %s ...\r", argv[3]); + write(STDOUT_FILENO, buffer, strlen(buffer)); + + /* + * If no response in 30 seconds, go away. + */ + alarm(30); + + signal(SIGALRM, alarm_handler); + + /* + * Lets try and connect to the far end. + */ + if (connect(s, (struct sockaddr *)&axconnect, addrlen) != 0) { + switch (errno) { + case ECONNREFUSED: + strcpy(buffer, "*** Connection refused - aborting\r"); + break; + case ENETUNREACH: + strcpy(buffer, "*** No known route - aborting\r"); + break; + case EINTR: + strcpy(buffer, "*** Connection timed out - aborting\r"); + break; + default: + sprintf(buffer, "ERROR: cannot connect to AX.25 callsign, %s\r", strerror(errno)); + break; + } + + err(buffer); + } + + /* + * We got there. + */ + alarm(0); + + strcpy(buffer, "*** Connected\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + + /* + * Loop until one end of the connection goes away. + */ + for (;;) { + FD_ZERO(&read_fd); + FD_SET(STDIN_FILENO, &read_fd); + FD_SET(s, &read_fd); + + select(s + 1, &read_fd, NULL, NULL, NULL); + + if (FD_ISSET(s, &read_fd)) { + if ((n = read(s, buffer, 512)) == -1) { + strcpy(buffer, "\r*** Disconnected\r"); + err(buffer); + } + write(STDOUT_FILENO, buffer, n); + } + + if (FD_ISSET(STDIN_FILENO, &read_fd)) { + if ((n = read(STDIN_FILENO, buffer, 512)) == -1) { + close(s); + break; + } + write(s, buffer, n); + } + } + + return 0; +} diff --git a/user_call/netrom_call.c b/user_call/netrom_call.c new file mode 100644 index 0000000..004b109 --- /dev/null +++ b/user_call/netrom_call.c @@ -0,0 +1,165 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> + +#include <sys/time.h> +#include <sys/types.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrom/netrom.h> +#include <netrose/rose.h> + +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/nrconfig.h> + +void alarm_handler(int sig) +{ +} + +void err(char *message) +{ + write(STDOUT_FILENO, message, strlen(message)); + exit(1); +} + +int main(int argc, char **argv) +{ + char buffer[512], *addr; + fd_set read_fd; + int n, s, addrlen = sizeof(struct full_sockaddr_ax25); + struct full_sockaddr_ax25 nrbind, nrconnect; + + /* + * Arguments should be "netrom_call port mycall remaddr" + */ + if (argc != 4) { + strcpy(buffer, "ERROR: invalid number of parameters\r"); + err(buffer); + } + + if (nr_config_load_ports() == 0) { + strcpy(buffer, "ERROR: problem with nrports file\r"); + err(buffer); + } + + /* + * Parse the passed values for correctness. + */ + nrconnect.fsa_ax25.sax25_family = nrbind.fsa_ax25.sax25_family = AF_NETROM; + nrbind.fsa_ax25.sax25_ndigis = 1; + nrconnect.fsa_ax25.sax25_ndigis = 0; + + if ((addr = nr_config_get_addr(argv[1])) == NULL) { + sprintf(buffer, "ERROR: invalid NET/ROM port name - %s\r", argv[1]); + err(buffer); + } + + if (ax25_aton_entry(addr, nrbind.fsa_ax25.sax25_call.ax25_call) == -1) { + sprintf(buffer, "ERROR: invalid NET/ROM port callsign - %s\r", argv[1]); + err(buffer); + } + + if (ax25_aton_entry(argv[2], nrbind.fsa_digipeater[0].ax25_call) == -1) { + sprintf(buffer, "ERROR: invalid callsign - %s\r", argv[2]); + err(buffer); + } + + if ((addr = strchr(argv[3], ':')) == NULL) + addr = argv[3]; + else + addr++; + + if (ax25_aton_entry(addr, nrconnect.fsa_ax25.sax25_call.ax25_call) == -1) { + sprintf(buffer, "ERROR: invalid callsign - %s\r", argv[3]); + err(buffer); + } + + /* + * Open the socket into the kernel. + */ + if ((s = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + sprintf(buffer, "ERROR: cannot open NET/ROM socket, %s\r", strerror(errno)); + err(buffer); + } + + /* + * Set our AX.25 callsign and NET/ROM callsign accordingly. + */ + if (bind(s, (struct sockaddr *)&nrbind, addrlen) != 0) { + sprintf(buffer, "ERROR: cannot bind NET/ROM socket, %s\r", strerror(errno)); + err(buffer); + } + + sprintf(buffer, "Connecting to %s ...\r", argv[3]); + write(STDOUT_FILENO, buffer, strlen(buffer)); + + /* + * If no response in 30 seconds, go away. + */ + alarm(30); + + signal(SIGALRM, alarm_handler); + + /* + * Lets try and connect to the far end. + */ + if (connect(s, (struct sockaddr *)&nrconnect, addrlen) != 0) { + switch (errno) { + case ECONNREFUSED: + strcpy(buffer, "*** Connection refused - aborting\r"); + break; + case ENETUNREACH: + strcpy(buffer, "*** No known route - aborting\r"); + break; + case EINTR: + strcpy(buffer, "*** Connection timed out - aborting\r"); + break; + default: + sprintf(buffer, "ERROR: cannot connect to NET/ROM node, %s\r", strerror(errno)); + break; + } + + err(buffer); + } + + /* + * We got there. + */ + alarm(0); + + strcpy(buffer, "*** Connected\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + + /* + * Loop until one end of the connection goes away. + */ + for (;;) { + FD_ZERO(&read_fd); + FD_SET(STDIN_FILENO, &read_fd); + FD_SET(s, &read_fd); + + select(s + 1, &read_fd, NULL, NULL, NULL); + + if (FD_ISSET(s, &read_fd)) { + if ((n = read(s, buffer, 512)) == -1) { + strcpy(buffer, "\r*** Disconnected\r"); + err(buffer); + } + write(STDOUT_FILENO, buffer, n); + } + + if (FD_ISSET(STDIN_FILENO, &read_fd)) { + if ((n = read(STDIN_FILENO, buffer, 512)) == -1) { + close(s); + break; + } + write(s, buffer, n); + } + } + + return 0; +} diff --git a/user_call/rose_call.c b/user_call/rose_call.c new file mode 100644 index 0000000..606284d --- /dev/null +++ b/user_call/rose_call.c @@ -0,0 +1,162 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> + +#include <sys/time.h> +#include <sys/types.h> + +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> +#include <netax25/axconfig.h> +#include <netax25/rsconfig.h> + +void alarm_handler(int sig) +{ +} + +void err(char *message) +{ + write(STDOUT_FILENO, message, strlen(message)); + exit(1); +} + +int main(int argc, char **argv) +{ + char buffer[512], *addr; + fd_set read_fd; + int n, s, addrlen = sizeof(struct sockaddr_rose); + struct sockaddr_rose rosebind, roseconnect; + + /* + * Arguments should be "rose_call port mycall remcall remaddr" + */ + if (argc != 5) { + strcpy(buffer, "ERROR: invalid number of parameters\r"); + err(buffer); + } + + if (rs_config_load_ports() == 0) { + strcpy(buffer, "ERROR: problem with rsports file\r"); + err(buffer); + } + + /* + * Parse the passed values for correctness. + */ + roseconnect.srose_family = rosebind.srose_family = AF_ROSE; + roseconnect.srose_ndigis = rosebind.srose_ndigis = 0; + + if ((addr = rs_config_get_addr(argv[1])) == NULL) { + sprintf(buffer, "ERROR: invalid Rose port name - %s\r", argv[1]); + err(buffer); + } + + if (rose_aton(addr, rosebind.srose_addr.rose_addr) == -1) { + sprintf(buffer, "ERROR: invalid Rose port address - %s\r", argv[1]); + err(buffer); + } + + if (ax25_aton_entry(argv[2], rosebind.srose_call.ax25_call) == -1) { + sprintf(buffer, "ERROR: invalid callsign - %s\r", argv[2]); + err(buffer); + } + + if (ax25_aton_entry(argv[3], roseconnect.srose_call.ax25_call) == -1) { + sprintf(buffer, "ERROR: invalid callsign - %s\r", argv[3]); + err(buffer); + } + + if (rose_aton(argv[4], roseconnect.srose_addr.rose_addr) == -1) { + sprintf(buffer, "ERROR: invalid Rose address - %s\r", argv[4]); + err(buffer); + } + + /* + * Open the socket into the kernel. + */ + if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) { + sprintf(buffer, "ERROR: cannot open Rose socket, %s\r", strerror(errno)); + err(buffer); + } + + /* + * Set our AX.25 callsign and Rose address accordingly. + */ + if (bind(s, (struct sockaddr *)&rosebind, addrlen) != 0) { + sprintf(buffer, "ERROR: cannot bind Rose socket, %s\r", strerror(errno)); + err(buffer); + } + + sprintf(buffer, "Connecting to %s @ %s ...\r", argv[3], argv[4]); + write(STDOUT_FILENO, buffer, strlen(buffer)); + + /* + * If no response in 30 seconds, go away. + */ + alarm(30); + + signal(SIGALRM, alarm_handler); + + /* + * Lets try and connect to the far end. + */ + if (connect(s, (struct sockaddr *)&roseconnect, addrlen) != 0) { + switch (errno) { + case ECONNREFUSED: + strcpy(buffer, "*** Connection refused - aborting\r"); + break; + case ENETUNREACH: + strcpy(buffer, "*** No known route - aborting\r"); + break; + case EINTR: + strcpy(buffer, "*** Connection timed out - aborting\r"); + break; + default: + sprintf(buffer, "ERROR: cannot connect to Rose address, %s\r", strerror(errno)); + break; + } + + err(buffer); + } + + /* + * We got there. + */ + alarm(0); + + strcpy(buffer, "*** Connected\r"); + write(STDOUT_FILENO, buffer, strlen(buffer)); + + /* + * Loop until one end of the connection goes away. + */ + for (;;) { + FD_ZERO(&read_fd); + FD_SET(STDIN_FILENO, &read_fd); + FD_SET(s, &read_fd); + + select(s + 1, &read_fd, NULL, NULL, NULL); + + if (FD_ISSET(s, &read_fd)) { + if ((n = read(s, buffer, 512)) == -1) { + strcpy(buffer, "\r*** Disconnected\r"); + err(buffer); + } + write(STDOUT_FILENO, buffer, n); + } + + if (FD_ISSET(STDIN_FILENO, &read_fd)) { + if ((n = read(STDIN_FILENO, buffer, 512)) == -1) { + close(s); + break; + } + write(s, buffer, n); + } + } + + return 0; +} |