summaryrefslogtreecommitdiff
path: root/usr.sbin/ppp
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ppp')
-rw-r--r--usr.sbin/ppp/Makefile23
-rw-r--r--usr.sbin/ppp/README.alias352
-rw-r--r--usr.sbin/ppp/alias_cmd.c191
-rw-r--r--usr.sbin/ppp/alias_cmd.h6
-rw-r--r--usr.sbin/ppp/arp.c314
-rw-r--r--usr.sbin/ppp/arp.h25
-rw-r--r--usr.sbin/ppp/async.c198
-rw-r--r--usr.sbin/ppp/async.h8
-rw-r--r--usr.sbin/ppp/auth.c223
-rw-r--r--usr.sbin/ppp/auth.h41
-rw-r--r--usr.sbin/ppp/ccp.c284
-rw-r--r--usr.sbin/ppp/ccp.h56
-rw-r--r--usr.sbin/ppp/chap.c311
-rw-r--r--usr.sbin/ppp/chap.h30
-rw-r--r--usr.sbin/ppp/chap_ms.c115
-rw-r--r--usr.sbin/ppp/chap_ms.h31
-rw-r--r--usr.sbin/ppp/chat.c641
-rw-r--r--usr.sbin/ppp/chat.h29
-rw-r--r--usr.sbin/ppp/command.c1628
-rw-r--r--usr.sbin/ppp/command.h62
-rw-r--r--usr.sbin/ppp/defs.c92
-rw-r--r--usr.sbin/ppp/defs.h95
-rw-r--r--usr.sbin/ppp/filter.c495
-rw-r--r--usr.sbin/ppp/filter.h87
-rw-r--r--usr.sbin/ppp/fsm.c789
-rw-r--r--usr.sbin/ppp/fsm.h132
-rw-r--r--usr.sbin/ppp/hdlc.c423
-rw-r--r--usr.sbin/ppp/hdlc.h67
-rw-r--r--usr.sbin/ppp/id.c146
-rw-r--r--usr.sbin/ppp/id.h13
-rw-r--r--usr.sbin/ppp/ip.c522
-rw-r--r--usr.sbin/ppp/ip.h30
-rw-r--r--usr.sbin/ppp/ipcp.c601
-rw-r--r--usr.sbin/ppp/ipcp.h79
-rw-r--r--usr.sbin/ppp/lcp.c716
-rw-r--r--usr.sbin/ppp/lcp.h78
-rw-r--r--usr.sbin/ppp/lcpproto.h39
-rw-r--r--usr.sbin/ppp/loadalias.c92
-rw-r--r--usr.sbin/ppp/loadalias.h21
-rw-r--r--usr.sbin/ppp/log.c222
-rw-r--r--usr.sbin/ppp/log.h44
-rw-r--r--usr.sbin/ppp/lqr.c270
-rw-r--r--usr.sbin/ppp/lqr.h64
-rw-r--r--usr.sbin/ppp/main.c1091
-rw-r--r--usr.sbin/ppp/main.h31
-rw-r--r--usr.sbin/ppp/mbuf.c175
-rw-r--r--usr.sbin/ppp/mbuf.h63
-rw-r--r--usr.sbin/ppp/modem.c913
-rw-r--r--usr.sbin/ppp/modem.h42
-rw-r--r--usr.sbin/ppp/os.c380
-rw-r--r--usr.sbin/ppp/os.h30
-rw-r--r--usr.sbin/ppp/pap.c216
-rw-r--r--usr.sbin/ppp/pap.h29
-rw-r--r--usr.sbin/ppp/patch/auth4.patch12
-rw-r--r--usr.sbin/ppp/patch/command5.patch24
-rw-r--r--usr.sbin/ppp/patch/loopback2.patch36
-rw-r--r--usr.sbin/ppp/patch/random.patch11
-rw-r--r--usr.sbin/ppp/patch/thr.patch972
-rw-r--r--usr.sbin/ppp/patch/thr.tgzbin0 -> 1115 bytes
-rw-r--r--usr.sbin/ppp/pathnames.h43
-rw-r--r--usr.sbin/ppp/phase.c66
-rw-r--r--usr.sbin/ppp/phase.h32
-rw-r--r--usr.sbin/ppp/ppp.82453
-rw-r--r--usr.sbin/ppp/pred.c222
-rw-r--r--usr.sbin/ppp/pred.h25
-rw-r--r--usr.sbin/ppp/route.c484
-rw-r--r--usr.sbin/ppp/route.h27
-rw-r--r--usr.sbin/ppp/server.c145
-rw-r--r--usr.sbin/ppp/server.h9
-rw-r--r--usr.sbin/ppp/sig.c73
-rw-r--r--usr.sbin/ppp/sig.h11
-rw-r--r--usr.sbin/ppp/slcompress.c587
-rw-r--r--usr.sbin/ppp/slcompress.h134
-rw-r--r--usr.sbin/ppp/systems.c368
-rw-r--r--usr.sbin/ppp/systems.h31
-rw-r--r--usr.sbin/ppp/throughput.c127
-rw-r--r--usr.sbin/ppp/throughput.h24
-rw-r--r--usr.sbin/ppp/timer.c296
-rw-r--r--usr.sbin/ppp/timer.h51
-rw-r--r--usr.sbin/ppp/tun.c46
-rw-r--r--usr.sbin/ppp/tun.h20
-rw-r--r--usr.sbin/ppp/vars.c194
-rw-r--r--usr.sbin/ppp/vars.h204
-rw-r--r--usr.sbin/ppp/vjcomp.c155
-rw-r--r--usr.sbin/ppp/vjcomp.h7
85 files changed, 19544 insertions, 0 deletions
diff --git a/usr.sbin/ppp/Makefile b/usr.sbin/ppp/Makefile
new file mode 100644
index 00000000000..f9dbc19e38e
--- /dev/null
+++ b/usr.sbin/ppp/Makefile
@@ -0,0 +1,23 @@
+# $Id: Makefile,v 1.1 1997/11/23 20:27:32 brian Exp $
+
+PROG= ppp
+SRCS= arp.c async.c auth.c ccp.c chap.c chap_ms.c chat.c \
+ command.c defs.c filter.c fsm.c hdlc.c id.c ip.c ipcp.c lcp.c \
+ log.c lqr.c main.c mbuf.c modem.c os.c pap.c phase.c \
+ pred.c route.c server.c sig.c slcompress.c systems.c throughput.c \
+ timer.c tun.c vars.c vjcomp.c
+CFLAGS+=-Wall -Wmissing-prototypes -DHAVE_DES
+LDADD+= -lutil -ldes
+DPADD+= ${LIBUTIL} ${LIBDES}
+MAN= ppp.8
+BINMODE=4550
+BINOWN= root
+BINGRP= network
+
+.if exists(/usr/include/alias.h)
+SRCS+= alias_cmd.c loadalias.c
+.else
+CFLAGS+=-DNOALIAS
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ppp/README.alias b/usr.sbin/ppp/README.alias
new file mode 100644
index 00000000000..de5b3c90af7
--- /dev/null
+++ b/usr.sbin/ppp/README.alias
@@ -0,0 +1,352 @@
+User PPP Packet Aliasing
+
+
+
+0. Contents
+ 1. Background
+ 2. Setup
+ 3. New commands in ppp
+ 4. Future Work
+ 5. Authors / Acknowledgments
+ 6. Revision History for Aliasing Code
+
+
+
+1. Background
+
+User mode ppp has embedded packet aliasing (IP masquerading) code.
+Enabling this, either by the "-alias" command line option or the
+"alias enable yes" command in a ppp.conf file, makes the ppp host
+automatically alias IP packets forwarded from a local network, making
+them appear to come from the ppp host machine. Incoming packets
+from the outside world are then appropriately de-aliased.
+
+The process of aliasing involves both the IP address and the TCP or UDP
+port numbers. ICMP echo and timestamp packets are aliased by their id
+numbers. ICMP error messages can be properly directed by examining the
+fragment of the offending packet which is contained in the body of the
+message.
+
+This software was specifically meant to support users who have
+unregistered, private address IP networks (e.g. 192.168.0.x or 10.0.0.x
+addresses). The ppp host can act as a gateway for these networks, and
+computers on the local area net will have some degree of Internet access
+without the need for a registered IP address. Additionally, there will
+be no need for an Internet service provider to maintain routing tables
+for the local area network.
+
+A disadvantage of packet aliasing is that machines on the local network,
+behind the ppp host, are not visible from the outside world. They can
+establish TCP connections and make UDP inquiries (such as domain name
+service requests) but the connections seem to come from the ppp host
+itself. There is, in effect, a partial firewall. Of course, if this is
+what you want, the disadvantage becomes an advantage.
+
+A second disadvantage is that "IP encoding" protocols, which send IP
+address or port information within the data stream, are not supported
+for the cases where exception code exists. This implementation has
+workarounds for FTP and IRC DCC, the most well known of the IP encoding
+protocols. This frees users from depending on using the ftp passive
+mode and avoiding IRC DCC sends, as is sometimes the case with other
+masquerading solutions.
+
+The implementation supports all standard, non-encoding TCP and UDP protocols.
+Examples of these protocols are http, gopher and telnet. The standard UDP
+mode of RealAudio is not presently supported, but the TCP mode does work
+correctly.
+
+The packet aliasing code also handle many ICMP messages. In particular,
+ping and traceroute are supported.
+
+
+
+2. Packet Aliasing Setup
+
+It is recommended that users first verify correct ppp operation without
+packet aliasing enabled. This will confirm that the ppp.conf file is
+properly set up and that there are no ppp problems. Then start ppp with
+the "-alias" option on the command line. The user should verify that
+the ppp host can correctly connect to the Internet in packet aliasing
+mode. Finally, check that machines on the private network can access
+the Internet.
+
+The masquerading software aliases all packets, whether they come from
+the host or another computer on the local area network. Thus, a correctly
+operating ppp host indicates that the software should work properly for
+other computers on the private network.
+
+If the ppp host can access the Internet, but other computers on the local
+network cannot, check that IP forwarding is enabled on the ppp host. Also,
+verify that the other computers use this machine as a gateway. Of course,
+you should also verify that machines within the local area network
+communicate properly. A common error is inconsistent subnet addresses
+and masks.
+
+
+
+3. New commands in ppp
+
+In order to control aliasing behavior in a simple manner (no need for
+recompilation), a new command has been added to iij-ppp: alias. This
+is in addition to the -alias command line option. System managers and
+more experienced users may prefer to use the iij-ppp command syntax
+within the ppp.conf file. The alias command also allows packet aliasing
+behavior to be more precisely specified.
+
+The decision to add a command instead of extending 'set' or 'option' was
+to make obvious that these options only work when aliasing is enabled.
+
+The syntax for 'alias' is
+
+ ppp> alias option [yes|no]
+
+where option is given by one of the following templates.
+
+
+ - alias enable [yes|no] (default no)
+
+Enable packet aliasing functionality. If disabled, no other alias
+options will have any effect. You should usually enable aliasing
+before routing any packets over the link; good points are in the
+initial script or right before adding a route. If you do not always
+want aliasing, consider using the -alias option to ppp instead of this
+command.
+
+
+ - alias deny_incoming [yes|no] (default yes)
+
+Set to "yes" to disable all incoming connections. This just drops
+connections to, for example, ftp, telnet or web servers. The aliasing
+mechanism prevents these connections. Technically, this option denies
+all incoming TCP and UDP requests, making the aliasing software a
+fairly efficient one-way firewall. The default is no, which will
+all incoming connections to telnetd, ftpd, etc.
+
+
+ - alias log [yes|no]
+
+Controls logging of alias link creation to "/var/log/alias.log" - this
+is usually only useful if debugging a setup, to see if the bug is in
+the PPP aliasing. The debugging information is fairly limited, listing
+the number of aliasing links open for different prototocols.
+
+
+ - alias same_ports [yes|no] (default yes)
+
+When a connection is being established going through the aliasing
+routines, it will normally have its port number changed to allow the
+aliasing code to track it. If same_ports is enabled, the alias
+software attempts to keep the connection's source port unchanged.
+This will allow rsh, RPC and other specialized protocols to work
+_most of the time_, at least on the host machine. Please, do not
+report this being unstable as a bug - it is a result of the way
+aliasing has to work. TCP/IP was intended to have one IP address
+per machine.
+
+
+ - alias use_sockets [yes|no] (default yes)
+
+This is a fairly obscure option. For the most part, the packet aliasing
+software does not have to allocate system sockets when it chooses an
+aliasing port number. Under very specific circumstances, FTP data
+connections (which don't know the remote port nubmer, though it is
+usually 20) and IRC DCC send (which doesn't know either the address or
+the port from which the connection will come), there can potentially be
+some interference with an open server socket having the same port number
+on the ppp host machine. This possibility for interferience only exists
+until the TCP connection has been acknowledged on both sides. The safe
+option is yes, though fewer system resources are consumed by specifying
+no.
+
+
+ - alias unregistered_only [yes|no] (default no)
+
+Packet aliasing normally remaps all packets coming from the local area
+network to the ppp host machine address. Set this option to only map
+addresses from the following standard ranges for private, unregistered
+addresses:
+
+ 10.0.0.0 -> 10.255.255.255
+ 172.16.0.0 -> 172.31.255.255
+ 192.168.0.0 -> 192.168.255.255 */
+
+In the instance that there is a subnet of public addresses and another
+subnet of private addresses being routed by the ppp host, then only the
+packets on the private subnet will be aliased.
+
+
+- alias port <proto> <local addr>:<port> <alias port>
+
+This command allows incoming traffic to <alias port> on the host
+machine to be redirected to a specific machine and port on the
+local area network. One example of this would be:
+
+ alias port tcp 192.168.0.4:telnet 8066
+
+All traffic to port 8066 fthe ppp host would then be sent to
+the telnet port (23) of machine 192.168.0.4. Port numbers
+can either be designated numerically or by symbolic names
+listed in /etc/services. Similarly, addresses can be either
+in dotted quad notation or in /etc/hosts.
+
+
+- alias addr <local addr> <public addr>
+
+This command allows traffic for a public IP address to be
+redirected to a machine on the local network. This function
+is known as "static NAT". An address assignment of 0 refers
+to the default address of the ppp host. Normally static
+NAT is useful if your ISP has allocated a small block of
+IP addresses to the user, but it can even be used in the
+case of a single, dynamically allocated IP address:
+
+ alias addr 10.0.0.8 0
+
+The above command would redirect all incoming traffic to
+machine 10.0.0.8.
+
+If several address aliases specifiy the same public addres
+as follows
+
+ alias addr 192.168.0.2 public_addr
+ alias addr 192.168.0.3 public_addr
+ alias addr 192.168.0.4 public_addr
+
+then incoming traffice will be directed to the last
+translated local address (192.168.0.4), but outgoing
+traffic to the first two addresses will still be aliased
+to the specified public address.
+
+
+
+4. Future Work
+
+What is called packet aliasing here has been variously called masquerading,
+network address translation (NAT) and transparent proxying by others. It
+is an extremely useful function to many users, but it is also necessarily
+imperfect. The occasional IP-encoding protocols always need workarounds
+(hacks). Users who are interested in supporting new IP-encoding protocols
+can follow the examples of alias_ftp.c and alias_irc.c.
+
+ICMP error messages are currently handled only in the incoming direction.
+A handler needs to be added to correctly alias outgoing error messages.
+
+IRC and FTP exception handling make reasonable, though not strictly correct
+assumptions, about how IP encoded messages will appear in the control
+stream. Programmers may wish to consider how to make this process more
+robust.
+
+The packet aliasing engine (alias.c, alias_db.c, alias_ftp.c, alias_irc.c
+and alias_util.c) runs in user space, and is intended to be both portable
+and reusable for interfaces other than ppp. To access the basic engine
+only requires four simple function calls (initialization, communication of
+host address, outgoing aliasing and incoming de-aliasing).
+
+
+
+5. Authors / Acknowledgments
+
+Charles Mott (cmott@srv.net) <versions 1.0 - 1.8, 2.0, 2.1>
+Eivind Eklund (perhaps@yes.no) <versions 1.8b - 1.9, new ppp commands>
+
+Listed below, in chronological order, are individuals who have provided
+valuable comments and/or debugging assistance.
+
+ Gary Roberts
+ Tom Torrance
+ Reto Burkhalter
+ Martin Renters
+ Brian Somers
+ Paul Traina
+ Ari Suutari
+ J. Fortes
+ Andrzej Bialeki
+
+
+
+6. Revision History for Aliasing Code
+
+Version 1.0: August 11, 1996 (cjm)
+
+Version 1.1: August 20, 1996 (cjm)
+ PPP host accepts incoming connections for ports 0 to 1023.
+
+Version 1.2: September 7, 1996 (cjm)
+ Fragment handling error in alias_db.c corrected.
+
+Version 1.3: September 15, 1996 (cjm)
+ - Generalized mechanism for handling incoming connections
+ (no more 0 to 1023 restriction).
+ - Increased ICMP support (will handle traceroute now).
+ - Improved TCP close connection logic.
+
+Version 1.4: September 16, 1996
+ Can't remember (this version only lasted a day -- cjm).
+
+Version 1.5: September 17, 1996 (cjm)
+ Corrected error in handling incoming UDP packets
+ with zero checksum.
+
+Version 1.6: September 18, 1996
+ Simplified ICMP data storage. Will now handle
+ tracert from Win95 as well as FreeBSD traceroute.
+
+Verstion 1.7: January 9, 1997 (cjm)
+ - Reduced malloc() activity for ICMP echo and
+ timestamp requests.
+ - Added handling for out-of-order IP fragments.
+ - Switched to differential checksum computation
+ for IP headers (TCP, UDP and ICMP checksums
+ were already differential).
+ - Accepts FTP data connections from other than
+ port 20. This allows one ftp connections
+ from two hosts which are both running packet
+ aliasing.
+
+Verstion 1.8: January 14, 1997 (cjm)
+ - Fixed data type error in function StartPoint()
+ in alias_db.c (this bug did not exist before v1.7)
+
+Version 1.8b: January 16, 1997 (Eivind Eklund <perhaps@yes.no>)
+ - Upgraded base PPP version to be the sourcecode from
+ FreeBSD 2.1.6, with additional security patches. This
+ version should still be possible to run on 2.1.5, though -
+ I've run it with a 2.1.5 kernel without problems.
+ (Update done with the permission of cjm)
+
+Version 1.9: February 1, 1997 (Eivind Eklund <perhaps@yes.no>)
+ - Added support for IRC DCC (ee)
+ - Changed the aliasing routines to use ANSI style throughout -
+ minor API changes for integration with other programs than PPP (ee)
+ - Changed the build process, making all options switchable
+ from the Makefile (ee)
+ - Fixed minor security hole in alias_ftp.c for other applications
+ of the aliasing software. Hole could _not_ manifest in
+ PPP+pktAlias, but could potentially manifest in other
+ applications of the aliasing. (ee)
+ - Connections initiated from packet aliasing host machine will
+ not have their port number aliased unless it conflicts with
+ an aliasing port already being used. (There is an option to
+ disable this for debugging) (cjm)
+ - Sockets will be allocated in cases where there might be
+ port interference with the host machine. This can be disabled
+ in cases where the ppp host will be acting purely as a
+ masquerading router and not generate any traffic of its own.
+ (cjm)
+
+Version 2.0: March, 1997 (cjm)
+ - Incoming packets which are not recognized by the packet
+ aliasing engine are now completely dropped in ip.c.
+ - Aliasing links are cleared when a host interface address
+ changes (due to re-dial and dynamic address allocatioa).
+ - PacketAliasPermanentLink() API added.
+ - Option for only aliasing private, unregistered IP addresses
+ added.
+ - Substantial rework to the aliasing lookup engine.
+
+Version 2.1: May, 1997 (cjm)
+ - Continuing rework to the aliasing lookup engine to support
+ multiple incoming addresses and static NAT.
+ - Now supports outgoing as well as incoming ICMP error messges/
+ - PPP commands to support address and port redirection.
+
diff --git a/usr.sbin/ppp/alias_cmd.c b/usr.sbin/ppp/alias_cmd.c
new file mode 100644
index 00000000000..240772833e2
--- /dev/null
+++ b/usr.sbin/ppp/alias_cmd.c
@@ -0,0 +1,191 @@
+/*
+ * $Id: alias_cmd.c,v 1.1 1997/11/23 20:27:32 brian Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "defs.h"
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "alias_cmd.h"
+
+
+static int StrToAddr(const char *, struct in_addr *);
+static int StrToPort(const char *, u_short *, const char *);
+static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, const char *);
+
+
+int
+AliasRedirectPort(struct cmdargs const *arg)
+{
+ if (!(mode & MODE_ALIAS)) {
+ if (VarTerm)
+ fprintf(VarTerm, "Alias not enabled\n");
+ } else if (arg->argc == 3) {
+ char proto_constant;
+ const char *proto;
+ u_short local_port;
+ u_short alias_port;
+ int error;
+ struct in_addr local_addr;
+ struct in_addr null_addr;
+ struct alias_link *link;
+
+ proto = arg->argv[0];
+ if (strcmp(proto, "tcp") == 0) {
+ proto_constant = IPPROTO_TCP;
+ } else if (strcmp(proto, "udp") == 0) {
+ proto_constant = IPPROTO_UDP;
+ } else {
+ if (VarTerm) {
+ fprintf(VarTerm, "port redirect: protocol must be tcp or udp\n");
+ fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name,
+ arg->cmd->syntax);
+ }
+ return 1;
+ }
+
+ error = StrToAddrAndPort(arg->argv[1], &local_addr, &local_port, proto);
+ if (error) {
+ if (VarTerm) {
+ fprintf(VarTerm, "port redirect: error reading local addr:port\n");
+ fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax);
+ }
+ return 1;
+ }
+ error = StrToPort(arg->argv[2], &alias_port, proto);
+ if (error) {
+ if (VarTerm) {
+ fprintf(VarTerm, "port redirect: error reading alias port\n");
+ fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax);
+ }
+ return 1;
+ }
+ null_addr.s_addr = 0;
+
+ link = VarPacketAliasRedirectPort(local_addr, local_port,
+ null_addr, 0,
+ null_addr, alias_port,
+ proto_constant);
+
+ if (link == NULL && VarTerm)
+ fprintf(VarTerm, "port redirect: error returned by packed"
+ " aliasing engine (code=%d)\n", error);
+ } else if (VarTerm)
+ fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax);
+
+ return 1;
+}
+
+
+int
+AliasRedirectAddr(struct cmdargs const *arg)
+{
+ if (!(mode & MODE_ALIAS)) {
+ if (VarTerm)
+ fprintf(VarTerm, "alias not enabled\n");
+ } else if (arg->argc == 2) {
+ int error;
+ struct in_addr local_addr;
+ struct in_addr alias_addr;
+ struct alias_link *link;
+
+ error = StrToAddr(arg->argv[0], &local_addr);
+ if (error) {
+ if (VarTerm)
+ fprintf(VarTerm, "address redirect: invalid local address\n");
+ return 1;
+ }
+ error = StrToAddr(arg->argv[1], &alias_addr);
+ if (error) {
+ if (VarTerm) {
+ fprintf(VarTerm, "address redirect: invalid alias address\n");
+ fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax);
+ }
+ return 1;
+ }
+ link = VarPacketAliasRedirectAddr(local_addr, alias_addr);
+ if (link == NULL && VarTerm) {
+ fprintf(VarTerm, "address redirect: packet aliasing engine error\n");
+ fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax);
+ }
+ } else if (VarTerm)
+ fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax);
+
+ return 1;
+}
+
+
+static int
+StrToAddr(const char *str, struct in_addr *addr)
+{
+ struct hostent *hp;
+
+ if (inet_aton(str, addr))
+ return 0;
+
+ hp = gethostbyname(str);
+ if (!hp) {
+ LogPrintf(LogWARN, "StrToAddr: Unknown host %s.\n", str);
+ return -1;
+ }
+ *addr = *((struct in_addr *) hp->h_addr);
+ return 0;
+}
+
+
+static int
+StrToPort(const char *str, u_short *port, const char *proto)
+{
+ int iport;
+ struct servent *sp;
+ char *end;
+
+ iport = strtol(str, &end, 10);
+ if (end != str) {
+ *port = htons(iport);
+ return 0;
+ }
+ sp = getservbyname(str, proto);
+ if (!sp) {
+ LogPrintf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n",
+ str, proto);
+ return -1;
+ }
+ *port = sp->s_port;
+ return 0;
+}
+
+
+static int
+StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *port, const char *proto)
+{
+ char *colon;
+ int res;
+
+ colon = strchr(str, ':');
+ if (!colon) {
+ LogPrintf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str);
+ return -1;
+ }
+
+ *colon = '\0'; /* Cheat the const-ness ! */
+ res = StrToAddr(str, addr);
+ *colon = ':'; /* Cheat the const-ness ! */
+ if (res != 0)
+ return -1;
+
+ return StrToPort(colon+1, port, proto);
+}
diff --git a/usr.sbin/ppp/alias_cmd.h b/usr.sbin/ppp/alias_cmd.h
new file mode 100644
index 00000000000..6b5e37eeee5
--- /dev/null
+++ b/usr.sbin/ppp/alias_cmd.h
@@ -0,0 +1,6 @@
+/*
+ * $Id: alias_cmd.h,v 1.1 1997/11/23 20:27:32 brian Exp $
+ */
+
+extern int AliasRedirectPort(struct cmdargs const *);
+extern int AliasRedirectAddr(struct cmdargs const *);
diff --git a/usr.sbin/ppp/arp.c b/usr.sbin/ppp/arp.c
new file mode 100644
index 00000000000..bed1cd879aa
--- /dev/null
+++ b/usr.sbin/ppp/arp.c
@@ -0,0 +1,314 @@
+/*
+ * sys-bsd.c - System-dependent procedures for setting up
+ * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: arp.c,v 1.1 1997/11/23 20:27:32 brian Exp $
+ *
+ */
+
+/*
+ * TODO:
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef __FreeBSD__
+#include <net/if_var.h>
+#endif
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <net/if_types.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "id.h"
+#include "arp.h"
+
+static int rtm_seq;
+
+static int get_ether_addr(int, u_long, struct sockaddr_dl *);
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ memset((char *) &(addr), '\0', sizeof(addr)); \
+ addr.sa_family = (family); \
+ addr.sa_len = sizeof(addr);
+
+
+#if RTM_VERSION >= 3
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+static struct {
+ struct rt_msghdr hdr;
+ struct sockaddr_inarp dst;
+ struct sockaddr_dl hwa;
+ char extra[128];
+} arpmsg;
+
+static int arpmsg_valid;
+
+int
+sifproxyarp(int unit, u_long hisaddr)
+{
+ int routes;
+
+ /*
+ * Get the hardware address of an interface on the same subnet as our local
+ * address.
+ */
+ memset(&arpmsg, 0, sizeof(arpmsg));
+ if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) {
+ LogPrintf(LogERROR, "Cannot determine ethernet address for proxy ARP\n");
+ return 0;
+ }
+ routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET);
+ if (routes < 0) {
+ LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n",
+ strerror(errno));
+ return 0;
+ }
+ arpmsg.hdr.rtm_type = RTM_ADD;
+ arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
+ arpmsg.hdr.rtm_version = RTM_VERSION;
+ arpmsg.hdr.rtm_seq = ++rtm_seq;
+ arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ arpmsg.hdr.rtm_inits = RTV_EXPIRE;
+ arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
+ arpmsg.dst.sin_family = AF_INET;
+ arpmsg.dst.sin_addr.s_addr = hisaddr;
+ arpmsg.dst.sin_other = SIN_PROXY;
+
+ arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
+ + arpmsg.hwa.sdl_len;
+ if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+ LogPrintf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno));
+ close(routes);
+ return 0;
+ }
+ close(routes);
+ arpmsg_valid = 1;
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(int unit, u_long hisaddr)
+{
+ int routes;
+
+ if (!arpmsg_valid)
+ return 0;
+ arpmsg_valid = 0;
+
+ arpmsg.hdr.rtm_type = RTM_DELETE;
+ arpmsg.hdr.rtm_seq = ++rtm_seq;
+
+ routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET);
+ if (routes < 0) {
+ LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n",
+ strerror(errno));
+ return 0;
+ }
+ if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+ LogPrintf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno));
+ close(routes);
+ return 0;
+ }
+ close(routes);
+ return 1;
+}
+
+#else /* RTM_VERSION */
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(int unit, u_long hisaddr)
+{
+ struct arpreq arpreq;
+ struct {
+ struct sockaddr_dl sdl;
+ char space[128];
+ } dls;
+
+ memset(&arpreq, '\0', sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet as our local
+ * address.
+ */
+ if (!get_ether_addr(unit, hisaddr, &dls.sdl)) {
+ LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n");
+ return 0;
+ }
+ arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
+ arpreq.arp_ha.sa_family = AF_UNSPEC;
+ memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen);
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ID0ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) {
+ LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): %s\n", strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(int unit, u_long hisaddr)
+{
+ struct arpreq arpreq;
+
+ memset(&arpreq, '\0', sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ if (ID0ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) {
+ LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): %s\n", strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+#endif /* RTM_VERSION */
+
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+static int
+get_ether_addr(int s, u_long ipaddr, struct sockaddr_dl *hwaddr)
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ u_long ina, mask;
+ struct sockaddr_dl *dla;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
+ LogPrintf(LogERROR, "get_ether_addr: ioctl(SIOCGIFCONF): %s\n",
+ strerror(errno));
+ return 0;
+ }
+
+ /*
+ * Scan through looking for an interface with an Internet address on the
+ * same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend;) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr.s_addr;
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
+
+ /*
+ * Check that the interface is up, and not point-to-point or loopback.
+ */
+ if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP))
+ != (IFF_UP | IFF_BROADCAST))
+ goto nextif;
+
+ /*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ goto nextif;
+
+ break;
+ }
+nextif:
+ ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ if (ifr >= ifend)
+ return 0;
+ LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", ifr->ifr_name);
+
+ /*
+ * Now scan through again looking for a link-level address for this
+ * interface.
+ */
+ ifp = ifr;
+ for (ifr = ifc.ifc_req; ifr < ifend;) {
+ if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
+ && ifr->ifr_addr.sa_family == AF_LINK) {
+
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *) & ifr->ifr_addr;
+ memcpy(hwaddr, dla, dla->sdl_len);
+ return 1;
+ }
+ ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ return 0;
+}
+
+
+#ifdef DEBUG
+int
+main()
+{
+ u_long ipaddr;
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ ipaddr = inet_addr("192.168.1.32");
+ sifproxyarp(s, ipaddr);
+ close(s);
+}
+#endif
diff --git a/usr.sbin/ppp/arp.h b/usr.sbin/ppp/arp.h
new file mode 100644
index 00000000000..53b6b934b04
--- /dev/null
+++ b/usr.sbin/ppp/arp.h
@@ -0,0 +1,25 @@
+/*
+ * User Process PPP
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: arp.h,v 1.1 1997/11/23 20:27:32 brian Exp $
+ *
+ */
+
+extern int cifproxyarp(int, u_long);
+extern int sifproxyarp(int, u_long);
diff --git a/usr.sbin/ppp/async.c b/usr.sbin/ppp/async.c
new file mode 100644
index 00000000000..1f04ace6507
--- /dev/null
+++ b/usr.sbin/ppp/async.c
@@ -0,0 +1,198 @@
+/*
+ * PPP Async HDLC Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: async.c,v 1.1 1997/11/23 20:27:32 brian Exp $
+ *
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "hdlc.h"
+#include "lcp.h"
+#include "lcpproto.h"
+#include "modem.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "os.h"
+#include "async.h"
+
+#define HDLCSIZE (MAX_MRU*2+6)
+
+static struct async_state {
+ int mode;
+ int length;
+ u_char hbuff[HDLCSIZE]; /* recv buffer */
+ u_char xbuff[HDLCSIZE]; /* xmit buffer */
+ u_long my_accmap;
+ u_long his_accmap;
+} AsyncState;
+
+#define MODE_HUNT 0x01
+#define MODE_ESC 0x02
+
+void
+AsyncInit()
+{
+ struct async_state *stp = &AsyncState;
+
+ stp->mode = MODE_HUNT;
+ stp->length = 0;
+ stp->my_accmap = stp->his_accmap = 0xffffffff;
+}
+
+void
+SetLinkParams(struct lcpstate *lcp)
+{
+ struct async_state *stp = &AsyncState;
+
+ stp->my_accmap = lcp->want_accmap;
+ stp->his_accmap = lcp->his_accmap;
+}
+
+/*
+ * Encode into async HDLC byte code if necessary
+ */
+static void
+HdlcPutByte(u_char **cp, u_char c, int proto)
+{
+ u_char *wp;
+
+ wp = *cp;
+ if ((c < 0x20 && (proto == PROTO_LCP || (AsyncState.his_accmap & (1 << c))))
+ || (c == HDLC_ESC) || (c == HDLC_SYN)) {
+ *wp++ = HDLC_ESC;
+ c ^= HDLC_XOR;
+ }
+ if (EscMap[32] && EscMap[c >> 3] & (1 << (c & 7))) {
+ *wp++ = HDLC_ESC;
+ c ^= HDLC_XOR;
+ }
+ *wp++ = c;
+ *cp = wp;
+}
+
+void
+AsyncOutput(int pri, struct mbuf *bp, int proto)
+{
+ struct async_state *hs = &AsyncState;
+ u_char *cp, *sp, *ep;
+ struct mbuf *wp;
+ int cnt;
+
+ if (plength(bp) > HDLCSIZE) {
+ pfree(bp);
+ return;
+ }
+ cp = hs->xbuff;
+ ep = cp + HDLCSIZE - 10;
+ wp = bp;
+ *cp++ = HDLC_SYN;
+ while (wp) {
+ sp = MBUF_CTOP(wp);
+ for (cnt = wp->cnt; cnt > 0; cnt--) {
+ HdlcPutByte(&cp, *sp++, proto);
+ if (cp >= ep) {
+ pfree(bp);
+ return;
+ }
+ }
+ wp = wp->next;
+ }
+ *cp++ = HDLC_SYN;
+
+ cnt = cp - hs->xbuff;
+ LogDumpBuff(LogASYNC, "WriteModem", hs->xbuff, cnt);
+ WriteModem(pri, (char *) hs->xbuff, cnt);
+ ModemAddOutOctets(cnt);
+ pfree(bp);
+}
+
+static struct mbuf *
+AsyncDecode(u_char c)
+{
+ struct async_state *hs = &AsyncState;
+ struct mbuf *bp;
+
+ if ((hs->mode & MODE_HUNT) && c != HDLC_SYN)
+ return (NULLBUFF);
+
+ switch (c) {
+ case HDLC_SYN:
+ hs->mode &= ~MODE_HUNT;
+ if (hs->length) { /* packet is ready. */
+ bp = mballoc(hs->length, MB_ASYNC);
+ mbwrite(bp, hs->hbuff, hs->length);
+ hs->length = 0;
+ return (bp);
+ }
+ break;
+ case HDLC_ESC:
+ if (!(hs->mode & MODE_ESC)) {
+ hs->mode |= MODE_ESC;
+ break;
+ }
+ /* Fall into ... */
+ default:
+ if (hs->length >= HDLCSIZE) {
+ /* packet is too large, discard it */
+ LogPrintf(LogERROR, "Packet too large (%d), discarding.\n", hs->length);
+ hs->length = 0;
+ hs->mode = MODE_HUNT;
+ break;
+ }
+ if (hs->mode & MODE_ESC) {
+ c ^= HDLC_XOR;
+ hs->mode &= ~MODE_ESC;
+ }
+ hs->hbuff[hs->length++] = c;
+ break;
+ }
+ return NULLBUFF;
+}
+
+void
+AsyncInput(u_char *buff, int cnt)
+{
+ struct mbuf *bp;
+
+ ModemAddInOctets(cnt);
+ if (DEV_IS_SYNC) {
+ bp = mballoc(cnt, MB_ASYNC);
+ memcpy(MBUF_CTOP(bp), buff, cnt);
+ bp->cnt = cnt;
+ HdlcInput(bp);
+ } else {
+ while (cnt > 0) {
+ bp = AsyncDecode(*buff++);
+ if (bp)
+ HdlcInput(bp);
+ cnt--;
+ }
+ }
+}
diff --git a/usr.sbin/ppp/async.h b/usr.sbin/ppp/async.h
new file mode 100644
index 00000000000..0f185c4793c
--- /dev/null
+++ b/usr.sbin/ppp/async.h
@@ -0,0 +1,8 @@
+/*
+ * $Id: async.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ */
+
+extern void AsyncInit(void);
+extern void SetLinkParams(struct lcpstate *);
+extern void AsyncOutput(int, struct mbuf *, int);
+extern void AsyncInput(u_char *, int);
diff --git a/usr.sbin/ppp/auth.c b/usr.sbin/ppp/auth.c
new file mode 100644
index 00000000000..c3a2b055e24
--- /dev/null
+++ b/usr.sbin/ppp/auth.c
@@ -0,0 +1,223 @@
+/*
+ * PPP Secret Key Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: auth.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ * o Implement check against with registered IP addresses.
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcpproto.h"
+#include "ipcp.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "filter.h"
+#include "auth.h"
+#include "chat.h"
+#include "systems.h"
+
+void
+LocalAuthInit()
+{
+ if (!(mode&MODE_DAEMON))
+ /* We're allowed in interactive mode */
+ VarLocalAuth = LOCAL_AUTH;
+ else if (VarHaveLocalAuthKey)
+ VarLocalAuth = *VarLocalAuthKey == '\0' ? LOCAL_AUTH : LOCAL_NO_AUTH;
+ else
+ switch (LocalAuthValidate(SECRETFILE, VarShortHost, "")) {
+ case NOT_FOUND:
+ VarLocalAuth = LOCAL_DENY;
+ break;
+ case VALID:
+ VarLocalAuth = LOCAL_AUTH;
+ break;
+ case INVALID:
+ VarLocalAuth = LOCAL_NO_AUTH;
+ break;
+ }
+}
+
+LOCAL_AUTH_VALID
+LocalAuthValidate(const char *fname, const char *system, const char *key)
+{
+ FILE *fp;
+ int n;
+ char *vector[3];
+ char buff[LINE_LEN];
+ LOCAL_AUTH_VALID rc;
+
+ rc = NOT_FOUND; /* No system entry */
+ fp = OpenSecret(fname);
+ if (fp == NULL)
+ return (rc);
+ while (fgets(buff, sizeof(buff), fp)) {
+ if (buff[0] == '#')
+ continue;
+ buff[strlen(buff) - 1] = 0;
+ memset(vector, '\0', sizeof(vector));
+ n = MakeArgs(buff, vector, VECSIZE(vector));
+ if (n < 1)
+ continue;
+ if (strcmp(vector[0], system) == 0) {
+ if ((vector[1] == (char *) NULL && (key == NULL || *key == '\0')) ||
+ (vector[1] != (char *) NULL && strcmp(vector[1], key) == 0)) {
+ rc = VALID; /* Valid */
+ } else {
+ rc = INVALID; /* Invalid */
+ }
+ break;
+ }
+ }
+ CloseSecret(fp);
+ return (rc);
+}
+
+int
+AuthValidate(const char *fname, const char *system, const char *key)
+{
+ FILE *fp;
+ int n;
+ char *vector[4];
+ char buff[LINE_LEN];
+ char passwd[100];
+
+ fp = OpenSecret(fname);
+ if (fp == NULL)
+ return (0);
+ while (fgets(buff, sizeof(buff), fp)) {
+ if (buff[0] == '#')
+ continue;
+ buff[strlen(buff) - 1] = 0;
+ memset(vector, '\0', sizeof(vector));
+ n = MakeArgs(buff, vector, VECSIZE(vector));
+ if (n < 2)
+ continue;
+ if (strcmp(vector[0], system) == 0) {
+ ExpandString(vector[1], passwd, sizeof(passwd), 0);
+ if (strcmp(passwd, key) == 0) {
+ CloseSecret(fp);
+ memset(&DefHisAddress, '\0', sizeof(DefHisAddress));
+ n -= 2;
+ if (n > 0) {
+ if (ParseAddr(n--, (char const *const *)(vector+2),
+ &DefHisAddress.ipaddr,
+ &DefHisAddress.mask,
+ &DefHisAddress.width) == 0) {
+ return (0); /* Invalid */
+ }
+ }
+ IpcpInit();
+ return (1); /* Valid */
+ }
+ }
+ }
+ CloseSecret(fp);
+ return (0); /* Invalid */
+}
+
+char *
+AuthGetSecret(const char *fname, const char *system, int len, int setaddr)
+{
+ FILE *fp;
+ int n;
+ char *vector[4];
+ char buff[LINE_LEN];
+ static char passwd[100];
+
+ fp = OpenSecret(fname);
+ if (fp == NULL)
+ return (NULL);
+ while (fgets(buff, sizeof(buff), fp)) {
+ if (buff[0] == '#')
+ continue;
+ buff[strlen(buff) - 1] = 0;
+ memset(vector, '\0', sizeof(vector));
+ n = MakeArgs(buff, vector, VECSIZE(vector));
+ if (n < 2)
+ continue;
+ if (strlen(vector[0]) == len && strncmp(vector[0], system, len) == 0) {
+ ExpandString(vector[1], passwd, sizeof(passwd), 0);
+ if (setaddr) {
+ memset(&DefHisAddress, '\0', sizeof(DefHisAddress));
+ }
+ n -= 2;
+ if (n > 0 && setaddr) {
+ LogPrintf(LogDEBUG, "AuthGetSecret: n = %d, %s\n", n, vector[2]);
+ if (ParseAddr(n--, (char const *const *)(vector+2),
+ &DefHisAddress.ipaddr,
+ &DefHisAddress.mask,
+ &DefHisAddress.width) != 0)
+ IpcpInit();
+ }
+ return (passwd);
+ }
+ }
+ CloseSecret(fp);
+ return (NULL); /* Invalid */
+}
+
+static void
+AuthTimeout(void *vauthp)
+{
+ struct pppTimer *tp;
+ struct authinfo *authp = (struct authinfo *)vauthp;
+
+ tp = &authp->authtimer;
+ StopTimer(tp);
+ if (--authp->retry > 0) {
+ StartTimer(tp);
+ (authp->ChallengeFunc) (++authp->id);
+ }
+}
+
+void
+StartAuthChallenge(struct authinfo *authp)
+{
+ struct pppTimer *tp;
+
+ tp = &authp->authtimer;
+ StopTimer(tp);
+ tp->func = AuthTimeout;
+ tp->load = VarRetryTimeout * SECTICKS;
+ tp->state = TIMER_STOPPED;
+ tp->arg = (void *) authp;
+ StartTimer(tp);
+ authp->retry = 3;
+ authp->id = 1;
+ (authp->ChallengeFunc) (authp->id);
+}
+
+void
+StopAuthTimer(struct authinfo *authp)
+{
+ StopTimer(&authp->authtimer);
+}
diff --git a/usr.sbin/ppp/auth.h b/usr.sbin/ppp/auth.h
new file mode 100644
index 00000000000..aa430576da9
--- /dev/null
+++ b/usr.sbin/ppp/auth.h
@@ -0,0 +1,41 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: auth.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+typedef enum {
+ VALID,
+ INVALID,
+ NOT_FOUND
+} LOCAL_AUTH_VALID;
+
+struct authinfo {
+ void (*ChallengeFunc) (int);
+ struct pppTimer authtimer;
+ int retry;
+ int id;
+};
+
+extern LOCAL_AUTH_VALID LocalAuthValidate(const char *, const char *, const char *);
+extern void StopAuthTimer(struct authinfo *);
+extern void StartAuthChallenge(struct authinfo *);
+extern void LocalAuthInit(void);
+extern int AuthValidate(const char *, const char *, const char *);
+extern char *AuthGetSecret(const char *, const char *, int, int);
diff --git a/usr.sbin/ppp/ccp.c b/usr.sbin/ppp/ccp.c
new file mode 100644
index 00000000000..e60d64070d7
--- /dev/null
+++ b/usr.sbin/ppp/ccp.c
@@ -0,0 +1,284 @@
+/*
+ * PPP Compression Control Protocol (CCP) Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ccp.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ * o Support other compression protocols
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "ccp.h"
+#include "phase.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "pred.h"
+
+struct ccpstate CcpInfo;
+
+static void CcpSendConfigReq(struct fsm *);
+static void CcpSendTerminateReq(struct fsm *);
+static void CcpSendTerminateAck(struct fsm *);
+static void CcpDecodeConfig(u_char *, int, int);
+static void CcpLayerStart(struct fsm *);
+static void CcpLayerFinish(struct fsm *);
+static void CcpLayerUp(struct fsm *);
+static void CcpLayerDown(struct fsm *);
+static void CcpInitRestartCounter(struct fsm *);
+
+#define REJECTED(p, x) (p->his_reject & (1<<x))
+
+struct fsm CcpFsm = {
+ "CCP",
+ PROTO_CCP,
+ CCP_MAXCODE,
+ OPEN_ACTIVE,
+ ST_INITIAL,
+ 0, 0, 0,
+ 0,
+ {0, 0, 0, NULL, NULL, NULL},
+ {0, 0, 0, NULL, NULL, NULL},
+ LogCCP,
+
+ CcpLayerUp,
+ CcpLayerDown,
+ CcpLayerStart,
+ CcpLayerFinish,
+ CcpInitRestartCounter,
+ CcpSendConfigReq,
+ CcpSendTerminateReq,
+ CcpSendTerminateAck,
+ CcpDecodeConfig,
+};
+
+static char const *cftypes[] = {
+ /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
+ "OUI", /* 0: OUI */
+ "PRED1", /* 1: Predictor type 1 */
+ "PRED2", /* 2: Predictor type 2 */
+ "PUDDLE", /* 3: Puddle Jumber */
+ "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???",
+ "HWPPC", /* 16: Hewlett-Packard PPC */
+ "STAC", /* 17: Stac Electronics LZS */
+ "MSPPC", /* 18: Microsoft PPC */
+ "GAND", /* 19: Gandalf FZA */
+ "V42BIS", /* 20: ARG->DATA.42bis compression */
+ "BSD", /* BSD LZW Compress */
+};
+
+#define NCFTYPES (sizeof(cftypes)/sizeof(char *))
+
+int
+ReportCcpStatus(struct cmdargs const *arg)
+{
+ struct ccpstate *icp = &CcpInfo;
+ struct fsm *fp = &CcpFsm;
+
+ if (VarTerm) {
+ fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
+ fprintf(VarTerm, "myproto = %s, hisproto = %s\n",
+ cftypes[icp->want_proto], cftypes[icp->his_proto]);
+ fprintf(VarTerm, "Input: %ld --> %ld, Output: %ld --> %ld\n",
+ icp->orgin, icp->compin, icp->orgout, icp->compout);
+ }
+ return 0;
+}
+
+void
+CcpInit()
+{
+ struct ccpstate *icp = &CcpInfo;
+
+ FsmInit(&CcpFsm);
+ memset(icp, '\0', sizeof(struct ccpstate));
+ if (Enabled(ConfPred1))
+ icp->want_proto = TY_PRED1;
+ CcpFsm.maxconfig = 10;
+}
+
+static void
+CcpInitRestartCounter(struct fsm *fp)
+{
+ fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
+ fp->restart = 5;
+}
+
+static void
+CcpSendConfigReq(struct fsm *fp)
+{
+ u_char *cp;
+ struct ccpstate *icp = &CcpInfo;
+
+ cp = ReqBuff;
+ LogPrintf(LogCCP, "CcpSendConfigReq\n");
+ if (icp->want_proto && !REJECTED(icp, TY_PRED1)) {
+ *cp++ = TY_PRED1;
+ *cp++ = 2;
+ }
+ FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
+}
+
+void
+CcpSendResetReq(struct fsm *fp)
+{
+ LogPrintf(LogCCP, "CcpSendResetReq\n");
+ FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
+}
+
+static void
+CcpSendTerminateReq(struct fsm *fp)
+{
+ /* XXX: No code yet */
+}
+
+static void
+CcpSendTerminateAck(struct fsm *fp)
+{
+ LogPrintf(LogCCP, "CcpSendTerminateAck\n");
+ FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
+}
+
+void
+CcpRecvResetReq(struct fsm *fp)
+{
+ Pred1Init(2); /* Initialize Output part */
+}
+
+static void
+CcpLayerStart(struct fsm *fp)
+{
+ LogPrintf(LogCCP, "CcpLayerStart.\n");
+}
+
+static void
+CcpLayerFinish(struct fsm *fp)
+{
+ LogPrintf(LogCCP, "CcpLayerFinish.\n");
+}
+
+static void
+CcpLayerDown(struct fsm *fp)
+{
+ LogPrintf(LogCCP, "CcpLayerDown.\n");
+}
+
+/*
+ * Called when CCP has reached to OPEN state
+ */
+static void
+CcpLayerUp(struct fsm *fp)
+{
+ LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state);
+ LogPrintf(LogCCP, "myproto = %d, hisproto = %d\n",
+ CcpInfo.want_proto, CcpInfo.his_proto);
+ Pred1Init(3); /* Initialize Input and Output */
+}
+
+void
+CcpUp()
+{
+ FsmUp(&CcpFsm);
+ LogPrintf(LogCCP, "CCP Up event!!\n");
+}
+
+void
+CcpOpen()
+{
+ if (Enabled(ConfPred1))
+ FsmOpen(&CcpFsm);
+}
+
+static void
+CcpDecodeConfig(u_char *cp, int plen, int mode_type)
+{
+ int type, length;
+ char tbuff[100];
+
+ ackp = AckBuff;
+ nakp = NakBuff;
+ rejp = RejBuff;
+
+ while (plen >= sizeof(struct fsmconfig)) {
+ if (plen < 0)
+ break;
+ type = *cp;
+ length = cp[1];
+ if (type < NCFTYPES)
+ snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length);
+ else
+ snprintf(tbuff, sizeof(tbuff), " ");
+
+ LogPrintf(LogCCP, "%s\n", tbuff);
+
+ switch (type) {
+ case TY_PRED1:
+ switch (mode_type) {
+ case MODE_REQ:
+ if (Acceptable(ConfPred1)) {
+ memcpy(ackp, cp, length);
+ ackp += length;
+ CcpInfo.his_proto = type;
+ } else {
+ memcpy(rejp, cp, length);
+ rejp += length;
+ }
+ break;
+ case MODE_NAK:
+ case MODE_REJ:
+ CcpInfo.his_reject |= (1 << type);
+ CcpInfo.want_proto = 0;
+ break;
+ }
+ break;
+ case TY_BSD:
+ default:
+ CcpInfo.my_reject |= (1 << type);
+ memcpy(rejp, cp, length);
+ rejp += length;
+ break;
+ }
+ plen -= length;
+ cp += length;
+ }
+}
+
+void
+CcpInput(struct mbuf *bp)
+{
+ if (phase == PHASE_NETWORK)
+ FsmInput(&CcpFsm, bp);
+ else {
+ if (phase > PHASE_NETWORK)
+ LogPrintf(LogERROR, "Unexpected CCP in phase %d\n", phase);
+ pfree(bp);
+ }
+}
diff --git a/usr.sbin/ppp/ccp.h b/usr.sbin/ppp/ccp.h
new file mode 100644
index 00000000000..f6343a53cbf
--- /dev/null
+++ b/usr.sbin/ppp/ccp.h
@@ -0,0 +1,56 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ccp.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+#define CCP_MAXCODE CODE_RESETACK
+
+#define TY_OUI 0 /* OUI */
+#define TY_PRED1 1 /* Predictor type 1 */
+#define TY_PRED2 2 /* Predictor type 2 */
+#define TY_PUDDLE 3 /* Puddle Jumper */
+#define TY_HWPPC 16 /* Hewlett-Packard PPC */
+#define TY_STAC 17 /* Stac Electronics LZS */
+#define TY_MSPPC 18 /* Microsoft PPC */
+#define TY_GAND 19 /* Gandalf FZA */
+#define TY_V42BIS 20 /* V.42bis compression */
+#define TY_BSD 21 /* BSD LZW Compress */
+
+struct ccpstate {
+ u_long his_proto; /* peer's compression protocol */
+ u_long want_proto; /* my compression protocol */
+
+ u_long his_reject; /* Request codes rejected by peer */
+ u_long my_reject; /* Request codes I have rejected */
+
+ u_long orgout, compout;
+ u_long orgin, compin;
+};
+
+extern struct ccpstate CcpInfo;
+extern struct fsm CcpFsm;
+
+extern void CcpRecvResetReq(struct fsm *);
+extern void CcpSendResetReq(struct fsm *);
+extern void CcpInput(struct mbuf *);
+extern void CcpUp(void);
+extern void CcpOpen(void);
+extern void CcpInit(void);
+extern int ReportCcpStatus(struct cmdargs const *);
diff --git a/usr.sbin/ppp/chap.c b/usr.sbin/ppp/chap.c
new file mode 100644
index 00000000000..539d629e3ff
--- /dev/null
+++ b/usr.sbin/ppp/chap.c
@@ -0,0 +1,311 @@
+/*
+ * PPP CHAP Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#ifdef HAVE_DES
+#include <md4.h>
+#endif
+#include <md5.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef __OpenBSD__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include <utmp.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "chap.h"
+#include "chap_ms.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "hdlc.h"
+#include "phase.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "auth.h"
+
+static const char *chapcodes[] = {
+ "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
+};
+
+static void
+ChapOutput(u_int code, u_int id, const u_char * ptr, int count)
+{
+ int plen;
+ struct fsmheader lh;
+ struct mbuf *bp;
+
+ plen = sizeof(struct fsmheader) + count;
+ lh.code = code;
+ lh.id = id;
+ lh.length = htons(plen);
+ bp = mballoc(plen, MB_FSM);
+ memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
+ if (count)
+ memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
+ LogDumpBp(LogDEBUG, "ChapOutput", bp);
+ LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]);
+ HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
+}
+
+
+static char challenge_data[80];
+static int challenge_len;
+
+static void
+SendChapChallenge(int chapid)
+{
+ int len, i;
+ char *cp;
+
+ randinit();
+ cp = challenge_data;
+ *cp++ = challenge_len = random() % 32 + 16;
+ for (i = 0; i < challenge_len; i++)
+ *cp++ = random() & 0xff;
+ len = strlen(VarAuthName);
+ memcpy(cp, VarAuthName, len);
+ cp += len;
+ ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
+}
+
+struct authinfo AuthChapInfo = {
+ SendChapChallenge,
+};
+
+static void
+RecvChapTalk(struct fsmheader *chp, struct mbuf *bp)
+{
+ int valsize, len;
+ int arglen, keylen, namelen;
+ char *cp, *argp, *ap, *name, *digest;
+ char *keyp;
+ MD5_CTX MD5context; /* context for MD5 */
+ char answer[100];
+ char cdigest[16];
+#ifdef HAVE_DES
+ int ix;
+ MD4_CTX MD4context; /* context for MD4 */
+#endif
+
+ len = ntohs(chp->length);
+ LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len);
+ arglen = len - sizeof(struct fsmheader);
+ cp = (char *) MBUF_CTOP(bp);
+ valsize = *cp++ & 255;
+ name = cp + valsize;
+ namelen = arglen - valsize - 1;
+ name[namelen] = 0;
+ LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name);
+
+ switch (chp->code) {
+ case CHAP_CHALLENGE:
+ keyp = VarAuthKey;
+ keylen = strlen(VarAuthKey);
+ name = VarAuthName;
+ namelen = strlen(VarAuthName);
+
+#ifdef HAVE_DES
+ if (VarMSChap)
+ argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN);
+ else
+#endif
+ argp = malloc(1 + valsize + namelen + 16);
+
+ if (argp == NULL) {
+ ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
+ return;
+ }
+#ifdef HAVE_DES
+ if (VarMSChap) {
+ digest = argp; /* this is the response */
+ *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */
+ memset(digest, '\0', 24);
+ digest += 24;
+
+ ap = answer; /* this is the challenge */
+ memcpy(ap, keyp, keylen);
+ ap += 2 * keylen;
+ memcpy(ap, cp, valsize);
+ LogDumpBuff(LogDEBUG, "recv", ap, valsize);
+ ap += valsize;
+ for (ix = keylen; ix > 0 ; ix--) {
+ answer[2*ix-2] = answer[ix-1];
+ answer[2*ix-1] = 0;
+ }
+ MD4Init(&MD4context);
+ MD4Update(&MD4context, answer, 2 * keylen);
+ MD4Final(digest, &MD4context);
+ memcpy(digest + 25, name, namelen);
+ ap += 2 * keylen;
+ ChapMS(digest, answer + 2 * keylen, valsize);
+ LogDumpBuff(LogDEBUG, "answer", digest, 24);
+ ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + MS_CHAP_RESPONSE_LEN + 1);
+ } else {
+#endif
+ digest = argp;
+ *digest++ = 16; /* value size */
+ ap = answer;
+ *ap++ = chp->id;
+ memcpy(ap, keyp, keylen);
+ ap += keylen;
+ memcpy(ap, cp, valsize);
+ LogDumpBuff(LogDEBUG, "recv", ap, valsize);
+ ap += valsize;
+ MD5Init(&MD5context);
+ MD5Update(&MD5context, answer, ap - answer);
+ MD5Final(digest, &MD5context);
+ LogDumpBuff(LogDEBUG, "answer", digest, 16);
+ memcpy(digest + 16, name, namelen);
+ ap += namelen;
+ /* Send answer to the peer */
+ ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
+#ifdef HAVE_DES
+ }
+#endif
+ free(argp);
+ break;
+ case CHAP_RESPONSE:
+ /*
+ * Get a secret key corresponds to the peer
+ */
+ keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
+ if (keyp) {
+ /*
+ * Compute correct digest value
+ */
+ keylen = strlen(keyp);
+ ap = answer;
+ *ap++ = chp->id;
+ memcpy(ap, keyp, keylen);
+ ap += keylen;
+ MD5Init(&MD5context);
+ MD5Update(&MD5context, answer, ap - answer);
+ MD5Update(&MD5context, challenge_data + 1, challenge_len);
+ MD5Final(cdigest, &MD5context);
+ LogDumpBuff(LogDEBUG, "got", cp, 16);
+ LogDumpBuff(LogDEBUG, "expect", cdigest, 16);
+
+ /*
+ * Compare with the response
+ */
+ if (memcmp(cp, cdigest, 16) == 0) {
+ ChapOutput(CHAP_SUCCESS, chp->id, "Welcome!!", 10);
+ if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp))
+ if (Utmp)
+ LogPrintf(LogERROR, "Oops, already logged in on %s\n",
+ VarBaseDevice);
+ else {
+ struct utmp ut;
+ memset(&ut, 0, sizeof(ut));
+ time(&ut.ut_time);
+ strncpy(ut.ut_name, name, sizeof(ut.ut_name)-1);
+ strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1);
+ if (logout(ut.ut_line))
+ logwtmp(ut.ut_line, "", "");
+ login(&ut);
+ Utmp = 1;
+ }
+ NewPhase(PHASE_NETWORK);
+ break;
+ }
+ }
+
+ /*
+ * Peer is not registerd, or response digest is wrong.
+ */
+ ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
+ reconnect(RECON_FALSE);
+ LcpClose();
+ break;
+ }
+}
+
+static void
+RecvChapResult(struct fsmheader *chp, struct mbuf *bp)
+{
+ int len;
+ struct lcpstate *lcp = &LcpInfo;
+
+ len = ntohs(chp->length);
+ LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len);
+ if (chp->code == CHAP_SUCCESS) {
+ if (lcp->auth_iwait == PROTO_CHAP) {
+ lcp->auth_iwait = 0;
+ if (lcp->auth_ineed == 0)
+ NewPhase(PHASE_NETWORK);
+ }
+ } else {
+
+ /*
+ * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
+ */
+ ;
+ }
+}
+
+void
+ChapInput(struct mbuf *bp)
+{
+ int len = plength(bp);
+ struct fsmheader *chp;
+
+ if (len >= sizeof(struct fsmheader)) {
+ chp = (struct fsmheader *) MBUF_CTOP(bp);
+ if (len >= ntohs(chp->length)) {
+ if (chp->code < 1 || chp->code > 4)
+ chp->code = 0;
+ LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]);
+
+ bp->offset += sizeof(struct fsmheader);
+ bp->cnt -= sizeof(struct fsmheader);
+
+ switch (chp->code) {
+ case CHAP_RESPONSE:
+ StopAuthTimer(&AuthChapInfo);
+ /* Fall into.. */
+ case CHAP_CHALLENGE:
+ RecvChapTalk(chp, bp);
+ break;
+ case CHAP_SUCCESS:
+ case CHAP_FAILURE:
+ RecvChapResult(chp, bp);
+ break;
+ }
+ }
+ }
+ pfree(bp);
+}
diff --git a/usr.sbin/ppp/chap.h b/usr.sbin/ppp/chap.h
new file mode 100644
index 00000000000..c41ecde74a4
--- /dev/null
+++ b/usr.sbin/ppp/chap.h
@@ -0,0 +1,30 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
+
+extern struct authinfo AuthChapInfo;
+
+extern void ChapInput(struct mbuf *);
diff --git a/usr.sbin/ppp/chap_ms.c b/usr.sbin/ppp/chap_ms.c
new file mode 100644
index 00000000000..370bd94c06f
--- /dev/null
+++ b/usr.sbin/ppp/chap_ms.c
@@ -0,0 +1,115 @@
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap_ms.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ */
+
+#include <sys/types.h>
+
+#include <des.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "timer.h"
+#include "chap.h"
+#include "chap_ms.h"
+
+/* unused, for documentation only */
+/* only NTResp is filled in for FreeBSD */
+typedef struct {
+ u_char LANManResp[24];
+ u_char NTResp[24];
+ u_char UseNT; /* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+
+static void DesEncrypt(u_char *, u_char *, u_char *);
+static void MakeKey(u_char *, u_char *);
+
+static void /* IN 8 octets IN 16 octets OUT 24 octets */
+ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
+{
+ char ZPasswordHash[21];
+
+ memset(ZPasswordHash, '\0', sizeof(ZPasswordHash));
+ memcpy(ZPasswordHash, pwHash, 16);
+
+ DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
+ DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
+ DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+}
+
+static void /* IN 8 octets IN 7 octest OUT 8 octets */
+DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
+{
+ des_cblock des_key;
+ des_key_schedule key_schedule;
+
+ MakeKey(key, des_key);
+ des_set_key(&des_key, key_schedule);
+ des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+}
+
+static u_char Get7Bits(u_char *input, int startBit)
+{
+ register unsigned int word;
+
+ word = (unsigned)input[startBit / 8] << 8;
+ word |= (unsigned)input[startBit / 8 + 1];
+
+ word >>= 15 - (startBit % 8 + 7);
+
+ return word & 0xFE;
+}
+
+/* IN 56 bit DES key missing parity bits
+ OUT 64 bit DES key with parity bits added */
+static void MakeKey(u_char *key, u_char *des_key)
+{
+ des_key[0] = Get7Bits(key, 0);
+ des_key[1] = Get7Bits(key, 7);
+ des_key[2] = Get7Bits(key, 14);
+ des_key[3] = Get7Bits(key, 21);
+ des_key[4] = Get7Bits(key, 28);
+ des_key[5] = Get7Bits(key, 35);
+ des_key[6] = Get7Bits(key, 42);
+ des_key[7] = Get7Bits(key, 49);
+
+ des_set_odd_parity((des_cblock *)des_key);
+}
+
+/* passwordHash 16-bytes MD4 hashed password
+ challenge 8-bytes peer CHAP challenge
+ since passwordHash is in a 24-byte buffer, response is written in there */
+void
+ChapMS(char *passwordHash, char *challenge, int challenge_len)
+{
+ u_char response[24];
+
+ ChallengeResponse(challenge, passwordHash, response);
+ memcpy(passwordHash, response, 24);
+ passwordHash += 24;
+ *passwordHash = 1;
+}
diff --git a/usr.sbin/ppp/chap_ms.h b/usr.sbin/ppp/chap_ms.h
new file mode 100644
index 00000000000..74ddc3b5e85
--- /dev/null
+++ b/usr.sbin/ppp/chap_ms.h
@@ -0,0 +1,31 @@
+/*
+ * chap.h - Cryptographic Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap_ms.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ */
+
+/* Max # of (Unicode) chars in an NT password */
+#define MAX_NT_PASSWORD 256
+
+/* Don't rely on sizeof(MS_ChapResponse) in case of struct padding */
+#define MS_CHAP_RESPONSE_LEN 49
+
+extern void ChapMS(char *, char *, int);
diff --git a/usr.sbin/ppp/chat.c b/usr.sbin/ppp/chat.c
new file mode 100644
index 00000000000..2f42b56abb0
--- /dev/null
+++ b/usr.sbin/ppp/chat.c
@@ -0,0 +1,641 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com).
+ *
+ * Chat -- a program for automatic session establishment (i.e. dial
+ * the phone and log in).
+ *
+ * This software is in the public domain.
+ *
+ * Please send all bug reports, requests for information, etc. to:
+ *
+ * Karl Fox <karl@MorningStar.Com>
+ * Morning Star Technologies, Inc.
+ * 1760 Zollinger Road
+ * Columbus, OH 43221
+ * (614)451-1883
+ *
+ * $Id: chat.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ * o Support more UUCP compatible control sequences.
+ * o Dialing shoud not block monitor process.
+ * o Reading modem by select should be unified into main.c
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "chat.h"
+#include "sig.h"
+#include "modem.h"
+
+#ifndef isblank
+#define isblank(c) ((c) == '\t' || (c) == ' ')
+#endif
+
+
+#define IBSIZE LINE_LEN
+
+static int TimeoutSec;
+static int abort_next, timeout_next;
+static int numaborts;
+static char *AbortStrings[50];
+static char inbuff[IBSIZE * 2 + 1];
+
+#define MATCH 1
+#define NOMATCH 0
+#define ABORT -1
+
+static char *
+findblank(char *p, int instring)
+{
+ if (instring) {
+ while (*p) {
+ if (*p == '\\') {
+ strcpy(p, p + 1);
+ if (!*p)
+ break;
+ } else if (*p == '"')
+ return (p);
+ p++;
+ }
+ } else {
+ while (*p) {
+ if (isblank(*p))
+ return (p);
+ p++;
+ }
+ }
+ return p;
+}
+
+int
+MakeArgs(char *script, char **pvect, int maxargs)
+{
+ int nargs, nb;
+ int instring;
+
+ nargs = 0;
+ while (*script) {
+ nb = strspn(script, " \t");
+ script += nb;
+ if (*script) {
+ if (*script == '"') {
+ instring = 1;
+ script++;
+ if (*script == '\0')
+ break; /* Shouldn't return here. Need to null
+ * terminate below */
+ } else
+ instring = 0;
+ if (nargs >= maxargs - 1)
+ break;
+ *pvect++ = script;
+ nargs++;
+ script = findblank(script, instring);
+ if (*script)
+ *script++ = '\0';
+ }
+ }
+ *pvect = NULL;
+ return nargs;
+}
+
+/*
+ * \c don't add a cr
+ * \d Sleep a little (delay 2 seconds
+ * \n Line feed character
+ * \P Auth Key password
+ * \p pause 0.25 sec
+ * \r Carrige return character
+ * \s Space character
+ * \T Telephone number(s) (defined via `set phone')
+ * \t Tab character
+ * \U Auth User
+ */
+char *
+ExpandString(const char *str, char *result, int reslen, int sendmode)
+{
+ int addcr = 0;
+ char *phone;
+
+ result[--reslen] = '\0';
+ if (sendmode)
+ addcr = 1;
+ while (*str && reslen > 0) {
+ switch (*str) {
+ case '\\':
+ str++;
+ switch (*str) {
+ case 'c':
+ if (sendmode)
+ addcr = 0;
+ break;
+ case 'd': /* Delay 2 seconds */
+ nointr_sleep(2);
+ break;
+ case 'p':
+ nointr_usleep(250000);
+ break; /* Pause 0.25 sec */
+ case 'n':
+ *result++ = '\n';
+ reslen--;
+ break;
+ case 'r':
+ *result++ = '\r';
+ reslen--;
+ break;
+ case 's':
+ *result++ = ' ';
+ reslen--;
+ break;
+ case 't':
+ *result++ = '\t';
+ reslen--;
+ break;
+ case 'P':
+ strncpy(result, VarAuthKey, reslen);
+ reslen -= strlen(result);
+ result += strlen(result);
+ break;
+ case 'T':
+ if (VarAltPhone == NULL) {
+ if (VarNextPhone == NULL) {
+ strcpy(VarPhoneCopy, VarPhoneList);
+ VarNextPhone = VarPhoneCopy;
+ }
+ VarAltPhone = strsep(&VarNextPhone, ":");
+ }
+ phone = strsep(&VarAltPhone, "|");
+ strncpy(result, phone, reslen);
+ reslen -= strlen(result);
+ result += strlen(result);
+ if (VarTerm)
+ fprintf(VarTerm, "Phone: %s\n", phone);
+ LogPrintf(LogPHASE, "Phone: %s\n", phone);
+ break;
+ case 'U':
+ strncpy(result, VarAuthName, reslen);
+ reslen -= strlen(result);
+ result += strlen(result);
+ break;
+ default:
+ reslen--;
+ *result++ = *str;
+ break;
+ }
+ if (*str)
+ str++;
+ break;
+ case '^':
+ str++;
+ if (*str) {
+ *result++ = *str++ & 0x1f;
+ reslen--;
+ }
+ break;
+ default:
+ *result++ = *str++;
+ reslen--;
+ break;
+ }
+ }
+ if (--reslen > 0) {
+ if (addcr)
+ *result++ = '\r';
+ }
+ if (--reslen > 0)
+ *result++ = '\0';
+ return (result);
+}
+
+#define MAXLOGBUFF LINE_LEN
+static char logbuff[MAXLOGBUFF];
+static int loglen = 0;
+
+static void
+clear_log(void)
+{
+ memset(logbuff, 0, MAXLOGBUFF);
+ loglen = 0;
+}
+
+static void
+flush_log(void)
+{
+ if (LogIsKept(LogCONNECT))
+ LogPrintf(LogCONNECT, "%s\n", logbuff);
+ else if (LogIsKept(LogCARRIER) && strstr(logbuff, "CARRIER"))
+ LogPrintf(LogCARRIER, "%s\n", logbuff);
+
+ clear_log();
+}
+
+static void
+connect_log(const char *str, int single_p)
+{
+ int space = MAXLOGBUFF - loglen - 1;
+
+ while (space--) {
+ if (*str == '\n') {
+ flush_log();
+ } else {
+ logbuff[loglen++] = *str;
+ }
+ if (single_p || !*++str)
+ break;
+ }
+ if (!space)
+ flush_log();
+}
+
+static int
+WaitforString(const char *estr)
+{
+ struct timeval timeout;
+ char *s, *str, ch;
+ char *inp;
+ fd_set rfds;
+ int i, nfds, nb;
+ char buff[IBSIZE];
+
+
+#ifdef SIGALRM
+ int omask;
+
+ omask = sigblock(sigmask(SIGALRM));
+#endif
+ clear_log();
+ ExpandString(estr, buff, sizeof(buff), 0);
+ LogPrintf(LogCHAT, "Wait for (%d): %s --> %s\n", TimeoutSec, estr, buff);
+ str = buff;
+ inp = inbuff;
+
+ if (strlen(str) >= IBSIZE) {
+ str[IBSIZE - 1] = 0;
+ LogPrintf(LogCHAT, "Truncating String to %d character: %s\n", IBSIZE, str);
+ }
+ nfds = modem + 1;
+ s = str;
+ for (;;) {
+ FD_ZERO(&rfds);
+ FD_SET(modem, &rfds);
+
+ /*
+ * Because it is not clear whether select() modifies timeout value, it is
+ * better to initialize timeout values everytime.
+ */
+ timeout.tv_sec = TimeoutSec;
+ timeout.tv_usec = 0;
+ i = select(nfds, &rfds, NULL, NULL, &timeout);
+#ifdef notdef
+ TimerService();
+#endif
+ if (i < 0) {
+#ifdef SIGALRM
+ if (errno == EINTR)
+ continue;
+ sigsetmask(omask);
+#endif
+ LogPrintf(LogERROR, "WaitForString: select(): %s\n", strerror(errno));
+ *inp = 0;
+ return (NOMATCH);
+ } else if (i == 0) { /* Timeout reached! */
+ *inp = 0;
+ if (inp != inbuff)
+ LogPrintf(LogCHAT, "Got: %s\n", inbuff);
+ LogPrintf(LogCHAT, "Can't get (%d).\n", timeout.tv_sec);
+#ifdef SIGALRM
+ sigsetmask(omask);
+#endif
+ return (NOMATCH);
+ }
+ if (FD_ISSET(modem, &rfds)) { /* got something */
+ if (DEV_IS_SYNC) {
+ int length;
+
+ if ((length = strlen(inbuff)) > IBSIZE) {
+ /* shuffle down next part */
+ memcpy(inbuff, &(inbuff[IBSIZE]), IBSIZE + 1);
+ length = strlen(inbuff);
+ }
+ nb = read(modem, &(inbuff[length]), IBSIZE);
+ inbuff[nb + length] = 0;
+ connect_log(inbuff, 0);
+ if (strstr(inbuff, str)) {
+#ifdef SIGALRM
+ sigsetmask(omask);
+#endif
+ flush_log();
+ return (MATCH);
+ }
+ for (i = 0; i < numaborts; i++) {
+ if (strstr(inbuff, AbortStrings[i])) {
+ LogPrintf(LogCHAT, "Abort: %s\n", AbortStrings[i]);
+#ifdef SIGALRM
+ sigsetmask(omask);
+#endif
+ flush_log();
+ return (ABORT);
+ }
+ }
+ } else {
+ if (read(modem, &ch, 1) < 0) {
+ LogPrintf(LogERROR, "read error: %s\n", strerror(errno));
+ *inp = '\0';
+ return (NOMATCH);
+ }
+ connect_log(&ch, 1);
+ *inp++ = ch;
+ if (ch == *s) {
+ s++;
+ if (*s == '\0') {
+#ifdef SIGALRM
+ sigsetmask(omask);
+#endif
+ *inp = 0;
+ flush_log();
+ return (MATCH);
+ }
+ } else
+ s = str;
+ if (inp == inbuff + IBSIZE) {
+ memcpy(inbuff, inp - 100, 100);
+ inp = inbuff + 100;
+ }
+ if (s == str) {
+ for (i = 0; i < numaborts; i++) { /* Look for Abort strings */
+ int len;
+ char *s1;
+
+ s1 = AbortStrings[i];
+ len = strlen(s1);
+ if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) {
+ LogPrintf(LogCHAT, "Abort: %s\n", s1);
+ *inp = 0;
+#ifdef SIGALRM
+ sigsetmask(omask);
+#endif
+ flush_log();
+ return (ABORT);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+ExecStr(char *command, char *out)
+{
+ int pid;
+ int fids[2];
+ char *vector[MAXARGS];
+ int stat, nb;
+ char *cp;
+ char tmp[300];
+
+ cp = inbuff + strlen(inbuff) - 1;
+ while (cp > inbuff) {
+ if (*cp < ' ' && *cp != '\t') {
+ cp++;
+ break;
+ }
+ cp--;
+ }
+ if (snprintf(tmp, sizeof tmp, "%s %s", command, cp) >= sizeof tmp) {
+ LogPrintf(LogCHAT, "Too long string to ExecStr: \"%s\"\n", command);
+ return;
+ }
+ MakeArgs(tmp, vector, VECSIZE(vector));
+
+ if (pipe(fids) < 0) {
+ LogPrintf(LogCHAT, "Unable to create pipe in ExecStr: %s\n",
+ strerror(errno));
+ return;
+ }
+ pid = fork();
+ if (pid == 0) {
+ TermTimerService();
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGALRM, SIG_DFL);
+ close(fids[0]);
+ if (dup2(fids[1], 1) < 0) {
+ LogPrintf(LogCHAT, "dup2(fids[1], 1) in ExecStr: %s\n", strerror(errno));
+ return;
+ }
+ close(fids[1]);
+ nb = open("/dev/tty", O_RDWR);
+ if (dup2(nb, 0) < 0) {
+ LogPrintf(LogCHAT, "dup2(nb, 0) in ExecStr: %s\n", strerror(errno));
+ return;
+ }
+ setuid(geteuid());
+ LogPrintf(LogCHAT, "exec: %s\n", command);
+ pid = execvp(command, (char **)vector);
+ LogPrintf(LogCHAT, "execvp failed for (%d/%d): %s\n", pid, errno, command);
+ exit(127);
+ } else {
+ close(fids[1]);
+ for (;;) {
+ nb = read(fids[0], out, 1);
+ if (nb <= 0)
+ break;
+ out++;
+ }
+ *out = '\0';
+ close(fids[0]);
+ close(fids[1]);
+ waitpid(pid, &stat, WNOHANG);
+ }
+}
+
+static void
+SendString(const char *str)
+{
+ char *cp;
+ int on;
+ char buff[LINE_LEN];
+
+ if (abort_next) {
+ abort_next = 0;
+ ExpandString(str, buff, sizeof(buff), 0);
+ AbortStrings[numaborts++] = strdup(buff);
+ } else if (timeout_next) {
+ timeout_next = 0;
+ TimeoutSec = atoi(str);
+ if (TimeoutSec <= 0)
+ TimeoutSec = 30;
+ } else {
+ if (*str == '!') {
+ ExpandString(str + 1, buff + 2, sizeof(buff) - 2, 0);
+ ExecStr(buff + 2, buff + 2);
+ } else {
+ ExpandString(str, buff + 2, sizeof(buff) - 2, 1);
+ }
+ if (strstr(str, "\\P")) /* Do not log the password itself. */
+ LogPrintf(LogCHAT, "sending: %s\n", str);
+ else
+ LogPrintf(LogCHAT, "sending: %s\n", buff + 2);
+ cp = buff;
+ if (DEV_IS_SYNC)
+ memcpy(buff, "\377\003", 2); /* Prepend HDLC header */
+ else
+ cp += 2;
+ on = strlen(cp);
+ write(modem, cp, on);
+ }
+}
+
+static int
+ExpectString(char *str)
+{
+ char *minus;
+ int state;
+
+ if (strcmp(str, "ABORT") == 0) {
+ ++abort_next;
+ return (MATCH);
+ }
+ if (strcmp(str, "TIMEOUT") == 0) {
+ ++timeout_next;
+ return (MATCH);
+ }
+ LogPrintf(LogCHAT, "Expecting %s\n", str);
+ while (*str) {
+
+ /*
+ * Check whether if string contains sub-send-expect.
+ */
+ for (minus = str; *minus; minus++) {
+ if (*minus == '-') {
+ if (minus == str || minus[-1] != '\\')
+ break;
+ }
+ }
+ if (*minus == '-') { /* We have sub-send-expect. */
+ *minus = '\0'; /* XXX: Cheat with the const string */
+ state = WaitforString(str);
+ *minus = '-'; /* XXX: Cheat with the const string */
+ minus++;
+ if (state != NOMATCH)
+ return (state);
+
+ /*
+ * Can't get expect string. Sendout send part.
+ */
+ str = minus;
+ for (minus = str; *minus; minus++) {
+ if (*minus == '-') {
+ if (minus == str || minus[-1] != '\\')
+ break;
+ }
+ }
+ if (*minus == '-') {
+ *minus = '\0'; /* XXX: Cheat with the const string */
+ SendString(str);
+ *minus = '-'; /* XXX: Cheat with the const string */
+ str = ++minus;
+ } else {
+ SendString(str);
+ return (MATCH);
+ }
+ } else {
+
+ /*
+ * Simple case. Wait for string.
+ */
+ return (WaitforString(str));
+ }
+ }
+ return (MATCH);
+}
+
+static jmp_buf ChatEnv;
+static void (*oint) (int);
+
+static void
+StopDial(int sig)
+{
+ LogPrintf(LogPHASE, "DoChat: Caught signal %d, abort connect\n", sig);
+ longjmp(ChatEnv, 1);
+}
+
+int
+DoChat(char *script)
+{
+ char *vector[MAXARGS];
+ char *const *argv;
+ int argc, n, state;
+
+ if (!script || !*script)
+ return MATCH;
+
+ /* While we're chatting, we want an INT to fail us */
+ if (setjmp(ChatEnv)) {
+ signal(SIGINT, oint);
+ return (-1);
+ }
+ oint = signal(SIGINT, StopDial);
+
+ timeout_next = abort_next = 0;
+ for (n = 0; AbortStrings[n]; n++) {
+ free(AbortStrings[n]);
+ AbortStrings[n] = NULL;
+ }
+ numaborts = 0;
+
+ memset(vector, '\0', sizeof(vector));
+ argc = MakeArgs(script, vector, VECSIZE(vector));
+ argv = vector;
+ TimeoutSec = 30;
+ while (*argv) {
+ if (strcmp(*argv, "P_ZERO") == 0 ||
+ strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) {
+ ChangeParity(*argv++);
+ continue;
+ }
+ state = ExpectString(*argv++);
+ switch (state) {
+ case MATCH:
+ if (*argv)
+ SendString(*argv++);
+ break;
+ case ABORT:
+ case NOMATCH:
+ signal(SIGINT, oint);
+ return (NOMATCH);
+ }
+ }
+ signal(SIGINT, oint);
+ return (MATCH);
+}
diff --git a/usr.sbin/ppp/chat.h b/usr.sbin/ppp/chat.h
new file mode 100644
index 00000000000..4a53844c35c
--- /dev/null
+++ b/usr.sbin/ppp/chat.h
@@ -0,0 +1,29 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com).
+ *
+ * Chat -- a program for automatic session establishment (i.e. dial
+ * the phone and log in).
+ *
+ * This software is in the public domain.
+ *
+ * Please send all bug reports, requests for information, etc. to:
+ *
+ * Karl Fox <karl@MorningStar.Com>
+ * Morning Star Technologies, Inc.
+ * 1760 Zollinger Road
+ * Columbus, OH 43221
+ * (614)451-1883
+ *
+ * $Id: chat.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ */
+
+#define VECSIZE(v) (sizeof(v) / sizeof(v[0]))
+
+extern char *ExpandString(const char *, char *, int, int);
+extern int MakeArgs(char *, char **, int); /* Mangles the first arg ! */
+extern int DoChat(char *); /* passes arg to MakeArgs() */
diff --git a/usr.sbin/ppp/command.c b/usr.sbin/ppp/command.c
new file mode 100644
index 00000000000..002cc44f5db
--- /dev/null
+++ b/usr.sbin/ppp/command.c
@@ -0,0 +1,1628 @@
+/*
+ * PPP User command processing module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: command.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ */
+#include <sys/param.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <netdb.h>
+
+#ifndef NOALIAS
+#include <alias.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "phase.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "modem.h"
+#include "filter.h"
+#ifndef NOALIAS
+#include "alias_cmd.h"
+#endif
+#include "hdlc.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "systems.h"
+#include "chat.h"
+#include "os.h"
+#include "server.h"
+#include "main.h"
+#include "route.h"
+#include "ccp.h"
+#include "ip.h"
+#include "slcompress.h"
+#include "auth.h"
+
+struct in_addr ifnetmask;
+
+static int ShowCommand(struct cmdargs const *arg);
+static int TerminalCommand(struct cmdargs const *arg);
+static int QuitCommand(struct cmdargs const *arg);
+static int CloseCommand(struct cmdargs const *arg);
+static int DialCommand(struct cmdargs const *arg);
+static int DownCommand(struct cmdargs const *arg);
+static int AllowCommand(struct cmdargs const *arg);
+static int SetCommand(struct cmdargs const *arg);
+static int AddCommand(struct cmdargs const *arg);
+static int DeleteCommand(struct cmdargs const *arg);
+static int BgShellCommand(struct cmdargs const *arg);
+static int FgShellCommand(struct cmdargs const *arg);
+#ifndef NOALIAS
+static int AliasCommand(struct cmdargs const *arg);
+static int AliasEnable(struct cmdargs const *arg);
+static int AliasOption(struct cmdargs const *arg);
+#endif
+
+static int
+HelpCommand(struct cmdargs const *arg)
+{
+ struct cmdtab const *cmd;
+ int n, cmax, dmax, cols;
+
+ if (!VarTerm)
+ return 0;
+
+ if (arg->argc > 0) {
+ for (cmd = arg->cmd; cmd->name; cmd++)
+ if (strcasecmp(cmd->name, *arg->argv) == 0 &&
+ (cmd->lauth & VarLocalAuth)) {
+ fprintf(VarTerm, "%s\n", cmd->syntax);
+ return 0;
+ }
+ return -1;
+ }
+ cmax = dmax = 0;
+ for (cmd = arg->cmd; cmd->func; cmd++)
+ if (cmd->name && (cmd->lauth & VarLocalAuth)) {
+ if ((n = strlen(cmd->name)) > cmax)
+ cmax = n;
+ if ((n = strlen(cmd->helpmes)) > dmax)
+ dmax = n;
+ }
+
+ cols = 80 / (dmax + cmax + 3);
+ n = 0;
+ for (cmd = arg->cmd; cmd->func; cmd++)
+ if (cmd->name && (cmd->lauth & VarLocalAuth)) {
+ fprintf(VarTerm, " %-*.*s: %-*.*s",
+ cmax, cmax, cmd->name, dmax, dmax, cmd->helpmes);
+ if (++n % cols == 0)
+ fprintf(VarTerm, "\n");
+ }
+ if (n % cols != 0)
+ fprintf(VarTerm, "\n");
+
+ return 0;
+}
+
+int
+IsInteractive(int Display)
+{
+ const char *mes = NULL;
+
+ if (mode & MODE_DDIAL)
+ mes = "Working in dedicated dial mode.";
+ else if (mode & MODE_BACKGROUND)
+ mes = "Working in background mode.";
+ else if (mode & MODE_AUTO)
+ mes = "Working in auto mode.";
+ else if (mode & MODE_DIRECT)
+ mes = "Working in direct mode.";
+ else if (mode & MODE_DEDICATED)
+ mes = "Working in dedicated mode.";
+ if (mes) {
+ if (Display && VarTerm)
+ fprintf(VarTerm, "%s\n", mes);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+DialCommand(struct cmdargs const *arg)
+{
+ int tries;
+ int res;
+
+ if (LcpFsm.state > ST_CLOSED) {
+ if (VarTerm)
+ fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]);
+ return 0;
+ }
+
+ if (arg->argc > 0 && (res = LoadCommand(arg)) != 0)
+ return res;
+
+ tries = 0;
+ do {
+ if (VarTerm)
+ fprintf(VarTerm, "Dial attempt %u of %d\n", ++tries, VarDialTries);
+ if (OpenModem() < 0) {
+ if (VarTerm)
+ fprintf(VarTerm, "Failed to open modem.\n");
+ break;
+ }
+ if ((res = DialModem()) == EX_DONE) {
+ nointr_sleep(1);
+ ModemTimeout(NULL);
+ PacketMode();
+ break;
+ } else if (res == EX_SIG)
+ return 1;
+ } while (VarDialTries == 0 || tries < VarDialTries);
+
+ return 0;
+}
+
+static int
+SetLoopback(struct cmdargs const *arg)
+{
+ if (arg->argc == 1)
+ if (!strcasecmp(*arg->argv, "on")) {
+ VarLoopback = 1;
+ return 0;
+ }
+ else if (!strcasecmp(*arg->argv, "off")) {
+ VarLoopback = 0;
+ return 0;
+ }
+ return -1;
+}
+
+static int
+ShellCommand(struct cmdargs const *arg, int bg)
+{
+ const char *shell;
+ pid_t shpid;
+ FILE *oVarTerm;
+ int argc;
+ char *argv[MAXARGS];
+
+#ifdef SHELL_ONLY_INTERACTIVELY
+ /* we're only allowed to shell when we run ppp interactively */
+ if (mode != MODE_INTER) {
+ LogPrintf(LogWARN, "Can only start a shell in interactive mode\n");
+ return 1;
+ }
+#endif
+#ifdef NO_SHELL_IN_AUTO_INTERACTIVE
+
+ /*
+ * we want to stop shell commands when we've got a telnet connection to an
+ * auto mode ppp
+ */
+ if (VarTerm && !(mode & MODE_INTER)) {
+ LogPrintf(LogWARN, "Shell is not allowed interactively in auto mode\n");
+ return 1;
+ }
+#endif
+
+ if (arg->argc == 0)
+ if (!(mode & MODE_INTER)) {
+ if (VarTerm)
+ LogPrintf(LogWARN, "Can't start an interactive shell from"
+ " a telnet session\n");
+ else
+ LogPrintf(LogWARN, "Can only start an interactive shell in"
+ " interactive mode\n");
+ return 1;
+ } else if (bg) {
+ LogPrintf(LogWARN, "Can only start an interactive shell in"
+ " the foreground mode\n");
+ return 1;
+ }
+ if ((shell = getenv("SHELL")) == 0)
+ shell = _PATH_BSHELL;
+
+ if ((shpid = fork()) == 0) {
+ int dtablesize, i, fd;
+
+ if (VarTerm)
+ fd = fileno(VarTerm);
+ else if ((fd = open("/dev/null", O_RDWR)) == -1) {
+ LogPrintf(LogALERT, "Failed to open /dev/null: %s\n", strerror(errno));
+ exit(1);
+ }
+ for (i = 0; i < 3; i++)
+ dup2(fd, i);
+
+ if (fd > 2)
+ if (VarTerm) {
+ oVarTerm = VarTerm;
+ VarTerm = 0;
+ if (oVarTerm && oVarTerm != stdout)
+ fclose(oVarTerm);
+ } else
+ close(fd);
+
+ for (dtablesize = getdtablesize(), i = 3; i < dtablesize; i++)
+ close(i);
+
+ TtyOldMode();
+ setuid(geteuid());
+ if (arg->argc > 0) {
+ /* substitute pseudo args */
+ argv[0] = strdup(arg->argv[0]);
+ for (argc = 1; argc < arg->argc; argc++) {
+ if (strcasecmp(arg->argv[argc], "HISADDR") == 0)
+ argv[argc] = strdup(inet_ntoa(IpcpInfo.his_ipaddr));
+ else if (strcasecmp(arg->argv[argc], "INTERFACE") == 0)
+ argv[argc] = strdup(IfDevName);
+ else if (strcasecmp(arg->argv[argc], "MYADDR") == 0)
+ argv[argc] = strdup(inet_ntoa(IpcpInfo.want_ipaddr));
+ else
+ argv[argc] = strdup(arg->argv[argc]);
+ }
+ argv[argc] = NULL;
+ if (bg) {
+ pid_t p;
+
+ p = getpid();
+ if (daemon(1, 1) == -1) {
+ LogPrintf(LogERROR, "%d: daemon: %s\n", p, strerror(errno));
+ exit(1);
+ }
+ } else if (VarTerm)
+ fprintf(VarTerm, "ppp: Pausing until %s finishes\n", arg->argv[0]);
+ execvp(argv[0], argv);
+ } else {
+ if (VarTerm)
+ fprintf(VarTerm, "ppp: Pausing until %s finishes\n", shell);
+ execl(shell, shell, NULL);
+ }
+
+ LogPrintf(LogWARN, "exec() of %s failed\n", arg->argc > 0 ? arg->argv[0] : shell);
+ exit(255);
+ }
+ if (shpid == (pid_t) - 1) {
+ LogPrintf(LogERROR, "Fork failed: %s\n", strerror(errno));
+ } else {
+ int status;
+
+ waitpid(shpid, &status, 0);
+ }
+
+ TtyCommandMode(1);
+
+ return (0);
+}
+
+static int
+BgShellCommand(struct cmdargs const *arg)
+{
+ if (arg->argc == 0)
+ return -1;
+ return ShellCommand(arg, 1);
+}
+
+static int
+FgShellCommand(struct cmdargs const *arg)
+{
+ return ShellCommand(arg, 0);
+}
+
+static struct cmdtab const Commands[] = {
+ {"accept", NULL, AcceptCommand, LOCAL_AUTH,
+ "accept option request", "accept option .."},
+ {"add", NULL, AddCommand, LOCAL_AUTH,
+ "add route", "add dest mask gateway"},
+ {"allow", "auth", AllowCommand, LOCAL_AUTH,
+ "Allow ppp access", "allow users|modes ...."},
+ {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
+ "Run a background command", "[!]bg command"},
+ {"close", NULL, CloseCommand, LOCAL_AUTH,
+ "Close connection", "close"},
+ {"delete", NULL, DeleteCommand, LOCAL_AUTH,
+ "delete route", "delete ALL | dest [gateway [mask]]"},
+ {"deny", NULL, DenyCommand, LOCAL_AUTH,
+ "Deny option request", "deny option .."},
+ {"dial", "call", DialCommand, LOCAL_AUTH,
+ "Dial and login", "dial|call [remote]"},
+ {"disable", NULL, DisableCommand, LOCAL_AUTH,
+ "Disable option", "disable option .."},
+ {"display", NULL, DisplayCommand, LOCAL_AUTH,
+ "Display option configs", "display"},
+ {"enable", NULL, EnableCommand, LOCAL_AUTH,
+ "Enable option", "enable option .."},
+ {"passwd", NULL, LocalAuthCommand, LOCAL_NO_AUTH,
+ "Password for manipulation", "passwd LocalPassword"},
+ {"load", NULL, LoadCommand, LOCAL_AUTH,
+ "Load settings", "load [remote]"},
+ {"save", NULL, SaveCommand, LOCAL_AUTH,
+ "Save settings", "save"},
+ {"set", "setup", SetCommand, LOCAL_AUTH,
+ "Set parameters", "set[up] var value"},
+ {"shell", "!", FgShellCommand, LOCAL_AUTH,
+ "Run a subshell", "shell|! [sh command]"},
+ {"show", NULL, ShowCommand, LOCAL_AUTH,
+ "Show status and stats", "show var"},
+ {"term", NULL, TerminalCommand, LOCAL_AUTH,
+ "Enter terminal mode", "term"},
+#ifndef NOALIAS
+ {"alias", NULL, AliasCommand, LOCAL_AUTH,
+ "alias control", "alias option [yes|no]"},
+#endif
+ {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
+ "Quit PPP program", "quit|bye [all]"},
+ {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
+ "Display this message", "help|? [command]", Commands},
+ {NULL, "down", DownCommand, LOCAL_AUTH,
+ "Generate down event", "down"},
+ {NULL, NULL, NULL},
+};
+
+static int
+ShowLoopback(struct cmdargs const *arg)
+{
+ if (VarTerm)
+ fprintf(VarTerm, "Local loopback is %s\n", VarLoopback ? "on" : "off");
+
+ return 0;
+}
+
+static int
+ShowLogLevel(struct cmdargs const *arg)
+{
+ int i;
+
+ if (!VarTerm)
+ return 0;
+
+ fprintf(VarTerm, "Log: ");
+ for (i = LogMIN; i <= LogMAX; i++)
+ if (LogIsKept(i) & LOG_KEPT_SYSLOG)
+ fprintf(VarTerm, " %s", LogName(i));
+
+ fprintf(VarTerm, "\nLocal:");
+ for (i = LogMIN; i <= LogMAX; i++)
+ if (LogIsKept(i) & LOG_KEPT_LOCAL)
+ fprintf(VarTerm, " %s", LogName(i));
+
+ fprintf(VarTerm, "\n");
+
+ return 0;
+}
+
+static int
+ShowEscape(struct cmdargs const *arg)
+{
+ int code, bit;
+
+ if (!VarTerm)
+ return 0;
+ if (EscMap[32]) {
+ for (code = 0; code < 32; code++)
+ if (EscMap[code])
+ for (bit = 0; bit < 8; bit++)
+ if (EscMap[code] & (1 << bit))
+ fprintf(VarTerm, " 0x%02x", (code << 3) + bit);
+ fprintf(VarTerm, "\n");
+ }
+ return 0;
+}
+
+static int
+ShowTimeout(struct cmdargs const *arg)
+{
+ if (VarTerm)
+ fprintf(VarTerm, " Idle Timer: %d secs LQR Timer: %d secs"
+ " Retry Timer: %d secs\n", VarIdleTimeout, VarLqrTimeout,
+ VarRetryTimeout);
+ return 0;
+}
+
+static int
+ShowStopped(struct cmdargs const *arg)
+{
+ if (!VarTerm)
+ return 0;
+
+ fprintf(VarTerm, " Stopped Timer: LCP: ");
+ if (!LcpFsm.StoppedTimer.load)
+ fprintf(VarTerm, "Disabled");
+ else
+ fprintf(VarTerm, "%ld secs", LcpFsm.StoppedTimer.load / SECTICKS);
+
+ fprintf(VarTerm, ", IPCP: ");
+ if (!IpcpFsm.StoppedTimer.load)
+ fprintf(VarTerm, "Disabled");
+ else
+ fprintf(VarTerm, "%ld secs", IpcpFsm.StoppedTimer.load / SECTICKS);
+
+ fprintf(VarTerm, ", CCP: ");
+ if (!CcpFsm.StoppedTimer.load)
+ fprintf(VarTerm, "Disabled");
+ else
+ fprintf(VarTerm, "%ld secs", CcpFsm.StoppedTimer.load / SECTICKS);
+
+ fprintf(VarTerm, "\n");
+
+ return 0;
+}
+
+static int
+ShowAuthKey(struct cmdargs const *arg)
+{
+ if (!VarTerm)
+ return 0;
+ fprintf(VarTerm, "AuthName = %s\n", VarAuthName);
+ fprintf(VarTerm, "AuthKey = %s\n", VarAuthKey);
+#ifdef HAVE_DES
+ fprintf(VarTerm, "Encrypt = %s\n", VarMSChap ? "MSChap" : "MD5" );
+#endif
+ return 0;
+}
+
+static int
+ShowVersion(struct cmdargs const *arg)
+{
+ if (VarTerm)
+ fprintf(VarTerm, "%s - %s \n", VarVersion, VarLocalVersion);
+ return 0;
+}
+
+static int
+ShowInitialMRU(struct cmdargs const *arg)
+{
+ if (VarTerm)
+ fprintf(VarTerm, " Initial MRU: %ld\n", VarMRU);
+ return 0;
+}
+
+static int
+ShowPreferredMTU(struct cmdargs const *arg)
+{
+ if (VarTerm)
+ if (VarPrefMTU)
+ fprintf(VarTerm, " Preferred MTU: %ld\n", VarPrefMTU);
+ else
+ fprintf(VarTerm, " Preferred MTU: unspecified\n");
+ return 0;
+}
+
+static int
+ShowReconnect(struct cmdargs const *arg)
+{
+ if (VarTerm)
+ fprintf(VarTerm, " Reconnect Timer: %d, %d tries\n",
+ VarReconnectTimer, VarReconnectTries);
+ return 0;
+}
+
+static int
+ShowRedial(struct cmdargs const *arg)
+{
+ if (!VarTerm)
+ return 0;
+ fprintf(VarTerm, " Redial Timer: ");
+
+ if (VarRedialTimeout >= 0) {
+ fprintf(VarTerm, " %d seconds, ", VarRedialTimeout);
+ } else {
+ fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD);
+ }
+
+ fprintf(VarTerm, " Redial Next Timer: ");
+
+ if (VarRedialNextTimeout >= 0) {
+ fprintf(VarTerm, " %d seconds, ", VarRedialNextTimeout);
+ } else {
+ fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD);
+ }
+
+ if (VarDialTries)
+ fprintf(VarTerm, "%d dial tries", VarDialTries);
+
+ fprintf(VarTerm, "\n");
+
+ return 0;
+}
+
+#ifndef NOMSEXT
+static int
+ShowMSExt(struct cmdargs const *arg)
+{
+ if (VarTerm) {
+ fprintf(VarTerm, " MS PPP extention values \n");
+ fprintf(VarTerm, " Primary NS : %s\n", inet_ntoa(ns_entries[0]));
+ fprintf(VarTerm, " Secondary NS : %s\n", inet_ntoa(ns_entries[1]));
+ fprintf(VarTerm, " Primary NBNS : %s\n", inet_ntoa(nbns_entries[0]));
+ fprintf(VarTerm, " Secondary NBNS : %s\n", inet_ntoa(nbns_entries[1]));
+ }
+ return 0;
+}
+
+#endif
+
+static struct cmdtab const ShowCommands[] = {
+ {"afilter", NULL, ShowAfilter, LOCAL_AUTH,
+ "Show keep-alive filters", "show afilter option .."},
+ {"auth", NULL, ShowAuthKey, LOCAL_AUTH,
+ "Show auth details", "show auth"},
+ {"ccp", NULL, ReportCcpStatus, LOCAL_AUTH,
+ "Show CCP status", "show cpp"},
+ {"compress", NULL, ReportCompress, LOCAL_AUTH,
+ "Show compression stats", "show compress"},
+ {"dfilter", NULL, ShowDfilter, LOCAL_AUTH,
+ "Show Demand filters", "show dfilteroption .."},
+ {"escape", NULL, ShowEscape, LOCAL_AUTH,
+ "Show escape characters", "show escape"},
+ {"hdlc", NULL, ReportHdlcStatus, LOCAL_AUTH,
+ "Show HDLC errors", "show hdlc"},
+ {"ifilter", NULL, ShowIfilter, LOCAL_AUTH,
+ "Show Input filters", "show ifilter option .."},
+ {"ipcp", NULL, ReportIpcpStatus, LOCAL_AUTH,
+ "Show IPCP status", "show ipcp"},
+ {"lcp", NULL, ReportLcpStatus, LOCAL_AUTH,
+ "Show LCP status", "show lcp"},
+ {"loopback", NULL, ShowLoopback, LOCAL_AUTH,
+ "Show loopback setting", "show loopback"},
+ {"log", NULL, ShowLogLevel, LOCAL_AUTH,
+ "Show log levels", "show log"},
+ {"mem", NULL, ShowMemMap, LOCAL_AUTH,
+ "Show memory map", "show mem"},
+ {"modem", NULL, ShowModemStatus, LOCAL_AUTH,
+ "Show modem setups", "show modem"},
+ {"mru", NULL, ShowInitialMRU, LOCAL_AUTH,
+ "Show Initial MRU", "show mru"},
+ {"mtu", NULL, ShowPreferredMTU, LOCAL_AUTH,
+ "Show Preferred MTU", "show mtu"},
+ {"ofilter", NULL, ShowOfilter, LOCAL_AUTH,
+ "Show Output filters", "show ofilter option .."},
+ {"proto", NULL, ReportProtStatus, LOCAL_AUTH,
+ "Show protocol summary", "show proto"},
+ {"reconnect", NULL, ShowReconnect, LOCAL_AUTH,
+ "Show reconnect timer", "show reconnect"},
+ {"redial", NULL, ShowRedial, LOCAL_AUTH,
+ "Show Redial timeout", "show redial"},
+ {"route", NULL, ShowRoute, LOCAL_AUTH,
+ "Show routing table", "show route"},
+ {"timeout", NULL, ShowTimeout, LOCAL_AUTH,
+ "Show Idle timeout", "show timeout"},
+ {"stopped", NULL, ShowStopped, LOCAL_AUTH,
+ "Show STOPPED timeout", "show stopped"},
+#ifndef NOMSEXT
+ {"msext", NULL, ShowMSExt, LOCAL_AUTH,
+ "Show MS PPP extentions", "show msext"},
+#endif
+ {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
+ "Show version string", "show version"},
+ {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
+ "Display this message", "show help|? [command]", ShowCommands},
+ {NULL, NULL, NULL},
+};
+
+static struct cmdtab const *
+FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
+{
+ int nmatch;
+ int len;
+ struct cmdtab const *found;
+
+ found = NULL;
+ len = strlen(str);
+ nmatch = 0;
+ while (cmds->func) {
+ if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
+ if (cmds->name[len] == '\0') {
+ *pmatch = 1;
+ return cmds;
+ }
+ nmatch++;
+ found = cmds;
+ } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
+ if (cmds->alias[len] == '\0') {
+ *pmatch = 1;
+ return cmds;
+ }
+ nmatch++;
+ found = cmds;
+ }
+ cmds++;
+ }
+ *pmatch = nmatch;
+ return found;
+}
+
+static int
+FindExec(struct cmdtab const *cmds, int argc, char const *const *argv)
+{
+ struct cmdtab const *cmd;
+ int val = 1;
+ int nmatch;
+ struct cmdargs arg;
+
+ cmd = FindCommand(cmds, *argv, &nmatch);
+ if (nmatch > 1)
+ LogPrintf(LogWARN, "%s: Ambiguous command\n", *argv);
+ else if (cmd && (cmd->lauth & VarLocalAuth)) {
+ arg.cmd = cmds;
+ arg.argc = argc-1;
+ arg.argv = argv+1;
+ arg.data = cmd->args;
+ val = (cmd->func) (&arg);
+ } else
+ LogPrintf(LogWARN, "%s: Invalid command\n", *argv);
+
+ if (val == -1)
+ LogPrintf(LogWARN, "Usage: %s\n", cmd->syntax);
+ else if (val)
+ LogPrintf(LogCOMMAND, "%s: Failed %d\n", *argv, val);
+
+ return val;
+}
+
+int aft_cmd = 1;
+
+void
+Prompt()
+{
+ const char *pconnect, *pauth;
+
+ if (!VarTerm || TermMode)
+ return;
+
+ if (!aft_cmd)
+ fprintf(VarTerm, "\n");
+ else
+ aft_cmd = 0;
+
+ if (VarLocalAuth == LOCAL_AUTH)
+ pauth = " ON ";
+ else
+ pauth = " on ";
+ if (IpcpFsm.state == ST_OPENED && phase == PHASE_NETWORK)
+ pconnect = "PPP";
+ else
+ pconnect = "ppp";
+ fprintf(VarTerm, "%s%s%s> ", pconnect, pauth, VarShortHost);
+ fflush(VarTerm);
+}
+
+void
+InterpretCommand(char *buff, int nb, int *argc, char ***argv)
+{
+ static char *vector[MAXARGS];
+ char *cp;
+
+ if (nb > 0) {
+ cp = buff + strcspn(buff, "\r\n");
+ if (cp)
+ *cp = '\0';
+ *argc = MakeArgs(buff, vector, VECSIZE(vector));
+ *argv = vector;
+ } else
+ *argc = 0;
+}
+
+void
+RunCommand(int argc, char const *const *argv, const char *label)
+{
+ if (argc > 0) {
+ if (LogIsKept(LogCOMMAND)) {
+ static char buf[LINE_LEN];
+ int f, n;
+
+ *buf = '\0';
+ if (label) {
+ strcpy(buf, label);
+ strcat(buf, ": ");
+ }
+ n = strlen(buf);
+ for (f = 0; f < argc; f++) {
+ if (n < sizeof(buf)-1 && f)
+ buf[n++] = ' ';
+ strncpy(buf+n, argv[f], sizeof(buf)-n-1);
+ n += strlen(buf+n);
+ }
+ LogPrintf(LogCOMMAND, "%s\n", buf);
+ }
+ FindExec(Commands, argc, argv);
+ }
+}
+
+void
+DecodeCommand(char *buff, int nb, const char *label)
+{
+ int argc;
+ char **argv;
+
+ InterpretCommand(buff, nb, &argc, &argv);
+ RunCommand(argc, (char const *const *)argv, label);
+}
+
+static int
+ShowCommand(struct cmdargs const *arg)
+{
+ if (arg->argc > 0)
+ FindExec(ShowCommands, arg->argc, arg->argv);
+ else if (VarTerm)
+ fprintf(VarTerm, "Use ``show ?'' to get a arg->cmd.\n");
+ else
+ LogPrintf(LogWARN, "show command must have arguments\n");
+
+ return 0;
+}
+
+static int
+TerminalCommand(struct cmdargs const *arg)
+{
+ if (LcpFsm.state > ST_CLOSED) {
+ if (VarTerm)
+ fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]);
+ return 1;
+ }
+ if (!IsInteractive(1))
+ return (1);
+ if (OpenModem() < 0) {
+ if (VarTerm)
+ fprintf(VarTerm, "Failed to open modem.\n");
+ return (1);
+ }
+ if (VarTerm) {
+ fprintf(VarTerm, "Enter to terminal mode.\n");
+ fprintf(VarTerm, "Type `~?' for help.\n");
+ }
+ TtyTermMode();
+ return (0);
+}
+
+static int
+QuitCommand(struct cmdargs const *arg)
+{
+ if (VarTerm) {
+ DropClient();
+ if (mode & MODE_INTER)
+ Cleanup(EX_NORMAL);
+ else if (arg->argc > 0 && !strcasecmp(*arg->argv, "all") && VarLocalAuth&LOCAL_AUTH)
+ Cleanup(EX_NORMAL);
+ }
+
+ return 0;
+}
+
+static int
+CloseCommand(struct cmdargs const *arg)
+{
+ reconnect(RECON_FALSE);
+ LcpClose();
+ return 0;
+}
+
+static int
+DownCommand(struct cmdargs const *arg)
+{
+ LcpDown();
+ return 0;
+}
+
+static int
+SetModemSpeed(struct cmdargs const *arg)
+{
+ int speed;
+
+ if (arg->argc > 0) {
+ if (strcasecmp(*arg->argv, "sync") == 0) {
+ VarSpeed = 0;
+ return 0;
+ }
+ speed = atoi(*arg->argv);
+ if (IntToSpeed(speed) != B0) {
+ VarSpeed = speed;
+ return 0;
+ }
+ LogPrintf(LogWARN, "%s: Invalid speed\n", *arg->argv);
+ }
+ return -1;
+}
+
+static int
+SetReconnect(struct cmdargs const *arg)
+{
+ if (arg->argc == 2) {
+ VarReconnectTimer = atoi(arg->argv[0]);
+ VarReconnectTries = atoi(arg->argv[1]);
+ return 0;
+ }
+ return -1;
+}
+
+static int
+SetRedialTimeout(struct cmdargs const *arg)
+{
+ int timeout;
+ int tries;
+ char *dot;
+
+ if (arg->argc == 1 || arg->argc == 2) {
+ if (strncasecmp(arg->argv[0], "random", 6) == 0 &&
+ (arg->argv[0][6] == '\0' || arg->argv[0][6] == '.')) {
+ VarRedialTimeout = -1;
+ randinit();
+ } else {
+ timeout = atoi(arg->argv[0]);
+
+ if (timeout >= 0)
+ VarRedialTimeout = timeout;
+ else {
+ LogPrintf(LogWARN, "Invalid redial timeout\n");
+ return -1;
+ }
+ }
+
+ dot = strchr(arg->argv[0], '.');
+ if (dot) {
+ if (strcasecmp(++dot, "random") == 0) {
+ VarRedialNextTimeout = -1;
+ randinit();
+ } else {
+ timeout = atoi(dot);
+ if (timeout >= 0)
+ VarRedialNextTimeout = timeout;
+ else {
+ LogPrintf(LogWARN, "Invalid next redial timeout\n");
+ return -1;
+ }
+ }
+ } else
+ VarRedialNextTimeout = NEXT_REDIAL_PERIOD; /* Default next timeout */
+
+ if (arg->argc == 2) {
+ tries = atoi(arg->argv[1]);
+
+ if (tries >= 0) {
+ VarDialTries = tries;
+ } else {
+ LogPrintf(LogWARN, "Invalid retry value\n");
+ return 1;
+ }
+ }
+ return 0;
+ }
+ return -1;
+}
+
+static int
+SetStoppedTimeout(struct cmdargs const *arg)
+{
+ LcpFsm.StoppedTimer.load = 0;
+ IpcpFsm.StoppedTimer.load = 0;
+ CcpFsm.StoppedTimer.load = 0;
+ if (arg->argc <= 3) {
+ if (arg->argc > 0) {
+ LcpFsm.StoppedTimer.load = atoi(arg->argv[0]) * SECTICKS;
+ if (arg->argc > 1) {
+ IpcpFsm.StoppedTimer.load = atoi(arg->argv[1]) * SECTICKS;
+ if (arg->argc > 2)
+ CcpFsm.StoppedTimer.load = atoi(arg->argv[2]) * SECTICKS;
+ }
+ }
+ return 0;
+ }
+ return -1;
+}
+
+#define ismask(x) \
+ (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
+
+static int
+SetServer(struct cmdargs const *arg)
+{
+ int res = -1;
+
+ if (arg->argc > 0 && arg->argc < 4) {
+ const char *port, *passwd, *mask;
+
+ /* What's what ? */
+ port = arg->argv[0];
+ if (arg->argc == 2)
+ if (ismask(arg->argv[1])) {
+ passwd = NULL;
+ mask = arg->argv[1];
+ } else {
+ passwd = arg->argv[1];
+ mask = NULL;
+ }
+ else if (arg->argc == 3) {
+ passwd = arg->argv[1];
+ mask = arg->argv[2];
+ if (!ismask(mask))
+ return -1;
+ } else
+ passwd = mask = NULL;
+
+ if (passwd == NULL)
+ VarHaveLocalAuthKey = 0;
+ else {
+ strncpy(VarLocalAuthKey, passwd, sizeof VarLocalAuthKey);
+ VarLocalAuthKey[sizeof VarLocalAuthKey - 1] = '\0';
+ VarHaveLocalAuthKey = 1;
+ }
+ LocalAuthInit();
+
+ if (strcasecmp(port, "none") == 0) {
+ int oserver;
+
+ if (mask != NULL || passwd != NULL)
+ return -1;
+ oserver = server;
+ ServerClose();
+ if (oserver != -1)
+ LogPrintf(LogPHASE, "Disabling server port.\n");
+ res = 0;
+ } else if (*port == '/') {
+ mode_t imask;
+
+ if (mask != NULL) {
+ unsigned m;
+
+ if (sscanf(mask, "%o", &m) == 1)
+ imask = m;
+ else
+ return -1;
+ } else
+ imask = (mode_t)-1;
+ res = ServerLocalOpen(port, imask);
+ } else {
+ int iport;
+
+ if (mask != NULL)
+ return -1;
+
+ if (strspn(port, "0123456789") != strlen(port)) {
+ struct servent *s;
+
+ if ((s = getservbyname(port, "tcp")) == NULL) {
+ iport = 0;
+ LogPrintf(LogWARN, "%s: Invalid port or service\n", port);
+ } else
+ iport = ntohs(s->s_port);
+ } else
+ iport = atoi(port);
+ res = iport ? ServerTcpOpen(iport) : -1;
+ }
+ }
+
+ return res;
+}
+
+static int
+SetModemParity(struct cmdargs const *arg)
+{
+ return arg->argc > 0 ? ChangeParity(*arg->argv) : -1;
+}
+
+static int
+SetLogLevel(struct cmdargs const *arg)
+{
+ int i;
+ int res;
+ int argc;
+ char const *const *argv, *argp;
+ void (*Discard)(int), (*Keep)(int);
+ void (*DiscardAll)(void);
+
+ argc = arg->argc;
+ argv = arg->argv;
+ res = 0;
+ if (argc == 0 || strcasecmp(argv[0], "local")) {
+ Discard = LogDiscard;
+ Keep = LogKeep;
+ DiscardAll = LogDiscardAll;
+ } else {
+ argc--;
+ argv++;
+ Discard = LogDiscardLocal;
+ Keep = LogKeepLocal;
+ DiscardAll = LogDiscardAllLocal;
+ }
+
+ if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-'))
+ DiscardAll();
+ while (argc--) {
+ argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv;
+ for (i = LogMIN; i <= LogMAX; i++)
+ if (strcasecmp(argp, LogName(i)) == 0) {
+ if (**argv == '-')
+ (*Discard)(i);
+ else
+ (*Keep)(i);
+ break;
+ }
+ if (i > LogMAX) {
+ LogPrintf(LogWARN, "%s: Invalid log value\n", argp);
+ res = -1;
+ }
+ argv++;
+ }
+ return res;
+}
+
+static int
+SetEscape(struct cmdargs const *arg)
+{
+ int code;
+ int argc = arg->argc;
+ char const *const *argv = arg->argv;
+
+ for (code = 0; code < 33; code++)
+ EscMap[code] = 0;
+
+ while (argc-- > 0) {
+ sscanf(*argv++, "%x", &code);
+ code &= 0xff;
+ EscMap[code >> 3] |= (1 << (code & 7));
+ EscMap[32] = 1;
+ }
+ return 0;
+}
+
+static int
+SetInitialMRU(struct cmdargs const *arg)
+{
+ long mru;
+ const char *err;
+
+ if (arg->argc > 0) {
+ mru = atol(*arg->argv);
+ if (mru < MIN_MRU)
+ err = "Given MRU value (%ld) is too small.\n";
+ else if (mru > MAX_MRU)
+ err = "Given MRU value (%ld) is too big.\n";
+ else {
+ VarMRU = mru;
+ return 0;
+ }
+ LogPrintf(LogWARN, err, mru);
+ }
+ return -1;
+}
+
+static int
+SetPreferredMTU(struct cmdargs const *arg)
+{
+ long mtu;
+ const char *err;
+
+ if (arg->argc > 0) {
+ mtu = atol(*arg->argv);
+ if (mtu == 0) {
+ VarPrefMTU = 0;
+ return 0;
+ } else if (mtu < MIN_MTU)
+ err = "Given MTU value (%ld) is too small.\n";
+ else if (mtu > MAX_MTU)
+ err = "Given MTU value (%ld) is too big.\n";
+ else {
+ VarPrefMTU = mtu;
+ return 0;
+ }
+ LogPrintf(LogWARN, err, mtu);
+ }
+ return -1;
+}
+
+static int
+SetIdleTimeout(struct cmdargs const *arg)
+{
+ if (arg->argc > 0) {
+ VarIdleTimeout = atoi(arg->argv[0]);
+ UpdateIdleTimer(); /* If we're connected, restart the idle timer */
+ if (arg->argc > 1) {
+ VarLqrTimeout = atoi(arg->argv[1]);
+ if (VarLqrTimeout < 1)
+ VarLqrTimeout = 30;
+ if (arg->argc > 2) {
+ VarRetryTimeout = atoi(arg->argv[2]);
+ if (VarRetryTimeout < 1 || VarRetryTimeout > 10)
+ VarRetryTimeout = 3;
+ }
+ }
+ return 0;
+ }
+ return -1;
+}
+
+static struct in_addr
+GetIpAddr(const char *cp)
+{
+ struct hostent *hp;
+ struct in_addr ipaddr;
+
+ hp = gethostbyname(cp);
+ if (hp && hp->h_addrtype == AF_INET)
+ memcpy(&ipaddr, hp->h_addr, hp->h_length);
+ else if (inet_aton(cp, &ipaddr) == 0)
+ ipaddr.s_addr = 0;
+ return (ipaddr);
+}
+
+static int
+SetInterfaceAddr(struct cmdargs const *arg)
+{
+ DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L;
+
+ if (arg->argc > 4)
+ return -1;
+
+ HaveTriggerAddress = 0;
+ ifnetmask.s_addr = 0;
+
+ if (arg->argc > 0) {
+ if (ParseAddr(arg->argc, arg->argv,
+ &DefMyAddress.ipaddr,
+ &DefMyAddress.mask,
+ &DefMyAddress.width) == 0)
+ return 1;
+ if (arg->argc > 1) {
+ if (ParseAddr(arg->argc, arg->argv+1,
+ &DefHisAddress.ipaddr,
+ &DefHisAddress.mask,
+ &DefHisAddress.width) == 0)
+ return 2;
+ if (arg->argc > 2) {
+ ifnetmask = GetIpAddr(arg->argv[2]);
+ if (arg->argc > 3) {
+ TriggerAddress = GetIpAddr(arg->argv[3]);
+ HaveTriggerAddress = 1;
+ }
+ }
+ }
+ }
+
+ /*
+ * For backwards compatibility, 0.0.0.0 means any address.
+ */
+ if (DefMyAddress.ipaddr.s_addr == 0) {
+ DefMyAddress.mask.s_addr = 0;
+ DefMyAddress.width = 0;
+ }
+ if (DefHisAddress.ipaddr.s_addr == 0) {
+ DefHisAddress.mask.s_addr = 0;
+ DefHisAddress.width = 0;
+ }
+ IpcpInfo.want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
+ IpcpInfo.his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
+
+ if ((mode & MODE_AUTO) &&
+ OsSetIpaddress(DefMyAddress.ipaddr, DefHisAddress.ipaddr, ifnetmask) < 0)
+ return 4;
+
+ return 0;
+}
+
+#ifndef NOMSEXT
+
+static void
+SetMSEXT(struct in_addr * pri_addr,
+ struct in_addr * sec_addr,
+ int argc,
+ char const *const *argv)
+{
+ int dummyint;
+ struct in_addr dummyaddr;
+
+ pri_addr->s_addr = sec_addr->s_addr = 0L;
+
+ if (argc > 0) {
+ ParseAddr(argc, argv++, pri_addr, &dummyaddr, &dummyint);
+ if (--argc > 0)
+ ParseAddr(argc, argv++, sec_addr, &dummyaddr, &dummyint);
+ else
+ sec_addr->s_addr = pri_addr->s_addr;
+ }
+
+ /*
+ * if the primary/secondary ns entries are 0.0.0.0 we should set them to
+ * either the localhost's ip, or the values in /etc/resolv.conf ??
+ *
+ * up to you if you want to implement this...
+ */
+
+}
+
+static int
+SetNS(struct cmdargs const *arg)
+{
+ SetMSEXT(&ns_entries[0], &ns_entries[1], arg->argc, arg->argv);
+ return 0;
+}
+
+static int
+SetNBNS(struct cmdargs const *arg)
+{
+ SetMSEXT(&nbns_entries[0], &nbns_entries[1], arg->argc, arg->argv);
+ return 0;
+}
+
+#endif /* MS_EXT */
+
+int
+SetVariable(struct cmdargs const *arg)
+{
+ u_long map;
+ const char *argp;
+ int param = (int)arg->data;
+
+ if (arg->argc > 0)
+ argp = *arg->argv;
+ else
+ argp = "";
+
+ switch (param) {
+ case VAR_AUTHKEY:
+ strncpy(VarAuthKey, argp, sizeof(VarAuthKey) - 1);
+ VarAuthKey[sizeof(VarAuthKey) - 1] = '\0';
+ break;
+ case VAR_AUTHNAME:
+ strncpy(VarAuthName, argp, sizeof(VarAuthName) - 1);
+ VarAuthName[sizeof(VarAuthName) - 1] = '\0';
+ break;
+ case VAR_DIAL:
+ strncpy(VarDialScript, argp, sizeof(VarDialScript) - 1);
+ VarDialScript[sizeof(VarDialScript) - 1] = '\0';
+ break;
+ case VAR_LOGIN:
+ strncpy(VarLoginScript, argp, sizeof(VarLoginScript) - 1);
+ VarLoginScript[sizeof(VarLoginScript) - 1] = '\0';
+ break;
+ case VAR_DEVICE:
+ if (modem != -1)
+ LogPrintf(LogWARN, "Cannot change device to \"%s\" when \"%s\" is open\n",
+ argp, VarDevice);
+ else {
+ strncpy(VarDevice, argp, sizeof(VarDevice) - 1);
+ VarDevice[sizeof(VarDevice) - 1] = '\0';
+ VarBaseDevice = strrchr(VarDevice, '/');
+ VarBaseDevice = VarBaseDevice ? VarBaseDevice + 1 : "";
+ }
+ break;
+ case VAR_ACCMAP:
+ sscanf(argp, "%lx", &map);
+ VarAccmap = map;
+ break;
+ case VAR_PHONE:
+ strncpy(VarPhoneList, argp, sizeof(VarPhoneList) - 1);
+ VarPhoneList[sizeof(VarPhoneList) - 1] = '\0';
+ strcpy(VarPhoneCopy, VarPhoneList);
+ VarNextPhone = VarPhoneCopy;
+ VarAltPhone = NULL;
+ break;
+ case VAR_HANGUP:
+ strncpy(VarHangupScript, argp, sizeof(VarHangupScript) - 1);
+ VarHangupScript[sizeof(VarHangupScript) - 1] = '\0';
+ break;
+#ifdef HAVE_DES
+ case VAR_ENC:
+ VarMSChap = !strcasecmp(argp, "mschap");
+ break;
+#endif
+ }
+ return 0;
+}
+
+static int
+SetCtsRts(struct cmdargs const *arg)
+{
+ if (arg->argc > 0) {
+ if (strcmp(*arg->argv, "on") == 0)
+ VarCtsRts = 1;
+ else if (strcmp(*arg->argv, "off") == 0)
+ VarCtsRts = 0;
+ else
+ return -1;
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+SetOpenMode(struct cmdargs const *arg)
+{
+ if (arg->argc > 0) {
+ if (strcmp(*arg->argv, "active") == 0)
+ VarOpenMode = OPEN_ACTIVE;
+ else if (strcmp(*arg->argv, "passive") == 0)
+ VarOpenMode = OPEN_PASSIVE;
+ else
+ return -1;
+ return 0;
+ }
+ return -1;
+}
+
+static struct cmdtab const SetCommands[] = {
+ {"accmap", NULL, SetVariable, LOCAL_AUTH,
+ "Set accmap value", "set accmap hex-value", (const void *) VAR_ACCMAP},
+ {"afilter", NULL, SetAfilter, LOCAL_AUTH,
+ "Set keep Alive filter", "set afilter ..."},
+ {"authkey", "key", SetVariable, LOCAL_AUTH,
+ "Set authentication key", "set authkey|key key", (const void *) VAR_AUTHKEY},
+ {"authname", NULL, SetVariable, LOCAL_AUTH,
+ "Set authentication name", "set authname name", (const void *) VAR_AUTHNAME},
+ {"ctsrts", NULL, SetCtsRts, LOCAL_AUTH,
+ "Use CTS/RTS modem signalling", "set ctsrts [on|off]"},
+ {"device", "line", SetVariable, LOCAL_AUTH, "Set modem device name",
+ "set device|line device-name", (const void *) VAR_DEVICE},
+ {"dfilter", NULL, SetDfilter, LOCAL_AUTH,
+ "Set demand filter", "set dfilter ..."},
+ {"dial", NULL, SetVariable, LOCAL_AUTH,
+ "Set dialing script", "set dial chat-script", (const void *) VAR_DIAL},
+#ifdef HAVE_DES
+ {"encrypt", NULL, SetVariable, LOCAL_AUTH, "Set CHAP encryption algorithm",
+ "set encrypt MSChap|MD5", (const void *) VAR_ENC},
+#endif
+ {"escape", NULL, SetEscape, LOCAL_AUTH,
+ "Set escape characters", "set escape hex-digit ..."},
+ {"hangup", NULL, SetVariable, LOCAL_AUTH,
+ "Set hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
+ {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "Set destination address",
+ "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
+ {"ifilter", NULL, SetIfilter, LOCAL_AUTH,
+ "Set input filter", "set ifilter ..."},
+ {"loopback", NULL, SetLoopback, LOCAL_AUTH,
+ "Set loopback facility", "set loopback on|off"},
+ {"log", NULL, SetLogLevel, LOCAL_AUTH,
+ "Set log level", "set log [local] [+|-]value..."},
+ {"login", NULL, SetVariable, LOCAL_AUTH,
+ "Set login script", "set login chat-script", (const void *) VAR_LOGIN},
+ {"mru", NULL, SetInitialMRU, LOCAL_AUTH,
+ "Set Initial MRU value", "set mru value"},
+ {"mtu", NULL, SetPreferredMTU, LOCAL_AUTH,
+ "Set Preferred MTU value", "set mtu value"},
+ {"ofilter", NULL, SetOfilter, LOCAL_AUTH,
+ "Set output filter", "set ofilter ..."},
+ {"openmode", NULL, SetOpenMode, LOCAL_AUTH,
+ "Set open mode", "set openmode [active|passive]"},
+ {"parity", NULL, SetModemParity, LOCAL_AUTH,
+ "Set modem parity", "set parity [odd|even|none]"},
+ {"phone", NULL, SetVariable, LOCAL_AUTH, "Set telephone number(s)",
+ "set phone phone1[:phone2[...]]", (const void *) VAR_PHONE},
+ {"reconnect", NULL, SetReconnect, LOCAL_AUTH,
+ "Set Reconnect timeout", "set reconnect value ntries"},
+ {"redial", NULL, SetRedialTimeout, LOCAL_AUTH, "Set Redial timeout",
+ "set redial value|random[.value|random] [dial_attempts]"},
+ {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH, "Set STOPPED timeouts",
+ "set stopped [LCPseconds [IPCPseconds [CCPseconds]]]"},
+ {"server", "socket", SetServer, LOCAL_AUTH,
+ "Set server port", "set server|socket TcpPort|LocalName|none [mask]"},
+ {"speed", NULL, SetModemSpeed, LOCAL_AUTH,
+ "Set modem speed", "set speed value"},
+ {"timeout", NULL, SetIdleTimeout, LOCAL_AUTH,
+ "Set Idle timeout", "set timeout value"},
+#ifndef NOMSEXT
+ {"ns", NULL, SetNS, LOCAL_AUTH,
+ "Set NameServer", "set ns pri-addr [sec-addr]"},
+ {"nbns", NULL, SetNBNS, LOCAL_AUTH,
+ "Set NetBIOS NameServer", "set nbns pri-addr [sec-addr]"},
+#endif
+ {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
+ "Display this message", "set help|? [command]", SetCommands},
+ {NULL, NULL, NULL},
+};
+
+static int
+SetCommand(struct cmdargs const *arg)
+{
+ if (arg->argc > 0)
+ FindExec(SetCommands, arg->argc, arg->argv);
+ else if (VarTerm)
+ fprintf(VarTerm, "Use `set ?' to get a arg->cmd or `set ? <var>' for"
+ " syntax help.\n");
+ else
+ LogPrintf(LogWARN, "set command must have arguments\n");
+
+ return 0;
+}
+
+
+static int
+AddCommand(struct cmdargs const *arg)
+{
+ struct in_addr dest, gateway, netmask;
+
+ if (arg->argc == 3) {
+ if (strcasecmp(arg->argv[0], "MYADDR") == 0)
+ dest = IpcpInfo.want_ipaddr;
+ else
+ dest = GetIpAddr(arg->argv[0]);
+ netmask = GetIpAddr(arg->argv[1]);
+ if (strcasecmp(arg->argv[2], "HISADDR") == 0)
+ gateway = IpcpInfo.his_ipaddr;
+ else
+ gateway = GetIpAddr(arg->argv[2]);
+ OsSetRoute(RTM_ADD, dest, gateway, netmask);
+ return 0;
+ }
+ return -1;
+}
+
+static int
+DeleteCommand(struct cmdargs const *arg)
+{
+ struct in_addr dest, gateway, netmask;
+
+ if (arg->argc == 1 && strcasecmp(arg->argv[0], "all") == 0)
+ DeleteIfRoutes(0);
+ else if (arg->argc > 0 && arg->argc < 4) {
+ if (strcasecmp(arg->argv[0], "MYADDR") == 0)
+ dest = IpcpInfo.want_ipaddr;
+ else
+ dest = GetIpAddr(arg->argv[0]);
+ netmask.s_addr = INADDR_ANY;
+ if (arg->argc > 1) {
+ if (strcasecmp(arg->argv[1], "HISADDR") == 0)
+ gateway = IpcpInfo.his_ipaddr;
+ else
+ gateway = GetIpAddr(arg->argv[1]);
+ if (arg->argc == 3) {
+ if (inet_aton(arg->argv[2], &netmask) == 0) {
+ LogPrintf(LogWARN, "Bad netmask value.\n");
+ return -1;
+ }
+ }
+ } else
+ gateway.s_addr = INADDR_ANY;
+ OsSetRoute(RTM_DELETE, dest, gateway, netmask);
+ } else
+ return -1;
+
+ return 0;
+}
+
+#ifndef NOALIAS
+static struct cmdtab const AliasCommands[] =
+{
+ {"enable", NULL, AliasEnable, LOCAL_AUTH,
+ "enable IP aliasing", "alias enable [yes|no]"},
+ {"port", NULL, AliasRedirectPort, LOCAL_AUTH,
+ "port redirection", "alias port [proto addr_local:port_local port_alias]"},
+ {"addr", NULL, AliasRedirectAddr, LOCAL_AUTH,
+ "static address translation", "alias addr [addr_local addr_alias]"},
+ {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
+ "stop incoming connections", "alias deny_incoming [yes|no]",
+ (const void *) PKT_ALIAS_DENY_INCOMING},
+ {"log", NULL, AliasOption, LOCAL_AUTH,
+ "log aliasing link creation", "alias log [yes|no]",
+ (const void *) PKT_ALIAS_LOG},
+ {"same_ports", NULL, AliasOption, LOCAL_AUTH,
+ "try to leave port numbers unchanged", "alias same_ports [yes|no]",
+ (const void *) PKT_ALIAS_SAME_PORTS},
+ {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
+ "allocate host sockets", "alias use_sockets [yes|no]",
+ (const void *) PKT_ALIAS_USE_SOCKETS},
+ {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
+ "alias unregistered (private) IP address space only",
+ "alias unregistered_only [yes|no]",
+ (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
+ {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
+ "Display this message", "alias help|? [command]", AliasCommands},
+ {NULL, NULL, NULL},
+};
+
+
+static int
+AliasCommand(struct cmdargs const *arg)
+{
+ if (arg->argc > 0)
+ FindExec(AliasCommands, arg->argc, arg->argv);
+ else if (VarTerm)
+ fprintf(VarTerm, "Use `alias help' to get a arg->cmd or `alias help <option>'"
+ " for syntax help.\n");
+ else
+ LogPrintf(LogWARN, "alias command must have arguments\n");
+
+ return 0;
+}
+
+static int
+AliasEnable(struct cmdargs const *arg)
+{
+ if (arg->argc == 1)
+ if (strcasecmp(arg->argv[0], "yes") == 0) {
+ if (!(mode & MODE_ALIAS)) {
+ if (loadAliasHandlers(&VarAliasHandlers) == 0) {
+ mode |= MODE_ALIAS;
+ return 0;
+ }
+ LogPrintf(LogWARN, "Cannot load alias library\n");
+ return 1;
+ }
+ return 0;
+ } else if (strcasecmp(arg->argv[0], "no") == 0) {
+ if (mode & MODE_ALIAS) {
+ unloadAliasHandlers();
+ mode &= ~MODE_ALIAS;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+AliasOption(struct cmdargs const *arg)
+{
+ unsigned param = (unsigned)arg->data;
+ if (arg->argc == 1)
+ if (strcasecmp(arg->argv[0], "yes") == 0) {
+ if (mode & MODE_ALIAS) {
+ VarPacketAliasSetMode(param, param);
+ return 0;
+ }
+ LogPrintf(LogWARN, "alias not enabled\n");
+ } else if (strcmp(arg->argv[0], "no") == 0) {
+ if (mode & MODE_ALIAS) {
+ VarPacketAliasSetMode(0, param);
+ return 0;
+ }
+ LogPrintf(LogWARN, "alias not enabled\n");
+ }
+ return -1;
+}
+#endif /* #ifndef NOALIAS */
+
+static struct cmdtab const AllowCommands[] = {
+ {"users", "user", AllowUsers, LOCAL_AUTH,
+ "Allow users access to ppp", "allow users logname..."},
+ {"modes", "mode", AllowModes, LOCAL_AUTH,
+ "Only allow certain ppp modes", "allow modes mode..."},
+ {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
+ "Display this message", "allow help|? [command]", AllowCommands},
+ {NULL, NULL, NULL},
+};
+
+static int
+AllowCommand(struct cmdargs const *arg)
+{
+ if (arg->argc > 0)
+ FindExec(AllowCommands, arg->argc, arg->argv);
+ else if (VarTerm)
+ fprintf(VarTerm, "Use `allow ?' to get a arg->cmd or `allow ? <cmd>' for"
+ " syntax help.\n");
+ else
+ LogPrintf(LogWARN, "allow command must have arguments\n");
+
+ return 0;
+}
diff --git a/usr.sbin/ppp/command.h b/usr.sbin/ppp/command.h
new file mode 100644
index 00000000000..e74f7c48031
--- /dev/null
+++ b/usr.sbin/ppp/command.h
@@ -0,0 +1,62 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: command.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+struct cmdtab;
+
+struct cmdargs {
+ struct cmdtab const *cmd;
+ int argc;
+ char const *const *argv;
+ const void *data;
+};
+
+struct cmdtab {
+ const char *name;
+ const char *alias;
+ int (*func) (struct cmdargs const *);
+ u_char lauth;
+ const char *helpmes;
+ const char *syntax;
+ const void *args;
+};
+
+#define VAR_AUTHKEY 0
+#define VAR_DIAL 1
+#define VAR_LOGIN 2
+#define VAR_AUTHNAME 3
+#define VAR_DEVICE 4
+#define VAR_ACCMAP 5
+#define VAR_PHONE 6
+#define VAR_HANGUP 7
+#ifdef HAVE_DES
+#define VAR_ENC 8
+#endif
+
+extern struct in_addr ifnetmask;
+extern int aft_cmd;
+
+extern int SetVariable(struct cmdargs const *);
+extern void Prompt(void);
+extern int IsInteractive(int);
+extern void InterpretCommand(char *, int, int *, char ***);
+extern void RunCommand(int, char const *const *, const char *label);
+extern void DecodeCommand(char *, int, const char *label);
diff --git a/usr.sbin/ppp/defs.c b/usr.sbin/ppp/defs.c
new file mode 100644
index 00000000000..a942a097f37
--- /dev/null
+++ b/usr.sbin/ppp/defs.c
@@ -0,0 +1,92 @@
+/*
+ * $Id: defs.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "defs.h"
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "loadalias.h"
+#include "vars.h"
+
+int mode = MODE_INTER;
+int BGFiledes[2] = { -1, -1 };
+int modem = -1;
+int tun_in = -1;
+int tun_out = -1;
+int netfd = -1;
+
+static char dstsystem[50];
+
+void
+SetLabel(const char *label)
+{
+ if (label)
+ strncpy(dstsystem, label, sizeof dstsystem);
+ else
+ *dstsystem = '\0';
+}
+
+const char *
+GetLabel()
+{
+ return *dstsystem ? dstsystem : NULL;
+}
+
+void
+randinit()
+{
+#ifdef __FreeBSD__
+ static int initdone;
+
+ if (!initdone) {
+ initdone = 1;
+ srandomdev();
+ }
+#else
+ srandom(time(NULL)^getpid());
+#endif
+}
+
+
+int
+GetShortHost()
+{
+ char *p;
+
+ if (gethostname(VarShortHost, sizeof(VarShortHost))) {
+ LogPrintf(LogERROR, "GetShortHost: gethostbyname: %s\n", strerror(errno));
+ return 0;
+ }
+
+ if ((p = strchr(VarShortHost, '.')))
+ *p = '\0';
+
+ return 1;
+}
+
+void
+DropClient()
+{
+ FILE *oVarTerm;
+
+ if (VarTerm && !(mode & MODE_INTER)) {
+ oVarTerm = VarTerm;
+ VarTerm = 0;
+ if (oVarTerm)
+ fclose(oVarTerm);
+ close(netfd);
+ netfd = -1;
+ LogPrintf(LogPHASE, "Client connection closed.\n");
+ }
+}
diff --git a/usr.sbin/ppp/defs.h b/usr.sbin/ppp/defs.h
new file mode 100644
index 00000000000..7d3e846dc39
--- /dev/null
+++ b/usr.sbin/ppp/defs.h
@@ -0,0 +1,95 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: defs.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+/*
+ * Check following definitions for your machine environment
+ */
+#ifdef __FreeBSD__
+# define MODEM_DEV "/dev/cuaa1" /* name of tty device */
+# define BASE_MODEM_DEV "cuaa1" /* name of base tty device */
+#else
+# ifdef __OpenBSD__
+# define MODEM_DEV "/dev/cua01" /* name of tty device */
+# define BASE_MODEM_DEV "cua01" /* name of base tty device */
+# else
+# define MODEM_DEV "/dev/tty01" /* name of tty device */
+# define BASE_MODEM_DEV "tty01" /* name of base tty device */
+# endif
+#endif
+
+#define MODEM_SPEED B38400 /* tty speed */
+#define SERVER_PORT 3000 /* Base server port no. */
+#define MODEM_CTSRTS 1 /* Default (true): use CTS/RTS signals */
+#define RECONNECT_TIMER 3 /* Default timer for carrier loss */
+#define RECONNECT_TRIES 0 /* Default retries on carrier loss */
+#define REDIAL_PERIOD 30 /* Default Hold time to redial */
+#define NEXT_REDIAL_PERIOD 3 /* Default Hold time to next number redial */
+#define SCRIPT_LEN 512 /* Size of login scripts */
+#define LINE_LEN SCRIPT_LEN /* Size of login scripts */
+#define MAXARGS 40 /* How many args per config line */
+
+#define CONFFILE "ppp.conf"
+#define LINKUPFILE "ppp.linkup"
+#define LINKDOWNFILE "ppp.linkdown"
+#define SECRETFILE "ppp.secret"
+
+/*
+ * Definition of working mode
+ */
+#define MODE_INTER 1 /* Interactive mode */
+#define MODE_AUTO 2 /* Auto calling mode */
+#define MODE_DIRECT 4 /* Direct connection mode */
+#define MODE_DEDICATED 8 /* Dedicated line mode */
+#define MODE_DDIAL 16 /* Dedicated dialing line mode */
+#define MODE_ALIAS 32 /* Packet aliasing (masquerading) */
+#define MODE_BACKGROUND 64 /* Background mode. */
+
+#define MODE_DAEMON (2|4|8|16|64)
+#define MODE_OUTGOING_DAEMON (2|8|16|64)
+
+#define EX_SIG -1
+#define EX_NORMAL 0
+#define EX_START 1
+#define EX_SOCK 2
+#define EX_MODEM 3
+#define EX_DIAL 4
+#define EX_DEAD 5
+#define EX_DONE 6
+#define EX_REBOOT 7
+#define EX_ERRDEAD 8
+#define EX_HANGUP 10
+#define EX_TERM 11
+#define EX_NODIAL 12
+#define EX_NOLOGIN 13
+
+extern int mode;
+extern int BGFiledes[2];
+extern int modem;
+extern int tun_in;
+extern int tun_out;
+extern int netfd;
+
+extern void SetLabel(const char *);
+extern const char *GetLabel(void);
+extern void randinit(void);
+extern int GetShortHost(void);
+extern void DropClient(void);
diff --git a/usr.sbin/ppp/filter.c b/usr.sbin/ppp/filter.c
new file mode 100644
index 00000000000..119ce0f3f09
--- /dev/null
+++ b/usr.sbin/ppp/filter.c
@@ -0,0 +1,495 @@
+/*
+ * PPP Filter command Interface
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: filter.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO: Shoud send ICMP error message when we discard packets.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "loadalias.h"
+#include "defs.h"
+#include "vars.h"
+#include "ipcp.h"
+#include "filter.h"
+
+struct filterent ifilters[MAXFILTERS]; /* incoming packet filter */
+struct filterent ofilters[MAXFILTERS]; /* outgoing packet filter */
+struct filterent dfilters[MAXFILTERS]; /* dial-out packet filter */
+struct filterent afilters[MAXFILTERS]; /* keep-alive packet filter */
+
+static struct filterent filterdata;
+
+static u_long netmasks[33] = {
+ 0x00000000,
+ 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
+ 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
+ 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
+ 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
+ 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
+ 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
+ 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
+ 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
+};
+
+int
+ParseAddr(int argc,
+ char const *const *argv,
+ struct in_addr * paddr,
+ struct in_addr * pmask,
+ int *pwidth)
+{
+ int bits, len;
+ char *wp;
+ const char *cp;
+
+ if (argc < 1) {
+ LogPrintf(LogWARN, "ParseAddr: address/mask is expected.\n");
+ return (0);
+ }
+ pmask->s_addr = 0xffffffff; /* Assume 255.255.255.255 as default */
+
+ cp = strchr(*argv, '/');
+ len = cp ? cp - *argv : strlen(*argv);
+
+ if (strncasecmp(*argv, "HISADDR", len) == 0)
+ *paddr = IpcpInfo.his_ipaddr;
+ else if (strncasecmp(*argv, "MYADDR", len) == 0)
+ *paddr = IpcpInfo.want_ipaddr;
+ else if (len > 15)
+ LogPrintf(LogWARN, "ParseAddr: %s: Bad address\n", *argv);
+ else {
+ char s[16];
+ strncpy(s, *argv, len);
+ s[len] = '\0';
+ if (inet_aton(s, paddr) == 0) {
+ LogPrintf(LogWARN, "ParseAddr: %s: Bad address\n", s);
+ return (0);
+ }
+ }
+ if (cp && *++cp) {
+ bits = strtol(cp, &wp, 0);
+ if (cp == wp || bits < 0 || bits > 32) {
+ LogPrintf(LogWARN, "ParseAddr: bad mask width.\n");
+ return (0);
+ }
+ } else {
+ /* if width is not given, assume whole 32 bits are meaningfull */
+ bits = 32;
+ }
+
+ *pwidth = bits;
+ pmask->s_addr = htonl(netmasks[bits]);
+
+ return (1);
+}
+
+static int
+ParseProto(int argc, char const *const *argv)
+{
+ int proto;
+
+ if (argc < 1)
+ return (P_NONE);
+
+ if (!strcmp(*argv, "tcp"))
+ proto = P_TCP;
+ else if (!strcmp(*argv, "udp"))
+ proto = P_UDP;
+ else if (!strcmp(*argv, "icmp"))
+ proto = P_ICMP;
+ else
+ proto = P_NONE;
+ return (proto);
+}
+
+static int
+ParsePort(const char *service, int proto)
+{
+ const char *protocol_name;
+ char *cp;
+ struct servent *servent;
+ int port;
+
+ switch (proto) {
+ case P_UDP:
+ protocol_name = "udp";
+ break;
+ case P_TCP:
+ protocol_name = "tcp";
+ break;
+ default:
+ protocol_name = 0;
+ }
+
+ servent = getservbyname(service, protocol_name);
+ if (servent != 0)
+ return (ntohs(servent->s_port));
+
+ port = strtol(service, &cp, 0);
+ if (cp == service) {
+ LogPrintf(LogWARN, "ParsePort: %s is not a port name or number.\n",
+ service);
+ return (0);
+ }
+ return (port);
+}
+
+/*
+ * ICMP Syntax: src eq icmp_message_type
+ */
+static int
+ParseIcmp(int argc, char const *const *argv)
+{
+ int type;
+ char *cp;
+
+ switch (argc) {
+ case 0:
+ /* permit/deny all ICMP types */
+ filterdata.opt.srcop = OP_NONE;
+ break;
+ default:
+ LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
+ return (0);
+ case 3:
+ if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) {
+ type = strtol(argv[2], &cp, 0);
+ if (cp == argv[2]) {
+ LogPrintf(LogWARN, "ParseIcmp: type is expected.\n");
+ return (0);
+ }
+ filterdata.opt.srcop = OP_EQ;
+ filterdata.opt.srcport = type;
+ }
+ break;
+ }
+ return (1);
+}
+
+static int
+ParseOp(const char *cp)
+{
+ int op = OP_NONE;
+
+ if (!strcmp(cp, "eq"))
+ op = OP_EQ;
+ else if (!strcmp(cp, "gt"))
+ op = OP_GT;
+ else if (!strcmp(cp, "lt"))
+ op = OP_LT;
+ return (op);
+}
+
+/*
+ * UDP Syntax: [src op port] [dst op port]
+ */
+static int
+ParseUdpOrTcp(int argc, char const *const *argv, int proto)
+{
+ filterdata.opt.srcop = filterdata.opt.dstop = OP_NONE;
+ filterdata.opt.estab = 0;
+
+ if (argc == 0) {
+ /* permit/deny all tcp traffic */
+ return (1);
+ }
+
+ if (argc >= 3 && !strcmp(*argv, "src")) {
+ filterdata.opt.srcop = ParseOp(argv[1]);
+ if (filterdata.opt.srcop == OP_NONE) {
+ LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
+ return (0);
+ }
+ filterdata.opt.srcport = ParsePort(argv[2], proto);
+ if (filterdata.opt.srcport == 0)
+ return (0);
+ argc -= 3;
+ argv += 3;
+ if (argc == 0)
+ return (1);
+ }
+ if (argc >= 3 && !strcmp(argv[0], "dst")) {
+ filterdata.opt.dstop = ParseOp(argv[1]);
+ if (filterdata.opt.dstop == OP_NONE) {
+ LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
+ return (0);
+ }
+ filterdata.opt.dstport = ParsePort(argv[2], proto);
+ if (filterdata.opt.dstport == 0)
+ return (0);
+ argc -= 3;
+ argv += 3;
+ if (argc == 0)
+ return (1);
+ }
+ if (argc == 1 && proto == P_TCP) {
+ if (!strcmp(*argv, "estab")) {
+ filterdata.opt.estab = 1;
+ return (1);
+ }
+ LogPrintf(LogWARN, "ParseUdpOrTcp: estab is expected: %s\n", *argv);
+ return (0);
+ }
+ if (argc > 0)
+ LogPrintf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv);
+ return (0);
+}
+
+const char *opname[] = {"none", "eq", "gt", NULL, "lt"};
+
+static int
+Parse(int argc, char const *const *argv, struct filterent * ofp)
+{
+ int action, proto;
+ int val;
+ char *wp;
+ struct filterent *fp = &filterdata;
+
+ val = strtol(*argv, &wp, 0);
+ if (*argv == wp || val > MAXFILTERS) {
+ LogPrintf(LogWARN, "Parse: invalid filter number.\n");
+ return (0);
+ }
+ if (val < 0) {
+ for (val = 0; val < MAXFILTERS; val++) {
+ ofp->action = A_NONE;
+ ofp++;
+ }
+ LogPrintf(LogWARN, "Parse: filter cleared.\n");
+ return (1);
+ }
+ ofp += val;
+
+ if (--argc == 0) {
+ LogPrintf(LogWARN, "Parse: missing action.\n");
+ return (0);
+ }
+ argv++;
+
+ proto = P_NONE;
+ memset(&filterdata, '\0', sizeof(filterdata));
+
+ if (!strcmp(*argv, "permit")) {
+ action = A_PERMIT;
+ } else if (!strcmp(*argv, "deny")) {
+ action = A_DENY;
+ } else if (!strcmp(*argv, "clear")) {
+ ofp->action = A_NONE;
+ return (1);
+ } else {
+ LogPrintf(LogWARN, "Parse: bad action: %s\n", *argv);
+ return (0);
+ }
+ fp->action = action;
+
+ argc--;
+ argv++;
+
+ if (fp->action == A_DENY) {
+ if (!strcmp(*argv, "host")) {
+ fp->action |= A_UHOST;
+ argc--;
+ argv++;
+ } else if (!strcmp(*argv, "port")) {
+ fp->action |= A_UPORT;
+ argc--;
+ argv++;
+ }
+ }
+ proto = ParseProto(argc, argv);
+ if (proto == P_NONE) {
+ if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) {
+ argc--;
+ argv++;
+ proto = ParseProto(argc, argv);
+ if (proto == P_NONE) {
+ if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) {
+ argc--;
+ argv++;
+ }
+ proto = ParseProto(argc, argv);
+ if (proto != P_NONE) {
+ argc--;
+ argv++;
+ }
+ } else {
+ argc--;
+ argv++;
+ }
+ } else {
+ LogPrintf(LogWARN, "Parse: Address/protocol expected.\n");
+ return (0);
+ }
+ } else {
+ argc--;
+ argv++;
+ }
+
+ val = 1;
+ fp->proto = proto;
+
+ switch (proto) {
+ case P_TCP:
+ val = ParseUdpOrTcp(argc, argv, P_TCP);
+ break;
+ case P_UDP:
+ val = ParseUdpOrTcp(argc, argv, P_UDP);
+ break;
+ case P_ICMP:
+ val = ParseIcmp(argc, argv);
+ break;
+ }
+
+ LogPrintf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(fp->saddr));
+ LogPrintf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(fp->smask));
+ LogPrintf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(fp->daddr));
+ LogPrintf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(fp->dmask));
+ LogPrintf(LogDEBUG, "Parse: Proto = %d\n", proto);
+
+ LogPrintf(LogDEBUG, "Parse: src: %s (%d)\n", opname[fp->opt.srcop],
+ fp->opt.srcport);
+ LogPrintf(LogDEBUG, "Parse: dst: %s (%d)\n", opname[fp->opt.dstop],
+ fp->opt.dstport);
+ LogPrintf(LogDEBUG, "Parse: estab: %d\n", fp->opt.estab);
+
+ if (val)
+ *ofp = *fp;
+ return (val);
+}
+
+int
+SetIfilter(struct cmdargs const *arg)
+{
+ if (arg->argc > 0) {
+ Parse(arg->argc, arg->argv, ifilters);
+ return 0;
+ }
+ return -1;
+}
+
+int
+SetOfilter(struct cmdargs const *arg)
+{
+ if (arg->argc > 0) {
+ (void) Parse(arg->argc, arg->argv, ofilters);
+ return 0;
+ }
+ return -1;
+}
+
+int
+SetDfilter(struct cmdargs const *arg)
+{
+ if (arg->argc > 0) {
+ (void) Parse(arg->argc, arg->argv, dfilters);
+ return 0;
+ }
+ return -1;
+}
+
+int
+SetAfilter(struct cmdargs const *arg)
+{
+ if (arg->argc > 0) {
+ (void) Parse(arg->argc, arg->argv, afilters);
+ return 0;
+ }
+ return -1;
+}
+
+static const char *protoname[] = { "none", "tcp", "udp", "icmp" };
+static const char *actname[] = { "none ", "permit ", "deny " };
+
+static void
+ShowFilter(struct filterent * fp)
+{
+ int n;
+
+ if (!VarTerm)
+ return;
+
+ for (n = 0; n < MAXFILTERS; n++, fp++) {
+ if (fp->action != A_NONE) {
+ fprintf(VarTerm, "%2d %s", n, actname[fp->action & (A_PERMIT|A_DENY)]);
+ if (fp->action & A_UHOST)
+ fprintf(VarTerm, "host ");
+ else if (fp->action & A_UPORT)
+ fprintf(VarTerm, "port ");
+ else
+ fprintf(VarTerm, " ");
+ fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
+ fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
+ if (fp->proto) {
+ fprintf(VarTerm, "%s", protoname[fp->proto]);
+
+ if (fp->opt.srcop)
+ fprintf(VarTerm, " src %s %d", opname[fp->opt.srcop],
+ fp->opt.srcport);
+ if (fp->opt.dstop)
+ fprintf(VarTerm, " dst %s %d", opname[fp->opt.dstop],
+ fp->opt.dstport);
+ if (fp->opt.estab)
+ fprintf(VarTerm, " estab");
+
+ }
+ fprintf(VarTerm, "\n");
+ }
+ }
+}
+
+int
+ShowIfilter(struct cmdargs const *arg)
+{
+ ShowFilter(ifilters);
+ return 0;
+}
+
+int
+ShowOfilter(struct cmdargs const *arg)
+{
+ ShowFilter(ofilters);
+ return 0;
+}
+
+int
+ShowDfilter(struct cmdargs const *arg)
+{
+ ShowFilter(dfilters);
+ return 0;
+}
+
+int
+ShowAfilter(struct cmdargs const *arg)
+{
+ ShowFilter(afilters);
+ return 0;
+}
diff --git a/usr.sbin/ppp/filter.h b/usr.sbin/ppp/filter.h
new file mode 100644
index 00000000000..6235b9f6c84
--- /dev/null
+++ b/usr.sbin/ppp/filter.h
@@ -0,0 +1,87 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: filter.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+/*
+ * Actions
+ */
+#define A_NONE 0
+#define A_PERMIT 1
+#define A_DENY 2
+#define A_MASK 3
+#define A_UHOST 4
+#define A_UPORT 8
+
+/*
+ * Known protocols
+ */
+#define P_NONE 0
+#define P_TCP 1
+#define P_UDP 2
+#define P_ICMP 3
+
+/*
+ * Operations
+ */
+#define OP_NONE 0
+#define OP_EQ 1
+#define OP_GT 2
+#define OP_LT 4
+
+struct filterent {
+ int action; /* Filtering action */
+ int swidth; /* Effective source address width */
+ struct in_addr saddr; /* Source address */
+ struct in_addr smask; /* Source address mask */
+ int dwidth; /* Effective destination address width */
+ struct in_addr daddr; /* Destination address */
+ struct in_addr dmask; /* Destination address mask */
+ int proto; /* Protocol */
+ struct {
+ short srcop;
+ u_short srcport;
+ short dstop;
+ u_short dstport;
+ int estab;
+ } opt;
+};
+
+#define MAXFILTERS 20
+
+#define FL_IN 0
+#define FL_OUT 1
+#define FL_DIAL 2
+#define FL_KEEP 3
+
+extern struct filterent ifilters[MAXFILTERS]; /* incoming packet filter */
+extern struct filterent ofilters[MAXFILTERS]; /* outgoing packet filter */
+extern struct filterent dfilters[MAXFILTERS]; /* dial-out packet filter */
+extern struct filterent afilters[MAXFILTERS]; /* keep-alive packet filter */
+
+extern int ParseAddr(int, char const *const *, struct in_addr *, struct in_addr *, int *);
+extern int ShowIfilter(struct cmdargs const *);
+extern int ShowOfilter(struct cmdargs const *);
+extern int ShowDfilter(struct cmdargs const *);
+extern int ShowAfilter(struct cmdargs const *);
+extern int SetIfilter(struct cmdargs const *);
+extern int SetOfilter(struct cmdargs const *);
+extern int SetDfilter(struct cmdargs const *);
+extern int SetAfilter(struct cmdargs const *);
diff --git a/usr.sbin/ppp/fsm.c b/usr.sbin/ppp/fsm.c
new file mode 100644
index 00000000000..58083329105
--- /dev/null
+++ b/usr.sbin/ppp/fsm.c
@@ -0,0 +1,789 @@
+/*
+ * PPP Finite State Machine for LCP/IPCP
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: fsm.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ * o Refer loglevel for log output
+ * o Better option log display
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "hdlc.h"
+#include "lqr.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "ccp.h"
+#include "modem.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "pred.h"
+
+u_char AckBuff[200];
+u_char NakBuff[200];
+u_char RejBuff[100];
+u_char ReqBuff[200];
+u_char *ackp = NULL;
+u_char *nakp = NULL;
+u_char *rejp = NULL;
+
+static void FsmSendConfigReq(struct fsm *);
+static void FsmSendTerminateReq(struct fsm *);
+static void FsmInitRestartCounter(struct fsm *);
+
+char const *StateNames[] = {
+ "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
+ "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened",
+};
+
+static void
+StoppedTimeout(void *v)
+{
+ struct fsm *fp = (struct fsm *)v;
+
+ LogPrintf(fp->LogLevel, "Stopped timer expired\n");
+ if (modem != -1)
+ DownConnection();
+ else
+ FsmDown(fp);
+}
+
+void
+FsmInit(struct fsm * fp)
+{
+ LogPrintf(LogDEBUG, "FsmInit\n");
+ fp->state = ST_INITIAL;
+ fp->reqid = 1;
+ fp->restart = 1;
+ fp->maxconfig = 3;
+}
+
+static void
+NewState(struct fsm * fp, int new)
+{
+ LogPrintf(fp->LogLevel, "State change %s --> %s\n",
+ StateNames[fp->state], StateNames[new]);
+ if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING)
+ StopTimer(&fp->StoppedTimer);
+ fp->state = new;
+ if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) {
+ StopTimer(&fp->FsmTimer);
+ if (new == ST_STOPPED && fp->StoppedTimer.load) {
+ fp->StoppedTimer.state = TIMER_STOPPED;
+ fp->StoppedTimer.func = StoppedTimeout;
+ fp->StoppedTimer.arg = (void *) fp;
+ StartTimer(&fp->StoppedTimer);
+ }
+ }
+}
+
+void
+FsmOutput(struct fsm * fp, u_int code, u_int id, u_char * ptr, int count)
+{
+ int plen;
+ struct fsmheader lh;
+ struct mbuf *bp;
+
+ plen = sizeof(struct fsmheader) + count;
+ lh.code = code;
+ lh.id = id;
+ lh.length = htons(plen);
+ bp = mballoc(plen, MB_FSM);
+ memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
+ if (count)
+ memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
+ LogDumpBp(LogDEBUG, "FsmOutput", bp);
+ HdlcOutput(PRI_LINK, fp->proto, bp);
+}
+
+void
+FsmOpen(struct fsm * fp)
+{
+ switch (fp->state) {
+ case ST_INITIAL:
+ (fp->LayerStart) (fp);
+ NewState(fp, ST_STARTING);
+ break;
+ case ST_STARTING:
+ break;
+ case ST_CLOSED:
+ if (fp->open_mode == OPEN_PASSIVE) {
+ NewState(fp, ST_STOPPED);
+ } else {
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ }
+ break;
+ case ST_STOPPED: /* XXX: restart option */
+ case ST_REQSENT:
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ case ST_OPENED: /* XXX: restart option */
+ break;
+ case ST_CLOSING: /* XXX: restart option */
+ case ST_STOPPING: /* XXX: restart option */
+ NewState(fp, ST_STOPPING);
+ break;
+ }
+}
+
+void
+FsmUp(struct fsm * fp)
+{
+ switch (fp->state) {
+ case ST_INITIAL:
+ NewState(fp, ST_CLOSED);
+ break;
+ case ST_STARTING:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ default:
+ LogPrintf(fp->LogLevel, "Oops, Up at %s\n", StateNames[fp->state]);
+ break;
+ }
+}
+
+void
+FsmDown(struct fsm * fp)
+{
+ switch (fp->state) {
+ case ST_CLOSED:
+ case ST_CLOSING:
+ NewState(fp, ST_INITIAL);
+ break;
+ case ST_STOPPED:
+ (fp->LayerStart) (fp);
+ /* Fall into.. */
+ case ST_STOPPING:
+ case ST_REQSENT:
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ NewState(fp, ST_STARTING);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ NewState(fp, ST_STARTING);
+ break;
+ }
+}
+
+void
+FsmClose(struct fsm * fp)
+{
+ switch (fp->state) {
+ case ST_STARTING:
+ NewState(fp, ST_INITIAL);
+ break;
+ case ST_STOPPED:
+ NewState(fp, ST_CLOSED);
+ break;
+ case ST_STOPPING:
+ NewState(fp, ST_CLOSING);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ /* Fall down */
+ case ST_REQSENT:
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ FsmSendTerminateReq(fp);
+ NewState(fp, ST_CLOSING);
+ break;
+ }
+}
+
+/*
+ * Send functions
+ */
+static void
+FsmSendConfigReq(struct fsm * fp)
+{
+ if (--fp->maxconfig > 0) {
+ (fp->SendConfigReq) (fp);
+ StartTimer(&fp->FsmTimer); /* Start restart timer */
+ fp->restart--; /* Decrement restart counter */
+ } else {
+ FsmClose(fp);
+ }
+}
+
+static void
+FsmSendTerminateReq(struct fsm * fp)
+{
+ LogPrintf(fp->LogLevel, "SendTerminateReq.\n");
+ FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0);
+ (fp->SendTerminateReq) (fp);
+ StartTimer(&fp->FsmTimer); /* Start restart timer */
+ fp->restart--; /* Decrement restart counter */
+}
+
+static void
+FsmSendConfigAck(struct fsm * fp,
+ struct fsmheader * lhp,
+ u_char * option,
+ int count)
+{
+ LogPrintf(fp->LogLevel, "SendConfigAck(%s)\n", StateNames[fp->state]);
+ (fp->DecodeConfig) (option, count, MODE_NOP);
+ FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
+}
+
+static void
+FsmSendConfigRej(struct fsm * fp,
+ struct fsmheader * lhp,
+ u_char * option,
+ int count)
+{
+ LogPrintf(fp->LogLevel, "SendConfigRej(%s)\n", StateNames[fp->state]);
+ (fp->DecodeConfig) (option, count, MODE_NOP);
+ FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
+}
+
+static void
+FsmSendConfigNak(struct fsm * fp,
+ struct fsmheader * lhp,
+ u_char * option,
+ int count)
+{
+ LogPrintf(fp->LogLevel, "SendConfigNak(%s)\n", StateNames[fp->state]);
+ (fp->DecodeConfig) (option, count, MODE_NOP);
+ FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
+}
+
+/*
+ * Timeout actions
+ */
+static void
+FsmTimeout(void *v)
+{
+ struct fsm *fp = (struct fsm *)v;
+
+ if (fp->restart) {
+ switch (fp->state) {
+ case ST_CLOSING:
+ case ST_STOPPING:
+ FsmSendTerminateReq(fp);
+ break;
+ case ST_REQSENT:
+ case ST_ACKSENT:
+ FsmSendConfigReq(fp);
+ break;
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ StartTimer(&fp->FsmTimer);
+ } else {
+ switch (fp->state) {
+ case ST_CLOSING:
+ NewState(fp, ST_CLOSED);
+ (fp->LayerFinish) (fp);
+ break;
+ case ST_STOPPING:
+ NewState(fp, ST_STOPPED);
+ (fp->LayerFinish) (fp);
+ break;
+ case ST_REQSENT: /* XXX: 3p */
+ case ST_ACKSENT:
+ case ST_ACKRCVD:
+ NewState(fp, ST_STOPPED);
+ (fp->LayerFinish) (fp);
+ break;
+ }
+ }
+}
+
+static void
+FsmInitRestartCounter(struct fsm * fp)
+{
+ StopTimer(&fp->FsmTimer);
+ fp->FsmTimer.state = TIMER_STOPPED;
+ fp->FsmTimer.func = FsmTimeout;
+ fp->FsmTimer.arg = (void *) fp;
+ (fp->InitRestartCounter) (fp);
+}
+
+/*
+ * Actions when receive packets
+ */
+static void
+FsmRecvConfigReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+/* RCR */
+{
+ int plen, flen;
+ int ackaction = 0;
+
+ plen = plength(bp);
+ flen = ntohs(lhp->length) - sizeof(*lhp);
+ if (plen < flen) {
+ LogPrintf(LogERROR, "FsmRecvConfigReq: plen (%d) < flen (%d)\n",
+ plen, flen);
+ pfree(bp);
+ return;
+ }
+
+ /*
+ * Check and process easy case
+ */
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(fp->LogLevel, "Oops, RCR in %s.\n", StateNames[fp->state]);
+ pfree(bp);
+ return;
+ case ST_CLOSED:
+ (fp->SendTerminateAck) (fp);
+ pfree(bp);
+ return;
+ case ST_CLOSING:
+ LogPrintf(LogERROR, "Got ConfigReq while state = %d\n", fp->state);
+ case ST_STOPPING:
+ pfree(bp);
+ return;
+ }
+
+ (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_REQ);
+
+ if (nakp == NakBuff && rejp == RejBuff)
+ ackaction = 1;
+
+ switch (fp->state) {
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ FsmSendConfigReq(fp);
+ break;
+ case ST_STOPPED:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ break;
+ }
+
+ if (rejp != RejBuff)
+ FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff);
+ if (nakp != NakBuff)
+ FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff);
+ if (ackaction)
+ FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff);
+
+ switch (fp->state) {
+ case ST_STOPPED:
+ case ST_OPENED:
+ if (ackaction)
+ NewState(fp, ST_ACKSENT);
+ else
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_REQSENT:
+ if (ackaction)
+ NewState(fp, ST_ACKSENT);
+ break;
+ case ST_ACKRCVD:
+ if (ackaction) {
+ NewState(fp, ST_OPENED);
+ (fp->LayerUp) (fp);
+ }
+ break;
+ case ST_ACKSENT:
+ if (!ackaction)
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+static void
+FsmRecvConfigAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+/* RCA */
+{
+ switch (fp->state) {
+ case ST_CLOSED:
+ case ST_STOPPED:
+ (fp->SendTerminateAck) (fp);
+ break;
+ case ST_CLOSING:
+ case ST_STOPPING:
+ break;
+ case ST_REQSENT:
+ FsmInitRestartCounter(fp);
+ NewState(fp, ST_ACKRCVD);
+ break;
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ NewState(fp, ST_OPENED);
+ (fp->LayerUp) (fp);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+static void
+FsmRecvConfigNak(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+/* RCN */
+{
+ int plen, flen;
+
+ plen = plength(bp);
+ flen = ntohs(lhp->length) - sizeof(*lhp);
+ if (plen < flen) {
+ pfree(bp);
+ return;
+ }
+
+ /*
+ * Check and process easy case
+ */
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(fp->LogLevel, "Oops, RCN in %s.\n", StateNames[fp->state]);
+ pfree(bp);
+ return;
+ case ST_CLOSED:
+ case ST_STOPPED:
+ (fp->SendTerminateAck) (fp);
+ pfree(bp);
+ return;
+ case ST_CLOSING:
+ case ST_STOPPING:
+ pfree(bp);
+ return;
+ }
+
+ (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_NAK);
+
+ switch (fp->state) {
+ case ST_REQSENT:
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ /* Fall down */
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+
+ pfree(bp);
+}
+
+static void
+FsmRecvTermReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+/* RTR */
+{
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(fp->LogLevel, "Oops, RTR in %s\n", StateNames[fp->state]);
+ break;
+ case ST_CLOSED:
+ case ST_STOPPED:
+ case ST_CLOSING:
+ case ST_STOPPING:
+ case ST_REQSENT:
+ (fp->SendTerminateAck) (fp);
+ break;
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ (fp->SendTerminateAck) (fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ (fp->SendTerminateAck) (fp);
+ StartTimer(&fp->FsmTimer); /* Start restart timer */
+ fp->restart = 0;
+ NewState(fp, ST_STOPPING);
+ break;
+ }
+ pfree(bp);
+}
+
+static void
+FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+/* RTA */
+{
+ switch (fp->state) {
+ case ST_CLOSING:
+ NewState(fp, ST_CLOSED);
+ (fp->LayerFinish) (fp);
+ break;
+ case ST_STOPPING:
+ NewState(fp, ST_STOPPED);
+ (fp->LayerFinish) (fp);
+ break;
+ case ST_ACKRCVD:
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+static void
+FsmRecvConfigRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+/* RCJ */
+{
+ int plen, flen;
+
+ plen = plength(bp);
+ flen = ntohs(lhp->length) - sizeof(*lhp);
+ if (plen < flen) {
+ pfree(bp);
+ return;
+ }
+ LogPrintf(fp->LogLevel, "RecvConfigRej.\n");
+
+ /*
+ * Check and process easy case
+ */
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(fp->LogLevel, "Oops, RCJ in %s.\n", StateNames[fp->state]);
+ pfree(bp);
+ return;
+ case ST_CLOSED:
+ case ST_STOPPED:
+ (fp->SendTerminateAck) (fp);
+ pfree(bp);
+ return;
+ case ST_CLOSING:
+ case ST_STOPPING:
+ pfree(bp);
+ return;
+ }
+
+ (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_REJ);
+
+ switch (fp->state) {
+ case ST_REQSENT:
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown) (fp);
+ /* Fall down */
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+static void
+FsmRecvCodeRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ LogPrintf(fp->LogLevel, "RecvCodeRej\n");
+ pfree(bp);
+}
+
+static void
+FsmRecvProtoRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ u_short *sp, proto;
+
+ sp = (u_short *) MBUF_CTOP(bp);
+ proto = ntohs(*sp);
+ LogPrintf(fp->LogLevel, "-- Protocol (%04x) was rejected.\n", proto);
+
+ switch (proto) {
+ case PROTO_LQR:
+ StopLqr(LQM_LQR);
+ break;
+ case PROTO_CCP:
+ fp = &CcpFsm;
+ (fp->LayerFinish) (fp);
+ switch (fp->state) {
+ case ST_CLOSED:
+ case ST_CLOSING:
+ NewState(fp, ST_CLOSED);
+ default:
+ NewState(fp, ST_STOPPED);
+ break;
+ }
+ break;
+ }
+ pfree(bp);
+}
+
+static void
+FsmRecvEchoReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ u_char *cp;
+ u_long *lp, magic;
+
+ cp = MBUF_CTOP(bp);
+ lp = (u_long *) cp;
+ magic = ntohl(*lp);
+ if (magic != LcpInfo.his_magic) {
+ LogPrintf(LogERROR, "RecvEchoReq: his magic is bad!!\n");
+ /* XXX: We should send terminate request */
+ }
+ if (fp->state == ST_OPENED) {
+ *lp = htonl(LcpInfo.want_magic); /* Insert local magic number */
+ LogPrintf(fp->LogLevel, "SendEchoRep(%s)\n", StateNames[fp->state]);
+ FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp));
+ }
+ pfree(bp);
+}
+
+static void
+FsmRecvEchoRep(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ u_long *lp, magic;
+
+ lp = (u_long *) MBUF_CTOP(bp);
+ magic = ntohl(*lp);
+/*
+ * Tolerate echo replies with either magic number
+ */
+ if (magic != 0 && magic != LcpInfo.his_magic && magic != LcpInfo.want_magic) {
+ LogPrintf(LogERROR, "RecvEchoRep: his magic is wrong! expect: %x got: %x\n",
+ LcpInfo.his_magic, magic);
+
+ /*
+ * XXX: We should send terminate request. But poor implementation may die
+ * as a result.
+ */
+ }
+ RecvEchoLqr(bp);
+ pfree(bp);
+}
+
+static void
+FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ LogPrintf(fp->LogLevel, "RecvDiscReq\n");
+ pfree(bp);
+}
+
+static void
+FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ LogPrintf(fp->LogLevel, "RecvIdent\n");
+ pfree(bp);
+}
+
+static void
+FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ LogPrintf(fp->LogLevel, "RecvTimeRemain\n");
+ pfree(bp);
+}
+
+static void
+FsmRecvResetReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ LogPrintf(fp->LogLevel, "RecvResetReq\n");
+ CcpRecvResetReq(fp);
+ LogPrintf(fp->LogLevel, "SendResetAck\n");
+ FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0);
+ pfree(bp);
+}
+
+static void
+FsmRecvResetAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
+{
+ LogPrintf(fp->LogLevel, "RecvResetAck\n");
+ Pred1Init(1); /* Initialize Input part */
+ fp->reqid++;
+ pfree(bp);
+}
+
+struct fsmcodedesc FsmCodes[] = {
+ {FsmRecvConfigReq, "Configure Request",},
+ {FsmRecvConfigAck, "Configure Ack",},
+ {FsmRecvConfigNak, "Configure Nak",},
+ {FsmRecvConfigRej, "Configure Reject",},
+ {FsmRecvTermReq, "Terminate Request",},
+ {FsmRecvTermAck, "Terminate Ack",},
+ {FsmRecvCodeRej, "Code Reject",},
+ {FsmRecvProtoRej, "Protocol Reject",},
+ {FsmRecvEchoReq, "Echo Request",},
+ {FsmRecvEchoRep, "Echo Reply",},
+ {FsmRecvDiscReq, "Discard Request",},
+ {FsmRecvIdent, "Ident",},
+ {FsmRecvTimeRemain, "Time Remain",},
+ {FsmRecvResetReq, "Reset Request",},
+ {FsmRecvResetAck, "Reset Ack",},
+};
+
+void
+FsmInput(struct fsm * fp, struct mbuf * bp)
+{
+ int len;
+ struct fsmheader *lhp;
+ struct fsmcodedesc *codep;
+
+ len = plength(bp);
+ if (len < sizeof(struct fsmheader)) {
+ pfree(bp);
+ return;
+ }
+ lhp = (struct fsmheader *) MBUF_CTOP(bp);
+ if (lhp->code == 0 || lhp->code > fp->max_code) {
+ pfree(bp); /* XXX: Should send code reject */
+ return;
+ }
+ bp->offset += sizeof(struct fsmheader);
+ bp->cnt -= sizeof(struct fsmheader);
+
+ codep = FsmCodes + lhp->code - 1;
+ LogPrintf(fp->LogLevel, "Received %s (%d) state = %s (%d)\n",
+ codep->name, lhp->id, StateNames[fp->state], fp->state);
+ if (LogIsKept(LogDEBUG))
+ LogMemory();
+ (codep->action) (fp, lhp, bp);
+ if (LogIsKept(LogDEBUG))
+ LogMemory();
+}
diff --git a/usr.sbin/ppp/fsm.h b/usr.sbin/ppp/fsm.h
new file mode 100644
index 00000000000..e2f95d44fde
--- /dev/null
+++ b/usr.sbin/ppp/fsm.h
@@ -0,0 +1,132 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: fsm.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+/*
+ * State of machine
+ */
+#define ST_INITIAL 0
+#define ST_STARTING 1
+#define ST_CLOSED 2
+#define ST_STOPPED 3
+#define ST_CLOSING 4
+#define ST_STOPPING 5
+#define ST_REQSENT 6
+#define ST_ACKRCVD 7
+#define ST_ACKSENT 8
+#define ST_OPENED 9
+
+#define ST_MAX 10
+#define ST_UNDEF -1
+
+#define MODE_REQ 0
+#define MODE_NAK 1
+#define MODE_REJ 2
+#define MODE_NOP 3
+
+#define OPEN_ACTIVE 0
+#define OPEN_PASSIVE 1
+
+struct fsm {
+ const char *name; /* Name of protocol */
+ u_short proto; /* Protocol number */
+ u_short max_code;
+ int open_mode;
+ int state; /* State of the machine */
+ int reqid; /* Next request id */
+ int restart; /* Restart counter value */
+ int maxconfig;
+
+ int reqcode; /* Request code sent */
+ struct pppTimer FsmTimer; /* Restart Timer */
+
+ /*
+ * This timer times the ST_STOPPED state out after the given value
+ * (specified via "set stopped ..."). Although this isn't specified in the
+ * rfc, the rfc *does* say that "the application may use higher level
+ * timers to avoid deadlock". The StoppedTimer takes effect when the other
+ * side ABENDs rather than going into ST_ACKSENT (and sending the ACK),
+ * causing ppp to time out and drop into ST_STOPPED. At this point,
+ * nothing will change this state :-(
+ */
+ struct pppTimer StoppedTimer;
+ int LogLevel;
+
+ void (*LayerUp) (struct fsm *);
+ void (*LayerDown) (struct fsm *);
+ void (*LayerStart) (struct fsm *);
+ void (*LayerFinish) (struct fsm *);
+ void (*InitRestartCounter) (struct fsm *);
+ void (*SendConfigReq) (struct fsm *);
+ void (*SendTerminateReq) (struct fsm *);
+ void (*SendTerminateAck) (struct fsm *);
+ void (*DecodeConfig) (u_char *, int, int);
+};
+
+struct fsmheader {
+ u_char code; /* Request code */
+ u_char id; /* Identification */
+ u_short length; /* Length of packet */
+};
+
+#define CODE_CONFIGREQ 1
+#define CODE_CONFIGACK 2
+#define CODE_CONFIGNAK 3
+#define CODE_CONFIGREJ 4
+#define CODE_TERMREQ 5
+#define CODE_TERMACK 6
+#define CODE_CODEREJ 7
+#define CODE_PROTOREJ 8
+#define CODE_ECHOREQ 9 /* Used in LCP */
+#define CODE_ECHOREP 10 /* Used in LCP */
+#define CODE_DISCREQ 11
+#define CODE_IDENT 12 /* Used in LCP Extension */
+#define CODE_TIMEREM 13 /* Used in LCP Extension */
+#define CODE_RESETREQ 14 /* Used in CCP */
+#define CODE_RESETACK 15 /* Used in CCP */
+
+struct fsmcodedesc {
+ void (*action) (struct fsm *, struct fsmheader *, struct mbuf *);
+ const char *name;
+};
+
+struct fsmconfig {
+ u_char type;
+ u_char length;
+};
+
+extern u_char AckBuff[200];
+extern u_char NakBuff[200];
+extern u_char RejBuff[100];
+extern u_char ReqBuff[200];
+extern u_char *ackp;
+extern u_char *nakp;
+extern u_char *rejp;
+
+extern char const *StateNames[];
+
+extern void FsmInit(struct fsm *);
+extern void FsmOutput(struct fsm *, u_int, u_int, u_char *, int);
+extern void FsmOpen(struct fsm *);
+extern void FsmUp(struct fsm *);
+extern void FsmDown(struct fsm *);
+extern void FsmInput(struct fsm *, struct mbuf *);
+extern void FsmClose(struct fsm *);
diff --git a/usr.sbin/ppp/hdlc.c b/usr.sbin/ppp/hdlc.c
new file mode 100644
index 00000000000..1feff8d3d86
--- /dev/null
+++ b/usr.sbin/ppp/hdlc.c
@@ -0,0 +1,423 @@
+/*
+ * PPP High Level Link Control (HDLC) Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: hdlc.c,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "hdlc.h"
+#include "lcpproto.h"
+#include "ipcp.h"
+#include "ip.h"
+#include "vjcomp.h"
+#include "pap.h"
+#include "chap.h"
+#include "lcp.h"
+#include "async.h"
+#include "lqr.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "pred.h"
+#include "modem.h"
+#include "ccp.h"
+
+struct hdlcstat {
+ int badfcs;
+ int badaddr;
+ int badcommand;
+ int unknownproto;
+} HdlcStat;
+
+static int ifOutPackets;
+static int ifOutOctets;
+static int ifOutLQRs;
+static int ifInPackets;
+static int ifInOctets;
+
+struct protostat {
+ u_short number;
+ const char *name;
+ u_long in_count;
+ u_long out_count;
+} ProtocolStat[] = {
+
+ { PROTO_IP, "IP" },
+ { PROTO_VJUNCOMP, "VJ_UNCOMP" },
+ { PROTO_VJCOMP, "VJ_COMP" },
+ { PROTO_COMPD, "COMPD" },
+ { PROTO_LCP, "LCP" },
+ { PROTO_IPCP, "IPCP" },
+ { PROTO_CCP, "CCP" },
+ { PROTO_PAP, "PAP" },
+ { PROTO_LQR, "LQR" },
+ { PROTO_CHAP, "CHAP" },
+ { 0, "Others" }
+};
+
+static u_short const fcstab[256] = {
+ /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ /* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ /* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ /* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ /* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ /* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ /* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ /* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ /* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ /* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ /* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ /* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ /* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ /* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ /* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ /* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ /* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ /* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ /* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ /* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ /* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ /* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ /* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ /* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ /* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ /* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ /* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ /* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ /* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ /* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ /* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+u_char EscMap[33];
+
+void
+HdlcInit()
+{
+ ifInOctets = ifOutOctets = 0;
+ ifInPackets = ifOutPackets = 0;
+ ifOutLQRs = 0;
+}
+
+/*
+ * HDLC FCS computation. Read RFC 1171 Appendix B and CCITT X.25 section
+ * 2.27 for further details.
+ */
+inline u_short
+HdlcFcs(u_short fcs, u_char * cp, int len)
+{
+ while (len--)
+ fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+ return (fcs);
+}
+
+void
+HdlcOutput(int pri, u_short proto, struct mbuf * bp)
+{
+ struct mbuf *mhp, *mfcs;
+ struct protostat *statp;
+ struct lqrdata *lqr;
+ u_char *cp;
+ u_short fcs;
+
+ if ((proto & 0xfff1) == 0x21) { /* Network Layer protocol */
+ if (CcpFsm.state == ST_OPENED) {
+ if (CcpInfo.want_proto == TY_PRED1) {
+ Pred1Output(pri, proto, bp);
+ return;
+ }
+ }
+ }
+ if (DEV_IS_SYNC)
+ mfcs = NULLBUFF;
+ else
+ mfcs = mballoc(2, MB_HDLCOUT);
+ mhp = mballoc(4, MB_HDLCOUT);
+ mhp->cnt = 0;
+ cp = MBUF_CTOP(mhp);
+ if (proto == PROTO_LCP || LcpInfo.his_acfcomp == 0) {
+ *cp++ = HDLC_ADDR;
+ *cp++ = HDLC_UI;
+ mhp->cnt += 2;
+ }
+
+ /*
+ * If possible, compress protocol field.
+ */
+ if (LcpInfo.his_protocomp && (proto & 0xff00) == 0) {
+ *cp++ = proto;
+ mhp->cnt++;
+ } else {
+ *cp++ = proto >> 8;
+ *cp = proto & 0377;
+ mhp->cnt += 2;
+ }
+ mhp->next = bp;
+ bp->next = mfcs;
+
+ lqr = &MyLqrData;
+ lqr->PeerOutPackets = ifOutPackets++;
+ ifOutOctets += plength(mhp) + 1;
+ lqr->PeerOutOctets = ifOutOctets;
+
+ if (proto == PROTO_LQR) {
+ lqr->MagicNumber = LcpInfo.want_magic;
+ lqr->LastOutLQRs = HisLqrData.PeerOutLQRs;
+ lqr->LastOutPackets = HisLqrData.PeerOutPackets;
+ lqr->LastOutOctets = HisLqrData.PeerOutOctets;
+ lqr->PeerInLQRs = HisLqrSave.SaveInLQRs;
+ lqr->PeerInPackets = HisLqrSave.SaveInPackets;
+ lqr->PeerInDiscards = HisLqrSave.SaveInDiscards;
+ lqr->PeerInErrors = HisLqrSave.SaveInErrors;
+ lqr->PeerInOctets = HisLqrSave.SaveInOctets;
+ lqr->PeerOutLQRs = ++ifOutLQRs;
+ LqrDump("LqrOutput", lqr);
+ LqrChangeOrder(lqr, (struct lqrdata *) (MBUF_CTOP(bp)));
+ }
+ if (!DEV_IS_SYNC) {
+ fcs = HdlcFcs(INITFCS, MBUF_CTOP(mhp), mhp->cnt);
+ fcs = HdlcFcs(fcs, MBUF_CTOP(bp), bp->cnt);
+ fcs = ~fcs;
+ cp = MBUF_CTOP(mfcs);
+ *cp++ = fcs & 0377; /* Low byte first!! */
+ *cp++ = fcs >> 8;
+ }
+ LogDumpBp(LogHDLC, "HdlcOutput", mhp);
+ for (statp = ProtocolStat; statp->number; statp++)
+ if (statp->number == proto)
+ break;
+ statp->out_count++;
+ if (DEV_IS_SYNC)
+ ModemOutput(pri, mhp);
+ else
+ AsyncOutput(pri, mhp, proto);
+}
+
+void
+DecodePacket(u_short proto, struct mbuf * bp)
+{
+ u_char *cp;
+
+ LogPrintf(LogDEBUG, "DecodePacket: proto = %04x\n", proto);
+
+ switch (proto) {
+ case PROTO_LCP:
+ LcpInput(bp);
+ break;
+ case PROTO_PAP:
+ PapInput(bp);
+ break;
+ case PROTO_LQR:
+ HisLqrSave.SaveInLQRs++;
+ LqrInput(bp);
+ break;
+ case PROTO_CHAP:
+ ChapInput(bp);
+ break;
+ case PROTO_VJUNCOMP:
+ case PROTO_VJCOMP:
+ bp = VjCompInput(bp, proto);
+ if (bp == NULLBUFF) {
+ break;
+ }
+ /* fall down */
+ case PROTO_IP:
+ IpInput(bp);
+ break;
+ case PROTO_IPCP:
+ IpcpInput(bp);
+ break;
+ case PROTO_CCP:
+ CcpInput(bp);
+ break;
+ case PROTO_COMPD:
+ Pred1Input(bp);
+ break;
+ default:
+ LogPrintf(LogPHASE, "Unknown protocol 0x%04x\n", proto);
+ bp->offset -= 2;
+ bp->cnt += 2;
+ cp = MBUF_CTOP(bp);
+ LcpSendProtoRej(cp, bp->cnt);
+ HisLqrSave.SaveInDiscards++;
+ HdlcStat.unknownproto++;
+ pfree(bp);
+ break;
+ }
+}
+
+int
+ReportProtStatus(struct cmdargs const *arg)
+{
+ struct protostat *statp;
+ int cnt;
+
+ statp = ProtocolStat;
+ statp--;
+ cnt = 0;
+ fprintf(VarTerm, " Protocol in out Protocol in out\n");
+ do {
+ statp++;
+ fprintf(VarTerm, " %-9s: %8lu, %8lu",
+ statp->name, statp->in_count, statp->out_count);
+ if (++cnt == 2) {
+ fprintf(VarTerm, "\n");
+ cnt = 0;
+ }
+ } while (statp->number);
+ if (cnt)
+ fprintf(VarTerm, "\n");
+ return (1);
+}
+
+int
+ReportHdlcStatus(struct cmdargs const *arg)
+{
+ struct hdlcstat *hp = &HdlcStat;
+
+ if (VarTerm) {
+ fprintf(VarTerm, "HDLC level errors\n\n");
+ fprintf(VarTerm, "FCS: %u ADDR: %u COMMAND: %u PROTO: %u\n",
+ hp->badfcs, hp->badaddr, hp->badcommand, hp->unknownproto);
+ }
+ return 0;
+}
+
+static struct hdlcstat laststat;
+
+void
+HdlcErrorCheck()
+{
+ struct hdlcstat *hp = &HdlcStat;
+ struct hdlcstat *op = &laststat;
+
+ if (memcmp(hp, op, sizeof(laststat))) {
+ LogPrintf(LogPHASE, "HDLC errors -> FCS: %u ADDR: %u COMD: %u PROTO: %u\n",
+ hp->badfcs - op->badfcs, hp->badaddr - op->badaddr,
+ hp->badcommand - op->badcommand, hp->unknownproto - op->unknownproto);
+ }
+ laststat = HdlcStat;
+}
+
+void
+HdlcInput(struct mbuf * bp)
+{
+ u_short fcs, proto;
+ u_char *cp, addr, ctrl;
+ struct protostat *statp;
+
+ LogDumpBp(LogHDLC, "HdlcInput:", bp);
+ if (DEV_IS_SYNC)
+ fcs = GOODFCS;
+ else
+ fcs = HdlcFcs(INITFCS, MBUF_CTOP(bp), bp->cnt);
+ HisLqrSave.SaveInOctets += bp->cnt + 1;
+
+ LogPrintf(LogDEBUG, "HdlcInput: fcs = %04x (%s)\n",
+ fcs, (fcs == GOODFCS) ? "good" : "bad");
+ if (fcs != GOODFCS) {
+ HisLqrSave.SaveInErrors++;
+ LogPrintf(LogDEBUG, "HdlcInput: Bad FCS\n");
+ HdlcStat.badfcs++;
+ pfree(bp);
+ return;
+ }
+ if (!DEV_IS_SYNC)
+ bp->cnt -= 2; /* discard FCS part */
+
+ if (bp->cnt < 2) { /* XXX: raise this bar ? */
+ pfree(bp);
+ return;
+ }
+ cp = MBUF_CTOP(bp);
+
+ ifInPackets++;
+ ifInOctets += bp->cnt;
+
+ if (!LcpInfo.want_acfcomp) {
+
+ /*
+ * We expect that packet is not compressed.
+ */
+ addr = *cp++;
+ if (addr != HDLC_ADDR) {
+ HisLqrSave.SaveInErrors++;
+ HdlcStat.badaddr++;
+ LogPrintf(LogDEBUG, "HdlcInput: addr %02x\n", *cp);
+ pfree(bp);
+ return;
+ }
+ ctrl = *cp++;
+ if (ctrl != HDLC_UI) {
+ HisLqrSave.SaveInErrors++;
+ HdlcStat.badcommand++;
+ LogPrintf(LogDEBUG, "HdlcInput: %02x\n", *cp);
+ pfree(bp);
+ return;
+ }
+ bp->offset += 2;
+ bp->cnt -= 2;
+ } else if (cp[0] == HDLC_ADDR && cp[1] == HDLC_UI) {
+
+ /*
+ * We can receive compressed packet, but peer still send uncompressed
+ * packet to me.
+ */
+ cp += 2;
+ bp->offset += 2;
+ bp->cnt -= 2;
+ }
+ if (LcpInfo.want_protocomp) {
+ proto = 0;
+ cp--;
+ do {
+ cp++;
+ bp->offset++;
+ bp->cnt--;
+ proto = proto << 8;
+ proto += *cp;
+ } while (!(proto & 1));
+ } else {
+ proto = *cp++ << 8;
+ proto |= *cp++;
+ bp->offset += 2;
+ bp->cnt -= 2;
+ }
+
+ for (statp = ProtocolStat; statp->number; statp++)
+ if (statp->number == proto)
+ break;
+ statp->in_count++;
+ HisLqrSave.SaveInPackets++;
+
+ DecodePacket(proto, bp);
+}
diff --git a/usr.sbin/ppp/hdlc.h b/usr.sbin/ppp/hdlc.h
new file mode 100644
index 00000000000..7e2f900883e
--- /dev/null
+++ b/usr.sbin/ppp/hdlc.h
@@ -0,0 +1,67 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: hdlc.h,v 1.1 1997/11/23 20:27:33 brian Exp $
+ *
+ * TODO:
+ */
+
+/*
+ * Definition for Async HDLC
+ */
+#define HDLC_SYN 0x7e /* SYNC character */
+#define HDLC_ESC 0x7d /* Escape character */
+#define HDLC_XOR 0x20 /* Modifier value */
+
+#define HDLC_ADDR 0xff
+#define HDLC_UI 0x03
+/*
+ * Definition for HDLC Frame Check Sequence
+ */
+#define INITFCS 0xffff /* Initial value for FCS computation */
+#define GOODFCS 0xf0b8 /* Good FCS value */
+
+#define DEF_MRU 1500
+#define MAX_MRU 2048
+#define MIN_MRU 296
+
+#define DEF_MTU 0 /* whatever peer says */
+#define MAX_MTU 2048
+#define MIN_MTU 296
+
+/*
+ * Output priority
+ */
+/* PRI_NORMAL and PRI_FAST have meaning only on the IP queue.
+ * All IP frames have the same priority once they are compressed.
+ * IP frames stay on the IP queue till they can be sent on the
+ * link. They are compressed at that time.
+*/
+#define PRI_NORMAL 0 /* Normal priority */
+#define PRI_FAST 1 /* Fast (interractive) */
+#define PRI_LINK 1 /* Urgent (LQR packets) */
+
+extern u_char EscMap[33];
+
+extern void HdlcInit(void);
+extern void HdlcErrorCheck(void);
+extern void HdlcInput(struct mbuf *);
+extern void HdlcOutput(int, u_short, struct mbuf *bp);
+extern u_short HdlcFcs(u_short, u_char *, int);
+extern void DecodePacket(u_short, struct mbuf *);
+extern int ReportHdlcStatus(struct cmdargs const *);
+extern int ReportProtStatus(struct cmdargs const *);
diff --git a/usr.sbin/ppp/id.c b/usr.sbin/ppp/id.c
new file mode 100644
index 00000000000..e9ce99a602f
--- /dev/null
+++ b/usr.sbin/ppp/id.c
@@ -0,0 +1,146 @@
+/*
+ * $Id: id.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "main.h"
+#ifdef __OpenBSD__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include "id.h"
+
+static int uid;
+static int gid;
+static int euid;
+static int egid;
+
+void
+ID0init()
+{
+ uid = getuid();
+ gid = getgid();
+ euid = geteuid();
+ egid = getegid();
+}
+
+static void
+ID0setuser(void)
+{
+ if (seteuid(uid) == -1) {
+ LogPrintf(LogERROR, "ID0setuser: Unable to seteuid!\n");
+ Cleanup(EX_NOPERM);
+ }
+}
+
+uid_t
+ID0realuid()
+{
+ return uid;
+}
+
+static void
+ID0set0(void)
+{
+ if (seteuid(euid) == -1) {
+ LogPrintf(LogERROR, "ID0set0: Unable to seteuid!\n");
+ Cleanup(EX_NOPERM);
+ }
+}
+
+int
+ID0ioctl(int fd, unsigned long req, void *arg)
+{
+ int ret;
+
+ ID0set0();
+ ret = ioctl(fd, req, arg);
+ LogPrintf(LogID0, "%d = ioctl(%d, %d, %p)\n", ret, fd, req, arg);
+ ID0setuser();
+ return ret;
+}
+
+int
+ID0unlink(const char *name)
+{
+ int ret;
+
+ ID0set0();
+ ret = unlink(name);
+ LogPrintf(LogID0, "%d = unlink(\"%s\")\n", ret, name);
+ ID0setuser();
+ return ret;
+}
+
+int
+ID0socket(int domain, int type, int protocol)
+{
+ int ret;
+
+ ID0set0();
+ ret = socket(domain, type, protocol);
+ LogPrintf(LogID0, "%d = socket(%d, %d, %d)\n", ret, domain, type, protocol);
+ ID0setuser();
+ return ret;
+}
+
+FILE *
+ID0fopen(const char *path, const char *mode)
+{
+ FILE *ret;
+
+ ID0set0();
+ ret = fopen(path, mode);
+ LogPrintf(LogID0, "%p = fopen(\"%s\", \"%s\")\n", ret, path, mode);
+ ID0setuser();
+ return ret;
+}
+
+int
+ID0open(const char *path, int flags)
+{
+ int ret;
+
+ ID0set0();
+ ret = open(path, flags);
+ LogPrintf(LogID0, "%d = open(\"%s\", %d)\n", ret, path, flags);
+ ID0setuser();
+ return ret;
+}
+
+int
+ID0uu_lock(const char *basettyname)
+{
+ int ret;
+
+ ID0set0();
+ ret = uu_lock(basettyname);
+ LogPrintf(LogID0, "%d = uu_lock(\"%s\")\n", ret, basettyname);
+ ID0setuser();
+ return ret;
+}
+
+int
+ID0uu_unlock(const char *basettyname)
+{
+ int ret;
+
+ ID0set0();
+ ret = uu_unlock(basettyname);
+ LogPrintf(LogID0, "%d = uu_unlock(\"%s\")\n", ret, basettyname);
+ ID0setuser();
+ return ret;
+}
diff --git a/usr.sbin/ppp/id.h b/usr.sbin/ppp/id.h
new file mode 100644
index 00000000000..45049873e4d
--- /dev/null
+++ b/usr.sbin/ppp/id.h
@@ -0,0 +1,13 @@
+/*
+ * $Id: id.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ */
+
+extern void ID0init(void);
+extern uid_t ID0realuid(void);
+extern int ID0ioctl(int, unsigned long, void *);
+extern int ID0unlink(const char *);
+extern int ID0socket(int, int, int);
+extern FILE *ID0fopen(const char *, const char *);
+extern int ID0open(const char *, int);
+extern int ID0uu_lock(const char *);
+extern int ID0uu_unlock(const char *);
diff --git a/usr.sbin/ppp/ip.c b/usr.sbin/ppp/ip.c
new file mode 100644
index 00000000000..4120503042e
--- /dev/null
+++ b/usr.sbin/ppp/ip.c
@@ -0,0 +1,522 @@
+/*
+ * PPP IP Protocol Interface
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ip.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ * o Return ICMP message for filterd packet
+ * and optionaly record it into log.
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#ifdef __FreeBSD__
+#include <net/if_var.h>
+#endif
+#include <net/if_tun.h>
+
+#ifndef NOALIAS
+#include <alias.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcpproto.h"
+#include "hdlc.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "filter.h"
+#include "os.h"
+#include "ipcp.h"
+#include "vjcomp.h"
+#include "lcp.h"
+#include "modem.h"
+#include "tun.h"
+#include "ip.h"
+
+static struct pppTimer IdleTimer;
+
+static void
+IdleTimeout(void *v)
+{
+ LogPrintf(LogPHASE, "Idle timer expired.\n");
+ reconnect(RECON_FALSE);
+ LcpClose();
+}
+
+/*
+ * Start Idle timer. If timeout is reached, we call LcpClose() to
+ * close LCP and link.
+ */
+void
+StartIdleTimer()
+{
+ if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
+ StopTimer(&IdleTimer);
+ IdleTimer.func = IdleTimeout;
+ IdleTimer.load = VarIdleTimeout * SECTICKS;
+ IdleTimer.state = TIMER_STOPPED;
+ StartTimer(&IdleTimer);
+ }
+}
+
+void
+UpdateIdleTimer()
+{
+ if (OsLinkIsUp())
+ StartIdleTimer();
+}
+
+void
+StopIdleTimer()
+{
+ StopTimer(&IdleTimer);
+}
+
+/*
+ * If any IP layer traffic is detected, refresh IdleTimer.
+ */
+static void
+RestartIdleTimer(void)
+{
+ if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
+ StartTimer(&IdleTimer);
+ ipIdleSecs = 0;
+ }
+}
+
+static const u_short interactive_ports[32] = {
+ 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
+};
+
+#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p))
+
+static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
+
+static const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
+static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
+
+static int
+PortMatch(int op, u_short pport, u_short rport)
+{
+ switch (op) {
+ case OP_EQ:
+ return (pport == rport);
+ case OP_GT:
+ return (pport > rport);
+ case OP_LT:
+ return (pport < rport);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * Check a packet against with defined filters
+ */
+static int
+FilterCheck(struct ip * pip, int direction)
+{
+ struct filterent *fp = Filters[direction];
+ int gotinfo, cproto, estab, n;
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct icmp *ih;
+ char *ptop;
+ u_short sport, dport;
+
+ if (fp->action) {
+ cproto = gotinfo = estab = 0;
+ sport = dport = 0;
+ for (n = 0; n < MAXFILTERS; n++) {
+ if (fp->action) {
+ /* permit fragments on in and out filter */
+ if ((direction == FL_IN || direction == FL_OUT) &&
+ (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
+ return (A_PERMIT);
+ }
+ LogPrintf(LogDEBUG, "rule = %d\n", n);
+ if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
+ (fp->saddr.s_addr & fp->smask.s_addr) &&
+ (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
+ (fp->daddr.s_addr & fp->dmask.s_addr)) {
+ if (fp->proto) {
+ if (!gotinfo) {
+ ptop = (char *) pip + (pip->ip_hl << 2);
+
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ cproto = P_ICMP;
+ ih = (struct icmp *) ptop;
+ sport = ih->icmp_type;
+ estab = 1;
+ break;
+ case IPPROTO_UDP:
+ cproto = P_UDP;
+ uh = (struct udphdr *) ptop;
+ sport = ntohs(uh->uh_sport);
+ dport = ntohs(uh->uh_dport);
+ estab = 1;
+ break;
+ case IPPROTO_TCP:
+ cproto = P_TCP;
+ th = (struct tcphdr *) ptop;
+ sport = ntohs(th->th_sport);
+ dport = ntohs(th->th_dport);
+ estab = (th->th_flags & TH_ACK);
+ if (estab == 0)
+ LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
+ th->th_flags, sport, dport);
+ break;
+ default:
+ return (A_DENY);/* We'll block unknown type of packet */
+ }
+ gotinfo = 1;
+ LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
+ " dstop = %d, estab = %d\n", direction, cproto,
+ fp->opt.srcop, fp->opt.dstop, estab);
+ }
+ LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
+ " dport = %d\n", n, cproto, sport, dport);
+ LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
+
+ if (cproto == fp->proto) {
+ if ((fp->opt.srcop == OP_NONE ||
+ PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
+ &&
+ (fp->opt.dstop == OP_NONE ||
+ PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
+ &&
+ (fp->opt.estab == 0 || estab)) {
+ return (fp->action);
+ }
+ }
+ } else {
+ /* Address is mached. Make a decision. */
+ LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
+ return (fp->action);
+ }
+ }
+ }
+ fp++;
+ }
+ return (A_DENY); /* No rule is mached. Deny this packet */
+ }
+ return (A_PERMIT); /* No rule is given. Permit this packet */
+}
+
+static void
+IcmpError(struct ip * pip, int code)
+{
+#ifdef notdef
+ struct mbuf *bp;
+
+ if (pip->ip_p != IPPROTO_ICMP) {
+ bp = mballoc(cnt, MB_IPIN);
+ memcpy(MBUF_CTOP(bp), ptr, cnt);
+ SendPppFrame(bp);
+ RestartIdleTimer();
+ IpcpAddOutOctets(cnt);
+ }
+#endif
+}
+
+/*
+ * For debugging aid.
+ */
+int
+PacketCheck(char *cp, int nb, int direction)
+{
+ struct ip *pip;
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct icmp *icmph;
+ char *ptop;
+ int mask, len, n;
+ int pri = PRI_NORMAL;
+ int logit, loglen;
+ static char logbuf[200];
+
+ logit = LogIsKept(LogTCPIP);
+ loglen = 0;
+
+ pip = (struct ip *) cp;
+
+ if (logit && loglen < sizeof logbuf) {
+ snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
+ Direction[direction]);
+ loglen += strlen(logbuf + loglen);
+ }
+ ptop = (cp + (pip->ip_hl << 2));
+
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ if (logit && loglen < sizeof logbuf) {
+ icmph = (struct icmp *) ptop;
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
+ loglen += strlen(logbuf + loglen);
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
+ loglen += strlen(logbuf + loglen);
+ }
+ break;
+ case IPPROTO_UDP:
+ if (logit && loglen < sizeof logbuf) {
+ uh = (struct udphdr *) ptop;
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
+ loglen += strlen(logbuf + loglen);
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
+ loglen += strlen(logbuf + loglen);
+ }
+ break;
+ case IPPROTO_TCP:
+ th = (struct tcphdr *) ptop;
+ if (pip->ip_tos == IPTOS_LOWDELAY)
+ pri = PRI_FAST;
+ else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
+ if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
+ pri = PRI_FAST;
+ }
+ if (logit && loglen < sizeof logbuf) {
+ len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
+ loglen += strlen(logbuf + loglen);
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
+ loglen += strlen(logbuf + loglen);
+ n = 0;
+ for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
+ if (th->th_flags & mask) {
+ snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
+ loglen += strlen(logbuf + loglen);
+ }
+ n++;
+ }
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ " seq:%x ack:%x (%d/%d)",
+ ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
+ loglen += strlen(logbuf + loglen);
+ if ((th->th_flags & TH_SYN) && nb > 40) {
+ u_short *sp;
+
+ ptop += 20;
+ sp = (u_short *) ptop;
+ if (ntohs(sp[0]) == 0x0204) {
+ snprintf(logbuf + loglen, sizeof logbuf - loglen,
+ " MSS = %d", ntohs(sp[1]));
+ loglen += strlen(logbuf + loglen);
+ }
+ }
+ }
+ break;
+ }
+
+ if ((FilterCheck(pip, direction) & A_DENY)) {
+ if (logit)
+ LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
+ if (direction == 0)
+ IcmpError(pip, pri);
+ return (-1);
+ } else {
+ if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */
+ if (logit)
+ LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
+ ipKeepAlive = 0;
+ } else {
+ if (logit)
+ LogPrintf(LogTCPIP, "%s\n", logbuf);
+ ipKeepAlive = 1;
+ }
+ return (pri);
+ }
+}
+
+void
+IpInput(struct mbuf * bp)
+{ /* IN: Pointer to IP pakcet */
+ u_char *cp;
+ struct mbuf *wp;
+ int nb, nw;
+ struct tun_data tun;
+
+ tun_fill_header(tun, AF_INET);
+ cp = tun.data;
+ nb = 0;
+ for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */
+ memcpy(cp, MBUF_CTOP(wp), wp->cnt);
+ cp += wp->cnt;
+ nb += wp->cnt;
+ }
+
+#ifndef NOALIAS
+ if (mode & MODE_ALIAS) {
+ struct tun_data *frag;
+ int iresult;
+ char *fptr;
+
+ iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
+ nb = ntohs(((struct ip *) tun.data)->ip_len);
+
+ if (nb > MAX_MRU) {
+ LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
+ pfree(bp);
+ return;
+ }
+ if (iresult == PKT_ALIAS_OK
+ || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
+ if (PacketCheck(tun.data, nb, FL_IN) < 0) {
+ pfree(bp);
+ return;
+ }
+ IpcpAddInOctets(nb);
+
+ nb = ntohs(((struct ip *) tun.data)->ip_len);
+ nb += sizeof(tun)-sizeof(tun.data);
+ nw = write(tun_out, &tun, nb);
+ if (nw != nb)
+ if (nw == -1)
+ LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
+ strerror(errno));
+ else
+ LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
+
+ if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
+ while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
+ VarPacketAliasFragmentIn(tun.data, fptr);
+ nb = ntohs(((struct ip *) fptr)->ip_len);
+ frag = (struct tun_data *)((char *)fptr-sizeof(tun)+sizeof(tun.data));
+ nb += sizeof(tun)-sizeof(tun.data);
+ nw = write(tun_out, frag, nb);
+ if (nw != nb)
+ if (nw == -1)
+ LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
+ strerror(errno));
+ else
+ LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
+ free(frag);
+ }
+ }
+ } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
+ nb = ntohs(((struct ip *) tun.data)->ip_len);
+ nb += sizeof(tun)-sizeof(tun.data);
+ frag = (struct tun_data *)malloc(nb);
+ if (frag == NULL)
+ LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
+ else {
+ tun_fill_header(*frag, AF_INET);
+ memcpy(frag->data, tun.data, nb-sizeof(tun)+sizeof(tun.data));
+ VarPacketAliasSaveFragment(frag->data);
+ }
+ }
+ } else
+#endif /* #ifndef NOALIAS */
+ { /* no aliasing */
+ if (PacketCheck(tun.data, nb, FL_IN) < 0) {
+ pfree(bp);
+ return;
+ }
+ IpcpAddInOctets(nb);
+ nb += sizeof(tun)-sizeof(tun.data);
+ nw = write(tun_out, &tun, nb);
+ if (nw != nb)
+ if (nw == -1)
+ LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
+ else
+ LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
+ }
+ pfree(bp);
+
+ RestartIdleTimer();
+}
+
+static struct mqueue IpOutputQueues[PRI_FAST + 1];
+
+void
+IpEnqueue(int pri, char *ptr, int count)
+{
+ struct mbuf *bp;
+
+ bp = mballoc(count, MB_IPQ);
+ memcpy(MBUF_CTOP(bp), ptr, count);
+ Enqueue(&IpOutputQueues[pri], bp);
+}
+
+#if 0
+int
+IsIpEnqueued()
+{
+ struct mqueue *queue;
+ int exist = 0;
+
+ for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
+ if (queue->qlen > 0) {
+ exist = 1;
+ break;
+ }
+ }
+ return (exist);
+}
+#endif
+
+void
+IpStartOutput()
+{
+ struct mqueue *queue;
+ struct mbuf *bp;
+ int cnt;
+
+ if (IpcpFsm.state != ST_OPENED)
+ return;
+ for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
+ if (queue->top) {
+ bp = Dequeue(queue);
+ if (bp) {
+ cnt = plength(bp);
+ SendPppFrame(bp);
+ RestartIdleTimer();
+ IpcpAddOutOctets(cnt);
+ break;
+ }
+ }
+ }
+}
diff --git a/usr.sbin/ppp/ip.h b/usr.sbin/ppp/ip.h
new file mode 100644
index 00000000000..cf8d012dd5f
--- /dev/null
+++ b/usr.sbin/ppp/ip.h
@@ -0,0 +1,30 @@
+/*
+ * User Process PPP
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ip.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ */
+
+extern void IpStartOutput(void);
+extern int PacketCheck(char *, int, int);
+extern void IpEnqueue(int, char *, int);
+extern void IpInput(struct mbuf *);
+extern void StartIdleTimer(void);
+extern void StopIdleTimer(void);
+extern void UpdateIdleTimer(void);
diff --git a/usr.sbin/ppp/ipcp.c b/usr.sbin/ppp/ipcp.c
new file mode 100644
index 00000000000..0bc970f71d3
--- /dev/null
+++ b/usr.sbin/ppp/ipcp.c
@@ -0,0 +1,601 @@
+/*
+ * PPP IP Control Protocol (IPCP) Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipcp.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ * o More RFC1772 backwoard compatibility
+ */
+#include <sys/param.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "slcompress.h"
+#include "os.h"
+#include "phase.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "vjcomp.h"
+#include "ip.h"
+#include "throughput.h"
+
+#ifndef NOMSEXT
+struct in_addr ns_entries[2];
+struct in_addr nbns_entries[2];
+#endif
+
+struct ipcpstate IpcpInfo;
+struct in_range DefMyAddress;
+struct in_range DefHisAddress;
+struct in_addr TriggerAddress;
+int HaveTriggerAddress;
+
+static void IpcpSendConfigReq(struct fsm *);
+static void IpcpSendTerminateAck(struct fsm *);
+static void IpcpSendTerminateReq(struct fsm *);
+static void IpcpDecodeConfig(u_char *, int, int);
+static void IpcpLayerStart(struct fsm *);
+static void IpcpLayerFinish(struct fsm *);
+static void IpcpLayerUp(struct fsm *);
+static void IpcpLayerDown(struct fsm *);
+static void IpcpInitRestartCounter(struct fsm *);
+
+#define REJECTED(p, x) (p->his_reject & (1<<x))
+
+struct fsm IpcpFsm = {
+ "IPCP",
+ PROTO_IPCP,
+ IPCP_MAXCODE,
+ OPEN_ACTIVE,
+ ST_INITIAL,
+ 0, 0, 0,
+
+ 0,
+ {0, 0, 0, NULL, NULL, NULL},
+ {0, 0, 0, NULL, NULL, NULL},
+ LogIPCP,
+
+ IpcpLayerUp,
+ IpcpLayerDown,
+ IpcpLayerStart,
+ IpcpLayerFinish,
+ IpcpInitRestartCounter,
+ IpcpSendConfigReq,
+ IpcpSendTerminateReq,
+ IpcpSendTerminateAck,
+ IpcpDecodeConfig,
+};
+
+static const char *cftypes[] = {
+ /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
+ "???",
+ "IPADDRS", /* 1: IP-Addresses */ /* deprecated */
+ "COMPPROTO", /* 2: IP-Compression-Protocol */
+ "IPADDR", /* 3: IP-Address */
+};
+
+#define NCFTYPES (sizeof(cftypes)/sizeof(char *))
+
+static const char *cftypes128[] = {
+ /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
+ "???",
+ "PRIDNS", /* 129: Primary DNS Server Address */
+ "PRINBNS", /* 130: Primary NBNS Server Address */
+ "SECDNS", /* 131: Secondary DNS Server Address */
+ "SECNBNS", /* 132: Secondary NBNS Server Address */
+};
+
+#define NCFTYPES128 (sizeof(cftypes)/sizeof(char *))
+
+struct pppThroughput throughput;
+
+void
+IpcpAddInOctets(int n)
+{
+ throughput_addin(&throughput, n);
+}
+
+void
+IpcpAddOutOctets(int n)
+{
+ throughput_addout(&throughput, n);
+}
+
+int
+ReportIpcpStatus(struct cmdargs const *arg)
+{
+ struct ipcpstate *icp = &IpcpInfo;
+ struct fsm *fp = &IpcpFsm;
+
+ if (!VarTerm)
+ return 1;
+ fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
+ fprintf(VarTerm, " his side: %s, %lx\n",
+ inet_ntoa(icp->his_ipaddr), icp->his_compproto);
+ fprintf(VarTerm, " my side: %s, %lx\n",
+ inet_ntoa(icp->want_ipaddr), icp->want_compproto);
+
+ fprintf(VarTerm, "Defaults:\n");
+ fprintf(VarTerm, " My Address: %s/%d\n",
+ inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
+ fprintf(VarTerm, " His Address: %s/%d\n",
+ inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
+ if (HaveTriggerAddress)
+ fprintf(VarTerm, " Negotiation(trigger): %s\n", inet_ntoa(TriggerAddress));
+ else
+ fprintf(VarTerm, " Negotiation(trigger): MYADDR\n");
+
+ fprintf(VarTerm, "\n");
+ throughput_disp(&throughput, VarTerm);
+
+ return 0;
+}
+
+void
+IpcpDefAddress()
+{
+ struct hostent *hp;
+ char name[200];
+
+ memset(&DefMyAddress, '\0', sizeof(DefMyAddress));
+ memset(&DefHisAddress, '\0', sizeof(DefHisAddress));
+ TriggerAddress.s_addr = 0;
+ HaveTriggerAddress = 0;
+ if (gethostname(name, sizeof(name)) == 0) {
+ hp = gethostbyname(name);
+ if (hp && hp->h_addrtype == AF_INET) {
+ memcpy(&DefMyAddress.ipaddr.s_addr, hp->h_addr, hp->h_length);
+ }
+ }
+}
+
+void
+IpcpInit()
+{
+ struct ipcpstate *icp = &IpcpInfo;
+
+ FsmInit(&IpcpFsm);
+ memset(icp, '\0', sizeof(struct ipcpstate));
+ if ((mode & MODE_DEDICATED) && !GetLabel()) {
+ icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
+ } else {
+ icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
+ icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
+ }
+
+ /*
+ * Some implementations of PPP require that we send a
+ * *special* value as our address, even though the rfc specifies
+ * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
+ */
+ if (HaveTriggerAddress) {
+ icp->want_ipaddr.s_addr = TriggerAddress.s_addr;
+ LogPrintf(LogIPCP, "Using trigger address %s\n", inet_ntoa(TriggerAddress));
+ }
+ if (Enabled(ConfVjcomp))
+ icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8) | 1;
+ else
+ icp->want_compproto = 0;
+ icp->heis1172 = 0;
+ IpcpFsm.maxconfig = 10;
+ throughput_init(&throughput);
+}
+
+static void
+IpcpInitRestartCounter(struct fsm * fp)
+{
+ fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
+ fp->restart = 5;
+}
+
+static void
+IpcpSendConfigReq(struct fsm * fp)
+{
+ u_char *cp;
+ struct ipcpstate *icp = &IpcpInfo;
+
+ cp = ReqBuff;
+ LogPrintf(LogIPCP, "IpcpSendConfigReq\n");
+ if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
+ PutConfValue(LogIPCP, &cp, cftypes, TY_IPADDR, 6,
+ ntohl(icp->want_ipaddr.s_addr));
+ if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
+ if (icp->heis1172)
+ PutConfValue(LogIPCP, &cp, cftypes, TY_COMPPROTO, 4,
+ icp->want_compproto >> 16);
+ else
+ PutConfValue(LogIPCP, &cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
+ }
+ FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
+}
+
+static void
+IpcpSendTerminateReq(struct fsm * fp)
+{
+ /* XXX: No code yet */
+}
+
+static void
+IpcpSendTerminateAck(struct fsm * fp)
+{
+ LogPrintf(LogIPCP, "IpcpSendTerminateAck\n");
+ FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
+}
+
+static void
+IpcpLayerStart(struct fsm * fp)
+{
+ LogPrintf(LogIPCP, "IpcpLayerStart.\n");
+}
+
+static void
+IpcpLayerFinish(struct fsm * fp)
+{
+ LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
+ reconnect(RECON_FALSE);
+ LcpClose();
+ NewPhase(PHASE_TERMINATE);
+}
+
+static void
+IpcpLayerDown(struct fsm * fp)
+{
+ LogPrintf(LogIPCP, "IpcpLayerDown.\n");
+ throughput_stop(&throughput);
+ throughput_log(&throughput, LogIPCP, NULL);
+}
+
+/*
+ * Called when IPCP has reached to OPEN state
+ */
+static void
+IpcpLayerUp(struct fsm * fp)
+{
+ char tbuff[100];
+
+ Prompt();
+ LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state);
+ snprintf(tbuff, sizeof(tbuff), "myaddr = %s ",
+ inet_ntoa(IpcpInfo.want_ipaddr));
+
+ if (IpcpInfo.his_compproto >> 16 == PROTO_VJCOMP)
+ VjInit((IpcpInfo.his_compproto >> 8) & 255);
+
+ LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
+ tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
+ if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask) < 0) {
+ if (VarTerm)
+ LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
+ return;
+ }
+#ifndef NOALIAS
+ if (mode & MODE_ALIAS)
+ VarPacketAliasSetAddress(IpcpInfo.want_ipaddr);
+#endif
+ OsLinkup();
+ throughput_start(&throughput);
+ StartIdleTimer();
+}
+
+void
+IpcpUp()
+{
+ FsmUp(&IpcpFsm);
+ LogPrintf(LogIPCP, "IPCP Up event!!\n");
+}
+
+void
+IpcpOpen()
+{
+ FsmOpen(&IpcpFsm);
+}
+
+static int
+AcceptableAddr(struct in_range * prange, struct in_addr ipaddr)
+{
+ LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr));
+ LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr));
+ LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr));
+ LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange->
+ mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr));
+ return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
+ (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
+}
+
+static void
+IpcpDecodeConfig(u_char * cp, int plen, int mode_type)
+{
+ int type, length;
+ u_long *lp, compproto;
+ struct compreq *pcomp;
+ struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
+ char tbuff[100];
+ char tbuff2[100];
+
+ ackp = AckBuff;
+ nakp = NakBuff;
+ rejp = RejBuff;
+
+ while (plen >= sizeof(struct fsmconfig)) {
+ type = *cp;
+ length = cp[1];
+ if (type < NCFTYPES)
+ snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length);
+ else if (type > 128 && type < 128 + NCFTYPES128)
+ snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes128[type], length);
+ else
+ snprintf(tbuff, sizeof(tbuff), " ??? ");
+
+ switch (type) {
+ case TY_IPADDR: /* RFC1332 */
+ lp = (u_long *) (cp + 2);
+ ipaddr.s_addr = *lp;
+ LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
+
+ switch (mode_type) {
+ case MODE_REQ:
+ if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
+ /*
+ * If destination address is not acceptable, insist to use what we
+ * want to use.
+ */
+ memcpy(nakp, cp, 2);
+ memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length);
+ nakp += length;
+ break;
+ }
+ IpcpInfo.his_ipaddr = ipaddr;
+ memcpy(ackp, cp, length);
+ ackp += length;
+ break;
+ case MODE_NAK:
+ if (AcceptableAddr(&DefMyAddress, ipaddr)) {
+
+ /*
+ * Use address suggested by peer.
+ */
+ snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s ", tbuff,
+ inet_ntoa(IpcpInfo.want_ipaddr));
+ LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
+ IpcpInfo.want_ipaddr = ipaddr;
+ }
+ break;
+ case MODE_REJ:
+ IpcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_COMPPROTO:
+ lp = (u_long *) (cp + 2);
+ compproto = htonl(*lp);
+ LogPrintf(LogIPCP, "%s %08x\n", tbuff, compproto);
+
+ switch (mode_type) {
+ case MODE_REQ:
+ if (!Acceptable(ConfVjcomp)) {
+ memcpy(rejp, cp, length);
+ rejp += length;
+ } else {
+ pcomp = (struct compreq *) (cp + 2);
+ switch (length) {
+ case 4: /* RFC1172 */
+ if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
+ LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
+ IpcpInfo.heis1172 = 1;
+ IpcpInfo.his_compproto = compproto;
+ memcpy(ackp, cp, length);
+ ackp += length;
+ } else {
+ memcpy(nakp, cp, 2);
+ pcomp->proto = htons(PROTO_VJCOMP);
+ memcpy(nakp+2, &pcomp, 2);
+ nakp += length;
+ }
+ break;
+ case 6: /* RFC1332 */
+ if (ntohs(pcomp->proto) == PROTO_VJCOMP
+ && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
+ IpcpInfo.his_compproto = compproto;
+ IpcpInfo.heis1172 = 0;
+ memcpy(ackp, cp, length);
+ ackp += length;
+ } else {
+ memcpy(nakp, cp, 2);
+ pcomp->proto = htons(PROTO_VJCOMP);
+ pcomp->slots = MAX_STATES - 1;
+ pcomp->compcid = 0;
+ memcpy(nakp+2, &pcomp, sizeof(pcomp));
+ nakp += length;
+ }
+ break;
+ default:
+ memcpy(rejp, cp, length);
+ rejp += length;
+ break;
+ }
+ }
+ break;
+ case MODE_NAK:
+ LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
+ tbuff, IpcpInfo.want_compproto, compproto);
+ IpcpInfo.want_compproto = compproto;
+ break;
+ case MODE_REJ:
+ IpcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_IPADDRS: /* RFC1172 */
+ lp = (u_long *) (cp + 2);
+ ipaddr.s_addr = *lp;
+ lp = (u_long *) (cp + 6);
+ dstipaddr.s_addr = *lp;
+ snprintf(tbuff2, sizeof(tbuff2), "%s %s,", tbuff, inet_ntoa(ipaddr));
+ LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
+
+ switch (mode_type) {
+ case MODE_REQ:
+ IpcpInfo.his_ipaddr = ipaddr;
+ IpcpInfo.want_ipaddr = dstipaddr;
+ memcpy(ackp, cp, length);
+ ackp += length;
+ break;
+ case MODE_NAK:
+ snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s", tbuff,
+ inet_ntoa(IpcpInfo.want_ipaddr));
+ LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
+ IpcpInfo.want_ipaddr = ipaddr;
+ IpcpInfo.his_ipaddr = dstipaddr;
+ break;
+ case MODE_REJ:
+ IpcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+
+ /*
+ * MS extensions for MS's PPP
+ */
+
+#ifndef NOMSEXT
+ case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */
+ case TY_SECONDARY_DNS:
+ if (!Enabled(ConfMSExt)) {
+ LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
+ IpcpInfo.my_reject |= (1 << type);
+ memcpy(rejp, cp, length);
+ rejp += length;
+ break;
+ }
+ switch (mode_type) {
+ case MODE_REQ:
+ lp = (u_long *) (cp + 2);
+ dnsstuff.s_addr = *lp;
+ ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS) ? 1 : 0)].s_addr;
+ if (dnsstuff.s_addr != ms_info_req.s_addr) {
+
+ /*
+ * So the client has got the DNS stuff wrong (first request) so
+ * we'll tell 'em how it is
+ */
+ memcpy(nakp, cp, 2); /* copy first two (type/length) */
+ LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
+ type,
+ inet_ntoa(dnsstuff),
+ inet_ntoa(ms_info_req));
+ memcpy(nakp+2, &ms_info_req, length);
+ nakp += length;
+ break;
+ }
+
+ /*
+ * Otherwise they have it right (this time) so we send a ack packet
+ * back confirming it... end of story
+ */
+ LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
+ type,
+ inet_ntoa(ms_info_req));
+ memcpy(ackp, cp, length);
+ ackp += length;
+ break;
+ case MODE_NAK: /* what does this mean?? */
+ LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
+ break;
+ case MODE_REJ: /* confused?? me to :) */
+ LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
+ break;
+ }
+ break;
+
+ case TY_PRIMARY_NBNS: /* MS PPP NetBIOS nameserver hack */
+ case TY_SECONDARY_NBNS:
+ if (!Enabled(ConfMSExt)) {
+ LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
+ IpcpInfo.my_reject |= (1 << type);
+ memcpy(rejp, cp, length);
+ rejp += length;
+ break;
+ }
+ switch (mode_type) {
+ case MODE_REQ:
+ lp = (u_long *) (cp + 2);
+ dnsstuff.s_addr = *lp;
+ ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS) ? 1 : 0)].s_addr;
+ if (dnsstuff.s_addr != ms_info_req.s_addr) {
+ memcpy(nakp, cp, 2);
+ memcpy(nakp+2, &ms_info_req.s_addr, length);
+ LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
+ type,
+ inet_ntoa(dnsstuff),
+ inet_ntoa(ms_info_req));
+ nakp += length;
+ break;
+ }
+ LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
+ type,
+ inet_ntoa(ms_info_req));
+ memcpy(ackp, cp, length);
+ ackp += length;
+ break;
+ case MODE_NAK:
+ LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
+ break;
+ case MODE_REJ:
+ LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
+ break;
+ }
+ break;
+
+#endif
+
+ default:
+ IpcpInfo.my_reject |= (1 << type);
+ memcpy(rejp, cp, length);
+ rejp += length;
+ break;
+ }
+ plen -= length;
+ cp += length;
+ }
+}
+
+void
+IpcpInput(struct mbuf * bp)
+{
+ FsmInput(&IpcpFsm, bp);
+}
diff --git a/usr.sbin/ppp/ipcp.h b/usr.sbin/ppp/ipcp.h
new file mode 100644
index 00000000000..50b0f8ba195
--- /dev/null
+++ b/usr.sbin/ppp/ipcp.h
@@ -0,0 +1,79 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipcp.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ */
+
+#define IPCP_MAXCODE CODE_CODEREJ
+
+#define TY_IPADDRS 1
+#define TY_COMPPROTO 2
+#define TY_IPADDR 3
+
+/* MS PPP NameServer and NetBIOS NameServer stuff */
+
+#ifndef NOMSEXT
+#define TY_PRIMARY_DNS 129
+#define TY_PRIMARY_NBNS 130
+#define TY_SECONDARY_DNS 131
+#define TY_SECONDARY_NBNS 132
+
+extern struct in_addr ns_entries[2];
+extern struct in_addr nbns_entries[2];
+#endif
+
+struct ipcpstate {
+ struct in_addr his_ipaddr; /* IP address he is willing to use */
+ u_long his_compproto;
+
+ struct in_addr want_ipaddr; /* IP address I'm willing to use */
+ u_long want_compproto;
+
+ u_long his_reject; /* Request codes rejected by peer */
+ u_long my_reject; /* Request codes I have rejected */
+ int heis1172; /* True if he is speaking rfc1172 */
+};
+
+struct compreq {
+ u_short proto;
+ u_char slots;
+ u_char compcid;
+};
+
+struct in_range {
+ struct in_addr ipaddr;
+ struct in_addr mask;
+ int width;
+};
+
+extern struct ipcpstate IpcpInfo;
+extern struct in_range DefMyAddress;
+extern struct in_range DefHisAddress;
+extern struct in_addr TriggerAddress;
+extern int HaveTriggerAddress;
+extern struct fsm IpcpFsm;
+
+extern void IpcpInit(void);
+extern void IpcpDefAddress(void);
+extern void IpcpUp(void);
+extern void IpcpOpen(void);
+extern int ReportIpcpStatus(struct cmdargs const *);
+extern void IpcpInput(struct mbuf *);
+extern void IpcpAddInOctets(int);
+extern void IpcpAddOutOctets(int);
diff --git a/usr.sbin/ppp/lcp.c b/usr.sbin/ppp/lcp.c
new file mode 100644
index 00000000000..df6880b6f2d
--- /dev/null
+++ b/usr.sbin/ppp/lcp.c
@@ -0,0 +1,716 @@
+/*
+ * PPP Link Control Protocol (LCP) Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lcp.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ * o Validate magic number received from peer.
+ * o Limit data field length by MRU
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#ifdef __FreeBSD__
+#include <net/if_var.h>
+#endif
+#include <net/if_tun.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "lcpproto.h"
+#include "os.h"
+#include "hdlc.h"
+#include "ccp.h"
+#include "lqr.h"
+#include "phase.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "auth.h"
+#include "pap.h"
+#include "chap.h"
+#include "async.h"
+#include "main.h"
+#include "ip.h"
+#include "modem.h"
+#include "tun.h"
+
+struct lcpstate LcpInfo;
+
+static void LcpSendConfigReq(struct fsm *);
+static void LcpSendTerminateReq(struct fsm *);
+static void LcpSendTerminateAck(struct fsm *);
+static void LcpDecodeConfig(u_char *, int, int);
+static void LcpInitRestartCounter(struct fsm *);
+static void LcpLayerUp(struct fsm *);
+static void LcpLayerDown(struct fsm *);
+static void LcpLayerStart(struct fsm *);
+static void LcpLayerFinish(struct fsm *);
+
+#define REJECTED(p, x) (p->his_reject & (1<<x))
+
+static const char *cftypes[] = {
+ /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
+ "???",
+ "MRU", /* 1: Maximum-Receive-Unit */
+ "ACCMAP", /* 2: Async-Control-Character-Map */
+ "AUTHPROTO", /* 3: Authentication-Protocol */
+ "QUALPROTO", /* 4: Quality-Protocol */
+ "MAGICNUM", /* 5: Magic-Number */
+ "RESERVED", /* 6: RESERVED */
+ "PROTOCOMP", /* 7: Protocol-Field-Compression */
+ "ACFCOMP", /* 8: Address-and-Control-Field-Compression */
+ "FCSALT", /* 9: FCS-Alternatives */
+ "SDP", /* 10: Self-Describing-Pad */
+ "NUMMODE", /* 11: Numbered-Mode */
+ "MULTIPROC", /* 12: Multi-Link-Procedure */
+ "CALLBACK", /* 13: Callback */
+ "CONTIME", /* 14: Connect-Time */
+ "COMPFRAME", /* 15: Compound-Frames */
+ "NDE", /* 16: Nominal-Data-Encapsulation */
+ "MULTIMRRU", /* 17: Multilink-MRRU */
+ "MULTISSNH", /* 18: Multilink-Short-Sequence-Number-Header */
+ "MULTIED", /* 19: Multilink-Endpoint-Descriminator */
+ "PROPRIETRY", /* 20: Proprietary */
+ "DCEID", /* 21: DCE-Identifier */
+ "MULTIPP", /* 22: Multi-Link-Plus-Procedure */
+ "LDBACP", /* 23: Link Discriminator for BACP */
+};
+
+#define NCFTYPES (sizeof(cftypes)/sizeof(char *))
+
+struct fsm LcpFsm = {
+ "LCP", /* Name of protocol */
+ PROTO_LCP, /* Protocol Number */
+ LCP_MAXCODE,
+ OPEN_ACTIVE,
+ ST_INITIAL, /* State of machine */
+ 0, 0, 0,
+ 0,
+ {0, 0, 0, NULL, NULL, NULL},
+ {0, 0, 0, NULL, NULL, NULL},
+ LogLCP,
+
+ LcpLayerUp,
+ LcpLayerDown,
+ LcpLayerStart,
+ LcpLayerFinish,
+ LcpInitRestartCounter,
+ LcpSendConfigReq,
+ LcpSendTerminateReq,
+ LcpSendTerminateAck,
+ LcpDecodeConfig,
+};
+
+static struct pppTimer LcpReportTimer;
+static int LcpFailedMagic;
+
+static void
+LcpReportTime(void *data)
+{
+ if (LogIsKept(LogDEBUG)) {
+ time_t t;
+
+ time(&t);
+ LogPrintf(LogDEBUG, "LcpReportTime: %s\n", ctime(&t));
+ }
+ StopTimer(&LcpReportTimer);
+ LcpReportTimer.state = TIMER_STOPPED;
+ StartTimer(&LcpReportTimer);
+ HdlcErrorCheck();
+}
+
+int
+ReportLcpStatus(struct cmdargs const *arg)
+{
+ struct lcpstate *lcp = &LcpInfo;
+ struct fsm *fp = &LcpFsm;
+
+ if (!VarTerm)
+ return 1;
+
+ fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
+ fprintf(VarTerm,
+ " his side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
+ " REJECT %04lx\n",
+ lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp,
+ lcp->his_magic, lcp->his_reject);
+ fprintf(VarTerm,
+ " my side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
+ " REJECT %04lx\n",
+ lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp,
+ lcp->want_magic, lcp->my_reject);
+ fprintf(VarTerm, "\nDefaults: MRU = %ld, ACCMAP = %08x\t", VarMRU, VarAccmap);
+ fprintf(VarTerm, "Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE) ? "active" : "passive");
+ return 0;
+}
+
+/*
+ * Generate random number which will be used as magic number.
+ */
+static u_long
+GenerateMagic(void)
+{
+ randinit();
+ return (random());
+}
+
+void
+LcpInit()
+{
+ struct lcpstate *lcp = &LcpInfo;
+
+ FsmInit(&LcpFsm);
+ HdlcInit();
+
+ memset(lcp, '\0', sizeof(struct lcpstate));
+ lcp->want_mru = VarMRU;
+ lcp->his_mru = DEF_MRU;
+ lcp->his_accmap = 0xffffffff;
+ lcp->want_accmap = VarAccmap;
+ lcp->want_magic = GenerateMagic();
+ lcp->want_auth = lcp->his_auth = 0;
+ if (Enabled(ConfChap))
+ lcp->want_auth = PROTO_CHAP;
+ else if (Enabled(ConfPap))
+ lcp->want_auth = PROTO_PAP;
+ if (Enabled(ConfLqr))
+ lcp->want_lqrperiod = VarLqrTimeout * 100;
+ if (Enabled(ConfAcfcomp))
+ lcp->want_acfcomp = 1;
+ if (Enabled(ConfProtocomp))
+ lcp->want_protocomp = 1;
+ LcpFsm.maxconfig = 10;
+}
+
+static void
+LcpInitRestartCounter(struct fsm * fp)
+{
+ fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
+ fp->restart = 5;
+}
+
+void
+PutConfValue(int level, u_char ** cpp, const char **types, u_char type,
+ int len, u_long val)
+{
+ u_char *cp;
+ struct in_addr ina;
+
+ cp = *cpp;
+ *cp++ = type;
+ *cp++ = len;
+ if (len == 6) {
+ if (type == TY_IPADDR) {
+ ina.s_addr = htonl(val);
+ LogPrintf(level, " %s [%d] %s\n",
+ types[type], len, inet_ntoa(ina));
+ } else
+ LogPrintf(level, " %s [%d] %08x\n", types[type], len, val);
+ *cp++ = (val >> 24) & 0377;
+ *cp++ = (val >> 16) & 0377;
+ } else
+ LogPrintf(level, " %s [%d] %d\n", types[type], len, val);
+ *cp++ = (val >> 8) & 0377;
+ *cp++ = val & 0377;
+ *cpp = cp;
+}
+
+static void
+LcpSendConfigReq(struct fsm * fp)
+{
+ u_char *cp;
+ struct lcpstate *lcp = &LcpInfo;
+ struct lqrreq *req;
+
+ LogPrintf(LogLCP, "LcpSendConfigReq\n");
+ cp = ReqBuff;
+ if (!DEV_IS_SYNC) {
+ if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) {
+ *cp++ = TY_ACFCOMP;
+ *cp++ = 2;
+ LogPrintf(LogLCP, " %s\n", cftypes[TY_ACFCOMP]);
+ }
+ if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) {
+ *cp++ = TY_PROTOCOMP;
+ *cp++ = 2;
+ LogPrintf(LogLCP, " %s\n", cftypes[TY_PROTOCOMP]);
+ }
+ if (!REJECTED(lcp, TY_ACCMAP))
+ PutConfValue(LogLCP, &cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap);
+ }
+ if (!REJECTED(lcp, TY_MRU))
+ PutConfValue(LogLCP, &cp, cftypes, TY_MRU, 4, lcp->want_mru);
+ if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM))
+ PutConfValue(LogLCP, &cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic);
+ if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
+ req = (struct lqrreq *) cp;
+ req->type = TY_QUALPROTO;
+ req->length = sizeof(struct lqrreq);
+ req->proto = htons(PROTO_LQR);
+ req->period = htonl(lcp->want_lqrperiod);
+ cp += sizeof(struct lqrreq);
+ LogPrintf(LogLCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod);
+ }
+ switch (lcp->want_auth) {
+ case PROTO_PAP:
+ PutConfValue(LogLCP, &cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth);
+ break;
+ case PROTO_CHAP:
+ PutConfValue(LogLCP, &cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth);
+#ifdef HAVE_DES
+ *cp++ = VarMSChap ? 0x80 : 0x05; /* Use MSChap vs. RFC 1994 (MD5) */
+#else
+ *cp++ = 0x05; /* Use MD5 */
+#endif
+ break;
+ }
+ FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
+}
+
+void
+LcpSendProtoRej(u_char * option, int count)
+{
+ struct fsm *fp = &LcpFsm;
+
+ LogPrintf(LogLCP, "LcpSendProtoRej\n");
+ FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count);
+}
+
+static void
+LcpSendTerminateReq(struct fsm * fp)
+{
+ /* Most thins are done in fsm layer. Nothing to to. */
+}
+
+static void
+LcpSendTerminateAck(struct fsm * fp)
+{
+ LogPrintf(LogLCP, "LcpSendTerminateAck.\n");
+ FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
+}
+
+static void
+LcpLayerStart(struct fsm * fp)
+{
+ LogPrintf(LogLCP, "LcpLayerStart\n");
+ NewPhase(PHASE_ESTABLISH);
+}
+
+static void
+StopAllTimers(void)
+{
+ StopTimer(&LcpReportTimer);
+ StopIdleTimer();
+ StopTimer(&AuthPapInfo.authtimer);
+ StopTimer(&AuthChapInfo.authtimer);
+ StopLqrTimer();
+}
+
+static void
+LcpLayerFinish(struct fsm * fp)
+{
+ LogPrintf(LogLCP, "LcpLayerFinish\n");
+ HangupModem(0);
+ StopAllTimers();
+ /* We're down at last. Lets tell background and direct mode to get out */
+ NewPhase(PHASE_DEAD);
+ LcpInit();
+ IpcpInit();
+ CcpInit();
+ Prompt();
+}
+
+static void
+LcpLayerUp(struct fsm * fp)
+{
+ LogPrintf(LogLCP, "LcpLayerUp\n");
+ tun_configure(LcpInfo.his_mru, ModemSpeed());
+ SetLinkParams(&LcpInfo);
+
+ NewPhase(PHASE_AUTHENTICATE);
+
+ StartLqm();
+ StopTimer(&LcpReportTimer);
+ LcpReportTimer.state = TIMER_STOPPED;
+ LcpReportTimer.load = 60 * SECTICKS;
+ LcpReportTimer.func = LcpReportTime;
+ StartTimer(&LcpReportTimer);
+}
+
+static void
+LcpLayerDown(struct fsm * fp)
+{
+ StopAllTimers();
+ OsLinkdown();
+ LogPrintf(LogLCP, "LcpLayerDown\n");
+ /*
+ * OsLinkdown() brings CCP & IPCP down, then waits 'till we go from
+ * STOPPING to STOPPED. At this point, the FSM gives us a LayerFinish
+ */
+}
+
+void
+LcpUp()
+{
+ FsmUp(&LcpFsm);
+ LcpFailedMagic = 0;
+}
+
+void
+LcpDown()
+{ /* Sudden death */
+ LcpFailedMagic = 0;
+ FsmDown(&LcpFsm);
+ /* FsmDown() results in a LcpLayerDown() if we're currently open. */
+ LcpLayerFinish(&LcpFsm);
+}
+
+void
+LcpOpen(int open_mode)
+{
+ LcpFsm.open_mode = open_mode;
+ LcpFailedMagic = 0;
+ FsmOpen(&LcpFsm);
+}
+
+void
+LcpClose()
+{
+ NewPhase(PHASE_TERMINATE);
+ OsInterfaceDown(0);
+ FsmClose(&LcpFsm);
+ LcpFailedMagic = 0;
+}
+
+/*
+ * XXX: Should validate option length
+ */
+static void
+LcpDecodeConfig(u_char * cp, int plen, int mode_type)
+{
+ const char *request;
+ int type, length, mru, mtu;
+ u_long *lp, magic, accmap;
+ u_short *sp, proto;
+ struct lqrreq *req;
+
+ ackp = AckBuff;
+ nakp = NakBuff;
+ rejp = RejBuff;
+
+ while (plen >= sizeof(struct fsmconfig)) {
+ type = *cp;
+ length = cp[1];
+ if (type < NCFTYPES)
+ request = cftypes[type];
+ else
+ request = "???";
+
+ switch (type) {
+ case TY_MRU:
+ sp = (u_short *) (cp + 2);
+ mru = htons(*sp);
+ LogPrintf(LogLCP, " %s %d\n", request, mru);
+
+ switch (mode_type) {
+ case MODE_REQ:
+ mtu = VarPrefMTU;
+ if (mtu == 0)
+ mtu = MAX_MTU;
+ if (mru > mtu) {
+ *sp = htons(mtu);
+ memcpy(nakp, cp, 4);
+ nakp += 4;
+ } else if (mru < MIN_MRU) {
+ *sp = htons(MIN_MRU);
+ memcpy(nakp, cp, 4);
+ nakp += 4;
+ } else {
+ LcpInfo.his_mru = mru;
+ memcpy(ackp, cp, 4);
+ ackp += 4;
+ }
+ break;
+ case MODE_NAK:
+ if (mru >= MIN_MRU || mru <= MAX_MRU)
+ LcpInfo.want_mru = mru;
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_ACCMAP:
+ lp = (u_long *) (cp + 2);
+ accmap = htonl(*lp);
+ LogPrintf(LogLCP, " %s %08x\n", request, accmap);
+
+ switch (mode_type) {
+ case MODE_REQ:
+ LcpInfo.his_accmap = accmap;
+ memcpy(ackp, cp, 6);
+ ackp += 6;
+ break;
+ case MODE_NAK:
+ LcpInfo.want_accmap = accmap;
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_AUTHPROTO:
+ sp = (u_short *) (cp + 2);
+ proto = ntohs(*sp);
+ LogPrintf(LogLCP, " %s proto = %04x\n", request, proto);
+
+ switch (mode_type) {
+ case MODE_REQ:
+ switch (proto) {
+ case PROTO_PAP:
+ if (length != 4) {
+ LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
+ goto reqreject;
+ }
+ if (Acceptable(ConfPap)) {
+ LcpInfo.his_auth = proto;
+ memcpy(ackp, cp, length);
+ ackp += length;
+ } else if (Acceptable(ConfChap)) {
+ *nakp++ = *cp;
+ *nakp++ = 5;
+ *nakp++ = (unsigned char) (PROTO_CHAP >> 8);
+ *nakp++ = (unsigned char) PROTO_CHAP;
+ *nakp++ = 5;
+ } else
+ goto reqreject;
+ break;
+ case PROTO_CHAP:
+ if (length < 5) {
+ LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
+ goto reqreject;
+ }
+#ifdef HAVE_DES
+ if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80))
+#else
+ if (Acceptable(ConfChap) && cp[4] == 5)
+#endif
+ {
+ LcpInfo.his_auth = proto;
+ memcpy(ackp, cp, length);
+ ackp += length;
+#ifdef HAVE_DES
+ VarMSChap = cp[4] == 0x80;
+#endif
+ } else if (Acceptable(ConfPap)) {
+ *nakp++ = *cp;
+ *nakp++ = 4;
+ *nakp++ = (unsigned char) (PROTO_PAP >> 8);
+ *nakp++ = (unsigned char) PROTO_PAP;
+ } else
+ goto reqreject;
+ break;
+ default:
+ LogPrintf(LogLCP, " %s not implemented, NAK.\n", request);
+ memcpy(nakp, cp, length);
+ nakp += length;
+ break;
+ }
+ break;
+ case MODE_NAK:
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_QUALPROTO:
+ req = (struct lqrreq *) cp;
+ LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n",
+ request, ntohs(req->proto), ntohl(req->period) * 10);
+ switch (mode_type) {
+ case MODE_REQ:
+ if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
+ goto reqreject;
+ else {
+ LcpInfo.his_lqrperiod = ntohl(req->period);
+ if (LcpInfo.his_lqrperiod < 500)
+ LcpInfo.his_lqrperiod = 500;
+ req->period = htonl(LcpInfo.his_lqrperiod);
+ memcpy(ackp, cp, length);
+ ackp += length;
+ }
+ break;
+ case MODE_NAK:
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_MAGICNUM:
+ lp = (u_long *) (cp + 2);
+ magic = ntohl(*lp);
+ LogPrintf(LogLCP, " %s %08x\n", request, magic);
+
+ switch (mode_type) {
+ case MODE_REQ:
+ if (LcpInfo.want_magic) {
+ /* Validate magic number */
+ if (magic == LcpInfo.want_magic) {
+ LogPrintf(LogLCP, "Magic is same (%08x) - %d times\n",
+ magic, ++LcpFailedMagic);
+ LcpInfo.want_magic = GenerateMagic();
+ memcpy(nakp, cp, 6);
+ nakp += 6;
+ ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0);
+ sigpause(0);
+ } else {
+ LcpInfo.his_magic = magic;
+ memcpy(ackp, cp, length);
+ ackp += length;
+ LcpFailedMagic = 0;
+ }
+ } else {
+ LcpInfo.my_reject |= (1 << type);
+ goto reqreject;
+ }
+ break;
+ case MODE_NAK:
+ LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic);
+ LcpInfo.want_magic = GenerateMagic();
+ break;
+ case MODE_REJ:
+ LogPrintf(LogLCP, " %s magic has REJected\n", request);
+ LcpInfo.want_magic = 0;
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_PROTOCOMP:
+ LogPrintf(LogLCP, " %s\n", request);
+
+ switch (mode_type) {
+ case MODE_REQ:
+ if (Acceptable(ConfProtocomp)) {
+ LcpInfo.his_protocomp = 1;
+ memcpy(ackp, cp, 2);
+ ackp += 2;
+ } else {
+#ifdef OLDMST
+ /*
+ * MorningStar before v1.3 needs NAK
+ */
+ memcpy(nakp, cp, 2);
+ nakp += 2;
+#else
+ memcpy(rejp, cp, 2);
+ rejp += 2;
+ LcpInfo.my_reject |= (1 << type);
+#endif
+ }
+ break;
+ case MODE_NAK:
+ case MODE_REJ:
+ LcpInfo.want_protocomp = 0;
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_ACFCOMP:
+ LogPrintf(LogLCP, " %s\n", request);
+ switch (mode_type) {
+ case MODE_REQ:
+ if (Acceptable(ConfAcfcomp)) {
+ LcpInfo.his_acfcomp = 1;
+ memcpy(ackp, cp, 2);
+ ackp += 2;
+ } else {
+#ifdef OLDMST
+ /*
+ * MorningStar before v1.3 needs NAK
+ */
+ memcpy(nakp, cp, 2);
+ nakp += 2;
+#else
+ memcpy(rejp, cp, 2);
+ rejp += 2;
+ LcpInfo.my_reject |= (1 << type);
+#endif
+ }
+ break;
+ case MODE_NAK:
+ case MODE_REJ:
+ LcpInfo.want_acfcomp = 0;
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_SDP:
+ LogPrintf(LogLCP, " %s\n", request);
+ switch (mode_type) {
+ case MODE_REQ:
+ case MODE_NAK:
+ case MODE_REJ:
+ break;
+ }
+ break;
+ default:
+ LogPrintf(LogLCP, " %s[02x]\n", request, type);
+ if (mode_type == MODE_REQ) {
+ reqreject:
+ memcpy(rejp, cp, length);
+ rejp += length;
+ LcpInfo.my_reject |= (1 << type);
+ }
+ break;
+ }
+ /* to avoid inf. loop */
+ if (length == 0) {
+ LogPrintf(LogLCP, "LCP size zero\n");
+ break;
+ }
+ plen -= length;
+ cp += length;
+ }
+}
+
+void
+LcpInput(struct mbuf * bp)
+{
+ FsmInput(&LcpFsm, bp);
+}
diff --git a/usr.sbin/ppp/lcp.h b/usr.sbin/ppp/lcp.h
new file mode 100644
index 00000000000..a624cae9698
--- /dev/null
+++ b/usr.sbin/ppp/lcp.h
@@ -0,0 +1,78 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lcp.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ */
+
+struct lcpstate {
+ u_long his_mru;
+ u_long his_accmap;
+ u_long his_magic;
+ u_long his_lqrperiod;
+ u_char his_protocomp;
+ u_char his_acfcomp;
+ u_short his_auth;
+
+ u_long want_mru;
+ u_long want_accmap;
+ u_long want_magic;
+ u_long want_lqrperiod;
+ u_char want_protocomp;
+ u_char want_acfcomp;
+ u_short want_auth;
+
+ u_long his_reject; /* Request codes rejected by peer */
+ u_long my_reject; /* Request codes I have rejected */
+
+ u_short auth_iwait;
+ u_short auth_ineed;
+};
+
+#define LCP_MAXCODE CODE_DISCREQ
+
+#define TY_MRU 1 /* Maximum-Receive-Unit */
+#define TY_ACCMAP 2 /* Async-Control-Character-Map */
+#define TY_AUTHPROTO 3 /* Authentication-Protocol */
+#define TY_QUALPROTO 4 /* Quality-Protocol */
+#define TY_MAGICNUM 5 /* Magic-Number */
+#define TY_RESERVED 6 /* RESERVED */
+#define TY_PROTOCOMP 7 /* Protocol-Field-Compression */
+#define TY_ACFCOMP 8 /* Address-and-Control-Field-Compression */
+#define TY_FCSALT 9 /* FCS-Alternatives */
+#define TY_SDP 10 /* Self-Describing-Padding */
+
+struct lqrreq {
+ u_char type;
+ u_char length;
+ u_short proto; /* Quality protocol */
+ u_long period; /* Reporting interval */
+};
+
+extern struct lcpstate LcpInfo;
+extern struct fsm LcpFsm;
+
+extern void LcpInit(void);
+extern void LcpUp(void);
+extern void LcpSendProtoRej(u_char *, int);
+extern void LcpOpen(int);
+extern void LcpClose(void);
+extern void LcpDown(void);
+extern void PutConfValue(int, u_char **, const char **, u_char, int, u_long);
+extern int ReportLcpStatus(struct cmdargs const *);
+extern void LcpInput(struct mbuf *);
diff --git a/usr.sbin/ppp/lcpproto.h b/usr.sbin/ppp/lcpproto.h
new file mode 100644
index 00000000000..dadb2311e2b
--- /dev/null
+++ b/usr.sbin/ppp/lcpproto.h
@@ -0,0 +1,39 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lcpproto.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ */
+
+/*
+ * Definition of protocol numbers
+ */
+#define PROTO_IP 0x0021 /* IP */
+#define PROTO_VJUNCOMP 0x002f /* VJ Uncompressed */
+#define PROTO_VJCOMP 0x002d /* VJ Compressed */
+#define PROTO_ICOMPD 0x00fb /* Individual link compressed */
+#define PROTO_COMPD 0x00fd /* Compressed datagram */
+
+#define PROTO_IPCP 0x8021
+#define PROTO_ICCP 0x80fb
+#define PROTO_CCP 0x80fd
+
+#define PROTO_LCP 0xc021
+#define PROTO_PAP 0xc023
+#define PROTO_LQR 0xc025
+#define PROTO_CHAP 0xc223
diff --git a/usr.sbin/ppp/loadalias.c b/usr.sbin/ppp/loadalias.c
new file mode 100644
index 00000000000..3e4cf3bc4ed
--- /dev/null
+++ b/usr.sbin/ppp/loadalias.c
@@ -0,0 +1,92 @@
+/*
+ * $Id: loadalias.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <alias.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "systems.h"
+#include "id.h"
+#include "loadalias.h"
+#include "defs.h"
+#include "vars.h"
+
+#define _PATH_ALIAS "/usr/lib/libalias.so." ## __libalias_version
+
+#define off(item) ((int)&(((struct aliasHandlers *)0)->item))
+#define entry(a) { off(a), "_" #a }
+
+static struct {
+ int offset;
+ const char *name;
+} map[] = {
+ entry(PacketAliasGetFragment),
+ entry(PacketAliasInit),
+ entry(PacketAliasIn),
+ entry(PacketAliasOut),
+ entry(PacketAliasRedirectAddr),
+ entry(PacketAliasRedirectPort),
+ entry(PacketAliasSaveFragment),
+ entry(PacketAliasSetAddress),
+ entry(PacketAliasSetMode),
+ entry(PacketAliasFragmentIn),
+ { 0, 0 }
+};
+
+static void *dl;
+
+int
+loadAliasHandlers(struct aliasHandlers * h)
+{
+ const char *path;
+ const char *env;
+ int i;
+
+ path = _PATH_ALIAS;
+ env = getenv("_PATH_ALIAS");
+ if (env)
+ if (ID0realuid() == 0)
+ path = env;
+ else
+ LogPrintf(LogALERT, "Ignoring environment _PATH_ALIAS value (%s)\n", env);
+
+ dl = dlopen(path, RTLD_LAZY);
+ if (dl == (void *) 0) {
+ LogPrintf(LogWARN, "_PATH_ALIAS (%s): Invalid lib: %s\n",
+ path, dlerror());
+ return -1;
+ }
+ for (i = 0; map[i].name; i++) {
+ *(void **) ((char *) h + map[i].offset) = dlsym(dl, map[i].name);
+ if (*(void **) ((char *) h + map[i].offset) == (void *) 0) {
+ LogPrintf(LogWARN, "_PATH_ALIAS (%s): %s: %s\n", path,
+ map[i].name, dlerror());
+ (void) dlclose(dl);
+ dl = (void *) 0;
+ return -1;
+ }
+ }
+
+ VarPacketAliasInit();
+
+ return 0;
+}
+
+void
+unloadAliasHandlers()
+{
+ if (dl) {
+ dlclose(dl);
+ dl = (void *) 0;
+ }
+}
diff --git a/usr.sbin/ppp/loadalias.h b/usr.sbin/ppp/loadalias.h
new file mode 100644
index 00000000000..a4cc571e24d
--- /dev/null
+++ b/usr.sbin/ppp/loadalias.h
@@ -0,0 +1,21 @@
+/*
+ * $Id: loadalias.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ */
+
+struct aliasHandlers {
+ char *(*PacketAliasGetFragment)(char *);
+ void (*PacketAliasInit)(void);
+ int (*PacketAliasIn)(char *, int);
+ int (*PacketAliasOut)(char *, int);
+ struct alias_link *(*PacketAliasRedirectAddr)(struct in_addr, struct in_addr);
+ struct alias_link *(*PacketAliasRedirectPort)
+ (struct in_addr, u_short, struct in_addr, u_short,
+ struct in_addr, u_short, u_char);
+ int (*PacketAliasSaveFragment)(char *);
+ void (*PacketAliasSetAddress)(struct in_addr);
+ unsigned (*PacketAliasSetMode)(unsigned, unsigned);
+ void (*PacketAliasFragmentIn)(char *, char *);
+};
+
+extern int loadAliasHandlers(struct aliasHandlers *);
+extern void unloadAliasHandlers(void);
diff --git a/usr.sbin/ppp/log.c b/usr.sbin/ppp/log.c
new file mode 100644
index 00000000000..b6a52c61d5b
--- /dev/null
+++ b/usr.sbin/ppp/log.c
@@ -0,0 +1,222 @@
+/*
+ * $Id: log.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "loadalias.h"
+#include "defs.h"
+#include "vars.h"
+
+static const char *LogNames[] = {
+ "Async",
+ "Carrier",
+ "CCP",
+ "Chat",
+ "Command",
+ "Connect",
+ "Debug",
+ "HDLC",
+ "ID0",
+ "IPCP",
+ "LCP",
+ "Link",
+ "LQM",
+ "Phase",
+ "TCP/IP",
+ "Tun",
+ "Warning",
+ "Error",
+ "Alert"
+};
+
+#define MSK(n) (1<<((n)-1))
+
+static u_long LogMask = MSK(LogLINK) | MSK(LogCARRIER) | MSK(LogPHASE);
+static u_long LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
+static int LogTunno = -1;
+
+static int
+syslogLevel(int lev)
+{
+ switch (lev) {
+ case LogDEBUG:return LOG_DEBUG;
+ case LogWARN:
+ return LOG_WARNING;
+ case LogERROR:
+ return LOG_ERR;
+ case LogALERT:
+ return LOG_ALERT;
+ }
+ return lev >= LogMIN && lev <= LogMAX ? LOG_INFO : 0;
+}
+
+const char *
+LogName(int id)
+{
+ return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1];
+}
+
+void
+LogKeep(int id)
+{
+ if (id >= LogMIN && id <= LogMAXCONF)
+ LogMask |= MSK(id);
+}
+
+void
+LogKeepLocal(int id)
+{
+ if (id >= LogMIN && id <= LogMAXCONF)
+ LogMaskLocal |= MSK(id);
+}
+
+void
+LogDiscard(int id)
+{
+ if (id >= LogMIN && id <= LogMAXCONF)
+ LogMask &= ~MSK(id);
+}
+
+void
+LogDiscardLocal(int id)
+{
+ if (id >= LogMIN && id <= LogMAXCONF)
+ LogMaskLocal &= ~MSK(id);
+}
+
+void
+LogDiscardAll()
+{
+ LogMask = 0;
+}
+
+void
+LogDiscardAllLocal()
+{
+ LogMaskLocal = 0;
+}
+
+int
+LogIsKept(int id)
+{
+ if (id < LogMIN || id > LogMAX)
+ return 0;
+ if (id > LogMAXCONF)
+ return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG;
+
+ return ((LogMaskLocal & MSK(id)) ? LOG_KEPT_LOCAL : 0) |
+ ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0);
+}
+
+void
+LogOpen(const char *Name)
+{
+ openlog(Name, LOG_PID, LOG_DAEMON);
+}
+
+void
+LogSetTun(int tunno)
+{
+ LogTunno = tunno;
+}
+
+void
+LogClose()
+{
+ closelog();
+ LogTunno = -1;
+}
+
+void
+LogPrintf(int lev, const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (LogIsKept(lev)) {
+ static char nfmt[200];
+
+ if ((LogIsKept(lev) & LOG_KEPT_LOCAL) && VarTerm) {
+ if ((LogIsKept(LogTUN) & LOG_KEPT_LOCAL) && LogTunno != -1)
+ snprintf(nfmt, sizeof nfmt, "tun%d: %s: %s",
+ LogTunno, LogName(lev), fmt);
+ else
+ snprintf(nfmt, sizeof nfmt, "%s: %s", LogName(lev), fmt);
+ vfprintf(VarTerm, nfmt, ap);
+ fflush(VarTerm);
+ }
+
+ if ((LogIsKept(lev) & LOG_KEPT_SYSLOG) && (lev != LogWARN || !VarTerm)) {
+ if ((LogIsKept(LogTUN) & LOG_KEPT_SYSLOG) && LogTunno != -1)
+ snprintf(nfmt, sizeof nfmt, "tun%d: %s: %s",
+ LogTunno, LogName(lev), fmt);
+ else
+ snprintf(nfmt, sizeof nfmt, "%s: %s", LogName(lev), fmt);
+ vsyslog(syslogLevel(lev), nfmt, ap);
+ }
+ }
+ va_end(ap);
+}
+
+void
+LogDumpBp(int lev, const char *hdr, const struct mbuf * bp)
+{
+ if (LogIsKept(lev)) {
+ char buf[50];
+ char *b;
+ u_char *ptr;
+ int f;
+
+ if (hdr && *hdr)
+ LogPrintf(lev, "%s\n", hdr);
+
+ b = buf;
+ do {
+ f = bp->cnt;
+ ptr = MBUF_CTOP(bp);
+ while (f--) {
+ sprintf(b, " %02x", (int) *ptr++);
+ b += 3;
+ if (b == buf + sizeof buf - 2) {
+ strcpy(b, "\n");
+ LogPrintf(lev, buf);
+ b = buf;
+ }
+ }
+ } while ((bp = bp->next) != NULL);
+
+ if (b > buf) {
+ strcpy(b, "\n");
+ LogPrintf(lev, buf);
+ }
+ }
+}
+
+void
+LogDumpBuff(int lev, const char *hdr, const u_char * ptr, int n)
+{
+ if (LogIsKept(lev)) {
+ char buf[50];
+ char *b;
+
+ if (hdr && *hdr)
+ LogPrintf(lev, "%s\n", hdr);
+ while (n > 0) {
+ b = buf;
+ for (b = buf; b != buf + sizeof(buf) - 2 && n--; b += 3)
+ sprintf(b, " %02x", (int) *ptr++);
+ strcpy(b, "\n");
+ LogPrintf(lev, buf);
+ }
+ }
+}
diff --git a/usr.sbin/ppp/log.h b/usr.sbin/ppp/log.h
new file mode 100644
index 00000000000..d37ef9e7cab
--- /dev/null
+++ b/usr.sbin/ppp/log.h
@@ -0,0 +1,44 @@
+/*
+ * $Id: log.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ */
+
+#define LogMIN (1)
+#define LogASYNC (1) /* syslog(LOG_INFO, ....) */
+#define LogCARRIER (2)
+#define LogCCP (3)
+#define LogCHAT (4)
+#define LogCOMMAND (5)
+#define LogCONNECT (6)
+#define LogDEBUG (7) /* syslog(LOG_DEBUG, ....) */
+#define LogHDLC (8)
+#define LogID0 (9)
+#define LogIPCP (10)
+#define LogLCP (11)
+#define LogLINK (12)
+#define LogLQM (13)
+#define LogPHASE (14)
+#define LogTCPIP (15)
+#define LogTUN (16) /* If set, tun%d is output with each message */
+#define LogMAXCONF (16)
+#define LogWARN (17) /* Sent to VarTerm else syslog(LOG_WARNING, ) */
+#define LogERROR (18) /* syslog(LOG_ERR, ....), + sent to VarTerm */
+#define LogALERT (19) /* syslog(LOG_ALERT, ....) */
+#define LogMAX (19)
+
+/* The first int arg for all of the following is one of the above values */
+extern const char *LogName(int);
+extern void LogKeep(int);
+extern void LogKeepLocal(int);
+extern void LogDiscard(int);
+extern void LogDiscardLocal(int);
+extern void LogDiscardAll(void);
+extern void LogDiscardAllLocal(void);
+#define LOG_KEPT_SYSLOG (1) /* Results of LogIsKept() */
+#define LOG_KEPT_LOCAL (2) /* Results of LogIsKept() */
+extern int LogIsKept(int);
+extern void LogOpen(const char *);
+extern void LogSetTun(int);
+extern void LogClose(void);
+extern void LogPrintf(int, const char *,...);
+extern void LogDumpBp(int, const char *, const struct mbuf *);
+extern void LogDumpBuff(int, const char *, const u_char *, int);
diff --git a/usr.sbin/ppp/lqr.c b/usr.sbin/ppp/lqr.c
new file mode 100644
index 00000000000..df3bea3d898
--- /dev/null
+++ b/usr.sbin/ppp/lqr.c
@@ -0,0 +1,270 @@
+/*
+ * PPP Line Quality Monitoring (LQM) Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lqr.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * o LQR based on RFC1333
+ *
+ * TODO:
+ * o LQM policy
+ * o Allow user to configure LQM method and interval.
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcpproto.h"
+#include "lqr.h"
+#include "hdlc.h"
+#include "lcp.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "main.h"
+
+struct pppTimer LqrTimer;
+
+static u_long lastpeerin = (u_long) - 1;
+
+static int lqmmethod;
+static int echoseq;
+static int gotseq;
+static int lqrsendcnt;
+
+struct echolqr {
+ u_long magic;
+ u_long signature;
+ u_long sequence;
+};
+
+#define SIGNATURE 0x594e4f54
+
+static void
+SendEchoReq(void)
+{
+ struct fsm *fp = &LcpFsm;
+ struct echolqr *lqr, lqrdata;
+
+ if (fp->state == ST_OPENED) {
+ lqr = &lqrdata;
+ lqr->magic = htonl(LcpInfo.want_magic);
+ lqr->signature = htonl(SIGNATURE);
+ LogPrintf(LogLQM, "Send echo LQR [%d]\n", echoseq);
+ lqr->sequence = htonl(echoseq++);
+ FsmOutput(fp, CODE_ECHOREQ, fp->reqid++,
+ (u_char *) lqr, sizeof(struct echolqr));
+ }
+}
+
+void
+RecvEchoLqr(struct mbuf * bp)
+{
+ struct echolqr *lqr;
+ u_long seq;
+
+ if (plength(bp) == sizeof(struct echolqr)) {
+ lqr = (struct echolqr *) MBUF_CTOP(bp);
+ if (htonl(lqr->signature) == SIGNATURE) {
+ seq = ntohl(lqr->sequence);
+ LogPrintf(LogLQM, "Got echo LQR [%d]\n", ntohl(lqr->sequence));
+ gotseq = seq;
+ }
+ }
+}
+
+void
+LqrChangeOrder(struct lqrdata * src, struct lqrdata * dst)
+{
+ u_long *sp, *dp;
+ int n;
+
+ sp = (u_long *) src;
+ dp = (u_long *) dst;
+ for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_long); n++)
+ *dp++ = ntohl(*sp++);
+}
+
+static void
+SendLqrReport(void *v)
+{
+ struct mbuf *bp;
+
+ StopTimer(&LqrTimer);
+
+ if (lqmmethod & LQM_LQR) {
+ if (lqrsendcnt > 5) {
+
+ /*
+ * XXX: Should implement LQM strategy
+ */
+ LogPrintf(LogPHASE, "** 1 Too many ECHO packets are lost. **\n");
+ lqmmethod = 0; /* Prevent rcursion via LcpClose() */
+ reconnect(RECON_TRUE);
+ LcpClose();
+ } else {
+ bp = mballoc(sizeof(struct lqrdata), MB_LQR);
+ HdlcOutput(PRI_LINK, PROTO_LQR, bp);
+ lqrsendcnt++;
+ }
+ } else if (lqmmethod & LQM_ECHO) {
+ if (echoseq - gotseq > 5) {
+ LogPrintf(LogPHASE, "** 2 Too many ECHO packets are lost. **\n");
+ lqmmethod = 0; /* Prevent rcursion via LcpClose() */
+ reconnect(RECON_TRUE);
+ LcpClose();
+ } else
+ SendEchoReq();
+ }
+ if (lqmmethod && Enabled(ConfLqr))
+ StartTimer(&LqrTimer);
+}
+
+void
+LqrInput(struct mbuf * bp)
+{
+ int len;
+ u_char *cp;
+ struct lqrdata *lqr;
+
+ len = plength(bp);
+ if (len != sizeof(struct lqrdata)) {
+ pfree(bp);
+ return;
+ }
+ if (!Acceptable(ConfLqr)) {
+ bp->offset -= 2;
+ bp->cnt += 2;
+
+ cp = MBUF_CTOP(bp);
+ LcpSendProtoRej(cp, bp->cnt);
+ } else {
+ cp = MBUF_CTOP(bp);
+ lqr = (struct lqrdata *) cp;
+ if (ntohl(lqr->MagicNumber) != LcpInfo.his_magic) {
+ LogPrintf(LogERROR, "LqrInput: magic %x != expecting %x\n",
+ ntohl(lqr->MagicNumber), LcpInfo.his_magic);
+ pfree(bp);
+ return;
+ }
+
+ /*
+ * Convert byte order and save into our strage
+ */
+ LqrChangeOrder(lqr, &HisLqrData);
+ LqrDump("LqrInput", &HisLqrData);
+ lqrsendcnt = 0; /* we have received LQR from peer */
+
+ /*
+ * Generate LQR responce to peer, if i) We are not running LQR timer. ii)
+ * Two successive LQR's PeerInLQRs are same.
+ */
+ if (LqrTimer.load == 0 || lastpeerin == HisLqrData.PeerInLQRs) {
+ lqmmethod |= LQM_LQR;
+ SendLqrReport(0);
+ }
+ lastpeerin = HisLqrData.PeerInLQRs;
+ }
+ pfree(bp);
+}
+
+/*
+ * When LCP is reached to opened state, We'll start LQM activity.
+ */
+void
+StartLqm()
+{
+ struct lcpstate *lcp = &LcpInfo;
+ int period;
+
+ lqrsendcnt = 0; /* start waiting all over for ECHOs */
+ echoseq = 0;
+ gotseq = 0;
+
+ lqmmethod = LQM_ECHO;
+ if (Enabled(ConfLqr))
+ lqmmethod |= LQM_LQR;
+ StopTimer(&LqrTimer);
+ LogPrintf(LogLQM, "LQM method = %d\n", lqmmethod);
+
+ if (lcp->his_lqrperiod || lcp->want_lqrperiod) {
+
+ /*
+ * We need to run timer. Let's figure out period.
+ */
+ period = lcp->his_lqrperiod ? lcp->his_lqrperiod : lcp->want_lqrperiod;
+ StopTimer(&LqrTimer);
+ LqrTimer.state = TIMER_STOPPED;
+ LqrTimer.load = period * SECTICKS / 100;
+ LqrTimer.func = SendLqrReport;
+ SendLqrReport(0);
+ StartTimer(&LqrTimer);
+ LogPrintf(LogLQM, "Will send LQR every %d.%d secs\n",
+ period / 100, period % 100);
+ } else {
+ LogPrintf(LogLQM, "LQR is not activated.\n");
+ }
+}
+
+void
+StopLqrTimer()
+{
+ StopTimer(&LqrTimer);
+}
+
+void
+StopLqr(int method)
+{
+ LogPrintf(LogLQM, "StopLqr method = %x\n", method);
+
+ if (method == LQM_LQR)
+ LogPrintf(LogLQM, "Stop sending LQR, Use LCP ECHO instead.\n");
+ if (method == LQM_ECHO)
+ LogPrintf(LogLQM, "Stop sending LCP ECHO.\n");
+ lqmmethod &= ~method;
+ if (lqmmethod)
+ SendLqrReport(0);
+ else
+ StopTimer(&LqrTimer);
+}
+
+void
+LqrDump(const char *message, const struct lqrdata * lqr)
+{
+ if (LogIsKept(LogLQM)) {
+ LogPrintf(LogLQM, "%s:\n", message);
+ LogPrintf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n",
+ lqr->MagicNumber, lqr->LastOutLQRs);
+ LogPrintf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n",
+ lqr->LastOutPackets, lqr->LastOutOctets);
+ LogPrintf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n",
+ lqr->PeerInLQRs, lqr->PeerInPackets);
+ LogPrintf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n",
+ lqr->PeerInDiscards, lqr->PeerInErrors);
+ LogPrintf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n",
+ lqr->PeerInOctets, lqr->PeerOutLQRs);
+ LogPrintf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n",
+ lqr->PeerOutPackets, lqr->PeerOutOctets);
+ }
+}
diff --git a/usr.sbin/ppp/lqr.h b/usr.sbin/ppp/lqr.h
new file mode 100644
index 00000000000..ee378abc154
--- /dev/null
+++ b/usr.sbin/ppp/lqr.h
@@ -0,0 +1,64 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lqr.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ */
+
+/*
+ * Structure of LQR packet defined in RFC1333
+ */
+struct lqrdata {
+ u_long MagicNumber;
+ u_long LastOutLQRs;
+ u_long LastOutPackets;
+ u_long LastOutOctets;
+ u_long PeerInLQRs;
+ u_long PeerInPackets;
+ u_long PeerInDiscards;
+ u_long PeerInErrors;
+ u_long PeerInOctets;
+ u_long PeerOutLQRs;
+ u_long PeerOutPackets;
+ u_long PeerOutOctets;
+};
+
+struct lqrsave {
+ u_long SaveInLQRs;
+ u_long SaveInPackets;
+ u_long SaveInDiscards;
+ u_long SaveInErrors;
+ u_long SaveInOctets;
+};
+
+struct lqrdata MyLqrData, HisLqrData;
+struct lqrsave HisLqrSave;
+
+/*
+ * We support LQR and ECHO as LQM method
+ */
+#define LQM_LQR 1
+#define LQM_ECHO 2
+
+extern void LqrDump(const char *, const struct lqrdata *);
+extern void LqrChangeOrder(struct lqrdata *, struct lqrdata *);
+extern void StartLqm(void);
+extern void StopLqr(int);
+extern void StopLqrTimer(void);
+extern void RecvEchoLqr(struct mbuf *);
+extern void LqrInput(struct mbuf *);
diff --git a/usr.sbin/ppp/main.c b/usr.sbin/ppp/main.c
new file mode 100644
index 00000000000..daa6565fb1b
--- /dev/null
+++ b/usr.sbin/ppp/main.c
@@ -0,0 +1,1091 @@
+/*
+ * User Process PPP
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: main.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ * o Add commands for traffic summary, version display, etc.
+ * o Add signal handler for misc controls.
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#ifdef __FreeBSD__
+#include <net/if_var.h>
+#endif
+#include <net/if_tun.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "id.h"
+#include "timer.h"
+#include "fsm.h"
+#include "modem.h"
+#include "os.h"
+#include "hdlc.h"
+#include "ccp.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "auth.h"
+#include "filter.h"
+#include "systems.h"
+#include "ip.h"
+#include "sig.h"
+#include "server.h"
+#include "lcpproto.h"
+#include "main.h"
+#include "vjcomp.h"
+#include "async.h"
+#include "pathnames.h"
+#include "tun.h"
+#include "route.h"
+
+#ifndef O_NONBLOCK
+#ifdef O_NDELAY
+#define O_NONBLOCK O_NDELAY
+#endif
+#endif
+
+int TermMode = 0;
+int tunno = 0;
+
+static struct termios oldtio; /* Original tty mode */
+static struct termios comtio; /* Command level tty mode */
+static pid_t BGPid = 0;
+static char pid_filename[MAXPATHLEN];
+static int dial_up;
+
+static void DoLoop(void);
+static void TerminalStop(int);
+static const char *ex_desc(int);
+
+static void
+TtyInit(int DontWantInt)
+{
+ struct termios newtio;
+ int stat;
+
+ stat = fcntl(0, F_GETFL, 0);
+ if (stat > 0) {
+ stat |= O_NONBLOCK;
+ (void) fcntl(0, F_SETFL, stat);
+ }
+ newtio = oldtio;
+ newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
+ newtio.c_iflag = 0;
+ newtio.c_oflag &= ~OPOST;
+ newtio.c_cc[VEOF] = _POSIX_VDISABLE;
+ if (DontWantInt)
+ newtio.c_cc[VINTR] = _POSIX_VDISABLE;
+ newtio.c_cc[VMIN] = 1;
+ newtio.c_cc[VTIME] = 0;
+ newtio.c_cflag |= CS8;
+ tcsetattr(0, TCSADRAIN, &newtio);
+ comtio = newtio;
+}
+
+/*
+ * Set tty into command mode. We allow canonical input and echo processing.
+ */
+void
+TtyCommandMode(int prompt)
+{
+ struct termios newtio;
+ int stat;
+
+ if (!(mode & MODE_INTER))
+ return;
+ tcgetattr(0, &newtio);
+ newtio.c_lflag |= (ECHO | ISIG | ICANON);
+ newtio.c_iflag = oldtio.c_iflag;
+ newtio.c_oflag |= OPOST;
+ tcsetattr(0, TCSADRAIN, &newtio);
+ stat = fcntl(0, F_GETFL, 0);
+ if (stat > 0) {
+ stat |= O_NONBLOCK;
+ (void) fcntl(0, F_SETFL, stat);
+ }
+ TermMode = 0;
+ if (prompt)
+ Prompt();
+}
+
+/*
+ * Set tty into terminal mode which is used while we invoke term command.
+ */
+void
+TtyTermMode()
+{
+ int stat;
+
+ tcsetattr(0, TCSADRAIN, &comtio);
+ stat = fcntl(0, F_GETFL, 0);
+ if (stat > 0) {
+ stat &= ~O_NONBLOCK;
+ (void) fcntl(0, F_SETFL, stat);
+ }
+ TermMode = 1;
+}
+
+void
+TtyOldMode()
+{
+ int stat;
+
+ stat = fcntl(0, F_GETFL, 0);
+ if (stat > 0) {
+ stat &= ~O_NONBLOCK;
+ (void) fcntl(0, F_SETFL, stat);
+ }
+ tcsetattr(0, TCSANOW, &oldtio);
+}
+
+void
+Cleanup(int excode)
+{
+ DropClient();
+ ServerClose();
+ OsInterfaceDown(1);
+ HangupModem(1);
+ nointr_sleep(1);
+ DeleteIfRoutes(1);
+ ID0unlink(pid_filename);
+ if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
+ char c = EX_ERRDEAD;
+
+ if (write(BGFiledes[1], &c, 1) == 1)
+ LogPrintf(LogPHASE, "Parent notified of failure.\n");
+ else
+ LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
+ close(BGFiledes[1]);
+ }
+ LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
+ TtyOldMode();
+ LogClose();
+
+ exit(excode);
+}
+
+static void
+CloseConnection(int signo)
+{
+ /* NOTE, these are manual, we've done a setsid() */
+ pending_signal(SIGINT, SIG_IGN);
+ LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
+ reconnectState = RECON_FALSE;
+ reconnectCount = 0;
+ DownConnection();
+ dial_up = 0;
+ pending_signal(SIGINT, CloseConnection);
+}
+
+static void
+CloseSession(int signo)
+{
+ if (BGPid) {
+ kill(BGPid, SIGINT);
+ exit(EX_TERM);
+ }
+ LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
+ reconnect(RECON_FALSE);
+ LcpClose();
+ Cleanup(EX_TERM);
+}
+
+static void
+TerminalCont(int signo)
+{
+ pending_signal(SIGCONT, SIG_DFL);
+ pending_signal(SIGTSTP, TerminalStop);
+ TtyCommandMode(getpgrp() == tcgetpgrp(0));
+}
+
+static void
+TerminalStop(int signo)
+{
+ pending_signal(SIGCONT, TerminalCont);
+ TtyOldMode();
+ pending_signal(SIGTSTP, SIG_DFL);
+ kill(getpid(), signo);
+}
+
+static void
+SetUpServer(int signo)
+{
+ int res;
+
+ VarHaveLocalAuthKey = 0;
+ LocalAuthInit();
+ if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
+ LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
+ res, SERVER_PORT + tunno);
+}
+
+static void
+BringDownServer(int signo)
+{
+ VarHaveLocalAuthKey = 0;
+ LocalAuthInit();
+ ServerClose();
+}
+
+static const char *
+ex_desc(int ex)
+{
+ static char num[12];
+ static const char *desc[] = {
+ "normal", "start", "sock", "modem", "dial", "dead", "done",
+ "reboot", "errdead", "hangup", "term", "nodial", "nologin"
+ };
+
+ if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc))
+ return desc[ex];
+ snprintf(num, sizeof num, "%d", ex);
+ return num;
+}
+
+static void
+Usage(void)
+{
+ fprintf(stderr,
+ "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]"
+#ifndef NOALIAS
+ " [ -alias ]"
+#endif
+ " [system]\n");
+ exit(EX_START);
+}
+
+static char *
+ProcessArgs(int argc, char **argv)
+{
+ int optc;
+ char *cp;
+
+ optc = 0;
+ mode = MODE_INTER;
+ while (argc > 0 && **argv == '-') {
+ cp = *argv + 1;
+ if (strcmp(cp, "auto") == 0) {
+ mode |= MODE_AUTO;
+ mode &= ~MODE_INTER;
+ } else if (strcmp(cp, "background") == 0) {
+ mode |= MODE_BACKGROUND;
+ mode &= ~MODE_INTER;
+ } else if (strcmp(cp, "direct") == 0) {
+ mode |= MODE_DIRECT;
+ mode &= ~MODE_INTER;
+ } else if (strcmp(cp, "dedicated") == 0) {
+ mode |= MODE_DEDICATED;
+ mode &= ~MODE_INTER;
+ } else if (strcmp(cp, "ddial") == 0) {
+ mode |= MODE_DDIAL;
+ mode &= ~MODE_INTER;
+#ifndef NOALIAS
+ } else if (strcmp(cp, "alias") == 0) {
+ if (loadAliasHandlers(&VarAliasHandlers) == 0)
+ mode |= MODE_ALIAS;
+ else
+ LogPrintf(LogWARN, "Cannot load alias library\n");
+ optc--; /* this option isn't exclusive */
+#endif
+ } else
+ Usage();
+ optc++;
+ argv++;
+ argc--;
+ }
+ if (argc > 1) {
+ fprintf(stderr, "specify only one system label.\n");
+ exit(EX_START);
+ }
+
+ if (optc > 1) {
+ fprintf(stderr, "specify only one mode.\n");
+ exit(EX_START);
+ }
+
+ return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */
+}
+
+static void
+Greetings(void)
+{
+ if (VarTerm) {
+ fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
+ fflush(VarTerm);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ FILE *lockfile;
+ char *name, *label;
+
+ VarTerm = 0;
+ name = strrchr(argv[0], '/');
+ LogOpen(name ? name + 1 : argv[0]);
+
+ argc--;
+ argv++;
+ label = ProcessArgs(argc, argv);
+ if (!(mode & MODE_DIRECT))
+ VarTerm = stdout;
+
+ ID0init();
+ if (ID0realuid() != 0) {
+ char conf[200], *ptr;
+
+ snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE);
+ do {
+ if (!access(conf, W_OK)) {
+ LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf);
+ return -1;
+ }
+ ptr = conf + strlen(conf)-2;
+ while (ptr > conf && *ptr != '/')
+ *ptr-- = '\0';
+ } while (ptr >= conf);
+ }
+
+ if (!ValidSystem(label)) {
+ fprintf(stderr, "You may not use ppp in this mode with this label\n");
+ if (mode & MODE_DIRECT) {
+ const char *l;
+ l = label ? label : "default";
+ VarTerm = 0;
+ LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l);
+ }
+ LogClose();
+ return 1;
+ }
+
+ if (!GetShortHost())
+ return 1;
+ Greetings();
+ IpcpDefAddress();
+
+ if (mode & MODE_INTER)
+ VarLocalAuth = LOCAL_AUTH;
+
+ if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
+ fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
+
+ if (OpenTunnel(&tunno) < 0) {
+ LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno));
+ return EX_START;
+ }
+ if (mode & MODE_INTER) {
+ fprintf(VarTerm, "Interactive mode\n");
+ netfd = STDOUT_FILENO;
+ } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED))
+ if (label == NULL) {
+ if (VarTerm)
+ fprintf(VarTerm, "Destination system must be specified in"
+ " auto, background or ddial mode.\n");
+ return EX_START;
+ }
+
+ tcgetattr(0, &oldtio); /* Save original tty mode */
+
+ pending_signal(SIGHUP, CloseSession);
+ pending_signal(SIGTERM, CloseSession);
+ pending_signal(SIGINT, CloseConnection);
+ pending_signal(SIGQUIT, CloseSession);
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_IGN);
+#endif
+#ifdef SIGALRM
+ pending_signal(SIGALRM, SIG_IGN);
+#endif
+ if (mode & MODE_INTER) {
+#ifdef SIGTSTP
+ pending_signal(SIGTSTP, TerminalStop);
+#endif
+#ifdef SIGTTIN
+ pending_signal(SIGTTIN, TerminalStop);
+#endif
+#ifdef SIGTTOU
+ pending_signal(SIGTTOU, SIG_IGN);
+#endif
+ }
+ if (!(mode & MODE_INTER)) {
+#ifdef SIGUSR1
+ pending_signal(SIGUSR1, SetUpServer);
+#endif
+#ifdef SIGUSR2
+ pending_signal(SIGUSR2, BringDownServer);
+#endif
+ }
+
+ if (label) {
+ if (SelectSystem(label, CONFFILE) < 0) {
+ LogPrintf(LogWARN, "Destination system %s not found in conf file.\n",
+ GetLabel());
+ Cleanup(EX_START);
+ }
+ /*
+ * We don't SetLabel() 'till now in case SelectSystem() has an
+ * embeded load "otherlabel" command.
+ */
+ SetLabel(label);
+ if (mode & MODE_OUTGOING_DAEMON &&
+ DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
+ LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for"
+ " auto, background or ddial mode.\n", label);
+ Cleanup(EX_START);
+ }
+ }
+
+ if (mode & MODE_DAEMON) {
+ if (mode & MODE_BACKGROUND) {
+ if (pipe(BGFiledes)) {
+ LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
+ Cleanup(EX_SOCK);
+ }
+ }
+
+ if (!(mode & MODE_DIRECT)) {
+ pid_t bgpid;
+
+ bgpid = fork();
+ if (bgpid == -1) {
+ LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
+ Cleanup(EX_SOCK);
+ }
+ if (bgpid) {
+ char c = EX_NORMAL;
+
+ if (mode & MODE_BACKGROUND) {
+ /* Wait for our child to close its pipe before we exit. */
+ BGPid = bgpid;
+ close(BGFiledes[1]);
+ if (read(BGFiledes[0], &c, 1) != 1) {
+ fprintf(VarTerm, "Child exit, no status.\n");
+ LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
+ } else if (c == EX_NORMAL) {
+ fprintf(VarTerm, "PPP enabled.\n");
+ LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
+ } else {
+ fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
+ LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
+ ex_desc((int) c));
+ }
+ close(BGFiledes[0]);
+ }
+ return c;
+ } else if (mode & MODE_BACKGROUND)
+ close(BGFiledes[0]);
+ }
+
+ VarTerm = 0; /* We know it's currently stdout */
+ close(1);
+ close(2);
+
+ if (mode & MODE_DIRECT)
+ TtyInit(1);
+ else if (mode & MODE_DAEMON) {
+ setsid();
+ close(0);
+ }
+ } else {
+ TtyInit(0);
+ TtyCommandMode(1);
+ }
+
+ snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid",
+ _PATH_VARRUN, tunno);
+ lockfile = ID0fopen(pid_filename, "w");
+ if (lockfile != NULL) {
+ fprintf(lockfile, "%d\n", (int) getpid());
+ fclose(lockfile);
+ } else
+ LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
+ pid_filename, strerror(errno));
+
+ LogPrintf(LogPHASE, "PPP Started.\n");
+
+
+ do
+ DoLoop();
+ while (mode & MODE_DEDICATED);
+
+ Cleanup(EX_DONE);
+ return 0;
+}
+
+/*
+ * Turn into packet mode, where we speak PPP.
+ */
+void
+PacketMode()
+{
+ if (RawModem() < 0) {
+ LogPrintf(LogWARN, "PacketMode: Not connected.\n");
+ return;
+ }
+ AsyncInit();
+ VjInit(15);
+ LcpInit();
+ IpcpInit();
+ CcpInit();
+ LcpUp();
+
+ LcpOpen(VarOpenMode);
+ if (mode & MODE_INTER)
+ TtyCommandMode(1);
+ if (VarTerm) {
+ fprintf(VarTerm, "Packet mode.\n");
+ aft_cmd = 1;
+ }
+}
+
+static void
+ShowHelp(void)
+{
+ fprintf(stderr, "The following commands are available:\r\n");
+ fprintf(stderr, " ~p\tEnter Packet mode\r\n");
+ fprintf(stderr, " ~-\tDecrease log level\r\n");
+ fprintf(stderr, " ~+\tIncrease log level\r\n");
+ fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
+ fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
+ fprintf(stderr, " ~.\tTerminate program\r\n");
+ fprintf(stderr, " ~?\tThis help\r\n");
+}
+
+static void
+ReadTty(void)
+{
+ int n;
+ char ch;
+ static int ttystate;
+ char linebuff[LINE_LEN];
+
+ LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
+ TermMode, netfd, mode);
+ if (!TermMode) {
+ n = read(netfd, linebuff, sizeof(linebuff) - 1);
+ if (n > 0) {
+ aft_cmd = 1;
+ if (linebuff[n-1] == '\n')
+ linebuff[--n] = '\0';
+ if (n)
+ DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client");
+ Prompt();
+ } else if (n <= 0)
+ DropClient();
+ return;
+ }
+
+ /*
+ * We are in terminal mode, decode special sequences
+ */
+ n = read(fileno(VarTerm), &ch, 1);
+ LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
+
+ if (n > 0) {
+ switch (ttystate) {
+ case 0:
+ if (ch == '~')
+ ttystate++;
+ else
+ write(modem, &ch, n);
+ break;
+ case 1:
+ switch (ch) {
+ case '?':
+ ShowHelp();
+ break;
+ case 'p':
+
+ /*
+ * XXX: Should check carrier.
+ */
+ if (LcpFsm.state <= ST_CLOSED) {
+ VarOpenMode = OPEN_ACTIVE;
+ PacketMode();
+ }
+ break;
+ case '.':
+ TermMode = 1;
+ aft_cmd = 1;
+ TtyCommandMode(1);
+ break;
+ case 't':
+ if (LogIsKept(LogDEBUG)) {
+ ShowTimers();
+ break;
+ }
+ case 'm':
+ if (LogIsKept(LogDEBUG)) {
+ ShowMemMap(NULL);
+ break;
+ }
+ default:
+ if (write(modem, &ch, n) < 0)
+ LogPrintf(LogERROR, "error writing to modem.\n");
+ break;
+ }
+ ttystate = 0;
+ break;
+ }
+ }
+}
+
+
+/*
+ * Here, we'll try to detect HDLC frame
+ */
+
+static const char *FrameHeaders[] = {
+ "\176\377\003\300\041",
+ "\176\377\175\043\300\041",
+ "\176\177\175\043\100\041",
+ "\176\175\337\175\043\300\041",
+ "\176\175\137\175\043\100\041",
+ NULL,
+};
+
+static const u_char *
+HdlcDetect(u_char * cp, int n)
+{
+ const char *ptr, *fp, **hp;
+
+ cp[n] = '\0'; /* be sure to null terminated */
+ ptr = NULL;
+ for (hp = FrameHeaders; *hp; hp++) {
+ fp = *hp;
+ if (DEV_IS_SYNC)
+ fp++;
+ ptr = strstr((char *) cp, fp);
+ if (ptr)
+ break;
+ }
+ return ((const u_char *) ptr);
+}
+
+static struct pppTimer RedialTimer;
+
+static void
+RedialTimeout(void *v)
+{
+ StopTimer(&RedialTimer);
+ LogPrintf(LogPHASE, "Redialing timer expired.\n");
+}
+
+static void
+StartRedialTimer(int Timeout)
+{
+ StopTimer(&RedialTimer);
+
+ if (Timeout) {
+ RedialTimer.state = TIMER_STOPPED;
+
+ if (Timeout > 0)
+ RedialTimer.load = Timeout * SECTICKS;
+ else
+ RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
+
+ LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
+ RedialTimer.load / SECTICKS);
+
+ RedialTimer.func = RedialTimeout;
+ StartTimer(&RedialTimer);
+ }
+}
+
+
+static void
+DoLoop(void)
+{
+ fd_set rfds, wfds, efds;
+ int pri, i, n, wfd, nfds;
+ struct sockaddr_in hisaddr;
+ struct timeval timeout, *tp;
+ int ssize = sizeof(hisaddr);
+ const u_char *cp;
+ int tries;
+ int qlen;
+ int res;
+ pid_t pgroup;
+ struct tun_data tun;
+#define rbuff tun.data
+
+ pgroup = getpgrp();
+
+ if (mode & MODE_DIRECT) {
+ LogPrintf(LogDEBUG, "Opening modem\n");
+ if (OpenModem() < 0)
+ return;
+ LogPrintf(LogPHASE, "Packet mode enabled\n");
+ PacketMode();
+ } else if (mode & MODE_DEDICATED) {
+ if (modem < 0)
+ while (OpenModem() < 0)
+ nointr_sleep(VarReconnectTimer);
+ }
+ fflush(VarTerm);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ reconnectState = RECON_UNKNOWN;
+
+ if (mode & MODE_BACKGROUND)
+ dial_up = 1; /* Bring the line up */
+ else
+ dial_up = 0; /* XXXX */
+ tries = 0;
+ for (;;) {
+ nfds = 0;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+
+ /*
+ * If the link is down and we're in DDIAL mode, bring it back up.
+ */
+ if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
+ dial_up = 1;
+
+ /*
+ * If we lost carrier and want to re-establish the connection due to the
+ * "set reconnect" value, we'd better bring the line back up.
+ */
+ if (LcpFsm.state <= ST_CLOSED) {
+ if (!dial_up && reconnectState == RECON_TRUE) {
+ if (++reconnectCount <= VarReconnectTries) {
+ LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
+ reconnectCount, VarReconnectTries);
+ StartRedialTimer(VarReconnectTimer);
+ dial_up = 1;
+ } else {
+ if (VarReconnectTries)
+ LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
+ VarReconnectTries);
+ reconnectCount = 0;
+ if (mode & MODE_BACKGROUND)
+ Cleanup(EX_DEAD);
+ }
+ reconnectState = RECON_ENVOKED;
+ } else if (mode & MODE_DEDICATED)
+ if (VarOpenMode == OPEN_ACTIVE)
+ PacketMode();
+ }
+
+ /*
+ * If Ip packet for output is enqueued and require dial up, Just do it!
+ */
+ if (dial_up && RedialTimer.state != TIMER_RUNNING) {
+ LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
+ if (OpenModem() < 0) {
+ tries++;
+ if (!(mode & MODE_DDIAL) && VarDialTries)
+ LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
+ tries, VarDialTries);
+ else
+ LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
+
+ if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
+ if (mode & MODE_BACKGROUND)
+ Cleanup(EX_DIAL); /* Can't get the modem */
+ dial_up = 0;
+ reconnectState = RECON_UNKNOWN;
+ reconnectCount = 0;
+ tries = 0;
+ } else
+ StartRedialTimer(VarRedialTimeout);
+ } else {
+ tries++; /* Tries are per number, not per list of
+ * numbers. */
+ if (!(mode & MODE_DDIAL) && VarDialTries)
+ LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
+ else
+ LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
+
+ if ((res = DialModem()) == EX_DONE) {
+ nointr_sleep(1); /* little pause to allow peer starts */
+ ModemTimeout(NULL);
+ PacketMode();
+ dial_up = 0;
+ reconnectState = RECON_UNKNOWN;
+ tries = 0;
+ } else {
+ if (mode & MODE_BACKGROUND) {
+ if (VarNextPhone == NULL || res == EX_SIG)
+ Cleanup(EX_DIAL); /* Tried all numbers - no luck */
+ else
+ /* Try all numbers in background mode */
+ StartRedialTimer(VarRedialNextTimeout);
+ } else if (!(mode & MODE_DDIAL) &&
+ ((VarDialTries && tries >= VarDialTries) ||
+ res == EX_SIG)) {
+ /* I give up ! Can't get through :( */
+ StartRedialTimer(VarRedialTimeout);
+ dial_up = 0;
+ reconnectState = RECON_UNKNOWN;
+ reconnectCount = 0;
+ tries = 0;
+ } else if (VarNextPhone == NULL)
+ /* Dial failed. Keep quite during redial wait period. */
+ StartRedialTimer(VarRedialTimeout);
+ else
+ StartRedialTimer(VarRedialNextTimeout);
+ }
+ }
+ }
+ qlen = ModemQlen();
+
+ if (qlen == 0) {
+ IpStartOutput();
+ qlen = ModemQlen();
+ }
+ if (modem >= 0) {
+ if (modem + 1 > nfds)
+ nfds = modem + 1;
+ FD_SET(modem, &rfds);
+ FD_SET(modem, &efds);
+ if (qlen > 0) {
+ FD_SET(modem, &wfds);
+ }
+ }
+ if (server >= 0) {
+ if (server + 1 > nfds)
+ nfds = server + 1;
+ FD_SET(server, &rfds);
+ }
+
+ /*
+ * *** IMPORTANT ***
+ *
+ * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
+ * with great care. If this values is too big, it results loss of
+ * characters from modem and poor responce. If this values is too small,
+ * ppp process eats many CPU time.
+ */
+#ifndef SIGALRM
+ nointr_usleep(TICKUNIT);
+ TimerService();
+#else
+ handle_signals();
+#endif
+
+ /* If there are aren't many packets queued, look for some more. */
+ if (qlen < 20 && tun_in >= 0) {
+ if (tun_in + 1 > nfds)
+ nfds = tun_in + 1;
+ FD_SET(tun_in, &rfds);
+ }
+ if (netfd >= 0) {
+ if (netfd + 1 > nfds)
+ nfds = netfd + 1;
+ FD_SET(netfd, &rfds);
+ FD_SET(netfd, &efds);
+ }
+#ifndef SIGALRM
+
+ /*
+ * Normally, select() will not block because modem is writable. In AUTO
+ * mode, select will block until we find packet from tun
+ */
+ tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
+ i = select(nfds, &rfds, &wfds, &efds, tp);
+#else
+
+ /*
+ * When SIGALRM timer is running, a select function will be return -1 and
+ * EINTR after a Time Service signal hundler is done. If the redial
+ * timer is not running and we are trying to dial, poll with a 0 value
+ * timer.
+ */
+ tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
+ i = select(nfds, &rfds, &wfds, &efds, tp);
+#endif
+
+ if (i == 0) {
+ continue;
+ }
+ if (i < 0) {
+ if (errno == EINTR) {
+ handle_signals();
+ continue;
+ }
+ LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
+ break;
+ }
+ if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
+ LogPrintf(LogALERT, "Exception detected.\n");
+ break;
+ }
+ if (server >= 0 && FD_ISSET(server, &rfds)) {
+ LogPrintf(LogPHASE, "connected to client.\n");
+ wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
+ if (wfd < 0) {
+ LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
+ continue;
+ }
+ if (netfd >= 0) {
+ write(wfd, "already in use.\n", 16);
+ close(wfd);
+ continue;
+ } else
+ netfd = wfd;
+ VarTerm = fdopen(netfd, "a+");
+ LocalAuthInit();
+ Greetings();
+ IsInteractive(1);
+ Prompt();
+ }
+ if (netfd >= 0 && FD_ISSET(netfd, &rfds) &&
+ ((mode & MODE_OUTGOING_DAEMON) || pgroup == tcgetpgrp(0))) {
+ /* something to read from tty */
+ ReadTty();
+ }
+ if (modem >= 0) {
+ if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */
+ ModemStartOutput(modem);
+ }
+ if (FD_ISSET(modem, &rfds)) { /* something to read from modem */
+ if (LcpFsm.state <= ST_CLOSED)
+ nointr_usleep(10000);
+ n = read(modem, rbuff, sizeof(rbuff));
+ if ((mode & MODE_DIRECT) && n <= 0) {
+ DownConnection();
+ } else
+ LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
+
+ if (LcpFsm.state <= ST_CLOSED) {
+
+ /*
+ * In dedicated mode, we just discard input until LCP is started.
+ */
+ if (!(mode & MODE_DEDICATED)) {
+ cp = HdlcDetect(rbuff, n);
+ if (cp) {
+
+ /*
+ * LCP packet is detected. Turn ourselves into packet mode.
+ */
+ if (cp != rbuff) {
+ write(modem, rbuff, cp - rbuff);
+ write(modem, "\r\n", 2);
+ }
+ PacketMode();
+ } else
+ write(fileno(VarTerm), rbuff, n);
+ }
+ } else {
+ if (n > 0)
+ AsyncInput(rbuff, n);
+ }
+ }
+ }
+ if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read
+ * from tun */
+ n = read(tun_in, &tun, sizeof(tun));
+ if (n < 0) {
+ LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
+ continue;
+ }
+ n -= sizeof(tun)-sizeof(tun.data);
+ if (n <= 0) {
+ LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n);
+ continue;
+ }
+ if (!tun_check_header(tun, AF_INET))
+ continue;
+ if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
+ /* we've been asked to send something addressed *to* us :( */
+ if (VarLoopback) {
+ pri = PacketCheck(rbuff, n, FL_IN);
+ if (pri >= 0) {
+ struct mbuf *bp;
+
+#ifndef NOALIAS
+ if (mode & MODE_ALIAS) {
+ VarPacketAliasIn(rbuff, sizeof rbuff);
+ n = ntohs(((struct ip *) rbuff)->ip_len);
+ }
+#endif
+ bp = mballoc(n, MB_IPIN);
+ memcpy(MBUF_CTOP(bp), rbuff, n);
+ IpInput(bp);
+ LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
+ }
+ continue;
+ } else
+ LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
+ }
+
+ /*
+ * Process on-demand dialup. Output packets are queued within tunnel
+ * device until IPCP is opened.
+ */
+ if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
+ pri = PacketCheck(rbuff, n, FL_DIAL);
+ if (pri >= 0) {
+#ifndef NOALIAS
+ if (mode & MODE_ALIAS) {
+ VarPacketAliasOut(rbuff, sizeof rbuff);
+ n = ntohs(((struct ip *) rbuff)->ip_len);
+ }
+#endif
+ IpEnqueue(pri, rbuff, n);
+ dial_up = 1; /* XXX */
+ }
+ continue;
+ }
+ pri = PacketCheck(rbuff, n, FL_OUT);
+ if (pri >= 0) {
+#ifndef NOALIAS
+ if (mode & MODE_ALIAS) {
+ VarPacketAliasOut(rbuff, sizeof rbuff);
+ n = ntohs(((struct ip *) rbuff)->ip_len);
+ }
+#endif
+ IpEnqueue(pri, rbuff, n);
+ }
+ }
+ }
+ LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
+}
diff --git a/usr.sbin/ppp/main.h b/usr.sbin/ppp/main.h
new file mode 100644
index 00000000000..b44c699569c
--- /dev/null
+++ b/usr.sbin/ppp/main.h
@@ -0,0 +1,31 @@
+/*
+ * User Process PPP
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: main.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ */
+
+extern int TermMode;
+extern int tunno;
+
+extern void Cleanup(int);
+extern void TtyTermMode(void);
+extern void PacketMode(void);
+extern void TtyOldMode(void);
+extern void TtyCommandMode(int);
diff --git a/usr.sbin/ppp/mbuf.c b/usr.sbin/ppp/mbuf.c
new file mode 100644
index 00000000000..af0066f97c7
--- /dev/null
+++ b/usr.sbin/ppp/mbuf.c
@@ -0,0 +1,175 @@
+/*
+ * PPP Memory handling module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: mbuf.c,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "server.h"
+
+struct memmap {
+ struct mbuf *queue;
+ int count;
+} MemMap[MB_MAX + 2];
+
+static int totalalloced;
+
+int
+plength(struct mbuf * bp)
+{
+ int len;
+
+ for (len = 0; bp; bp = bp->next)
+ len += bp->cnt;
+ return (len);
+}
+
+struct mbuf *
+mballoc(int cnt, int type)
+{
+ u_char *p;
+ struct mbuf *bp;
+
+ if (type > MB_MAX)
+ LogPrintf(LogERROR, "Bad mbuf type %d\n", type);
+ bp = (struct mbuf *) malloc(sizeof(struct mbuf));
+ if (bp == NULL) {
+ LogPrintf(LogALERT, "failed to allocate memory: %u\n", sizeof(struct mbuf));
+ ServerClose();
+ exit(1);
+ }
+ memset(bp, '\0', sizeof(struct mbuf));
+ p = (u_char *) malloc(cnt);
+ if (p == NULL) {
+ LogPrintf(LogALERT, "failed to allocate memory: %d\n", cnt);
+ ServerClose();
+ exit(1);
+ }
+ MemMap[type].count += cnt;
+ totalalloced += cnt;
+ bp->base = p;
+ bp->size = bp->cnt = cnt;
+ bp->type = type;
+ return (bp);
+}
+
+struct mbuf *
+mbfree(struct mbuf * bp)
+{
+ struct mbuf *nbp;
+
+ if (bp) {
+ nbp = bp->next;
+ MemMap[bp->type].count -= bp->size;
+ totalalloced -= bp->size;
+ free(bp->base);
+ free(bp);
+ return (nbp);
+ }
+ return (bp);
+}
+
+void
+pfree(struct mbuf * bp)
+{
+ while (bp)
+ bp = mbfree(bp);
+}
+
+struct mbuf *
+mbread(struct mbuf * bp, u_char * ptr, int len)
+{
+ int nb;
+
+ while (bp && len > 0) {
+ if (len > bp->cnt)
+ nb = bp->cnt;
+ else
+ nb = len;
+ memcpy(ptr, MBUF_CTOP(bp), nb);
+ ptr += nb;
+ bp->cnt -= nb;
+ len -= nb;
+ bp->offset += nb;
+ if (bp->cnt == 0) {
+#ifdef notdef
+ bp = bp->next;
+#else
+ bp = mbfree(bp);
+#endif
+ }
+ }
+ return (bp);
+}
+
+void
+mbwrite(struct mbuf * bp, u_char * ptr, int cnt)
+{
+ int plen;
+ int nb;
+
+ plen = plength(bp);
+ if (plen < cnt)
+ cnt = plen;
+
+ while (cnt > 0) {
+ nb = (cnt < bp->cnt) ? cnt : bp->cnt;
+ memcpy(MBUF_CTOP(bp), ptr, nb);
+ cnt -= bp->cnt;
+ bp = bp->next;
+ }
+}
+
+int
+ShowMemMap(struct cmdargs const *arg)
+{
+ int i;
+
+ if (!VarTerm)
+ return 1;
+
+ for (i = 0; i <= MB_MAX; i += 2)
+ fprintf(VarTerm, "%d: %d %d: %d\n",
+ i, MemMap[i].count, i + 1, MemMap[i + 1].count);
+
+ return 0;
+}
+
+void
+LogMemory()
+{
+ LogPrintf(LogDEBUG, "LogMemory: mem alloced: %d\n", totalalloced);
+ LogPrintf(LogDEBUG, "LogMemory: 1: %d 2: %d 3: %d 4: %d\n",
+ MemMap[1].count, MemMap[2].count, MemMap[3].count, MemMap[4].count);
+ LogPrintf(LogDEBUG, "LogMemory: 5: %d 6: %d 7: %d 8: %d\n",
+ MemMap[5].count, MemMap[6].count, MemMap[7].count, MemMap[8].count);
+}
diff --git a/usr.sbin/ppp/mbuf.h b/usr.sbin/ppp/mbuf.h
new file mode 100644
index 00000000000..0b203a6cc01
--- /dev/null
+++ b/usr.sbin/ppp/mbuf.h
@@ -0,0 +1,63 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: mbuf.h,v 1.1 1997/11/23 20:27:34 brian Exp $
+ *
+ * TODO:
+ */
+
+struct mbuf {
+ u_char *base; /* pointer to top of buffer space */
+ short size; /* size allocated from base */
+ short offset; /* offset to start position */
+ short cnt; /* available byte count in buffer */
+ short type;
+ struct mbuf *next; /* link to next mbuf */
+ struct mbuf *pnext; /* link to next packet */
+};
+
+struct mqueue {
+ struct mbuf *top;
+ struct mbuf *last;
+ int qlen;
+};
+
+#define NULLBUFF ((struct mbuf *)0)
+
+#define MBUF_CTOP(bp) (bp->base + bp->offset)
+
+#define MB_ASYNC 1
+#define MB_FSM 2
+#define MB_HDLCOUT 3
+#define MB_IPIN 4
+#define MB_ECHO 5
+#define MB_LQR 6
+#define MB_MODEM 7
+#define MB_VJCOMP 8
+#define MB_LOG 9
+#define MB_IPQ 10
+#define MB_MAX MB_IPQ
+
+extern int plength(struct mbuf *);
+extern struct mbuf *mballoc(int, int);
+extern struct mbuf *mbfree(struct mbuf *);
+extern void pfree(struct mbuf *);
+extern void mbwrite(struct mbuf *, u_char *, int);
+extern struct mbuf *mbread(struct mbuf *, u_char *, int);
+extern void DumpBp(struct mbuf *);
+extern void LogMemory(void);
+extern int ShowMemMap(struct cmdargs const *);
diff --git a/usr.sbin/ppp/modem.c b/usr.sbin/ppp/modem.c
new file mode 100644
index 00000000000..8a8bb140fc1
--- /dev/null
+++ b/usr.sbin/ppp/modem.c
@@ -0,0 +1,913 @@
+/*
+ * PPP Modem handling module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: modem.c,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * TODO:
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "id.h"
+#include "timer.h"
+#include "fsm.h"
+#include "hdlc.h"
+#include "lcp.h"
+#include "ip.h"
+#include "modem.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "main.h"
+#include "chat.h"
+#include "throughput.h"
+#ifdef __OpenBSD__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+
+#ifndef O_NONBLOCK
+#ifdef O_NDELAY
+#define O_NONBLOCK O_NDELAY
+#endif
+#endif
+
+static int mbits; /* Current DCD status */
+static int connect_count;
+static struct pppTimer ModemTimer;
+
+#define Online (mbits & TIOCM_CD)
+
+static struct mbuf *modemout;
+static struct mqueue OutputQueues[PRI_LINK + 1];
+static int dev_is_modem;
+static struct pppThroughput throughput;
+
+static void CloseLogicalModem(void);
+
+void
+Enqueue(struct mqueue * queue, struct mbuf * bp)
+{
+ if (queue->last) {
+ queue->last->pnext = bp;
+ queue->last = bp;
+ } else
+ queue->last = queue->top = bp;
+ queue->qlen++;
+ LogPrintf(LogDEBUG, "Enqueue: len = %d\n", queue->qlen);
+}
+
+struct mbuf *
+Dequeue(struct mqueue * queue)
+{
+ struct mbuf *bp;
+
+ LogPrintf(LogDEBUG, "Dequeue: len = %d\n", queue->qlen);
+ bp = queue->top;
+ if (bp) {
+ queue->top = queue->top->pnext;
+ queue->qlen--;
+ if (queue->top == NULL) {
+ queue->last = queue->top;
+ if (queue->qlen)
+ LogPrintf(LogDEBUG, "Dequeue: Not zero (%d)!!!\n", queue->qlen);
+ }
+ }
+ return (bp);
+}
+
+static struct speeds {
+ int nspeed;
+ speed_t speed;
+} speeds[] = {
+
+#ifdef B50
+ { 50, B50, },
+#endif
+#ifdef B75
+ { 75, B75, },
+#endif
+#ifdef B110
+ { 110, B110, },
+#endif
+#ifdef B134
+ { 134, B134, },
+#endif
+#ifdef B150
+ { 150, B150, },
+#endif
+#ifdef B200
+ { 200, B200, },
+#endif
+#ifdef B300
+ { 300, B300, },
+#endif
+#ifdef B600
+ { 600, B600, },
+#endif
+#ifdef B1200
+ { 1200, B1200, },
+#endif
+#ifdef B1800
+ { 1800, B1800, },
+#endif
+#ifdef B2400
+ { 2400, B2400, },
+#endif
+#ifdef B4800
+ { 4800, B4800, },
+#endif
+#ifdef B9600
+ { 9600, B9600, },
+#endif
+#ifdef B19200
+ { 19200, B19200, },
+#endif
+#ifdef B38400
+ { 38400, B38400, },
+#endif
+#ifndef _POSIX_SOURCE
+#ifdef B7200
+ { 7200, B7200, },
+#endif
+#ifdef B14400
+ { 14400, B14400, },
+#endif
+#ifdef B28800
+ { 28800, B28800, },
+#endif
+#ifdef B57600
+ { 57600, B57600, },
+#endif
+#ifdef B76800
+ { 76800, B76800, },
+#endif
+#ifdef B115200
+ { 115200, B115200, },
+#endif
+#ifdef B230400
+ { 230400, B230400, },
+#endif
+#ifdef EXTA
+ { 19200, EXTA, },
+#endif
+#ifdef EXTB
+ { 38400, EXTB, },
+#endif
+#endif /* _POSIX_SOURCE */
+ { 0, 0 }
+};
+
+static int
+SpeedToInt(speed_t speed)
+{
+ struct speeds *sp;
+
+ for (sp = speeds; sp->nspeed; sp++) {
+ if (sp->speed == speed) {
+ return (sp->nspeed);
+ }
+ }
+ return 0;
+}
+
+speed_t
+IntToSpeed(int nspeed)
+{
+ struct speeds *sp;
+
+ for (sp = speeds; sp->nspeed; sp++) {
+ if (sp->nspeed == nspeed) {
+ return (sp->speed);
+ }
+ }
+ return B0;
+}
+
+void
+DownConnection()
+{
+ LogPrintf(LogPHASE, "Disconnected!\n");
+ LcpDown();
+}
+
+/*
+ * ModemTimeout() watches DCD signal and notifies if it's status is changed.
+ *
+ */
+void
+ModemTimeout(void *data)
+{
+ int ombits = mbits;
+ int change;
+
+ StopTimer(&ModemTimer);
+ StartTimer(&ModemTimer);
+
+ if (dev_is_modem) {
+ if (modem >= 0) {
+ if (ioctl(modem, TIOCMGET, &mbits) < 0) {
+ LogPrintf(LogPHASE, "ioctl error (%s)!\n", strerror(errno));
+ DownConnection();
+ return;
+ }
+ } else
+ mbits = 0;
+ change = ombits ^ mbits;
+ if (change & TIOCM_CD) {
+ if (Online) {
+ LogPrintf(LogDEBUG, "ModemTimeout: offline -> online\n");
+ /*
+ * In dedicated mode, start packet mode immediate after we detected
+ * carrier.
+ */
+ if (mode & MODE_DEDICATED)
+ PacketMode();
+ } else {
+ LogPrintf(LogDEBUG, "ModemTimeout: online -> offline\n");
+ reconnect(RECON_TRUE);
+ DownConnection();
+ }
+ }
+ else
+ LogPrintf(LogDEBUG, "ModemTimeout: Still %sline\n",
+ Online ? "on" : "off");
+ } else if (!Online) {
+ /* mbits was set to zero in OpenModem() */
+ mbits = TIOCM_CD;
+ }
+}
+
+static void
+StartModemTimer(void)
+{
+ StopTimer(&ModemTimer);
+ ModemTimer.state = TIMER_STOPPED;
+ ModemTimer.load = SECTICKS;
+ ModemTimer.func = ModemTimeout;
+ LogPrintf(LogDEBUG, "ModemTimer using ModemTimeout() - %p\n", ModemTimeout);
+ StartTimer(&ModemTimer);
+}
+
+struct parity {
+ const char *name;
+ const char *name1;
+ int set;
+} validparity[] = {
+ { "even", "P_EVEN", CS7 | PARENB },
+ { "odd", "P_ODD", CS7 | PARENB | PARODD },
+ { "none", "P_ZERO", CS8 },
+ { NULL, 0 },
+};
+
+static int
+GetParityValue(const char *str)
+{
+ struct parity *pp;
+
+ for (pp = validparity; pp->name; pp++) {
+ if (strcasecmp(pp->name, str) == 0 ||
+ strcasecmp(pp->name1, str) == 0) {
+ return VarParity = pp->set;
+ }
+ }
+ return (-1);
+}
+
+int
+ChangeParity(const char *str)
+{
+ struct termios rstio;
+ int val;
+
+ val = GetParityValue(str);
+ if (val > 0) {
+ VarParity = val;
+ tcgetattr(modem, &rstio);
+ rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
+ rstio.c_cflag |= val;
+ tcsetattr(modem, TCSADRAIN, &rstio);
+ return 0;
+ }
+ LogPrintf(LogWARN, "ChangeParity: %s: Invalid parity\n", str);
+ return -1;
+}
+
+static int
+OpenConnection(char *host, char *port)
+{
+ struct sockaddr_in dest;
+ int sock;
+ struct hostent *hp;
+ struct servent *sp;
+
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = inet_addr(host);
+ if (dest.sin_addr.s_addr == INADDR_NONE) {
+ hp = gethostbyname(host);
+ if (hp) {
+ memcpy(&dest.sin_addr.s_addr, hp->h_addr_list[0], 4);
+ } else {
+ LogPrintf(LogWARN, "OpenConnection: unknown host: %s\n", host);
+ return (-1);
+ }
+ }
+ dest.sin_port = htons(atoi(port));
+ if (dest.sin_port == 0) {
+ sp = getservbyname(port, "tcp");
+ if (sp) {
+ dest.sin_port = sp->s_port;
+ } else {
+ LogPrintf(LogWARN, "OpenConnection: unknown service: %s\n", port);
+ return (-1);
+ }
+ }
+ LogPrintf(LogPHASE, "Connecting to %s:%s\n", host, port);
+
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ return (sock);
+ }
+ if (connect(sock, (struct sockaddr *) & dest, sizeof(dest)) < 0) {
+ LogPrintf(LogWARN, "OpenConnection: connection failed.\n");
+ return (-1);
+ }
+ LogPrintf(LogDEBUG, "OpenConnection: modem fd is %d.\n", sock);
+ return (sock);
+}
+
+static char fn[MAXPATHLEN];
+
+static int
+LockModem(void)
+{
+ int res;
+ FILE *lockfile;
+
+ if (*VarDevice != '/')
+ return 0;
+
+ if (!(mode & MODE_DIRECT) && (res = ID0uu_lock(VarBaseDevice)) != UU_LOCK_OK) {
+ if (res == UU_LOCK_INUSE)
+ LogPrintf(LogPHASE, "Modem %s is in use\n", VarDevice);
+ else
+ LogPrintf(LogPHASE, "Modem %s is in use: uu_lock: %s\n",
+ VarDevice, uu_lockerr(res));
+ return (-1);
+ }
+
+ snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, VarBaseDevice);
+ lockfile = ID0fopen(fn, "w");
+ if (lockfile != NULL) {
+ fprintf(lockfile, "tun%d\n", tunno);
+ fclose(lockfile);
+ } else
+ LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", fn, strerror(errno));
+
+ return 0;
+}
+
+static void
+UnlockModem(void)
+{
+ if (*VarDevice != '/')
+ return;
+
+ snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, VarBaseDevice);
+ if (ID0unlink(fn) == -1)
+ LogPrintf(LogALERT, "Warning: Can't remove %s: %s\n", fn, strerror(errno));
+
+ if (!(mode & MODE_DIRECT) && ID0uu_unlock(VarBaseDevice) == -1)
+ LogPrintf(LogALERT, "Warning: Can't uu_unlock %s\n", fn);
+}
+
+static void
+HaveModem(void)
+{
+ throughput_start(&throughput);
+ connect_count++;
+ LogPrintf(LogPHASE, "Connected!\n");
+}
+
+static struct termios modemios;
+
+int
+OpenModem()
+{
+ struct termios rstio;
+ int oldflag;
+ char *host, *port;
+ char *cp;
+
+ if (modem >= 0)
+ LogPrintf(LogDEBUG, "OpenModem: Modem is already open!\n");
+ /* We're going back into "term" mode */
+ else if (mode & MODE_DIRECT) {
+ struct cmdargs arg;
+ arg.cmd = NULL;
+ arg.data = (const void *)VAR_DEVICE;
+ if (isatty(0)) {
+ LogPrintf(LogDEBUG, "OpenModem(direct): Modem is a tty\n");
+ cp = ttyname(0);
+ arg.argc = 1;
+ arg.argv = (char const *const *)&cp;
+ SetVariable(&arg);
+ if (LockModem() == -1) {
+ close(0);
+ return -1;
+ }
+ modem = 0;
+ HaveModem();
+ } else {
+ LogPrintf(LogDEBUG, "OpenModem(direct): Modem is not a tty\n");
+ arg.argc = 0;
+ arg.argv = NULL;
+ SetVariable(&arg);
+ /* We don't call ModemTimeout() with this type of connection */
+ HaveModem();
+ return modem = 0;
+ }
+ } else {
+ if (strncmp(VarDevice, "/dev/", 5) == 0) {
+ if (LockModem() == -1)
+ return (-1);
+ modem = ID0open(VarDevice, O_RDWR | O_NONBLOCK);
+ if (modem < 0) {
+ LogPrintf(LogERROR, "OpenModem failed: %s: %s\n", VarDevice,
+ strerror(errno));
+ UnlockModem();
+ return (-1);
+ }
+ HaveModem();
+ LogPrintf(LogDEBUG, "OpenModem: Modem is %s\n", VarDevice);
+ } else {
+ /* PPP over TCP */
+ cp = strchr(VarDevice, ':');
+ if (cp) {
+ *cp = '\0';
+ host = VarDevice;
+ port = cp + 1;
+ if (*host && *port) {
+ modem = OpenConnection(host, port);
+ *cp = ':'; /* Don't destroy VarDevice */
+ if (modem < 0)
+ return (-1);
+ HaveModem();
+ LogPrintf(LogDEBUG, "OpenModem: Modem is socket %s\n", VarDevice);
+ } else {
+ *cp = ':'; /* Don't destroy VarDevice */
+ LogPrintf(LogERROR, "Invalid host:port: \"%s\"\n", VarDevice);
+ return (-1);
+ }
+ } else {
+ LogPrintf(LogERROR,
+ "Device (%s) must be in /dev or be a host:port pair\n",
+ VarDevice);
+ return (-1);
+ }
+ }
+ }
+
+ /*
+ * If we are working on tty device, change it's mode into the one desired
+ * for further operation. In this implementation, we assume that modem is
+ * configuted to use CTS/RTS flow control.
+ */
+ mbits = 0;
+ dev_is_modem = isatty(modem) || DEV_IS_SYNC;
+ if (DEV_IS_SYNC)
+ nointr_sleep(1);
+ if (dev_is_modem && !DEV_IS_SYNC) {
+ tcgetattr(modem, &rstio);
+ modemios = rstio;
+ LogPrintf(LogDEBUG, "OpenModem: modem = %d\n", modem);
+ LogPrintf(LogDEBUG, "OpenModem: modem (get): iflag = %x, oflag = %x,"
+ " cflag = %x\n", rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
+ cfmakeraw(&rstio);
+ if (VarCtsRts)
+ rstio.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
+ else {
+ rstio.c_cflag |= CLOCAL;
+ rstio.c_iflag |= IXOFF;
+ }
+ rstio.c_iflag |= IXON;
+ if (!(mode & MODE_DEDICATED))
+ rstio.c_cflag |= HUPCL;
+ if ((mode & MODE_DIRECT) == 0) {
+
+ /*
+ * If we are working as direct mode, don't change tty speed.
+ */
+ rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
+ rstio.c_cflag |= VarParity;
+ if (cfsetspeed(&rstio, IntToSpeed(VarSpeed)) == -1) {
+ LogPrintf(LogWARN, "Unable to set modem speed (modem %d to %d)\n",
+ modem, VarSpeed);
+ }
+ }
+ tcsetattr(modem, TCSADRAIN, &rstio);
+ LogPrintf(LogDEBUG, "modem (put): iflag = %x, oflag = %x, cflag = %x\n",
+ rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
+
+ if (!(mode & MODE_DIRECT))
+ if (ioctl(modem, TIOCMGET, &mbits)) {
+ LogPrintf(LogERROR, "OpenModem: Cannot get modem status: %s\n",
+ strerror(errno));
+ CloseLogicalModem();
+ return (-1);
+ }
+ LogPrintf(LogDEBUG, "OpenModem: modem control = %o\n", mbits);
+
+ oldflag = fcntl(modem, F_GETFL, 0);
+ if (oldflag < 0) {
+ LogPrintf(LogERROR, "OpenModem: Cannot get modem flags: %s\n",
+ strerror(errno));
+ CloseLogicalModem();
+ return (-1);
+ }
+ (void) fcntl(modem, F_SETFL, oldflag & ~O_NONBLOCK);
+ }
+ StartModemTimer();
+
+ return (modem);
+}
+
+int
+ModemSpeed()
+{
+ struct termios rstio;
+
+ tcgetattr(modem, &rstio);
+ return (SpeedToInt(cfgetispeed(&rstio)));
+}
+
+/*
+ * Put modem tty line into raw mode which is necessary in packet mode operation
+ */
+int
+RawModem()
+{
+ struct termios rstio;
+ int oldflag;
+
+ if (!isatty(modem) || DEV_IS_SYNC)
+ return (0);
+ if (!(mode & MODE_DIRECT) && modem >= 0 && !Online) {
+ LogPrintf(LogDEBUG, "RawModem: mode = %d, modem = %d, mbits = %x\n", mode, modem, mbits);
+ }
+ tcgetattr(modem, &rstio);
+ cfmakeraw(&rstio);
+ if (VarCtsRts)
+ rstio.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
+ else
+ rstio.c_cflag |= CLOCAL;
+
+ if (!(mode & MODE_DEDICATED))
+ rstio.c_cflag |= HUPCL;
+ tcsetattr(modem, TCSADRAIN, &rstio);
+ oldflag = fcntl(modem, F_GETFL, 0);
+ if (oldflag < 0)
+ return (-1);
+ (void) fcntl(modem, F_SETFL, oldflag | O_NONBLOCK);
+ return (0);
+}
+
+static void
+UnrawModem(void)
+{
+ int oldflag;
+
+ if (isatty(modem) && !DEV_IS_SYNC) {
+ tcsetattr(modem, TCSAFLUSH, &modemios);
+ oldflag = fcntl(modem, F_GETFL, 0);
+ if (oldflag < 0)
+ return;
+ (void) fcntl(modem, F_SETFL, oldflag & ~O_NONBLOCK);
+ }
+}
+
+void
+ModemAddInOctets(int n)
+{
+ throughput_addin(&throughput, n);
+}
+
+void
+ModemAddOutOctets(int n)
+{
+ throughput_addout(&throughput, n);
+}
+
+static void
+ClosePhysicalModem(void)
+{
+ LogPrintf(LogDEBUG, "ClosePhysicalModem\n");
+ close(modem);
+ modem = -1;
+ throughput_log(&throughput, LogPHASE, "Modem");
+}
+
+void
+HangupModem(int flag)
+{
+ struct termios tio;
+
+ LogPrintf(LogDEBUG, "Hangup modem (%s)\n", modem >= 0 ? "open" : "closed");
+
+ if (modem < 0)
+ return;
+
+ StopTimer(&ModemTimer);
+ throughput_stop(&throughput);
+
+ if (TermMode) {
+ LogPrintf(LogDEBUG, "HangupModem: Not in 'term' mode\n");
+ return;
+ }
+
+ if (!isatty(modem)) {
+ mbits &= ~TIOCM_DTR;
+ ClosePhysicalModem();
+ return;
+ }
+
+ if (modem >= 0 && Online) {
+ mbits &= ~TIOCM_DTR;
+ tcgetattr(modem, &tio);
+ if (cfsetspeed(&tio, B0) == -1) {
+ LogPrintf(LogWARN, "Unable to set modem to speed 0\n");
+ }
+ tcsetattr(modem, TCSANOW, &tio);
+ nointr_sleep(1);
+ }
+
+ if (modem >= 0) {
+ char ScriptBuffer[SCRIPT_LEN];
+
+ strcpy(ScriptBuffer, VarHangupScript); /* arrays are the same size */
+ LogPrintf(LogDEBUG, "HangupModem: Script: %s\n", ScriptBuffer);
+ if (flag || !(mode & MODE_DEDICATED)) {
+ DoChat(ScriptBuffer);
+ tcflush(modem, TCIOFLUSH);
+ UnrawModem();
+ CloseLogicalModem();
+ } else {
+ /*
+ * If we are working as dedicated mode, never close it until we are
+ * directed to quit program.
+ */
+ mbits |= TIOCM_DTR;
+ ioctl(modem, TIOCMSET, &mbits);
+ DoChat(ScriptBuffer);
+ }
+ }
+}
+
+static void
+CloseLogicalModem(void)
+{
+ LogPrintf(LogDEBUG, "CloseLogicalModem\n");
+ if (modem >= 0) {
+ ClosePhysicalModem();
+ if (Utmp) {
+ struct utmp ut;
+ strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1);
+ ut.ut_line[sizeof(ut.ut_line)-1] = '\0';
+ if (logout(ut.ut_line))
+ logwtmp(ut.ut_line, "", "");
+ else
+ LogPrintf(LogERROR, "CloseLogicalModem: No longer logged in on %s\n",
+ ut.ut_line);
+ Utmp = 0;
+ }
+ UnlockModem();
+ }
+}
+
+/*
+ * Write to modem. Actualy, requested packets are queued, and goes out
+ * to the line when ModemStartOutput() is called.
+ */
+void
+WriteModem(int pri, const char *ptr, int count)
+{
+ struct mbuf *bp;
+
+ bp = mballoc(count, MB_MODEM);
+ memcpy(MBUF_CTOP(bp), ptr, count);
+
+ /*
+ * Should be NORMAL and LINK only. All IP frames get here marked NORMAL.
+ */
+ Enqueue(&OutputQueues[pri], bp);
+}
+
+void
+ModemOutput(int pri, struct mbuf * bp)
+{
+ struct mbuf *wp;
+ int len;
+
+ len = plength(bp);
+ wp = mballoc(len, MB_MODEM);
+ mbread(bp, MBUF_CTOP(wp), len);
+ Enqueue(&OutputQueues[pri], wp);
+ ModemStartOutput(modem);
+}
+
+int
+ModemQlen()
+{
+ struct mqueue *queue;
+ int len = 0;
+ int i;
+
+ for (i = PRI_NORMAL; i <= PRI_LINK; i++) {
+ queue = &OutputQueues[i];
+ len += queue->qlen;
+ }
+ return (len);
+
+}
+
+void
+ModemStartOutput(int fd)
+{
+ struct mqueue *queue;
+ int nb, nw;
+ int i;
+
+ if (modemout == NULL && ModemQlen() == 0)
+ IpStartOutput();
+ if (modemout == NULL) {
+ i = PRI_LINK;
+ for (queue = &OutputQueues[PRI_LINK]; queue >= OutputQueues; queue--) {
+ if (queue->top) {
+ modemout = Dequeue(queue);
+ if (LogIsKept(LogDEBUG)) {
+ if (i > PRI_NORMAL) {
+ struct mqueue *q;
+
+ q = &OutputQueues[0];
+ LogPrintf(LogDEBUG, "ModemStartOutput: Output from queue %d,"
+ " normal has %d\n", i, q->qlen);
+ }
+ LogPrintf(LogDEBUG, "ModemStartOutput: Dequeued %d\n", i);
+ }
+ break;
+ }
+ i--;
+ }
+ }
+ if (modemout) {
+ nb = modemout->cnt;
+ if (nb > 1600)
+ nb = 1600;
+ nw = write(fd, MBUF_CTOP(modemout), nb);
+ LogPrintf(LogDEBUG, "ModemStartOutput: wrote: %d(%d)\n", nw, nb);
+ LogDumpBuff(LogDEBUG, "ModemStartOutput: modem write",
+ MBUF_CTOP(modemout), nb);
+ if (nw > 0) {
+ modemout->cnt -= nw;
+ modemout->offset += nw;
+ if (modemout->cnt == 0) {
+ modemout = mbfree(modemout);
+ LogPrintf(LogDEBUG, "ModemStartOutput: mbfree\n");
+ }
+ } else if (nw < 0) {
+ if (errno != EAGAIN) {
+ LogPrintf(LogERROR, "modem write (%d): %s\n", modem, strerror(errno));
+ reconnect(RECON_TRUE);
+ DownConnection();
+ }
+ }
+ }
+}
+
+int
+DialModem()
+{
+ char ScriptBuffer[SCRIPT_LEN];
+ int excode;
+
+ strncpy(ScriptBuffer, VarDialScript, sizeof(ScriptBuffer) - 1);
+ ScriptBuffer[sizeof(ScriptBuffer) - 1] = '\0';
+ if ((excode = DoChat(ScriptBuffer)) > 0) {
+ if (VarTerm)
+ fprintf(VarTerm, "dial OK!\n");
+ strncpy(ScriptBuffer, VarLoginScript, sizeof(ScriptBuffer) - 1);
+ if ((excode = DoChat(ScriptBuffer)) > 0) {
+ VarAltPhone = NULL;
+ if (VarTerm)
+ fprintf(VarTerm, "login OK!\n");
+ return EX_DONE;
+ } else if (excode == -1)
+ excode = EX_SIG;
+ else {
+ LogPrintf(LogWARN, "DialModem: login failed.\n");
+ excode = EX_NOLOGIN;
+ }
+ ModemTimeout(NULL); /* Dummy call to check modem status */
+ } else if (excode == -1)
+ excode = EX_SIG;
+ else {
+ LogPrintf(LogWARN, "DialModem: dial failed.\n");
+ excode = EX_NODIAL;
+ }
+ HangupModem(0);
+ return (excode);
+}
+
+int
+ShowModemStatus(struct cmdargs const *arg)
+{
+ const char *dev;
+#ifdef TIOCOUTQ
+ int nb;
+#endif
+
+ if (!VarTerm)
+ return 1;
+
+ dev = *VarDevice ? VarDevice : "network";
+
+ fprintf(VarTerm, "device: %s speed: ", dev);
+ if (DEV_IS_SYNC)
+ fprintf(VarTerm, "sync\n");
+ else
+ fprintf(VarTerm, "%d\n", VarSpeed);
+
+ switch (VarParity & CSIZE) {
+ case CS7:
+ fprintf(VarTerm, "cs7, ");
+ break;
+ case CS8:
+ fprintf(VarTerm, "cs8, ");
+ break;
+ }
+ if (VarParity & PARENB) {
+ if (VarParity & PARODD)
+ fprintf(VarTerm, "odd parity, ");
+ else
+ fprintf(VarTerm, "even parity, ");
+ } else
+ fprintf(VarTerm, "no parity, ");
+
+ fprintf(VarTerm, "CTS/RTS %s.\n", (VarCtsRts ? "on" : "off"));
+
+ if (LogIsKept(LogDEBUG))
+ fprintf(VarTerm, "fd = %d, modem control = %o\n", modem, mbits);
+ fprintf(VarTerm, "connect count: %d\n", connect_count);
+#ifdef TIOCOUTQ
+ if (modem >= 0)
+ if (ioctl(modem, TIOCOUTQ, &nb) >= 0)
+ fprintf(VarTerm, "outq: %d\n", nb);
+ else
+ fprintf(VarTerm, "outq: ioctl probe failed: %s\n", strerror(errno));
+#endif
+ fprintf(VarTerm, "outqlen: %d\n", ModemQlen());
+ fprintf(VarTerm, "DialScript = %s\n", VarDialScript);
+ fprintf(VarTerm, "LoginScript = %s\n", VarLoginScript);
+ fprintf(VarTerm, "PhoneNumber(s) = %s\n", VarPhoneList);
+
+ fprintf(VarTerm, "\n");
+ throughput_disp(&throughput, VarTerm);
+
+ return 0;
+}
diff --git a/usr.sbin/ppp/modem.h b/usr.sbin/ppp/modem.h
new file mode 100644
index 00000000000..0fd81148090
--- /dev/null
+++ b/usr.sbin/ppp/modem.h
@@ -0,0 +1,42 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: modem.h,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * TODO:
+ */
+
+extern int RawModem(void);
+extern void UpModem(int);
+extern void DownModem(int);
+extern void WriteModem(int, const char *, int);
+extern void ModemStartOutput(int);
+extern int OpenModem(void);
+extern int ModemSpeed(void);
+extern int ModemQlen(void);
+extern int DialModem(void);
+extern speed_t IntToSpeed(int);
+extern void ModemTimeout(void *v);
+extern void DownConnection(void);
+extern void ModemOutput(int, struct mbuf *);
+extern int ChangeParity(const char *);
+extern void HangupModem(int);
+extern int ShowModemStatus(struct cmdargs const *);
+extern void Enqueue(struct mqueue *, struct mbuf *);
+extern struct mbuf *Dequeue(struct mqueue *);
+extern void ModemAddInOctets(int);
+extern void ModemAddOutOctets(int);
diff --git a/usr.sbin/ppp/os.c b/usr.sbin/ppp/os.c
new file mode 100644
index 00000000000..19c3ce97fc6
--- /dev/null
+++ b/usr.sbin/ppp/os.c
@@ -0,0 +1,380 @@
+/*
+ * PPP OS Layer Interface Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: os.c,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#ifdef __FreeBSD__
+#include <net/if_var.h>
+#endif
+#include <net/if_tun.h>
+#include <net/route.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "id.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "os.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "arp.h"
+#include "systems.h"
+#include "route.h"
+#include "ccp.h"
+#include "modem.h"
+
+char *IfDevName;
+
+static struct ifaliasreq ifra;
+static struct ifreq ifrq;
+static struct in_addr oldmine, oldhis;
+static int linkup;
+
+static int
+SetIpDevice(struct in_addr myaddr,
+ struct in_addr hisaddr,
+ struct in_addr netmask,
+ int updown)
+{
+ struct sockaddr_in *sock_in;
+ int s;
+ int changeaddr = 0;
+ u_long mask, addr;
+
+ s = ID0socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
+ return (-1);
+ }
+ if (updown == 0) {
+ if (Enabled(ConfProxy))
+ cifproxyarp(s, oldhis.s_addr);
+ if (oldmine.s_addr == 0 && oldhis.s_addr == 0) {
+ close(s);
+ return (0);
+ }
+ memset(&ifra.ifra_addr, '\0', sizeof(ifra.ifra_addr));
+ memset(&ifra.ifra_broadaddr, '\0', sizeof(ifra.ifra_addr));
+ memset(&ifra.ifra_mask, '\0', sizeof(ifra.ifra_addr));
+ if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
+ LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCDIFADDR): %s\n",
+ strerror(errno));
+ close(s);
+ return (-1);
+ }
+ oldmine.s_addr = oldhis.s_addr = 0;
+ } else {
+
+ /*
+ * If given addresses are alreay set, then ignore this request.
+ */
+ if (oldmine.s_addr == myaddr.s_addr && oldhis.s_addr == hisaddr.s_addr) {
+ close(s);
+ return (0);
+ }
+
+ /*
+ * If different address has been set, then delete it first.
+ */
+ if (oldmine.s_addr || oldhis.s_addr) {
+ changeaddr = 1;
+ }
+
+ /*
+ * Set interface address
+ */
+ sock_in = (struct sockaddr_in *) & (ifra.ifra_addr);
+ sock_in->sin_family = AF_INET;
+ sock_in->sin_addr = oldmine = myaddr;
+ sock_in->sin_len = sizeof(*sock_in);
+
+ /*
+ * Set destination address
+ */
+ sock_in = (struct sockaddr_in *) & (ifra.ifra_broadaddr);
+ sock_in->sin_family = AF_INET;
+ sock_in->sin_addr = oldhis = hisaddr;
+ sock_in->sin_len = sizeof(*sock_in);
+
+ /*
+ * */
+ addr = ntohl(myaddr.s_addr);
+ if (IN_CLASSA(addr))
+ mask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ mask = IN_CLASSB_NET;
+ else
+ mask = IN_CLASSC_NET;
+
+ /*
+ * if subnet mask is given, use it instead of class mask.
+ */
+ if (netmask.s_addr && (ntohl(netmask.s_addr) & mask) == mask)
+ mask = ntohl(netmask.s_addr);
+
+ sock_in = (struct sockaddr_in *) & (ifra.ifra_mask);
+ sock_in->sin_family = AF_INET;
+ sock_in->sin_addr.s_addr = htonl(mask);
+ sock_in->sin_len = sizeof(*sock_in);
+
+ if (changeaddr) {
+
+ /*
+ * Interface already exists. Just change the address.
+ */
+ memcpy(&ifrq.ifr_addr, &ifra.ifra_addr, sizeof(struct sockaddr));
+ if (ID0ioctl(s, SIOCSIFADDR, &ifra) < 0)
+ LogPrintf(LogERROR, "SetIpDevice: ioctl(SIFADDR): %s\n",
+ strerror(errno));
+ memcpy(&ifrq.ifr_dstaddr, &ifra.ifra_broadaddr, sizeof(struct sockaddr));
+ if (ID0ioctl(s, SIOCSIFDSTADDR, &ifrq) < 0)
+ LogPrintf(LogERROR, "SetIpDevice: ioctl(SIFDSTADDR): %s\n",
+ strerror(errno));
+#ifdef notdef
+ memcpy(&ifrq.ifr_broadaddr, &ifra.ifra_mask, sizeof(struct sockaddr));
+ if (ID0ioctl(s, SIOCSIFBRDADDR, &ifrq) < 0)
+ LogPrintf(LogERROR, "SetIpDevice: ioctl(SIFBRDADDR): %s\n",
+ strerror(errno));
+#endif
+ } else if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
+ LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
+ strerror(errno));
+ close(s);
+ return (-1);
+ }
+ if (Enabled(ConfProxy))
+ sifproxyarp(s, hisaddr.s_addr);
+ }
+ close(s);
+ return (0);
+}
+
+int
+OsSetIpaddress(struct in_addr myaddr,
+ struct in_addr hisaddr,
+ struct in_addr netmask)
+{
+ return (SetIpDevice(myaddr, hisaddr, netmask, 1));
+}
+
+static struct in_addr peer_addr;
+struct in_addr defaddr;
+
+void
+OsLinkup()
+{
+ char *s;
+
+ if (linkup == 0) {
+ reconnectState = RECON_UNKNOWN;
+ if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
+ char c = EX_NORMAL;
+
+ if (write(BGFiledes[1], &c, 1) == 1)
+ LogPrintf(LogPHASE, "Parent notified of success.\n");
+ else
+ LogPrintf(LogPHASE, "Failed to notify parent of success.\n");
+ close(BGFiledes[1]);
+ BGFiledes[1] = -1;
+ }
+ peer_addr = IpcpInfo.his_ipaddr;
+ s = (char *) inet_ntoa(peer_addr);
+ if (LogIsKept(LogLINK))
+ LogPrintf(LogLINK, "OsLinkup: %s\n", s);
+ else
+ LogPrintf(LogLCP, "OsLinkup: %s\n", s);
+
+ if (SelectSystem(inet_ntoa(IpcpInfo.want_ipaddr), LINKUPFILE) < 0) {
+ if (GetLabel()) {
+ if (SelectSystem(GetLabel(), LINKUPFILE) < 0)
+ SelectSystem("MYADDR", LINKUPFILE);
+ } else
+ SelectSystem("MYADDR", LINKUPFILE);
+ }
+ linkup = 1;
+ }
+}
+
+int
+OsLinkIsUp()
+{
+ return linkup;
+}
+
+void
+OsLinkdown()
+{
+ char *s;
+ int Level;
+
+ if (linkup) {
+ s = (char *) inet_ntoa(peer_addr);
+ Level = LogIsKept(LogLINK) ? LogLINK : LogIPCP;
+ LogPrintf(Level, "OsLinkdown: %s\n", s);
+
+ FsmDown(&IpcpFsm); /* IPCP must come down */
+ FsmDown(&CcpFsm); /* CCP must come down */
+
+ linkup = 0;
+ if (SelectSystem(s, LINKDOWNFILE) < 0) {
+ if (GetLabel()) {
+ if (SelectSystem(GetLabel(), LINKDOWNFILE) < 0)
+ SelectSystem("MYADDR", LINKDOWNFILE);
+ } else
+ SelectSystem("MYADDR", LINKDOWNFILE);
+ }
+ }
+}
+
+int
+OsInterfaceDown(int final)
+{
+ struct in_addr zeroaddr;
+ int s;
+
+ OsLinkdown();
+ if (!final && (mode & MODE_DAEMON)) /* We still want interface alive */
+ return (0);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ LogPrintf(LogERROR, "OsInterfaceDown: socket: %s\n", strerror(errno));
+ return (-1);
+ }
+ ifrq.ifr_flags &= ~IFF_UP;
+ if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
+ LogPrintf(LogERROR, "OsInterfaceDown: ioctl(SIOCSIFFLAGS): %s\n",
+ strerror(errno));
+ close(s);
+ return (-1);
+ }
+ zeroaddr.s_addr = 0;
+ SetIpDevice(zeroaddr, zeroaddr, zeroaddr, 0);
+
+ close(s);
+ return (0);
+}
+
+/*
+ * Open tunnel device and returns its descriptor
+ */
+
+#define MAX_TUN 256
+/* MAX_TUN is set at an arbitrarily large value *
+ * as the loop aborts when it reaches the first *
+ * 'Device not configured' (ENXIO), or the third *
+ * 'No such file or directory' (ENOENT) error. */
+int
+OpenTunnel(int *ptun)
+{
+ int s;
+ char ifname[IFNAMSIZ];
+ static char devname[14]; /* sufficient room for "/dev/tun65535" */
+ unsigned unit, enoentcount = 0;
+ int err;
+
+ err = ENOENT;
+ for (unit = 0; unit <= MAX_TUN; unit++) {
+ snprintf(devname, sizeof(devname), "/dev/tun%d", unit);
+ tun_out = ID0open(devname, O_RDWR);
+ if (tun_out >= 0)
+ break;
+ if (errno == ENXIO) {
+ unit = MAX_TUN;
+ err = errno;
+ } else if (errno == ENOENT) {
+ enoentcount++;
+ if (enoentcount > 2)
+ unit = MAX_TUN;
+ } else
+ err = errno;
+ }
+ if (unit > MAX_TUN) {
+ if (VarTerm)
+ fprintf(VarTerm, "No tunnel device is available (%s).\n", strerror(err));
+ return -1;
+ }
+ *ptun = unit;
+
+ LogSetTun(unit);
+
+ /*
+ * At first, name the interface.
+ */
+ strncpy(ifname, devname + 5, IFNAMSIZ - 1);
+
+ memset(&ifra, '\0', sizeof(ifra));
+ memset(&ifrq, '\0', sizeof(ifrq));
+
+ strncpy(ifrq.ifr_name, ifname, IFNAMSIZ - 1);
+ strncpy(ifra.ifra_name, ifname, IFNAMSIZ - 1);
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ LogPrintf(LogERROR, "OpenTunnel: socket(): %s\n", strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * Now, bring up the interface.
+ */
+ if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
+ LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n",
+ strerror(errno));
+ close(s);
+ return (-1);
+ }
+ ifrq.ifr_flags |= IFF_UP;
+ if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
+ LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n",
+ strerror(errno));
+ close(s);
+ return (-1);
+ }
+ tun_in = tun_out;
+ IfDevName = devname + 5;
+ if (GetIfIndex(IfDevName) < 0) {
+ LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n");
+ close(s);
+ return (-1);
+ }
+ if (VarTerm)
+ fprintf(VarTerm, "Using interface: %s\n", IfDevName);
+ LogPrintf(LogPHASE, "Using interface: %s\n", IfDevName);
+ close(s);
+ return (0);
+}
diff --git a/usr.sbin/ppp/os.h b/usr.sbin/ppp/os.h
new file mode 100644
index 00000000000..42a3f685ff7
--- /dev/null
+++ b/usr.sbin/ppp/os.h
@@ -0,0 +1,30 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: os.h,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * TODO:
+ */
+
+extern char *IfDevName;
+
+extern int OsSetIpaddress(struct in_addr, struct in_addr, struct in_addr);
+extern int OsInterfaceDown(int);
+extern int OpenTunnel(int *);
+extern void OsLinkup(void);
+extern int OsLinkIsUp(void);
+extern void OsLinkdown(void);
diff --git a/usr.sbin/ppp/pap.c b/usr.sbin/ppp/pap.c
new file mode 100644
index 00000000000..51e1e0b1290
--- /dev/null
+++ b/usr.sbin/ppp/pap.c
@@ -0,0 +1,216 @@
+/*
+ * PPP PAP Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993-94, Internet Initiative Japan, Inc.
+ * All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pap.c,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * TODO:
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef __OpenBSD__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include <utmp.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "pap.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "hdlc.h"
+#include "lcpproto.h"
+#include "phase.h"
+#include "auth.h"
+
+static const char *papcodes[] = { "???", "REQUEST", "ACK", "NAK" };
+
+static void
+SendPapChallenge(int papid)
+{
+ struct fsmheader lh;
+ struct mbuf *bp;
+ u_char *cp;
+ int namelen, keylen, plen;
+
+ namelen = strlen(VarAuthName);
+ keylen = strlen(VarAuthKey);
+ plen = namelen + keylen + 2;
+ LogPrintf(LogDEBUG, "SendPapChallenge: namelen = %d, keylen = %d\n",
+ namelen, keylen);
+ if (LogIsKept(LogDEBUG))
+ LogPrintf(LogPHASE, "PAP: %s (%s)\n", VarAuthName, VarAuthKey);
+ else
+ LogPrintf(LogPHASE, "PAP: %s\n", VarAuthName);
+ lh.code = PAP_REQUEST;
+ lh.id = papid;
+ lh.length = htons(plen + sizeof(struct fsmheader));
+ bp = mballoc(plen + sizeof(struct fsmheader), MB_FSM);
+ memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
+ cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
+ *cp++ = namelen;
+ memcpy(cp, VarAuthName, namelen);
+ cp += namelen;
+ *cp++ = keylen;
+ memcpy(cp, VarAuthKey, keylen);
+
+ HdlcOutput(PRI_LINK, PROTO_PAP, bp);
+}
+
+struct authinfo AuthPapInfo = {
+ SendPapChallenge,
+};
+
+static void
+SendPapCode(int id, int code, const char *message)
+{
+ struct fsmheader lh;
+ struct mbuf *bp;
+ u_char *cp;
+ int plen, mlen;
+
+ lh.code = code;
+ lh.id = id;
+ mlen = strlen(message);
+ plen = mlen + 1;
+ lh.length = htons(plen + sizeof(struct fsmheader));
+ bp = mballoc(plen + sizeof(struct fsmheader), MB_FSM);
+ memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
+ cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
+ *cp++ = mlen;
+ memcpy(cp, message, mlen);
+ LogPrintf(LogPHASE, "PapOutput: %s\n", papcodes[code]);
+ HdlcOutput(PRI_LINK, PROTO_PAP, bp);
+}
+
+/*
+ * Validate given username and passwrd against with secret table
+ */
+static int
+PapValidate(u_char * name, u_char * key)
+{
+ int nlen, klen;
+
+ nlen = *name++;
+ klen = *key;
+ *key++ = 0;
+ key[klen] = 0;
+ LogPrintf(LogDEBUG, "PapValidate: name %s (%d), key %s (%d)\n",
+ name, nlen, key, klen);
+
+#ifndef NOPASSWDAUTH
+ if (Enabled(ConfPasswdAuth)) {
+ struct passwd *pwd;
+ int result;
+
+ LogPrintf(LogLCP, "Using PasswdAuth\n");
+ result = (pwd = getpwnam(name)) &&
+ !strcmp(crypt(key, pwd->pw_passwd), pwd->pw_passwd);
+ endpwent();
+ return result;
+ }
+#endif
+
+ return (AuthValidate(SECRETFILE, name, key));
+}
+
+void
+PapInput(struct mbuf * bp)
+{
+ int len = plength(bp);
+ struct fsmheader *php;
+ struct lcpstate *lcp = &LcpInfo;
+ u_char *cp;
+
+ if (len >= sizeof(struct fsmheader)) {
+ php = (struct fsmheader *) MBUF_CTOP(bp);
+ if (len >= ntohs(php->length)) {
+ if (php->code < PAP_REQUEST || php->code > PAP_NAK)
+ php->code = 0;
+ LogPrintf(LogPHASE, "PapInput: %s\n", papcodes[php->code]);
+
+ switch (php->code) {
+ case PAP_REQUEST:
+ cp = (u_char *) (php + 1);
+ if (PapValidate(cp, cp + *cp + 1)) {
+ SendPapCode(php->id, PAP_ACK, "Greetings!!");
+ lcp->auth_ineed = 0;
+ if (lcp->auth_iwait == 0) {
+ if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp))
+ if (Utmp)
+ LogPrintf(LogERROR, "Oops, already logged in on %s\n",
+ VarBaseDevice);
+ else {
+ struct utmp ut;
+ memset(&ut, 0, sizeof(ut));
+ time(&ut.ut_time);
+ strncpy(ut.ut_name, cp+1, sizeof(ut.ut_name)-1);
+ strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1);
+ if (logout(ut.ut_line))
+ logwtmp(ut.ut_line, "", "");
+ login(&ut);
+ Utmp = 1;
+ }
+ NewPhase(PHASE_NETWORK);
+ }
+ } else {
+ SendPapCode(php->id, PAP_NAK, "Login incorrect");
+ reconnect(RECON_FALSE);
+ LcpClose();
+ }
+ break;
+ case PAP_ACK:
+ StopAuthTimer(&AuthPapInfo);
+ cp = (u_char *) (php + 1);
+ len = *cp++;
+ cp[len] = 0;
+ LogPrintf(LogPHASE, "Received PAP_ACK (%s)\n", cp);
+ if (lcp->auth_iwait == PROTO_PAP) {
+ lcp->auth_iwait = 0;
+ if (lcp->auth_ineed == 0)
+ NewPhase(PHASE_NETWORK);
+ }
+ break;
+ case PAP_NAK:
+ StopAuthTimer(&AuthPapInfo);
+ cp = (u_char *) (php + 1);
+ len = *cp++;
+ cp[len] = 0;
+ LogPrintf(LogPHASE, "Received PAP_NAK (%s)\n", cp);
+ reconnect(RECON_FALSE);
+ LcpClose();
+ break;
+ }
+ }
+ }
+ pfree(bp);
+}
diff --git a/usr.sbin/ppp/pap.h b/usr.sbin/ppp/pap.h
new file mode 100644
index 00000000000..60862b826ed
--- /dev/null
+++ b/usr.sbin/ppp/pap.h
@@ -0,0 +1,29 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pap.h,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * TODO:
+ */
+
+#define PAP_REQUEST 1
+#define PAP_ACK 2
+#define PAP_NAK 3
+
+extern struct authinfo AuthPapInfo;
+
+extern void PapInput(struct mbuf *);
diff --git a/usr.sbin/ppp/patch/auth4.patch b/usr.sbin/ppp/patch/auth4.patch
new file mode 100644
index 00000000000..a7231be4ae1
--- /dev/null
+++ b/usr.sbin/ppp/patch/auth4.patch
@@ -0,0 +1,12 @@
+--- main.c.orig Tue Nov 18 18:15:16 1997
++++ main.c Tue Nov 18 18:16:33 1997
+@@ -396,6 +396,9 @@
+ Greetings();
+ IpcpDefAddress();
+
++ if (mode & MODE_INTER)
++ VarLocalAuth = LOCAL_AUTH;
++
+ if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
+ fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
+
diff --git a/usr.sbin/ppp/patch/command5.patch b/usr.sbin/ppp/patch/command5.patch
new file mode 100644
index 00000000000..36930703fd0
--- /dev/null
+++ b/usr.sbin/ppp/patch/command5.patch
@@ -0,0 +1,24 @@
+Index: command.c
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/command.c,v
+retrieving revision 1.103
+diff -c -r1.103 command.c
+*** command.c 1997/11/18 00:19:28 1.103
+--- command.c 1997/11/18 19:35:36
+***************
+*** 1013,1019 ****
+ void (*DiscardAll)(void);
+
+ res = 0;
+! if (strcasecmp(argv[0], "local")) {
+ Discard = LogDiscard;
+ Keep = LogKeep;
+ DiscardAll = LogDiscardAll;
+--- 1013,1019 ----
+ void (*DiscardAll)(void);
+
+ res = 0;
+! if (argc == 0 || strcasecmp(argv[0], "local")) {
+ Discard = LogDiscard;
+ Keep = LogKeep;
+ DiscardAll = LogDiscardAll;
diff --git a/usr.sbin/ppp/patch/loopback2.patch b/usr.sbin/ppp/patch/loopback2.patch
new file mode 100644
index 00000000000..03ca19a6cec
--- /dev/null
+++ b/usr.sbin/ppp/patch/loopback2.patch
@@ -0,0 +1,36 @@
+Index: ppp.linkup.sample
+===================================================================
+RCS file: /home/ncvs/src/etc/ppp/ppp.linkup.sample,v
+retrieving revision 1.11
+diff -u -r1.11 ppp.linkup.sample
+--- ppp.linkup.sample 1997/11/08 20:58:41 1.11
++++ ppp.linkup.sample 1997/11/18 19:00:19
+@@ -53,3 +53,28 @@
+ #
+ min5minutes:
+ !bg sh -c "sleep 240; pppctl -p mypassword 3000 set timeout 60"
++
++# If you want to test ppp, do it through a loopback:
++#
++# Requires a line in /etc/services:
++# ppploop 6671/tcp # loopback ppp daemon
++#
++# and a line in /etc/inetd.conf:
++# ppploop stream tcp nowait root /usr/sbin/ppp ppp -direct loop-in
++#
++loop:
++ set timeout 0
++ set log phase chat connect lcp ipcp command
++ set device localhost:ppploop
++ set dial
++ set login
++ set escape 0xff
++ set ifaddr 127.0.0.2 127.0.0.3
++ set openmode passive
++ set server /tmp/loop ""
++
++loop-in:
++ set timeout 0
++ set log phase chat connect lcp ipcp command
++ set escape 0xff
++ allow mode direct
diff --git a/usr.sbin/ppp/patch/random.patch b/usr.sbin/ppp/patch/random.patch
new file mode 100644
index 00000000000..f490b9f1f61
--- /dev/null
+++ b/usr.sbin/ppp/patch/random.patch
@@ -0,0 +1,11 @@
+--- defs.c.orig Tue Nov 18 18:40:03 1997
++++ defs.c Tue Nov 18 18:40:19 1997
+@@ -46,7 +46,7 @@
+ void
+ randinit()
+ {
+- srandom(time(NULL));
++ srandom(time(NULL)&getpid());
+ }
+
+
diff --git a/usr.sbin/ppp/patch/thr.patch b/usr.sbin/ppp/patch/thr.patch
new file mode 100644
index 00000000000..1a9a9c64e21
--- /dev/null
+++ b/usr.sbin/ppp/patch/thr.patch
@@ -0,0 +1,972 @@
+Index: Makefile
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/Makefile,v
+retrieving revision 1.30
+diff -c -r1.30 Makefile
+*** Makefile 1997/11/16 22:15:02 1.30
+--- Makefile 1997/11/18 13:35:35
+***************
+*** 4,11 ****
+ SRCS= alias_cmd.c arp.c async.c auth.c ccp.c chap.c chat.c \
+ command.c defs.c filter.c fsm.c hdlc.c id.c ip.c ipcp.c lcp.c \
+ loadalias.c log.c lqr.c main.c mbuf.c modem.c os.c pap.c phase.c \
+! pred.c route.c server.c sig.c slcompress.c systems.c timer.c tun.c \
+! vars.c vjcomp.c
+ CFLAGS+=-Wall -Wmissing-prototypes
+ LDADD+= -lmd -lcrypt -lutil
+ DPADD+= ${LIBMD} ${LIBCRYPT} ${LIBUTIL}
+--- 4,11 ----
+ SRCS= alias_cmd.c arp.c async.c auth.c ccp.c chap.c chat.c \
+ command.c defs.c filter.c fsm.c hdlc.c id.c ip.c ipcp.c lcp.c \
+ loadalias.c log.c lqr.c main.c mbuf.c modem.c os.c pap.c phase.c \
+! pred.c route.c server.c sig.c slcompress.c systems.c throughput.c \
+! timer.c tun.c vars.c vjcomp.c
+ CFLAGS+=-Wall -Wmissing-prototypes
+ LDADD+= -lmd -lcrypt -lutil
+ DPADD+= ${LIBMD} ${LIBCRYPT} ${LIBUTIL}
+Index: ip.c
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/ip.c,v
+retrieving revision 1.30
+diff -c -r1.30 ip.c
+*** ip.c 1997/11/16 22:15:03 1.30
+--- ip.c 1997/11/18 12:46:18
+***************
+*** 251,257 ****
+ memcpy(MBUF_CTOP(bp), ptr, cnt);
+ SendPppFrame(bp);
+ RestartIdleTimer();
+! ipOutOctets += cnt;
+ }
+ #endif
+ }
+--- 251,257 ----
+ memcpy(MBUF_CTOP(bp), ptr, cnt);
+ SendPppFrame(bp);
+ RestartIdleTimer();
+! IpcpAddOutOctets(cnt);
+ }
+ #endif
+ }
+***************
+*** 405,411 ****
+ pfree(bp);
+ return;
+ }
+! ipInOctets += nb;
+
+ nb = ntohs(((struct ip *) tun.data)->ip_len);
+ nb += sizeof(tun)-sizeof(tun.data);
+--- 405,411 ----
+ pfree(bp);
+ return;
+ }
+! IpcpAddInOctets(nb);
+
+ nb = ntohs(((struct ip *) tun.data)->ip_len);
+ nb += sizeof(tun)-sizeof(tun.data);
+***************
+*** 450,456 ****
+ pfree(bp);
+ return;
+ }
+! ipInOctets += nb;
+ nb += sizeof(tun)-sizeof(tun.data);
+ nw = write(tun_out, &tun, nb);
+ if (nw != nb)
+--- 450,456 ----
+ pfree(bp);
+ return;
+ }
+! IpcpAddInOctets(nb);
+ nb += sizeof(tun)-sizeof(tun.data);
+ nw = write(tun_out, &tun, nb);
+ if (nw != nb)
+***************
+*** 509,515 ****
+ cnt = plength(bp);
+ SendPppFrame(bp);
+ RestartIdleTimer();
+! ipOutOctets += cnt;
+ break;
+ }
+ }
+--- 509,515 ----
+ cnt = plength(bp);
+ SendPppFrame(bp);
+ RestartIdleTimer();
+! IpcpAddOutOctets(cnt);
+ break;
+ }
+ }
+Index: ipcp.c
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/ipcp.c,v
+retrieving revision 1.36
+diff -c -r1.36 ipcp.c
+*** ipcp.c 1997/11/14 15:39:14 1.36
+--- ipcp.c 1997/11/18 14:09:09
+***************
+*** 33,38 ****
+--- 33,39 ----
+ #include <limits.h>
+ #include <stdio.h>
+ #include <string.h>
++ #include <time.h>
+ #include <unistd.h>
+
+ #include "mbuf.h"
+***************
+*** 51,56 ****
+--- 52,58 ----
+ #include "vars.h"
+ #include "vjcomp.h"
+ #include "ip.h"
++ #include "throughput.h"
+
+ #ifndef NOMSEXT
+ struct in_addr ns_entries[2];
+***************
+*** 62,68 ****
+ struct in_range DefHisAddress;
+ struct in_addr TriggerAddress;
+ int HaveTriggerAddress;
+- struct pppTimer IpcpReportTimer;
+
+ static void IpcpSendConfigReq(struct fsm *);
+ static void IpcpSendTerminateAck(struct fsm *);
+--- 64,69 ----
+***************
+*** 73,83 ****
+ static void IpcpLayerUp(struct fsm *);
+ static void IpcpLayerDown(struct fsm *);
+ static void IpcpInitRestartCounter(struct fsm *);
+- static int IpcpOctetsIn(void);
+- static int IpcpOctetsOut(void);
+-
+- static int lastInOctets, lastOutOctets;
+- static int StartingIpIn, StartingIpOut;
+
+ #define REJECTED(p, x) (p->his_reject & (1<<x))
+
+--- 74,79 ----
+***************
+*** 126,157 ****
+
+ #define NCFTYPES128 (sizeof(cftypes)/sizeof(char *))
+
+! /*
+! * Function called every second. Updates connection period and idle period,
+! * also update LQR information.
+! */
+! static void
+! IpcpReportFunc()
+ {
+! ipConnectSecs++;
+! if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets)
+! ipIdleSecs++;
+! lastInOctets = ipInOctets;
+! lastOutOctets = ipOutOctets;
+! StopTimer(&IpcpReportTimer);
+! IpcpReportTimer.state = TIMER_STOPPED;
+! StartTimer(&IpcpReportTimer);
+ }
+
+! static void
+! IpcpStartReport()
+ {
+! ipIdleSecs = ipConnectSecs = 0;
+! StopTimer(&IpcpReportTimer);
+! IpcpReportTimer.state = TIMER_STOPPED;
+! IpcpReportTimer.load = SECTICKS;
+! IpcpReportTimer.func = IpcpReportFunc;
+! StartTimer(&IpcpReportTimer);
+ }
+
+ int
+--- 122,139 ----
+
+ #define NCFTYPES128 (sizeof(cftypes)/sizeof(char *))
+
+! struct pppThroughput throughput;
+!
+! void
+! IpcpAddInOctets(int n)
+ {
+! throughput_addin(&throughput, n);
+ }
+
+! void
+! IpcpAddOutOctets(int n)
+ {
+! throughput_addout(&throughput, n);
+ }
+
+ int
+***************
+*** 167,176 ****
+ inet_ntoa(icp->his_ipaddr), icp->his_compproto);
+ fprintf(VarTerm, " my side: %s, %lx\n",
+ inet_ntoa(icp->want_ipaddr), icp->want_compproto);
+- fprintf(VarTerm, "Connected: %d secs, idle: %d secs\n\n",
+- ipConnectSecs, ipIdleSecs);
+- fprintf(VarTerm, " %d octets in, %d octets out\n",
+- IpcpOctetsIn(), IpcpOctetsOut());
+
+ fprintf(VarTerm, "Defaults:\n");
+ fprintf(VarTerm, " My Address: %s/%d\n",
+--- 149,154 ----
+***************
+*** 182,187 ****
+--- 160,168 ----
+ else
+ fprintf(VarTerm, " Negotiation(trigger): MYADDR\n");
+
++ fprintf(VarTerm, "\n");
++ throughput_disp(&throughput, VarTerm);
++
+ return 0;
+ }
+
+***************
+*** 232,239 ****
+ icp->want_compproto = 0;
+ icp->heis1172 = 0;
+ IpcpFsm.maxconfig = 10;
+! StartingIpIn = ipInOctets;
+! StartingIpOut = ipOutOctets;
+ }
+
+ static void
+--- 213,219 ----
+ icp->want_compproto = 0;
+ icp->heis1172 = 0;
+ IpcpFsm.maxconfig = 10;
+! throughput_init(&throughput);
+ }
+
+ static void
+***************
+*** 292,321 ****
+ NewPhase(PHASE_TERMINATE);
+ }
+
+- static int
+- IpcpOctetsIn()
+- {
+- return ipInOctets < StartingIpIn ?
+- INT_MAX - StartingIpIn + ipInOctets - INT_MIN + 1 :
+- ipInOctets - StartingIpIn;
+- }
+-
+- static int
+- IpcpOctetsOut()
+- {
+- return ipOutOctets < StartingIpOut ?
+- INT_MAX - StartingIpOut + ipOutOctets - INT_MIN + 1 :
+- ipOutOctets - StartingIpOut;
+- }
+-
+ static void
+ IpcpLayerDown(struct fsm * fp)
+ {
+ LogPrintf(LogIPCP, "IpcpLayerDown.\n");
+! LogPrintf(LogIPCP, "%d octets in, %d octets out\n",
+! IpcpOctetsIn(), IpcpOctetsOut());
+! StopTimer(&IpcpReportTimer);
+! Prompt();
+ }
+
+ /*
+--- 272,283 ----
+ NewPhase(PHASE_TERMINATE);
+ }
+
+ static void
+ IpcpLayerDown(struct fsm * fp)
+ {
+ LogPrintf(LogIPCP, "IpcpLayerDown.\n");
+! throughput_stop(&throughput);
+! throughput_log(&throughput, LogIPCP, NULL);
+ }
+
+ /*
+***************
+*** 344,352 ****
+ if (mode & MODE_ALIAS)
+ VarPacketAliasSetAddress(IpcpInfo.want_ipaddr);
+ OsLinkup();
+! StartingIpIn = ipInOctets;
+! StartingIpOut = ipOutOctets;
+! IpcpStartReport();
+ StartIdleTimer();
+ }
+
+--- 306,312 ----
+ if (mode & MODE_ALIAS)
+ VarPacketAliasSetAddress(IpcpInfo.want_ipaddr);
+ OsLinkup();
+! throughput_start(&throughput);
+ StartIdleTimer();
+ }
+
+Index: ipcp.h
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/ipcp.h,v
+retrieving revision 1.12
+diff -c -r1.12 ipcp.h
+*** ipcp.h 1997/10/26 12:42:11 1.12
+--- ipcp.h 1997/11/18 12:44:33
+***************
+*** 76,78 ****
+--- 76,80 ----
+ extern void IpcpOpen(void);
+ extern int ReportIpcpStatus(void);
+ extern void IpcpInput(struct mbuf *);
++ extern void IpcpAddInOctets(int);
++ extern void IpcpAddOutOctets(int);
+Index: lcp.c
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/lcp.c,v
+retrieving revision 1.46
+diff -c -r1.46 lcp.c
+*** lcp.c 1997/11/16 22:15:04 1.46
+--- lcp.c 1997/11/18 13:47:30
+***************
+*** 332,338 ****
+ StopAllTimers()
+ {
+ StopTimer(&LcpReportTimer);
+- StopTimer(&IpcpReportTimer);
+ StopIdleTimer();
+ StopTimer(&AuthPapInfo.authtimer);
+ StopTimer(&AuthChapInfo.authtimer);
+--- 332,337 ----
+Index: modem.c
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/modem.c,v
+retrieving revision 1.65
+diff -c -r1.65 modem.c
+*** modem.c 1997/11/18 08:49:03 1.65
+--- modem.c 1997/11/18 14:36:46
+***************
+*** 55,60 ****
+--- 55,61 ----
+ #include "vars.h"
+ #include "main.h"
+ #include "chat.h"
++ #include "throughput.h"
+ #ifdef __OpenBSD__
+ #include <util.h>
+ #else
+***************
+*** 76,81 ****
+--- 77,83 ----
+ static struct mbuf *modemout;
+ static struct mqueue OutputQueues[PRI_LINK + 1];
+ static int dev_is_modem;
++ static struct pppThroughput throughput;
+
+ static void CloseLogicalModem(void);
+
+***************
+*** 116,245 ****
+ } speeds[] = {
+
+ #ifdef B50
+! {
+! 50, B50,
+! },
+ #endif
+ #ifdef B75
+! {
+! 75, B75,
+! },
+ #endif
+ #ifdef B110
+! {
+! 110, B110,
+! },
+ #endif
+ #ifdef B134
+! {
+! 134, B134,
+! },
+ #endif
+ #ifdef B150
+! {
+! 150, B150,
+! },
+ #endif
+ #ifdef B200
+! {
+! 200, B200,
+! },
+ #endif
+ #ifdef B300
+! {
+! 300, B300,
+! },
+ #endif
+ #ifdef B600
+! {
+! 600, B600,
+! },
+ #endif
+ #ifdef B1200
+! {
+! 1200, B1200,
+! },
+ #endif
+ #ifdef B1800
+! {
+! 1800, B1800,
+! },
+ #endif
+ #ifdef B2400
+! {
+! 2400, B2400,
+! },
+ #endif
+ #ifdef B4800
+! {
+! 4800, B4800,
+! },
+ #endif
+ #ifdef B9600
+! {
+! 9600, B9600,
+! },
+ #endif
+ #ifdef B19200
+! {
+! 19200, B19200,
+! },
+ #endif
+ #ifdef B38400
+! {
+! 38400, B38400,
+! },
+ #endif
+ #ifndef _POSIX_SOURCE
+ #ifdef B7200
+! {
+! 7200, B7200,
+! },
+ #endif
+ #ifdef B14400
+! {
+! 14400, B14400,
+! },
+ #endif
+ #ifdef B28800
+! {
+! 28800, B28800,
+! },
+ #endif
+ #ifdef B57600
+! {
+! 57600, B57600,
+! },
+ #endif
+ #ifdef B76800
+! {
+! 76800, B76800,
+! },
+ #endif
+ #ifdef B115200
+! {
+! 115200, B115200,
+! },
+ #endif
+ #ifdef B230400
+! {
+! 230400, B230400,
+! },
+ #endif
+ #ifdef EXTA
+! {
+! 19200, EXTA,
+! },
+ #endif
+ #ifdef EXTB
+! {
+! 38400, EXTB,
+! },
+ #endif
+ #endif /* _POSIX_SOURCE */
+! {
+! 0, 0
+! }
+ };
+
+ static int
+--- 118,197 ----
+ } speeds[] = {
+
+ #ifdef B50
+! { 50, B50, },
+ #endif
+ #ifdef B75
+! { 75, B75, },
+ #endif
+ #ifdef B110
+! { 110, B110, },
+ #endif
+ #ifdef B134
+! { 134, B134, },
+ #endif
+ #ifdef B150
+! { 150, B150, },
+ #endif
+ #ifdef B200
+! { 200, B200, },
+ #endif
+ #ifdef B300
+! { 300, B300, },
+ #endif
+ #ifdef B600
+! { 600, B600, },
+ #endif
+ #ifdef B1200
+! { 1200, B1200, },
+ #endif
+ #ifdef B1800
+! { 1800, B1800, },
+ #endif
+ #ifdef B2400
+! { 2400, B2400, },
+ #endif
+ #ifdef B4800
+! { 4800, B4800, },
+ #endif
+ #ifdef B9600
+! { 9600, B9600, },
+ #endif
+ #ifdef B19200
+! { 19200, B19200, },
+ #endif
+ #ifdef B38400
+! { 38400, B38400, },
+ #endif
+ #ifndef _POSIX_SOURCE
+ #ifdef B7200
+! { 7200, B7200, },
+ #endif
+ #ifdef B14400
+! { 14400, B14400, },
+ #endif
+ #ifdef B28800
+! { 28800, B28800, },
+ #endif
+ #ifdef B57600
+! { 57600, B57600, },
+ #endif
+ #ifdef B76800
+! { 76800, B76800, },
+ #endif
+ #ifdef B115200
+! { 115200, B115200, },
+ #endif
+ #ifdef B230400
+! { 230400, B230400, },
+ #endif
+ #ifdef EXTA
+! { 19200, EXTA, },
+ #endif
+ #ifdef EXTB
+! { 38400, EXTB, },
+ #endif
+ #endif /* _POSIX_SOURCE */
+! { 0, 0 }
+ };
+
+ static int
+***************
+*** 268,276 ****
+ return B0;
+ }
+
+- static time_t uptime;
+- u_long OctetsIn, OctetsOut;
+-
+ void
+ DownConnection()
+ {
+--- 220,225 ----
+***************
+*** 478,485 ****
+ static void
+ HaveModem()
+ {
+! time(&uptime);
+! OctetsIn = OctetsOut = 0;
+ connect_count++;
+ LogPrintf(LogPHASE, "Connected!\n");
+ }
+--- 427,433 ----
+ static void
+ HaveModem()
+ {
+! throughput_start(&throughput);
+ connect_count++;
+ LogPrintf(LogPHASE, "Connected!\n");
+ }
+***************
+*** 497,503 ****
+ LogPrintf(LogDEBUG, "OpenModem: Modem is already open!\n");
+ /* We're going back into "term" mode */
+ else if (mode & MODE_DIRECT) {
+- HaveModem();
+ if (isatty(0)) {
+ LogPrintf(LogDEBUG, "OpenModem(direct): Modem is a tty\n");
+ cp = ttyname(0);
+--- 445,450 ----
+***************
+*** 507,516 ****
+--- 454,465 ----
+ return -1;
+ }
+ modem = 0;
++ HaveModem();
+ } else {
+ LogPrintf(LogDEBUG, "OpenModem(direct): Modem is not a tty\n");
+ SetVariable(0, 0, 0, VAR_DEVICE);
+ /* We don't call ModemTimeout() with this type of connection */
++ HaveModem();
+ return modem = 0;
+ }
+ } else {
+***************
+*** 599,605 ****
+ if (ioctl(modem, TIOCMGET, &mbits)) {
+ LogPrintf(LogERROR, "OpenModem: Cannot get modem status: %s\n",
+ strerror(errno));
+- uptime = 0;
+ CloseLogicalModem();
+ return (-1);
+ }
+--- 548,553 ----
+***************
+*** 609,615 ****
+ if (oldflag < 0) {
+ LogPrintf(LogERROR, "OpenModem: Cannot get modem flags: %s\n",
+ strerror(errno));
+- uptime = 0;
+ CloseLogicalModem();
+ return (-1);
+ }
+--- 557,562 ----
+***************
+*** 674,701 ****
+ }
+ }
+
+! void ModemAddInOctets(int n)
+ {
+! OctetsIn += n;
+ }
+
+! void ModemAddOutOctets(int n)
+ {
+! OctetsOut += n;
+ }
+
+ static void
+ ClosePhysicalModem()
+ {
+ close(modem);
+! if (uptime) {
+! LogPrintf(LogPHASE, "Connect time: %d secs\n", time(NULL) - uptime);
+! LogPrintf(LogPHASE, "Modem: %d octets in, %d octets out\n",
+! OctetsIn, OctetsOut);
+! OctetsIn = OctetsOut = 0;
+! uptime = 0;
+! }
+! modem = -1; /* Mark modem as closed */
+ }
+
+ void
+--- 621,645 ----
+ }
+ }
+
+! void
+! ModemAddInOctets(int n)
+ {
+! throughput_addin(&throughput, n);
+ }
+
+! void
+! ModemAddOutOctets(int n)
+ {
+! throughput_addout(&throughput, n);
+ }
+
+ static void
+ ClosePhysicalModem()
+ {
++ LogPrintf(LogDEBUG, "ClosePhysicalModem\n");
+ close(modem);
+! modem = -1;
+! throughput_log(&throughput, LogPHASE, "Modem");
+ }
+
+ void
+***************
+*** 703,715 ****
+ {
+ struct termios tio;
+
+! LogPrintf(LogDEBUG, "Hangup modem (%s), uptime %ld\n",
+! modem >= 0 ? "open" : "closed", (long)uptime);
+! StopTimer(&ModemTimer);
+
+ if (modem < 0)
+ return;
+
+ if (TermMode) {
+ LogPrintf(LogDEBUG, "HangupModem: Not in 'term' mode\n");
+ return;
+--- 647,660 ----
+ {
+ struct termios tio;
+
+! LogPrintf(LogDEBUG, "Hangup modem (%s)\n", modem >= 0 ? "open" : "closed");
+
+ if (modem < 0)
+ return;
+
++ StopTimer(&ModemTimer);
++ throughput_stop(&throughput);
++
+ if (TermMode) {
+ LogPrintf(LogDEBUG, "HangupModem: Not in 'term' mode\n");
+ return;
+***************
+*** 735,740 ****
+--- 680,686 ----
+ char ScriptBuffer[SCRIPT_LEN];
+
+ strcpy(ScriptBuffer, VarHangupScript); /* arrays are the same size */
++ LogPrintf(LogDEBUG, "HangupModem: Script: %s\n", ScriptBuffer);
+ if (flag || !(mode & MODE_DEDICATED)) {
+ DoChat(ScriptBuffer);
+ tcflush(modem, TCIOFLUSH);
+***************
+*** 755,760 ****
+--- 701,707 ----
+ static void
+ CloseLogicalModem()
+ {
++ LogPrintf(LogDEBUG, "CloseLogicalModem\n");
+ if (modem >= 0) {
+ ClosePhysicalModem();
+ if (Utmp) {
+***************
+*** 957,962 ****
+--- 904,912 ----
+ fprintf(VarTerm, "DialScript = %s\n", VarDialScript);
+ fprintf(VarTerm, "LoginScript = %s\n", VarLoginScript);
+ fprintf(VarTerm, "PhoneNumber(s) = %s\n", VarPhoneList);
++
++ fprintf(VarTerm, "\n");
++ throughput_disp(&throughput, VarTerm);
+
+ return 0;
+ }
+Index: ppp.8
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/ppp.8,v
+retrieving revision 1.79
+diff -c -r1.79 ppp.8
+*** ppp.8 1997/11/14 20:07:39 1.79
+--- ppp.8 1997/11/18 13:04:44
+***************
+*** 1548,1563 ****
+ may be one of the following:
+
+ .Bl -tag -width 20
+! .It vjcomp
+! Default: Enabled and Accepted. This option decides if Van Jacobson
+! header compression will be used.
+!
+! .It lqr
+! Default: Disabled and Accepted. This option decides if Link Quality
+! Requests will be sent. LQR is a protocol that allows
+! .Nm
+! to determine that the link is down without relying on the modems
+! carrier detect.
+
+ .It chap
+ Default: Disabled and Accepted. CHAP stands for Challenge Handshake
+--- 1548,1557 ----
+ may be one of the following:
+
+ .Bl -tag -width 20
+! .It acfcomp
+! Default: Enabled and Accepted. ACFComp stands for Address and Control
+! Field Compression. Non LCP packets usually have very similar address
+! and control fields - making them easily compressible.
+
+ .It chap
+ Default: Disabled and Accepted. CHAP stands for Challenge Handshake
+***************
+*** 1593,1598 ****
+--- 1587,1606 ----
+ .Dq set encrypt
+ command for further details.
+
++ .It lqr
++ Default: Disabled and Accepted. This option decides if Link Quality
++ Requests will be sent. LQR is a protocol that allows
++ .Nm
++ to determine that the link is down without relying on the modems
++ carrier detect.
++
++ .It msext
++ Default: Disabled. This option allows the use of Microsoft's
++ .Em PPP
++ extensions, supporting the negotiation of the DNS and the NetBIOS NS.
++ Enabling this allows us to pass back the values given in "set ns"
++ and "set nbns".
++
+ .It pap
+ Default: Disabled and Accepted. PAP stands for Password Authentication
+ Protocol. Only one of PAP and CHAP (above) may be negotiated. With
+***************
+*** 1619,1655 ****
+ .Pa /etc/ppp/ppp.conf .
+ PAP is accepted by default.
+
+! .It acfcomp
+! Default: Enabled and Accepted. ACFComp stands for Address and Control
+! Field Compression. Non LCP packets usually have very similar address
+! and control fields - making them easily compressible.
+
+ .It protocomp
+ Default: Enabled and Accepted. This option is used to negotiate
+ PFC (Protocol Field Compression), a mechanism where the protocol
+ field number is reduced to one octet rather than two.
+
+! .It pred1
+! Default: Enabled and Accepted. This option decides if Predictor 1
+! compression will be used.
+!
+! .It msext
+! Default: Disabled. This option allows the use of Microsoft's
+! .Em PPP
+! extensions, supporting the negotiation of the DNS and the NetBIOS NS.
+! Enabling this allows us to pass back the values given in "set ns"
+! and "set nbns".
+!
+ .El
+ The following options are not actually negotiated with the peer.
+ Therefore, accepting or denying them makes no sense.
+
+ .Bl -tag -width 20
+- .It proxy
+- Default: Disabled. Enabling this option will tell
+- .Nm
+- to proxy ARP for the peer.
+-
+ .It passwdauth
+ Default: Disabled. Enabling this option will tell the PAP authentication
+ code to use the password file (see
+--- 1627,1651 ----
+ .Pa /etc/ppp/ppp.conf .
+ PAP is accepted by default.
+
+! .It pred1
+! Default: Enabled and Accepted. This option decides if Predictor 1
+! compression will be used.
+
+ .It protocomp
+ Default: Enabled and Accepted. This option is used to negotiate
+ PFC (Protocol Field Compression), a mechanism where the protocol
+ field number is reduced to one octet rather than two.
+
+! .It vjcomp
+! Default: Enabled and Accepted. This option decides if Van Jacobson
+! header compression will be used.
+ .El
++
++ .Pp
+ The following options are not actually negotiated with the peer.
+ Therefore, accepting or denying them makes no sense.
+
+ .Bl -tag -width 20
+ .It passwdauth
+ Default: Disabled. Enabling this option will tell the PAP authentication
+ code to use the password file (see
+***************
+*** 1657,1662 ****
+--- 1653,1678 ----
+ to authenticate the caller rather than the
+ .Pa /etc/ppp/ppp.secret
+ file.
++
++ .It proxy
++ Default: Disabled. Enabling this option will tell
++ .Nm
++ to proxy ARP for the peer.
++
++ .It throughput
++ Default: Disabled. Enabling this option will tell
++ .Nm
++ to gather thoroughput statistics. Input and output is sampled over
++ a rolling 5 second window, and current, best and total figures are
++ retained. This data is output when the relevent
++ .Em PPP
++ layer shuts down, and is also available using the
++ .Dq show
++ command. Troughput statistics are available at the
++ .Dq IPCP
++ and
++ .Dq modem
++ levels.
+
+ .It utmp
+ Default: Enabled. Normally, when a user is authenticated using PAP or
+Index: vars.c
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/vars.c,v
+retrieving revision 1.34
+diff -c -r1.34 vars.c
+*** vars.c 1997/11/11 22:58:14 1.34
+--- vars.c 1997/11/18 11:31:31
+***************
+*** 65,70 ****
+--- 65,71 ----
+ {"msext", CONF_DISABLE, CONF_NONE},
+ {"passwdauth", CONF_DISABLE, CONF_NONE},
+ {"utmp", CONF_ENABLE, CONF_NONE},
++ {"throughput", CONF_DISABLE, CONF_NONE},
+ {NULL},
+ };
+
+Index: vars.h
+===================================================================
+RCS file: /home/ncvs/src/usr.sbin/ppp/vars.h,v
+retrieving revision 1.33
+diff -c -r1.33 vars.h
+*** vars.h 1997/11/09 22:07:29 1.33
+--- vars.h 1997/11/18 11:30:37
+***************
+*** 43,49 ****
+ #define ConfMSExt 8
+ #define ConfPasswdAuth 9
+ #define ConfUtmp 10
+! #define MAXCONFS 11
+
+ #define Enabled(x) (pppConfs[x].myside & CONF_ENABLE)
+ #define Acceptable(x) (pppConfs[x].hisside & CONF_ACCEPT)
+--- 43,50 ----
+ #define ConfMSExt 8
+ #define ConfPasswdAuth 9
+ #define ConfUtmp 10
+! #define ConfThroughput 11
+! #define MAXCONFS 12
+
+ #define Enabled(x) (pppConfs[x].myside & CONF_ENABLE)
+ #define Acceptable(x) (pppConfs[x].hisside & CONF_ACCEPT)
diff --git a/usr.sbin/ppp/patch/thr.tgz b/usr.sbin/ppp/patch/thr.tgz
new file mode 100644
index 00000000000..31425a069b5
--- /dev/null
+++ b/usr.sbin/ppp/patch/thr.tgz
Binary files differ
diff --git a/usr.sbin/ppp/pathnames.h b/usr.sbin/ppp/pathnames.h
new file mode 100644
index 00000000000..989731e946a
--- /dev/null
+++ b/usr.sbin/ppp/pathnames.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * $Id: pathnames.h,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * @(#)pathnames.h 5.2 (Berkeley) 6/1/90
+ */
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#define _PATH_PPP "/etc/ppp"
+#else
+#define _PATH_PPP "/etc"
+#endif
diff --git a/usr.sbin/ppp/phase.c b/usr.sbin/ppp/phase.c
new file mode 100644
index 00000000000..646151f27f4
--- /dev/null
+++ b/usr.sbin/ppp/phase.c
@@ -0,0 +1,66 @@
+/*
+ * $Id: phase.c,v 1.1 1997/11/23 20:27:35 brian Exp $
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "lcp.h"
+#include "lcpproto.h"
+#include "timer.h"
+#include "auth.h"
+#include "pap.h"
+#include "chap.h"
+#include "ipcp.h"
+#include "ccp.h"
+#include "defs.h"
+#include "main.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "phase.h"
+
+int phase = 0; /* Curent phase */
+
+static const char *PhaseNames[] = {
+ "Dead", "Establish", "Authenticate", "Network", "Terminate"
+};
+
+void
+NewPhase(int new)
+{
+ struct lcpstate *lcp = &LcpInfo;
+
+ phase = new;
+ LogPrintf(LogPHASE, "NewPhase: %s\n", PhaseNames[phase]);
+ switch (phase) {
+ case PHASE_AUTHENTICATE:
+ lcp->auth_ineed = lcp->want_auth;
+ lcp->auth_iwait = lcp->his_auth;
+ if (lcp->his_auth || lcp->want_auth) {
+ LogPrintf(LogPHASE, " his = %x, mine = %x\n", lcp->his_auth, lcp->want_auth);
+ if (lcp->his_auth == PROTO_PAP)
+ StartAuthChallenge(&AuthPapInfo);
+ if (lcp->want_auth == PROTO_CHAP)
+ StartAuthChallenge(&AuthChapInfo);
+ } else
+ NewPhase(PHASE_NETWORK);
+ break;
+ case PHASE_NETWORK:
+ IpcpUp();
+ IpcpOpen();
+ CcpUp();
+ CcpOpen();
+ break;
+ case PHASE_DEAD:
+ if (mode & MODE_DIRECT)
+ Cleanup(EX_DEAD);
+ if (mode & MODE_BACKGROUND && reconnectState != RECON_TRUE)
+ Cleanup(EX_DEAD);
+ break;
+ }
+}
diff --git a/usr.sbin/ppp/phase.h b/usr.sbin/ppp/phase.h
new file mode 100644
index 00000000000..75b909e6d00
--- /dev/null
+++ b/usr.sbin/ppp/phase.h
@@ -0,0 +1,32 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: phase.h,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * TODO:
+ */
+
+#define PHASE_DEAD 0 /* Link is dead */
+#define PHASE_ESTABLISH 1 /* Establishing link */
+#define PHASE_AUTHENTICATE 2 /* Being authenticated */
+#define PHASE_NETWORK 3
+#define PHASE_TERMINATE 4 /* Terminating link */
+#define PHASE_OSLINKED 5 /* The OS is linked up */
+
+extern int phase; /* Curent phase */
+
+extern void NewPhase(int);
diff --git a/usr.sbin/ppp/ppp.8 b/usr.sbin/ppp/ppp.8
new file mode 100644
index 00000000000..086152ddb78
--- /dev/null
+++ b/usr.sbin/ppp/ppp.8
@@ -0,0 +1,2453 @@
+.\" $Id: ppp.8,v 1.1 1997/11/23 20:27:35 brian Exp $
+.Dd 20 September 1995
+.Os OpenBSD
+.Dt PPP 8
+.Sh NAME
+.Nm ppp
+.Nd Point to Point Protocol (a.k.a. iijppp)
+.Sh SYNOPSIS
+.Nm
+.\" SOMEONE FIX ME ! The .Op macro can't handle enough args !
+[
+.Fl auto |
+.Fl background |
+.Fl ddial |
+.Fl direct |
+.Fl dedicated
+]
+.Op Fl alias
+.Op Ar system
+.Sh DESCRIPTION
+This is a user process
+.Em PPP
+software package. Normally,
+.Em PPP
+is implemented as a part of the kernel (e.g. as managed by
+.Xr pppd 8 )
+and it's thus somewhat hard to debug and/or modify its behaviour.
+However, in this implementation
+.Em PPP
+is done as a user process with the help of the
+tunnel device driver (tun).
+
+.Sh Major Features
+
+.Bl -diag
+.It Provides interactive user interface.
+Using its command mode, the user can
+easily enter commands to establish the connection with the remote end, check
+the status of connection and close the connection. All functions can
+also be optionally password protected for security.
+
+.It Supports both manual and automatic dialing.
+Interactive mode has a
+.Dq term
+command which enables you to talk to your modem directly. When your
+modem is connected to the remote peer and it starts to talk
+.Em PPP ,
+.Nm
+detects it and switches to packet mode automatically. Once you have
+determined the proper sequence for connecting with the remote host, you
+can write a chat script to define the necessary dialing and login
+procedure for later convenience.
+
+.It Supports on-demand dialup capability.
+By using
+.Fl auto
+mode,
+.Nm
+will act as a daemon and wait for a packet to be sent over the
+.Em PPP
+link. When this happens, the daemon automatically dials and establishes the
+connection.
+
+In almost the same manner
+.Fl ddial
+mode (direct-dial mode) also automatically dials and establishes the
+connection. However, it differs in that it will dial the remote site
+any time it detects the link is down, even if there are no packets to be
+sent. This mode is useful for full-time connections where we worry less
+about line charges and more about being connected full time.
+
+A third
+.Fl dedicated
+mode is also available. This mode is targeted at a dedicated link
+between two machines.
+.Nm Ppp
+will never voluntarily quit from dedicated mode - you must send it the
+.Dq quit all
+command via its diagnostic socket. A
+.Dv SIGHUP
+will force an LCP renegotiation, and a
+.Dv SIGTERM
+will force it to exit.
+
+.It Supports packet aliasing.
+Packet aliasing (a.k.a. IP masquerading) allows computers on a
+private, unregistered network to access the Internet. The
+.Em PPP
+host acts as a masquerading gateway. IP addresses as well as TCP and
+UDP port numbers are aliased for outgoing packets and de-aliased for
+returning packets.
+
+.It Supports background PPP connections.
+In background mode, if
+.Nm
+successfully establishes the connection, it will become a daemon.
+Otherwise, it will exit with an error. This allows the setup of
+scripts that wish to execute certain commands only if the connection
+is successfully established.
+
+.It Supports server-side PPP connections.
+In direct mode,
+.nm
+acts as server which accepts incoming
+.Em PPP
+connections on stdin/stdout.
+
+.It Supports PAP and CHAP authentication.
+With PAP or CHAP, it is possible to skip the Unix style
+.Xr login 1
+proceedure, and use the
+.Em PPP
+protocol for authentication instead.
+
+.It Supports Proxy Arp.
+When
+.Em PPP
+is set up as server, you can also configure it to do proxy arp for your
+connection.
+
+.It Supports packet filtering.
+User can define four kinds of filters:
+.Em ifilter
+for incoming packets,
+.Em ofilter
+for outgoing packets,
+.Em dfilter
+to define a dialing trigger packet and
+.Em afilter
+for keeping a connection alive with the trigger packet.
+
+.It Tunnel driver supports bpf.
+The user can use
+.Xr tcpdump 1
+to check the packet flow over the
+.Em PPP
+link.
+
+.It Supports PPP over TCP capability.
+
+
+.It Supports IETF draft Predictor-1 compression.
+.Nm
+supports not only VJ-compression but also Predictor-1 compression.
+Normally, a modem has built-in compression (e.g. v42.bis) and the system
+may receive higher data rates from it as a result of such compression.
+While this is generally a good thing in most other situations, this
+higher speed data imposes a penalty on the system by increasing the
+number of serial interrupts the system has to process in talking to the
+modem and also increases latency. Unlike VJ-compression, Predictor-1
+compression pre-compresses
+.Em all
+data flowing through the link, thus reducing overhead to a minimum.
+
+.It Supports Microsoft's IPCP extensions.
+Name Server Addresses and NetBIOS Name Server Addresses can be negotiated
+with clients using the Microsoft
+.Em PPP
+stack (ie. Win95, WinNT)
+
+.Sh PERMISSIONS
+.Nm Ppp
+is installed as user
+.Dv root
+and group
+.Dv network ,
+with permissions
+.Dv 4550 .
+By default,
+.Nm
+will not run if the invoking user id is not zero. This may be overridden
+by using the
+.Dq allow users
+command in
+.Pa /etc/ppp/ppp.conf .
+When running as a normal user,
+.Nm
+switches to user id 0 in order to alter the system routing table, set up
+system lock files and read the ppp configuration files. All
+external commands (executed via the "shell" or "!bg" commands) are executed
+as the user id that invoked
+.Nm ppp .
+Refer to the
+.Sq ID0
+logging facility if you're interested in what exactly is done as user id
+zero.
+
+.Sh GETTING STARTED
+
+When you first run
+.Nm
+you may need to deal with some initial configuration details. First,
+your kernel should include a tunnel device (the GENERIC kernel includes
+one by default). If it doesn't, or if you require more than one tun
+interface, you'll need to rebuild your kernel with the following line in
+your kernel configuration file:
+
+.Dl pseudo-device tun N
+
+where
+.Ar N
+is the maximum number of
+.Em PPP
+connections you wish to support.
+
+Second, check your
+.Pa /dev
+directory for the tunnel device entries
+.Pa /dev/tunN ,
+where
+.Sq N
+represents the number of the tun device, starting at zero.
+If they don't exist, you can create them by running "sh ./MAKEDEV tunN".
+This will create tun devices 0 through
+.Ar N .
+
+Last of all, create a log file.
+.Nm Ppp
+uses
+.Xr syslog 3
+to log information. A common log file name is
+.Pa /var/log/ppp.log .
+To make output go to this file, put the following lines in the
+.Pa /etc/syslog.conf
+file:
+
+.Dl !ppp
+.Dl *.*<TAB>/var/log/ppp.log
+
+Make sure you use actual TABs here. If you use spaces, the line will be
+silently ignored.
+
+It is possible to have more than one
+.Em PPP
+log file by creating a link to the
+.Nm
+executable:
+
+.Dl # cd /usr/sbin
+.Dl # ln ppp ppp0
+
+and using
+
+.Dl !ppp0
+.Dl *.* /var/log/ppp0.log
+
+in
+.Pa /etc/syslog.conf .
+Don't forget to send a
+.Dv HUP
+signal to
+.Xr syslogd 8
+after altering
+.Pa /etc/syslog.conf .
+
+.Sh MANUAL DIALING
+
+In the following examples, we assume that your machine name is
+.Dv awfulhak .
+
+If you set your host name and password in
+.Pa /etc/ppp/ppp.secret ,
+you can't do anything except run the help, passwd and quit commands.
+
+.Bd -literal -offset indent
+ppp on "your host name"> help
+ help : Display this message
+ passwd : Password for security
+ quit : Quit the PPP program
+ppp on awfulhak> pass <password>
+.Ed
+
+The "on" part of your prompt will change to "ON" if you specify the
+correct password.
+
+.Bd -literal -offset indent
+ppp ON awfulhak>
+.Ed
+
+You can now specify the device name, speed and parity for your modem,
+and whether CTS/RTS signalling should be used (CTS/RTS is used by
+default). If your hardware does not provide CTS/RTS lines (as
+may happen when you are connected directly to certain PPP-capable
+terminal servers),
+.Nm
+will never send any output through the port; it waits for a signal
+which never comes. Thus, if you have a direct line and can't seem
+to make a connection, try turning CTS/RTS off:
+
+
+.Bd -literal -offset indent
+ppp ON awfulhak> set line /dev/cuaa0
+ppp ON awfulhak> set speed 38400
+ppp ON awfulhak> set parity even
+ppp ON awfulhak> set ctsrts on
+ppp ON awfulhak> show modem
+
+* Modem related information is shown here *
+
+ppp ON awfulhak>
+.Ed
+
+The term command can now be used to talk directly with your modem:
+
+.Bd -literal -offset indent
+ppp ON awfulhak> term
+at
+OK
+atdt123456
+CONNECT
+login: ppp
+Password:
+Protocol: ppp
+.Ed
+
+When the peer starts to talk in
+.Em PPP ,
+.Nm
+detects this automatically and returns to command mode.
+
+.Bd -literal -offset indent
+ppp ON awfulhak>
+PPP ON awfulhak>
+.Ed
+
+You are now connected! Note that
+.Sq PPP
+in the prompt has changed to capital letters to indicate that you have
+a peer connection. The show command can be used to see how things are
+going:
+
+.Bd -literal -offset indent
+PPP ON awfulhak> show lcp
+
+* LCP related information is shown here *
+
+PPP ON awfulhak> show ipcp
+
+* IPCP related information is shown here *
+.Ed
+
+At this point, your machine has a host route to the peer. This means
+that you can only make a connection with the host on the other side
+of the link. If you want to add a default route entry (telling your
+machine to send all packets without another routing entry to the other
+side of the
+.Em PPP
+link), enter the following command:
+
+.Bd -literal -offset indent
+PPP ON awfulhak> add 0 0 HISADDR
+.Ed
+
+The string
+.Sq HISADDR
+represents the IP address of the connected peer. This variable is only
+available once a connection has been established. A common error
+is to specify the above command in your
+.Pa /etc/ppp/ppp.conf
+file. This won't work as the remote IP address hasn't been
+established when this file is read.
+
+You can now use your network applications (ping, telnet, ftp etc.)
+in other windows on your machine.
+
+Refer to the
+.Em PPP COMMAND LIST
+section for details on all available commands.
+
+.Sh AUTOMATIC DIALING
+
+To use automatic dialing, you must prepare some Dial and Login chat scripts.
+See the example definitions in
+.Pa /etc/ppp/ppp.conf.sample
+(the format of
+.Pa /etc/ppp/ppp.conf
+is pretty simple).
+
+Each line contains one comment, inclusion, label or command:
+
+.Bl -bullet -compact
+.It
+A line starting with a
+.Pq Dq #
+character is treated as a comment line.
+
+.It
+An inclusion is a line beginning with the word
+.Sq !include .
+It must have one argument - the file to include. You may wish to
+.Dq !include ~/.ppp.conf
+for compatibility with older versions of
+.Nm ppp .
+
+.It
+A label name starts in the first column and is followed by
+a colon
+.Pq Dq \&: .
+
+.It
+A command line must contain a space or tab in the first column.
+.El
+
+.Pp
+The
+.Pa /etc/ppp/ppp.conf
+file should consist of at least a
+.Dq default
+section. This section is always executed. It should also contain
+one or more sections, named according to their purpose, for example,
+.Dq MyISP
+would represent your ISP, and
+.Dq ppp-in
+would represent an incoming
+.Nm
+configuration.
+
+You can now specify the destination label name when you invoke
+.Nm ppp .
+Commands associated with the
+.Dq default
+label are executed, followed by those associated with the destination
+label provided. When
+.Nm
+is started with no arguments, the
+.Dq default
+section is still executed. The load command can be used to manually
+load a section from the
+.Pa /etc/ppp/ppp.conf
+file:
+
+.Bd -literal -offset indent
+PPP ON awfulhak> load MyISP
+.Ed
+
+Once the connection is made, the
+.Sq ppp
+portion of the prompt will change to
+.Sq PPP :
+
+.Bd -literal -offset indent
+# ppp MyISP
+...
+ppp ON awfulhak> dial
+dial OK!
+login OK!
+PPP ON awfulhak>
+.Ed
+
+If the
+.Pa /etc/ppp/ppp.linkup
+file is available, its contents are executed
+when the
+.Em PPP
+connection is established. See the provided
+.Dq pmdemand
+example in
+.Pa /etc/ppp/ppp.conf.sample
+which adds a default route. The strings
+.Dv HISADDR ,
+.Dv MYADDR
+and
+.Dv INTERFACE
+are available as the relevent IP addresses and interface name.
+Similarly, when a connection is closed, the
+contents of the
+.Pa /etc/ppp/ppp.linkdown
+file are executed.
+
+Both of these files have the same format as
+.Pa /etc/ppp/ppp.conf .
+
+.Sh BACKGROUND DIALING
+
+If you want to establish a connection using
+.Nm
+non-interactively (such as from a
+.Xr crontab 5
+entry or an
+.Xr at 1
+job) you should use the
+.Fl background
+option. You must also specify the destination label in
+.Pa /etc/ppp/ppp.conf
+to use. This label must contain the
+.Dq set ifaddr
+command to define the remote peers IP address. (refer to
+.Pa /etc/ppp/ppp.conf.sample )
+
+When
+.Fl background
+is specified,
+.Nm
+attempts to establish the connection immediately. If multiple phone
+numbers are specified, each phone number will be tried once. If the
+attempt fails,
+.Nm
+exits immediately with a non-zero exit code.
+
+If it succeeds, then
+.Nm
+becomes a daemon, and returns an exit status of zero to its caller.
+The daemon exits automatically if the connection is dropped by the
+remote system, or it receives a
+.Dv TERM
+signal.
+
+.Sh DIAL ON DEMAND
+
+Demand dialing is enabled with the
+.Fl auto
+or
+.Fl ddial
+options. You must also specify the destination label in
+.Pa /etc/ppp/ppp.conf
+to use. It must contain the
+.Dq set ifaddr
+command to define the remote peers IP address. (refer to
+.Pa /etc/ppp/ppp.conf.sample )
+
+.Bd -literal -offset indent
+# ppp -auto pmdemand
+...
+#
+.Ed
+
+When
+.Fl auto
+or
+.Fl ddial
+is specified,
+.Nm
+runs as a daemon but you can still configure or examine its
+configuration by using the diagnostic port as follows (this
+can be done in
+.Fl background
+and
+.Fl direct
+mode too):
+
+.Bd -literal -offset indent
+# pppctl -v 3000 show ipcp
+Password:
+IPCP [Opened]
+ his side: xxxx
+ ....
+.Ed
+
+Currently,
+.Xr telnet 1
+may also be used to talk interactively.
+
+.Pp
+In order to achieve this, you must use the
+.Dq set server
+command as described below. It is possible to retrospectively make a running
+.Nm
+program listen on a diagnostic port by configuring
+.Pa /etc/ppp/ppp.secret ,
+and sending it a
+.Dv USR1
+signal.
+
+In
+.Fl auto
+mode, when an outgoing packet is detected,
+.Nm
+will perform the dialing action (chat script) and try to connect
+with the peer. In
+.Fl ddial
+mode, the dialing action is performed any time the line is found
+to be down.
+
+If the connect fails, the default behaviour is to wait 30 seconds
+and then attempt to connect when another outgoing packet is detected.
+This behaviour can be changed with
+.Bd -literal -offset indent
+set redial seconds|random[.nseconds|random] [dial_attempts]
+.Ed
+.Pp
+.Sq Seconds
+is the number of seconds to wait before attempting
+to connect again. If the argument is
+.Sq random ,
+the delay period is a random value between 0 and 30 seconds.
+.Sq Nseconds
+is the number of seconds to wait before attempting
+to dial the next number in a list of numbers (see the
+.Dq set phone
+command). The default is 3 seconds. Again, if the argument is
+.Sq random ,
+the delay period is a random value between 0 and 30 seconds.
+.Sq dial_attempts
+is the number of times to try to connect for each outgoing packet
+that is received. The previous value is unchanged if this parameter
+is omitted. If a value of zero is specified for
+.Sq dial_attempts ,
+.Nm
+will keep trying until a connection is made.
+.Bd -literal -offset indent
+set redial 10.3 4
+.Ed
+.Pp
+will attempt to connect 4 times for each outgoing packet that is
+detected with a 3 second delay between each number and a 10 second
+delay after all numbers have been tried. If multiple phone numbers
+are specified, the total number of attempts is still 4 (it does not
+attempt each number 4 times).
+
+Modifying the dial delay is very useful when running
+.Nm
+in demand
+dial mode on both ends of the link. If each end has the same timeout,
+both ends wind up calling each other at the same time if the link
+drops and both ends have packets queued.
+
+At some locations, the serial link may not be reliable, and carrier
+may be lost at inappropriate times. It is possible to have
+.Nm
+redial should carrier be unexpectedly lost during a session.
+.Bd -literal -offset indent
+set reconnect timeout ntries
+.Ed
+
+This command tells
+.Nm
+to re-establish the connection
+.Ar ntries
+times on loss of carrier with a pause of
+.Ar timeout
+seconds before each try. For example,
+.Bd -literal -offset indent
+set reconnect 3 5
+.Ed
+
+tells
+.Nm
+that on an unexpected loss of carrier, it should wait
+.Ar 3
+seconds before attempting to reconnect. This may happen up to
+.Ar 5
+times before
+.Nm
+gives up. The default value of ntries is zero (no reconnect). Care
+should be taken with this option. If the local timeout is slightly
+longer than the remote timeout, the reconnect feature will always be
+triggered (up to the given number of times) after the remote side
+times out and hangs up.
+
+NOTE: In this context, losing too many LQRs constitutes a loss of
+carrier and will trigger a reconnect.
+
+If the
+.Fl background
+flag is specified, all phone numbers are dialed at most once until
+a connection is made. The next number redial period specified with
+the
+.Dq set redial
+command is honoured, as is the reconnect tries value. If your redial
+value is less than the number of phone numbers specified, not all
+the specified numbers will be tried.
+
+To terminate the program, type
+
+ PPP ON awfulhak> close
+ ppp ON awfulhak> quit all
+
+.Pp
+A simple
+.Dq quit
+command will terminate the
+.Xr pppctl 8
+or
+.Xr telnet 1
+connection but not the
+.Nm
+program itself.
+You must use
+.Dq quit all
+to terminate
+.Nm
+as well.
+
+.Sh RECEIVING INCOMING PPP CONNECTIONS (Method 1)
+
+To handle an incoming
+.Em PPP
+connection request, follow these steps:
+
+.Bl -enum
+.It
+Make sure the modem and (optionally)
+.Pa /etc/rc.serial
+is configured correctly.
+.Bl -bullet -compact
+.It
+Use Hardware Handshake (CTS/RTS) for flow control.
+.It
+Modem should be set to NO echo back (ATE0) and NO results string (ATQ1).
+.El
+
+.It
+Edit
+.Pa /etc/ttys
+to enable a
+.Xr getty 8
+on the port where the modem is attached.
+
+For example:
+
+.Dl ttyd1 "/usr/libexec/getty std.38400" dialup on secure
+
+Don't forget to send a
+.Dv HUP
+signal to the
+.Xr init 8
+process to start the
+.Xr getty 8 .
+
+.Dl # kill -HUP 1
+
+.It
+Prepare an account for the incoming user.
+.Bd -literal
+ppp:xxxx:66:66:PPP Login User:/home/ppp:/usr/local/bin/ppplogin
+.Ed
+
+.It
+Create a
+.Pa /usr/local/bin/ppplogin
+file with the following contents:
+.Bd -literal -offset indent
+#!/bin/sh -p
+exec /usr/sbin/ppp -direct
+.Ed
+
+(You can specify a label name for further control.)
+
+.Pp
+Direct mode
+.Pq Fl direct
+lets
+.Nm
+work with stdin and stdout. You can also use
+.Xr pppctl 8
+or
+.Xr telnet 1
+to connect to a configured diagnostic port, in the same manner as with
+client-side
+.Nm ppp .
+
+.It
+Optional support for Microsoft's IPCP Name Server and NetBIOS
+Name Server negotiation can be enabled use
+.Dq enable msext
+and
+.Dq set ns pri-addr [sec-addr]
+along with
+.Dq set nbns pri-addr [sec-addr]
+in your
+.Pa /etc/ppp/ppp.conf
+file.
+
+.El
+
+.Sh RECEIVING INCOMING PPP CONNECTIONS (Method 2)
+
+This method differs in that it recommends the use of
+.Em mgetty+sendfax
+to handle the modem connections. The latest versions (0.99 and higher)
+can be compiled with the
+.Dq AUTO_PPP
+option to allow detection of clients speaking
+.Em PPP
+to the login prompt.
+
+Follow these steps:
+
+.Bl -enum
+
+.It
+Get, configure, and install mgetty+sendfax v0.99 or later making
+sure you have used the AUTO_PPP option.
+
+.It
+Edit
+.Pa /etc/ttys
+to enable a mgetty on the port where the modem is attached. For
+example:
+
+.Dl cuaa1 "/usr/local/sbin/mgetty -s 57600" dialup on
+
+.It
+Prepare an account for the incoming user.
+.Bd -literal
+Pfred:xxxx:66:66:Fred's PPP:/home/ppp:/etc/ppp/ppp-dialup
+.Ed
+
+.It
+Examine the files
+.Pa /etc/ppp/sample.ppp-dialup ,
+.Pa /etc/ppp/sample.ppp-pap-dialup
+and
+.Pa /etc/ppp/ppp.conf.sample
+for ideas.
+.Pa /etc/ppp/ppp-pap-dialup
+is supposed to be called from
+.Pa /usr/local/etc/mgetty+sendfax/login.conf
+from a line like
+
+.Dl /AutoPPP/ - - /etc/ppp/ppp-pap-dialup
+.El
+
+.Sh PPP OVER TCP (a.k.a Tunneling)
+
+Instead of running
+.Nm
+over a serial link, it is possible to
+use a TCP connection instead by specifying a host and port as the
+device:
+
+.Dl set device ui-gate:6669
+
+Instead of opening a serial device,
+.Nm
+will open a TCP connection to the given machine on the given
+socket. It should be noted however that
+.Nm
+doesn't use the telnet protocol and will be unable to negotiate
+with a telnet server. You should set up a port for receiving this
+.Em PPP
+connection on the receiving machine (ui-gate). This is
+done by first updating
+.Pa /etc/services
+to name the service:
+
+.Dl ppp-in 6669/tcp # Incoming PPP connections over TCP
+
+and updating
+.Pa /etc/inetd.conf
+to tell
+.Xr inetd 8
+how to deal with incoming connections on that port:
+
+.Dl ppp-in stream tcp nowait root /usr/sbin/ppp ppp -direct ppp-in
+
+Don't forget to send a
+.Dv HUP
+signal to
+.Xr inetd 8
+after you've updated
+.Pa /etc/inetd.conf .
+
+Here, we use a label named
+.Dq ppp-in .
+The entry in
+.Pa /etc/ppp/ppp.conf
+on ui-gate (the receiver) should contain the following:
+
+.Bd -literal -offset indent
+ppp-in:
+ set timeout 0
+ set ifaddr 10.0.4.1 10.0.4.2
+ add 10.0.1.0 255.255.255.0 10.0.4.1
+.Ed
+
+You may also want to enable PAP or CHAP for security. To enable PAP, add
+the following line:
+.Bd -literal -offset indent
+ enable PAP
+.Ed
+.Pp
+You'll also need to create the following entry in
+.Pa /etc/ppp/ppp.secret :
+.Bd -literal -offset indent
+MyAuthName MyAuthPasswd
+.Ed
+.Pp
+The entry in
+.Pa /etc/ppp/ppp.conf
+on awfulhak (the initiator) should contain the following:
+
+.Bd -literal -offset indent
+ui-gate:
+ set escape 0xff
+ set device ui-gate:ppp-in
+ set dial
+ set timeout 30 5 4
+ set log Phase Chat Connect Carrier hdlc LCP IPCP CCP tun
+ set ifaddr 10.0.4.2 10.0.4.1
+ add 10.0.2.0 255.255.255.0 10.0.4.2
+.Ed
+.Pp
+Again, if you're enabling PAP, you'll also need:
+.Bd -literal -offset indent
+ set authname MyAuthName
+ set authkey MyAuthKey
+.Ed
+
+We're assigning the address of 10.0.4.1 to ui-gate, and the address
+10.0.4.2 to awfulhak.
+
+To open the connection, just type
+
+.Dl awfulhak # ppp -background ui-gate
+
+The result will be an additional "route" on awfulhak to the
+10.0.2.0/24 network via the TCP connection, and an additional
+"route" on ui-gate to the 10.0.1.0/24 network.
+
+The networks are effectively bridged - the underlying TCP
+connection may be across a public network (such as the
+Internet), and the
+.Em PPP
+traffic is conceptually encapsulated
+(although not packet by packet) inside the TCP stream between
+the two gateways.
+
+The major disadvantage of this mechanism is that there are two
+"guaranteed delivery" mechanisms in place - the underlying TCP
+stream and whatever protocol is used over the
+.Em PPP
+link - probably TCP again. If packets are lost, both levels will
+get in each others way trying to negotiate sending of the missing
+packet.
+
+.Sh PACKET ALIASING
+
+The
+.Fl alias
+command line option enables packet aliasing. This allows the
+.Nm
+host to act as a masquerading gateway for other computers over
+a local area network. Outgoing IP packets are aliased so that
+they appear to come from the
+.Nm
+host, and incoming packets are de-aliased so that they are routed
+to the correct machine on the local area network.
+
+Packet aliasing allows computers on private, unregistered
+subnets to have Internet access, although they are invisible
+from the outside world.
+
+In general, correct
+.Nm
+operation should first be verified with packet aliasing disabled.
+Then, the
+.Fl alias
+option should be switched on, and network applications (web browser,
+.Xr telnet 1 ,
+.Xr ftp 1 ,
+.Xr ping 8 ,
+.Xr traceroute 8 )
+should be checked on the
+.Nm
+host. Finally, the same or similar applications should be checked on other
+computers in the LAN.
+
+If network applications work correctly on the
+.Nm
+host, but not on other machines in the LAN, then the masquerading
+software is working properly, but the host is either not forwarding
+or possibly receiving IP packets. Check that IP forwarding is enabled in
+.Pa /etc/rc.conf
+and that other machines have designated the
+.Nm
+host as the gateway for the LAN.
+
+.Sh PACKET FILTERING
+
+This implementation supports packet filtering. There are four kinds of
+filters; ifilter, ofilter, dfilter and afilter. Here are the basics:
+
+.Bl -bullet -compact
+.It
+A filter definition has the following syntax:
+
+set filter-name rule-no action [src_addr/src_width] [dst_addr/dst_width]
+[proto [src [lt|eq|gt] port ]] [dst [lt|eq|gt] port] [estab]
+.Bl -enum
+.It
+.Sq filter-name
+should be one of ifilter, ofilter, dfilter or afilter.
+.It
+There are two actions:
+.Sq permit
+and
+.Sq deny .
+If a given packet
+matches the rule, the associated action is taken immediately.
+.It
+.Sq src_width
+and
+.Sq dst_width
+work like a netmask to represent an address range.
+.It
+.Sq proto
+must be one of icmp, udp or tcp.
+.It
+.Sq port number
+can be specified by number and service name from
+.Pa /etc/services .
+
+.El
+
+.It
+Each filter can hold up to 20 rules, starting from rule 0.
+The entire rule set is not effective until rule 0 is defined,
+ie. the default is to allow everything through.
+
+.It
+If no rule is matched to a packet, that packet will be discarded
+(blocked).
+
+.It
+Use
+.Dq set filter-name -1
+to flush all rules.
+
+.El
+
+See
+.Pa /etc/ppp/ppp.conf.filter.example .
+
+
+.Sh SETTING IDLE, LINE QUALITY REQUEST, RETRY TIMER
+
+To check/set idle timer, use the
+.Dq show timeout
+and
+.Dq set timeout [lqrtimer [retrytimer]]
+commands:
+
+.Bd -literal -offset indent
+ppp ON awfulhak> set timeout 600
+.Ed
+
+The timeout period is measured in seconds, the default values for which
+are timeout = 180 or 3 min, lqrtimer = 30sec and retrytimer = 3sec.
+To disable the idle timer function, use the command
+
+.Bd -literal -offset indent
+ppp ON awfulhak> set timeout 0
+.Ed
+
+In
+.Fl auto
+mode, an idle timeout causes the
+.Em PPP
+session to be
+closed, though the
+.Nm
+program itself remains running. Another trigger packet will cause it to
+attempt to reestablish the link.
+
+.Sh PREDICTOR-1 COMPRESSION
+
+This version supports CCP and Predictor type 1 compression based on
+the current IETF-draft specs. As a default behaviour,
+.Nm
+will attempt to use (or be willing to accept) this capability when the
+peer agrees (or requests it).
+
+To disable CCP/predictor functionality completely, use the
+.Dq disable pred1
+and
+.Dq deny pred1
+commands.
+
+.Sh CONTROLLING IP ADDRESS
+
+.Nm
+uses IPCP to negotiate IP addresses. Each side of the connection
+specifies the IP address that it's willing to use, and if the requested
+IP address is acceptable then
+.Nm
+returns ACK to the requester. Otherwise,
+.Nm
+returns NAK to suggest that the peer use a different IP address. When
+both sides of the connection agree to accept the received request (and
+send ACK), IPCP is set to the open state and a network level connection
+is established.
+
+To control this IPCP behaviour, this implementation has the
+.Dq set ifaddr
+command for defining the local and remote IP address:
+
+.Bd -literal -offset indent
+set ifaddr [src_addr [dst_addr [netmask [trigger_addr]]]]
+.Ed
+
+where,
+.Sq src_addr
+is the IP address that the local side is willing to use,
+.Sq dst_addr
+is the IP address which the remote side should use and
+.Sq netmask
+is the netmask that should be used.
+.Sq Src_addr
+and
+.Sq dst_addr
+default to 0.0.0.0, and
+.Sq netmask
+defaults to whatever mask is appropriate for
+.Sq src_addr .
+It is only possible to make
+.Sq netmask
+smaller than the default. The usual value is 255.255.255.255.
+Some incorrect
+.Em PPP
+implementations require that the peer negotiates a specific IP
+address instead of
+.Sq src_addr .
+If this is the case,
+.Sq trigger_addr
+may be used to specify this IP number. This will not affect the
+routing table unless the other side agrees with this proposed number.
+
+.Bd -literal -offset indent
+set ifaddr 192.244.177.38 192.244.177.2 255.255.255.255 0.0.0.0
+.Ed
+
+The above specification means:
+.Bl -bullet -compact
+.It
+I will first suggest that my IP address should be 0.0.0.0, but I
+will only accept an address of 192.244.177.38.
+
+.It
+I strongly insist that the peer uses 192.244.177.2 as his own
+address and won't permit the use of any IP address but 192.244.177.2.
+When the peer requests another IP address, I will always suggest that
+it uses 192.244.177.2.
+
+.It
+The routing table entry will have a netmask of 0xffffffff.
+.El
+
+This is all fine when each side has a pre-determined IP address, however
+it is often the case that one side is acting as a server which controls
+all IP addresses and the other side should obey the direction from it.
+
+In order to allow more flexible behaviour, `ifaddr' variable allows the
+user to specify IP address more loosely:
+
+.Dl set ifaddr 192.244.177.38/24 192.244.177.2/20
+
+A number followed by a slash (/) represent the number of bits significant in
+the IP address. The above example signifies that:
+
+.Bl -bullet -compact
+.It
+I'd like to use 192.244.177.38 as my address if it is possible, but I'll
+also accept any IP address between 192.244.177.0 and 192.244.177.255.
+
+.It
+I'd like to make him use 192.244.177.2 as his own address, but I'll also
+permit him to use any IP address between 192.244.176.0 and
+192.244.191.255.
+
+.It
+As you may have already noticed, 192.244.177.2 is equivalent to saying
+192.244.177.2/32.
+
+.It
+As an exception, 0 is equivalent to 0.0.0.0/0, meaning that I have no
+preferred IP address and will obey the remote peers selection. When
+using zero, no routing table entries will be made until a connection
+is established.
+
+.It
+192.244.177.2/0 means that I'll accept/permit any IP address but I'll
+try to insist that 192.244.177.2 be used first.
+.El
+
+.Sh CONNECTING WITH YOUR INTERNET SERVICE PROVIDER
+
+The following steps should be taken when connecting to your ISP:
+
+.Bl -enum
+.It
+Describe your providers phone number(s) in the dial script using the
+.Dq set phone
+command. This command allows you to set multiple phone numbers for
+dialing and redialing separated by either a pipe (|) or a colon (:)
+.Bd -literal -offset indent
+set phone "111[|222]...[:333[|444]...]...
+.Ed
+Numbers after the first in a pipe-separated list are only used if the
+previous number was used in a failed dial or login script. Numbers
+separated by a colon are used sequentially, irrespective of what happened
+as a result of using the previous number. For example:
+.Bd -literal -offset indent
+set phone "1234567|2345678:3456789|4567890"
+.Ed
+.Pp
+Here, the 1234567 number is attempted. If the dial or login script fails,
+the 2345678 number is used next time, but *only* if the dial or login script
+fails. On the dial after this, the 3456789 number is used. The 4567890
+number is only used if the dial or login script using the 3456789 fails. If
+the login script of the 2345678 number fails, the next number is still the
+3456789 number. As many pipes and colons can be used as are necessary
+(although a given site would usually prefer to use either the pipe or the
+colon, but not both). The next number redial timeout is used between all
+numbers. When the end of the list is reached, the normal redial period is
+used before starting at the beginning again.
+
+The selected phone number is substituted for the \\\\T string in the
+.Dq set dial
+command (see below).
+
+.It
+Set up your redial requirements using
+.Dq set redial .
+For example, if you have a bad telephone line or your provider is
+usually engaged (not so common these days), you may want to specify
+the following:
+.Bd -literal -offset indent
+set redial 10 4
+.Ed
+.Pp
+This says that up to 4 phone calls should be attempted with a pause of 10
+seconds before dialing the first number again.
+
+.It
+Describe your login procedure using the
+.Dq set dial
+and
+.Dq set login
+commands. The
+.Dq set dial
+command is used to talk to your modem and establish a link with your
+ISP, for example:
+.Bd -literal -offset indent
+set dial "ABORT BUSY ABORT NO\\\\sCARRIER TIMEOUT 4 \\"\\" ATZ OK-ATZ-OK ATDT\\\\T TIMEOUT 60 CONNECT"
+.Ed
+.Pp
+This modem "chat" string means:
+
+.Bl -bullet
+.It
+Abort if the string "BUSY" or "NO CARRIER" are received.
+.It
+Set the timeout to 4.
+.It
+Expect nothing.
+.It
+Send ATZ.
+.It
+Expect OK. If that's not received, send ATZ and expect OK.
+.It
+Send ATDTxxxxxxx where xxxxxxx is the next number in the phone list from
+above.
+.It
+Set the timeout to 60.
+.It
+Wait for the CONNECT string.
+.El
+
+Once the connection is established, the login script is executed. This
+script is written in the same style as the dial script:
+.Bd -literal -offset indent
+set login "TIMEOUT 15 login:-\\\\r-login: awfulhak word: xxx ocol: PPP HELLO"
+.Ed
+.Pp
+This login "chat" string means:
+
+.Bl -bullet
+.It
+Set the timeout to 15 seconds.
+.It
+Expect "login:". If it's not received, send a carriage return and expect
+"login:" again.
+.It
+Send "awfulhak"
+.It
+Expect "word:" (the tail end of a "Password:" prompt).
+.It
+Send "xxx".
+.It
+Expect "ocol:" (the tail end of a "Protocol:" prompt).
+.It
+Send "PPP".
+.It
+Expect "HELLO".
+.El
+.Pp
+Login scripts vary greatly between ISPs.
+
+.It
+Use
+.Dq set line
+and
+.Dq set speed
+to specify your serial line and speed, for example:
+.Bd -literal -offset indent
+set line /dev/cuaa0
+set speed 115200
+.Ed
+.Pp
+Cuaa0 is the first serial port on FreeBSD. If you're running
+.Nm
+on OpenBSD, cua00 is the first. A speed of 115200 should be specified
+if you have a modem capable of bit rates of 28800 or more. In general,
+the serial speed should be about four times the modem speed.
+
+.It
+Use the
+.Dq set ifaddr
+command to define the IP address.
+.Bl -bullet
+.It
+If you know what IP address your provider uses, then use it as the remote
+address (dst_addr), otherwise choose something like 10.0.0.2/0 (see below).
+.It
+If your provider has assigned a particular IP address to you, then use
+it as your address (src_addr).
+.It
+If your provider assigns your address dynamically, choose a suitably
+unobtrusive and unspecific IP number as your address. 10.0.0.1/0 would
+be appropriate. The bit after the / specifies how many bits of the
+address you consider to be important, so if you wanted to insist on
+something in the class C network 1.2.3.0, you could specify 1.2.3.1/24.
+.It
+If you find that your ISP accepts the first IP number that you suggest,
+specify third and forth arguments of
+.Dq 0.0.0.0 .
+This will force your ISP to assign a number. (The third argument will
+be ignored as it is less restrictive than the default mask for your
+.Sq src_addr .
+.El
+.Pp
+An example for a connection where you don't know your IP number or your
+ISPs IP number would be:
+.Bd -literal -offset indent
+set ifaddr 10.10.10.10/0 10.10.11.11/0 0.0.0.0 0.0.0.0
+.Ed
+
+.It
+In most cases, your ISP will also be your default router. If this is
+the case, add the lines
+
+.Bd -literal -offset indent
+delete ALL
+add 0 0 HISADDR
+.Ed
+
+.Pp
+to
+.Pa /etc/ppp/ppp.conf .
+.Pp
+This tells
+.Nm
+to delete all non-direct routing entries for the tun interface that
+.Nm
+is running on, then to add a default route to 10.10.11.11.
+.Pp
+If you're using dynamic IP numbers, you must also put these two lines
+in the
+.Pa /etc/ppp/ppp.linkup
+file:
+
+.Bd -literal -offset indent
+delete ALL
+add 0 0 HISADDR
+.Ed
+
+HISADDR is a macro meaning the "other side"s IP number, and is
+available once an IP number has been agreed (using IPCP).
+Now, once a connection is established,
+.Nm
+will delete all non-direct interface routes, and add a default route
+pointing at the peers IP number. You should use the same label as the
+one used in
+.Pa /etc/ppp/ppp.conf .
+.Pp
+If commands are being typed interactively, the only requirement is
+to type
+.Bd -literal -offset indent
+add 0 0 HISADDR
+.Ed
+.Pp
+after a successful dial.
+
+.It
+If your provider requests that you use PAP/CHAP authentication methods, add
+the next lines to your
+.Pa /etc/ppp/ppp.conf
+file:
+.Bd -literal -offset indent
+set authname MyName
+set authkey MyPassword
+.Ed
+.Pp
+Both are accepted by default, so
+.Nm
+will provide whatever your ISP requires.
+.El
+
+Please refer to
+.Pa /etc/ppp/ppp.conf.sample
+and
+.Pa /etc/ppp/ppp.linkup.sample
+for some real examples. The pmdemand label should be appropriate for most
+ISPs.
+
+.Sh LOGGING FACILITY
+
+.Nm
+is able to generate the following log info either via
+.Xr syslog 3
+or directly to the screen:
+
+.Bl -column SMMMMMM -offset indent
+.It Li Async Dump async level packet in hex
+.It Li Carrier Log Chat lines with 'CARRIER'
+.It Li CCP Generate a CCP packet trace
+.It Li Chat Generate Chat script trace log
+.It Li Command Log commands executed
+.It Li Connect Generate complete Chat log
+.It Li Debug Log (very verbose) debug information
+.It Li HDLC Dump HDLC packet in hex
+.It Li ID0 Log all function calls specifically made as user id 0.
+.It Li IPCP Generate an IPCP packet trace
+.It Li LCP Generate an LCP packet trace
+.It Li Link Log address assignments and link up/down events
+.It Li LQM Generate LQR report
+.It Li Phase Phase transition log output
+.It Li TCP/IP Dump all TCP/IP packets
+.It Li TUN Include the tun device on each log line
+.It Li Warning Output to the terminal device. If there is currently no
+terminal, output is sent to the log file using LOG_WARNING.
+.It Li Error Output to both the terminal device and the log file using
+LOG_ERROR.
+.It Li Alert Output to the log file using LOG_ALERT
+.El
+
+.Pp
+The
+.Dq set log
+command allows you to set the logging output level. Multiple levels
+can be specified on a single command line. The default is equivalent to
+.Dq set log Carrier Link Phase .
+
+.Pp
+It is also possible to log directly to the screen. The syntax is
+the same except that the word
+.Dq local
+should immediately follow
+.Dq set log .
+The default is
+.Dq set log local
+(ie. no direct screen logging).
+
+.Pp
+If The first argument to
+.Dq set log Op local
+begins with a '+' or a '-' character, the current log levels are
+not cleared, for example:
+
+.Bd -literal -offset indent
+PPP ON awfulhak> set log carrier link phase
+PPP ON awfulhak> show log
+Log: Carrier Link Phase Warning Error Alert
+Local: Warning Error Alert
+PPP ON awfulhak> set log -link +tcp/ip -warning
+PPP ON awfulhak> set log local +command
+PPP ON awfulhak> show log
+Log: Carrier Phase TCP/IP Warning Error Alert
+Local: Command Warning Error Alert
+.Ed
+
+.Pp
+Log messages of level Warning, Error and Alert are not controllable
+using
+.Dq set log Op local .
+
+.Pp
+The
+.Ar Warning
+level is special in that it will not be logged if it can be displayed
+locally.
+
+.Sh SIGNAL HANDLING
+
+.Nm Ppp
+deals with the following signals:
+
+.Bl -tag -width 20
+.It INT
+Receipt of this signal causes the termination of the current connection
+(if any). This will cause
+.Nm
+to exit unless it is in
+.Fl auto
+or
+.Fl ddial
+mode.
+
+.It HUP, TERM & QUIT
+These signals tell
+.Nm
+to exit.
+
+.It USR1
+This signal, when not in interactive mode, tells
+.Nm
+to close any existing server socket and open an Internet socket using
+port 3000 plus the current tunnel device number. This can only be
+achieved if a suitable local password is specified in
+.Pa /etc/ppp/ppp.secret .
+
+.It USR2
+This signal, tells
+.Nm
+to close any existing server socket.
+
+.El
+
+.Sh PPP COMMAND LIST
+
+This section lists the available commands and their effect. They are
+usable either from an interactive
+.Nm
+session, from a configuration file or from a
+.Xr pppctl 8
+or
+.Xr telnet 1
+session.
+
+.Bl -tag -width 20
+.It accept|deny|enable|disable option....
+These directives tell
+.Nm
+how to negotiate the initial connection with the peer. Each
+.Dq option
+has a default of either accept or deny and enable or disable.
+.Dq Accept
+means that the option will be ACK'd if the peer asks for it.
+.Dq Deny
+means that the option will be NAK'd if the peer asks for it.
+.Dq Enable
+means that the option will be requested by us.
+.Dq Disable
+means that the option will not be requested by us.
+.Pp
+.Dq Option
+may be one of the following:
+
+.Bl -tag -width 20
+.It acfcomp
+Default: Enabled and Accepted. ACFComp stands for Address and Control
+Field Compression. Non LCP packets usually have very similar address
+and control fields - making them easily compressible.
+
+.It chap
+Default: Disabled and Accepted. CHAP stands for Challenge Handshake
+Authentication Protocol. Only one of CHAP and PAP (below) may be
+negotiated. With CHAP, the authenticator sends a "challenge" message
+to its peer. The peer uses a one-way hash function to encrypt the
+challenge and sends the result back. The authenticator does the same,
+and compares the results. The advantage of this mechanism is that no
+passwords are sent across the connection.
+
+A challenge is made when the connection is first made. Subsequent
+challenges may occur. If you want to have your peer authenticate
+itself, you must
+.Dq enable chap .
+in
+.Pa /etc/ppp/ppp.conf ,
+and have an entry in
+.Pa /etc/ppp/ppp.secret
+for the peer.
+.Pp
+When using CHAP as the client, you need only specify
+.Dq AuthName
+and
+.Dq AuthKey
+in
+.Pa /etc/ppp/ppp.conf .
+CHAP is accepted by default.
+
+Some
+.Em PPP
+implementations use "MS-CHAP" rather than MD5 when encrypting the
+challenge. Refer to the description of the
+.Dq set encrypt
+command for further details.
+
+.It lqr
+Default: Disabled and Accepted. This option decides if Link Quality
+Requests will be sent. LQR is a protocol that allows
+.Nm
+to determine that the link is down without relying on the modems
+carrier detect.
+
+.It msext
+Default: Disabled. This option allows the use of Microsoft's
+.Em PPP
+extensions, supporting the negotiation of the DNS and the NetBIOS NS.
+Enabling this allows us to pass back the values given in "set ns"
+and "set nbns".
+
+.It pap
+Default: Disabled and Accepted. PAP stands for Password Authentication
+Protocol. Only one of PAP and CHAP (above) may be negotiated. With
+PAP, the ID and Password are sent repeatedly to the peer until
+authentication is acknowledged or the connection is terminated. This
+is a rather poor security mechanism. It is only performed when the
+connection is first established.
+
+If you want to have your peer authenticate itself, you must
+.Dq enable pap .
+in
+.Pa /etc/ppp/ppp.conf ,
+and have an entry in
+.Pa /etc/ppp/ppp.secret
+for the peer (although see the
+.Dq passwdauth
+option below).
+.Pp
+When using PAP as the client, you need only specify
+.Dq AuthName
+and
+.Dq AuthKey
+in
+.Pa /etc/ppp/ppp.conf .
+PAP is accepted by default.
+
+.It pred1
+Default: Enabled and Accepted. This option decides if Predictor 1
+compression will be used.
+
+.It protocomp
+Default: Enabled and Accepted. This option is used to negotiate
+PFC (Protocol Field Compression), a mechanism where the protocol
+field number is reduced to one octet rather than two.
+
+.It vjcomp
+Default: Enabled and Accepted. This option decides if Van Jacobson
+header compression will be used.
+.El
+
+.Pp
+The following options are not actually negotiated with the peer.
+Therefore, accepting or denying them makes no sense.
+
+.Bl -tag -width 20
+.It passwdauth
+Default: Disabled. Enabling this option will tell the PAP authentication
+code to use the password file (see
+.Xr passwd 5 )
+to authenticate the caller rather than the
+.Pa /etc/ppp/ppp.secret
+file.
+
+.It proxy
+Default: Disabled. Enabling this option will tell
+.Nm
+to proxy ARP for the peer.
+
+.It throughput
+Default: Disabled. Enabling this option will tell
+.Nm
+to gather thoroughput statistics. Input and output is sampled over
+a rolling 5 second window, and current, best and total figures are
+retained. This data is output when the relevent
+.Em PPP
+layer shuts down, and is also available using the
+.Dq show
+command. Troughput statistics are available at the
+.Dq IPCP
+and
+.Dq modem
+levels.
+
+.It utmp
+Default: Enabled. Normally, when a user is authenticated using PAP or
+CHAP, and when
+.Nm
+is running in
+.Fl direct
+mode, an entry is made in the utmp and wtmp files for that user. Disabling
+this option will tell
+.Nm
+not to make any utmp or wtmp entries. This is usually only necessary if
+you require the user to both login and authenticate themselves.
+
+.El
+
+.It add dest mask gateway
+.Dq Dest
+is the destination IP address and
+.Dq mask
+is its mask.
+.Dq 0 0
+refers to the default route.
+.Dq Gateway
+is the next hop gateway to get to the given
+.Dq dest
+machine/network.
+
+.It allow .....
+This command controls access to
+.Nm
+and its configuration files. It is possible to allow user-level access,
+depending on the configuration file label and on the mode that
+.Nm
+is being run in. For example, you may wish to configure
+.Nm
+so that only user
+.Sq fred
+may access label
+.Sq fredlabel
+in
+.Fl background
+mode.
+.Pp
+User id 0 is immune to these commands.
+
+.Bl -tag -width 20
+.It allow user|users logname...
+By default, only user id 0 is allowed access. If this command is specified,
+all of the listed users are allowed access to the section in which the
+.Dq allow users
+command is found. The
+.Sq default
+section is always checked first (although it is only ever automatically
+loaded at startup). Each successive
+.Dq allow users
+command overrides the previous one, so it's possible to allow users access
+to everything except a given label by specifying default users in the
+.Sq default
+section, and then specifying a new user list for that label.
+.Pp
+If user
+.Sq *
+is specified, access is allowed to all users.
+
+.It allow mode|modes modelist...
+By default, access using all
+.Nm
+modes is possible. If this command is used, it restricts the access
+modes allowed to load the label under which this command is specified.
+Again, as with the
+.Dq allow users
+command, each
+.Dq allow modes
+command overrides the previous, and the
+.Sq default
+section is always checked first.
+.Pp
+Possible modes are:
+.Sq interactive ,
+.Sq auto ,
+.Sq direct ,
+.Sq dedicated ,
+.Sq ddial ,
+.Sq background
+and
+.Sq * .
+.El
+
+.It alias .....
+This command allows the control of the aliasing (or masquerading)
+facilities that are built into
+.Nm ppp .
+Until this code is required, it is not loaded by
+.Nm ppp ,
+and it is quite possible that the alias library is not installed
+on your system (some administrators consider it a security risk).
+
+If aliasing is enabled on your system, the following commands are
+possible:
+
+.Bl -tag -width 20
+.It alias enable [yes|no]
+This command either switches aliasing on or turns it off.
+The
+.Fl alias
+command line flag is synonymous with
+.Dq alias enable yes .
+
+.It alias port [proto targetIP:targetPORT [aliasIP:]aliasPORT]
+This command allows us to redirect connections arriving at
+.Dq aliasPORT
+for machine [aliasIP] to
+.Dq targetPORT
+on
+.Dq targetIP .
+If proto is specified, only connections of the given protocol
+are matched. This option is useful if you wish to run things like
+Internet phone on the machines behind your gateway.
+
+.It alias addr [addr_local addr_alias]
+This command allows data for
+.Dq addr_alias
+to be redirected to
+.Dq addr_local .
+It is useful if you own a small number of real IP numbers that
+you wish to map to specific machines behind your gateway.
+
+.It alias deny_incoming [yes|no]
+If set to yes, this command will refuse all incoming connections
+by dropping the packets in much the same way as a firewall would.
+
+.It alias log [yes|no]
+This option causes various aliasing statistics and information to
+be logged to the file
+.Pa /var/log/alias.log .
+
+.It alias same_ports [yes|no]
+When enabled, this command will tell the alias library attempt to
+avoid changing the port number on outgoing packets. This is useful
+if you want to support protocols such as RPC and LPD which require
+connections to come from a well known port.
+
+.It alias use_sockets [yes|no]
+When enabled, this option tells the alias library to create a
+socket so that it can guarantee a correct incoming ftp data or
+IRC connection.
+
+.It alias unregistered_only [yes|no]
+Only alter outgoing packets with an unregistered source ad-
+dress. According to RFC 1918, unregistered source addresses
+are 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.
+
+.It alias help|?
+This command gives a summary of available alias commands.
+
+.El
+
+.It [!]bg command
+The given command is executed in the background.
+Any of the pseudo arguments
+.Dv HISADDR ,
+.Dv INTERFACE
+and
+.Dv MYADDR
+will be replaced with the appropriate values. If you wish to pause
+.Nm
+while the command executes, use the
+.Dv shell
+command instead.
+
+.It close
+Close the current connection (but don't quit).
+
+.It delete ALL | dest [gateway [mask]]
+If
+.Dq ALL
+is specified, all non-direct entries in the routing for the interface
+that
+.Nm
+is using are deleted. This means all entries for tunN, except the entry
+representing the actual link. When
+.Dq ALL
+is not used, any existing route with the given
+.Dq dest ,
+destination network
+.Dq mask
+and
+.Dq gateway
+is deleted. The default
+.Dq mask
+value is 0.0.0.0.
+
+.It dial|call [remote]
+If
+.Dq remote
+is specified, a connection is established using the
+.Dq dial
+and
+.Dq login
+scripts for the given
+.Dq remote
+system. Otherwise, the current settings are used to establish
+the connection.
+
+.It display
+Displays the current status of the negotiable protocol
+values as specified under
+.Dq accept|deny|enable|disable option....
+above.
+
+.It down
+Bring the link down ungracefully, as if the physical layer had become
+unavailable. It's not considered polite to use this command.
+
+.It help|? [command]
+Show a list of available commands. If
+.Dq command
+is specified, show the usage string for that command.
+
+.It load [remote]
+Load the given
+.Dq remote
+label. If
+.Dq remote
+is not given, the
+.Dq default
+label is assumed.
+
+.It passwd pass
+Specify the password required for access to the full
+.Nm
+command set.
+
+.It quit|bye [all]
+Exit
+.Nm ppp .
+If
+.Nm
+is in interactive mode or if the
+.Dq all
+argument is given,
+.Nm
+will exit, closing the connection. A simple
+.Dq quit
+issued from a
+.Xr pppctl 8
+or
+.Xr telnet 1
+session will not close the current connection.
+
+.It save
+This option is not (yet) implemented.
+
+.It set[up] var value
+This option allows the setting of any of the following variables:
+
+.Bl -tag -width 20
+.It set accmap hex-value
+ACCMap stands for Asyncronous Control Character Map. This is always
+negotiated with the peer, and defaults to a value of 0x00000000.
+This protocol is required to defeat hardware that depends on passing
+certain characters from end to end (such as XON/XOFF etc).
+
+.It set filter-name rule-no action [src_addr/src_width]
+[dst_addr/dst_width] [proto [src [lt|eq|gt] port ]]
+[dst [lt|eq|gt] port] [estab]
+.Pp
+.Nm Ppp
+supports four filter sets. The afilter specifies packets that keep
+the connection alive - reseting the idle timer. The dfilter specifies
+packets that cause
+.Nm
+to dial when in
+.Fl auto
+mode. The ifilter specifies packets that are allowed to travel
+into the machine and the ofilter specifies packets that are allowed
+out of the machine. By default all filter sets allow all packets
+to pass.
+
+Rules are processed in order according to
+.Dq n .
+Up to 20 rules may be given for each set. If a packet doesn't match
+any of the rules in a given set, it is discarded. In the case of
+ifilters and ofilters, this means that the packet is dropped. In
+the case of afilters it means that the packet will not reset the
+idle timer and in the case of dfilters it means that the packet will
+not trigger a dial.
+
+Refer to the section on PACKET FILTERING above for further details.
+
+.It set authkey|key value
+This sets the authentication key (or password) used in client mode
+PAP or CHAP negotiation to the given value. It can also be used to
+specify the password to be used in the dial or login scripts, preventing
+the actual password from being logged.
+
+.It set authname id
+This sets the authentication id used in client mode PAP or CHAP negotiation.
+
+.It set ctsrts
+This sets hardware flow control and is the default.
+
+.It set device|line value
+This sets the device to which
+.Nm
+will talk to the given
+.Dq value .
+All serial device names are expected to begin with
+.Pa /dev/ .
+If
+.Dq value
+does not begin with
+.Pa /dev/ ,
+it must be of the format
+.Dq host:port .
+If this is the case,
+.Nm
+will attempt to connect to the given
+.Dq host
+on the given
+.Dq port .
+Refer to the section on
+.Em PPP OVER TCP
+above for further details.
+
+.It set dial chat-script
+This specifies the chat script that will be used to dial the other
+side. See also the
+.Dv set login
+command below. Refer to
+.Xr chat 8
+and to the example configuration files for details of the chat script
+format. The string \\\\T will be replaced with the current phone number
+(see
+.Dq set phone
+below) and the string \\\\P will be replaced with the password (see
+.Dq set key
+above).
+
+.It set hangup chat-script
+This specifies the chat script that will be used to reset the modem
+before it is closed. It should not normally be necessary, but can
+be used for devices that fail to reset themselves properly on close.
+
+.It set encrypt MSChap|MD5
+This specifies the encryption algorithm to request and use when issuing
+the CHAP challenge, and defaults to MD5. If this is set to MSChap,
+.Nm
+will behave like a Microsoft RAS when sending the CHAP challenge (assuming
+CHAP is enabled). When responding to a challenge,
+.Nm
+determines how to encrypt the response based on the challenge, so this
+setting is ignored.
+
+.Bl -tag -width NOTE:
+.It NOTE:
+Because the Microsoft encryption algorithm uses a combination of MD4 and DES,
+if you have not installed DES encryption software on your machine
+before building
+.Nm ppp ,
+this option will not be available - only MD5 will be used.
+.El
+
+.It set escape value...
+This option is similar to the
+.Dq set accmap
+option above. It allows the user to specify a set of characters that
+will be `escaped' as they travel across the link.
+
+.It set ifaddr [myaddr [hisaddr [netmask [triggeraddr]]]]
+This command specifies the IP addresses that will be used during
+IPCP negotiation. Addresses are specified using the format
+
+.Dl a.b.c.d/n
+
+Where a.b.c.d is the preferred IP, but n specifies how many bits
+of the address we will insist on. If the /n bit is omitted, it
+defaults to /32 unless the IP address is 0.0.0.0 in which case
+the mask defaults to /0.
+
+If
+.Dq triggeraddr
+is specified, it is used in place of
+.Dq myaddr
+in the initial IPCP negotiation. However, only an address in the
+.Dq myaddr
+range will be accepted.
+
+.It set loopback on|off
+When set to
+.Dq on
+(the default),
+.Nm
+will automatically loop back packets being sent
+out with a destination address equal to that of the
+.Em PPP
+interface. If set to
+.Dq off ,
+.Nm
+will send the packet, probably resulting in an ICMP redirect from
+the other end.
+
+.It set log [local] [+|-]value...
+This command allows the adjustment of the current log level. Refer
+to the Logging Facility section for further details.
+
+.It set login chat-script
+This chat-script compliments the dial-script. If both are specified,
+the login script will be executed after the dial script. Escape
+sequences available in the dial script are also available here.
+
+.It set mru value
+The default MRU is 1500. If it is increased, the other side *may*
+increase its mtu. There is no use decreasing the MRU to below the
+default as the
+.Em PPP
+protocol *must* be able to accept packets of at
+least 1500 octets.
+
+.It set mtu value
+The default MTU is 1500. This may be increased by the MRU specified
+by the peer. It may only be subsequently decreased by this option.
+Increasing it is not valid as the peer is not necessarily able to
+receive the increased packet size.
+
+.It set openmode active|passive
+By default, openmode is always active. That is,
+.Nm
+will always initiate LCP/IPCP/CCP negotiation. If you want to wait for the
+peer to initiate negotiations, you may use the value
+.Dq passive .
+
+.It set parity odd|even|none|mark
+This allows the line parity to be set. The default value is none.
+
+.It set phone telno[|telno]...[:telno[|telno]...]...
+This allows the specification of the phone number to be used in
+place of the \\\\T string in the dial and login chat scripts.
+Multiple phone numbers may be given separated by a pipe (|) or
+a colon (:). Numbers after the pipe are only dialed if the dial or login
+script for the previous number failed. Numbers separated by a colon are
+tried sequentially, irrespective of the reason the line was dropped.
+If multiple numbers are given,
+.Nm
+will dial them according to these rules until a connection is made, retrying
+the maximum number of times specified by
+.Dq set redial
+below. In
+.Fl background
+mode, each number is attempted at most once.
+
+.It set reconnect timeout ntries
+Should the line drop unexpectedly (due to loss of CD or LQR
+failure), a connection will be re-established after the given
+.Dq timeout .
+The line will be re-connected at most
+.Dq ntries
+times.
+.Dq Ntries
+defaults to zero. A value of
+.Dq random
+for
+.Dq timeout
+will result in a variable pause, somewhere between 0 and 30 seconds.
+
+.It set redial seconds[.nseconds] [attempts]
+.Nm Ppp
+can be instructed to attempt to redial
+.Dq attempts
+times. If more than one number is specified (see
+.Dq set phone
+above), a pause of
+.Dq nseconds
+is taken before dialing each number. A pause of
+.Dq seconds
+is taken before starting at the first number again. A value of
+.Dq random
+may be used here too.
+
+.It set stopped [LCPseconds [IPCPseconds [CCPseconds]]]
+If this option is set,
+.Nm
+will time out after the given FSM (Finite State Machine) has been in
+the stopped state for the given number of
+.Dq seconds .
+This option may be useful if you see
+.Nm
+failing to respond in the stopped state. Use
+.Dq set log +lcp +ipcp +ccp
+to make
+.Nm
+log all state transitions.
+.Pp
+The default value is zero, where
+.Nm
+doesn't time out in the stopped state.
+
+.It set server|socket TcpPort|LocalName|none [password] [mask]
+This command tells
+.Nm
+to listen on the given socket or
+.Sq diagnostic port
+for incoming command connections. This is not possible if
+.Nm
+is in interactive mode. The word
+.Ar none
+instructs
+.Nm
+to close any existing socket. If you wish to specify a unix domain
+socket,
+.Ar LocalName
+must be specified as an absolute file name, otherwise it is assumed
+to be the name or number of a TCP port. You may specify the octal umask that
+should be used with unix domain sockets as a four character octal number
+beginning with
+.Sq 0 .
+Refer to
+.Xr umask 2
+for umask details. Refer to
+.Xr services 5
+for details of how to translate TCP port names.
+
+.Pp
+You may also specify the password that must be used by the client when
+connecting to this socket. If the password is not specified here,
+.Pa /etc/ppp/ppp.secret
+is searched for a machine name that's the same as your local host name
+without any domain suffix. Refer to
+.Xr hostname 1
+for further details. If a password is specified as the empty string,
+no password is required.
+
+.Pp
+When using
+.Nm
+with a server socket, the
+.Xr pppctl 8
+command is the preferred mechanism of communications. Currently,
+.Xr telnet 1
+can also be used, but link encryption may be implemented in the future, so
+.Xr telnet 1
+should not be relied upon.
+
+.It set speed value
+This sets the speed of the serial device.
+
+.It set timeout Idle [ lqr [ retry ] ]
+This command allows the setting of the idle timer, the LQR timer (if
+enabled) and the retry timer.
+
+.It set ns x.x.x.x y.y.y.y
+This option allows the setting of the Microsoft DNS servers that
+will be negotiated.
+
+.It set nbns x.x.x.x y.y.y.y
+This option allows the setting of the Microsoft NetBIOS DNS servers that
+will be negotiated.
+
+.It set help|?
+This command gives a summary of available set commands.
+.El
+
+.It shell|! [command]
+If
+.Dq command
+is not specified a shell is invoked according to the
+.Dv SHELL
+environment variable. Otherwise, the given command is executed.
+Any of the pseudo arguments
+.Dv HISADDR ,
+.Dv INTERFACE
+and
+.Dv MYADDR
+will be replaced with the appropriate values. Use of the ! character
+requires a following space as with any other commands. You should note
+that this command is executed in the foreground -
+.Nm
+will not continue running until this process has exited. Use the
+.Dv bg
+command if you wish processing to happen in the background.
+
+.It show var
+This command allows the user to examine the following:
+
+.Bl -tag -width 20
+.It show [adio]filter
+List the current rules for the given filter.
+
+.It show auth
+Show the current authname and authkey.
+
+.It show ccp
+Show the current CCP statistics.
+
+.It show compress
+Show the current compress statistics.
+
+.It show escape
+Show the current escape characters.
+
+.It show hdlc
+Show the current HDLC statistics.
+
+.It show ipcp
+Show the current IPCP statistics.
+
+.It show lcp
+Show the current LCP statistics.
+
+.It show loopback
+Show the current loopback status.
+
+.It show log
+Show the current log values.
+
+.It show mem
+Show current memory statistics.
+
+.It show modem
+Show current modem statistics.
+
+.It show mru
+Show the current MRU.
+
+.It show mtu
+Show the current MTU.
+
+.It show proto
+Show current protocol totals.
+
+.It show reconnect
+Show the current reconnect values.
+
+.It show redial
+Show the current redial values.
+
+.It show stopped
+Show the current stopped timeouts.
+
+.It show route
+Show the current routing tables.
+
+.It show timeout
+Show the current timeout values.
+
+.It show msext
+Show the current Microsoft extension values.
+
+.It show version
+Show the current version number of
+.Nm ppp .
+
+.It show help|?
+Give a summary of available show commands.
+.El
+
+.It term
+Go into terminal mode. Characters typed at the keyboard are sent to
+the modem. Characters read from the modem are displayed on the
+screen. When a
+.Nm
+peer is detected on the other side of the modem,
+.Nm
+automatically enables Packet Mode and goes back into command mode.
+
+.El
+
+.Sh MORE DETAILS
+
+.Bl -bullet -compact
+
+.It
+Read the example configuration files. They are a good source of information.
+
+.It
+Use
+.Dq help ,
+.Dq show ? ,
+.Dq alias ? ,
+.Dq set ?
+and
+.Dq set ? <var>
+commands.
+.El
+
+.Sh FILES
+.Nm Ppp
+refers to four files:
+.Pa ppp.conf ,
+.Pa ppp.linkup ,
+.Pa ppp.linkdown
+and
+.Pa ppp.secret .
+These files are placed in the
+.Pa /etc/ppp
+directory.
+
+.Bl -tag -width flag
+.It Pa /etc/ppp/ppp.conf
+System default configuration file.
+
+.It Pa /etc/ppp/ppp.secret
+An authorisation file for each system.
+
+.It Pa /etc/ppp/ppp.linkup
+A file to check when
+.Nm
+establishes a network level connection.
+
+.It Pa /etc/ppp/ppp.linkdown
+A file to check when
+.Nm
+closes a network level connection.
+
+.It Pa /var/log/ppp.log
+Logging and debugging information file. Note, this name is specified in
+.Pa /etc/syslogd.conf .
+See
+.Xr syslog.conf 5
+for further details.
+
+.It Pa /var/spool/lock/LCK..*
+tty port locking file. Refer to
+.Xr uucplock 3
+for further details.
+
+.It Pa /var/run/tunN.pid
+The process id (pid) of the
+.Nm
+program connected to the tunN device, where
+.Sq N
+is the number of the device. This file is only created in
+.Fl background ,
+.Fl auto
+and
+.Fl ddial
+modes.
+
+.It Pa /var/run/ttyXX.if
+The tun interface used by this port. Again, this file is only created in
+.Fl background ,
+.Fl auto
+and
+.Fl ddial
+modes.
+
+.It Pa /etc/services
+Get port number if port number is using service name.
+.El
+
+.Sh SEE ALSO
+
+.Xr at 1 ,
+.Xr chat 8 ,
+.Xr crontab 5 ,
+.Xr ftp 1 ,
+.Xr getty 8 ,
+.Xr hostname 1 ,
+.Xr inetd 8 ,
+.Xr init 8 ,
+.Xr login 1 ,
+.Xr passwd 5 ,
+.Xr ping 8 ,
+.Xr pppctl 8 ,
+.Xr pppd 8 ,
+.Xr syslog 3 ,
+.Xr syslog.conf 5 ,
+.Xr syslogd 8 ,
+.Xr tcpdump 1 ,
+.Xr telnet 1 ,
+.Xr traceroute 8 ,
+.Xr uucplock 3
+
+.Sh HISTORY
+
+This program was originally written by Toshiharu OHNO (tony-o@iij.ad.jp),
+and was submitted to FreeBSD-2.0.5 by Atsushi Murai (amurai@spec.co.jp).
+It has since had an enormous face lift and looks substantially different.
diff --git a/usr.sbin/ppp/pred.c b/usr.sbin/ppp/pred.c
new file mode 100644
index 00000000000..3430cee9cfa
--- /dev/null
+++ b/usr.sbin/ppp/pred.c
@@ -0,0 +1,222 @@
+/*
+ * pred.c -- Test program for Dave Rand's rendition of the
+ * predictor algorithm
+ * Updated by: iand@labtam.labtam.oz.au (Ian Donaldson)
+ * Updated by: Carsten Bormann <cabo@cs.tu-berlin.de>
+ * Original : Dave Rand <dlr@bungi.com>/<dave_rand@novell.com>
+ *
+ * $Id: pred.c,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "hdlc.h"
+#include "lcpproto.h"
+#include "ccp.h"
+#include "pred.h"
+
+/* The following hash code is the heart of the algorithm:
+ * It builds a sliding hash sum of the previous 3-and-a-bit characters
+ * which will be used to index the guess table.
+ * A better hash function would result in additional compression,
+ * at the expense of time.
+ */
+#define IHASH(x) do {iHash = (iHash << 4) ^ (x);} while(0)
+#define OHASH(x) do {oHash = (oHash << 4) ^ (x);} while(0)
+
+static unsigned short int iHash, oHash;
+static unsigned char InputGuessTable[65536];
+static unsigned char OutputGuessTable[65536];
+
+static int
+compress(u_char * source, u_char * dest, int len)
+{
+ int i, bitmask;
+ unsigned char *flagdest, flags, *orgdest;
+
+ orgdest = dest;
+ while (len) {
+ flagdest = dest++;
+ flags = 0; /* All guess wrong initially */
+ for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) {
+ if (OutputGuessTable[oHash] == *source) {
+ flags |= bitmask; /* Guess was right - don't output */
+ } else {
+ OutputGuessTable[oHash] = *source;
+ *dest++ = *source; /* Guess wrong, output char */
+ }
+ OHASH(*source++);
+ len--;
+ }
+ *flagdest = flags;
+ }
+ return (dest - orgdest);
+}
+
+static void
+SyncTable(u_char * source, u_char * dest, int len)
+{
+
+ while (len--) {
+ if (InputGuessTable[iHash] != *source) {
+ InputGuessTable[iHash] = *source;
+ }
+ IHASH(*dest++ = *source++);
+ }
+}
+
+static int
+decompress(u_char * source, u_char * dest, int len)
+{
+ int i, bitmask;
+ unsigned char flags, *orgdest;
+
+ orgdest = dest;
+ while (len) {
+ flags = *source++;
+ len--;
+ for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) {
+ if (flags & bitmask) {
+ *dest = InputGuessTable[iHash]; /* Guess correct */
+ } else {
+ if (!len)
+ break; /* we seem to be really done -- cabo */
+ InputGuessTable[iHash] = *source; /* Guess wrong */
+ *dest = *source++; /* Read from source */
+ len--;
+ }
+ IHASH(*dest++);
+ }
+ }
+ return (dest - orgdest);
+}
+
+void
+Pred1Init(int direction)
+{
+ if (direction & 1) { /* Input part */
+ iHash = 0;
+ memset(InputGuessTable, '\0', sizeof(InputGuessTable));
+ }
+ if (direction & 2) { /* Output part */
+ oHash = 0;
+ memset(OutputGuessTable, '\0', sizeof(OutputGuessTable));
+ }
+}
+
+void
+Pred1Output(int pri, u_short proto, struct mbuf * bp)
+{
+ struct mbuf *mwp;
+ u_char *cp, *wp, *hp;
+ int orglen, len;
+ u_char bufp[MAX_MTU + 2];
+ u_short fcs;
+
+ orglen = plength(bp) + 2; /* add count of proto */
+ mwp = mballoc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT);
+ hp = wp = MBUF_CTOP(mwp);
+ cp = bufp;
+ *wp++ = *cp++ = orglen >> 8;
+ *wp++ = *cp++ = orglen & 0377;
+ *cp++ = proto >> 8;
+ *cp++ = proto & 0377;
+ mbread(bp, cp, orglen - 2);
+ fcs = HdlcFcs(INITFCS, bufp, 2 + orglen);
+ fcs = ~fcs;
+
+ len = compress(bufp + 2, wp, orglen);
+ LogPrintf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len);
+ CcpInfo.orgout += orglen;
+ if (len < orglen) {
+ *hp |= 0x80;
+ wp += len;
+ CcpInfo.compout += len;
+ } else {
+ memcpy(wp, bufp + 2, orglen);
+ wp += orglen;
+ CcpInfo.compout += orglen;
+ }
+
+ *wp++ = fcs & 0377;
+ *wp++ = fcs >> 8;
+ mwp->cnt = wp - MBUF_CTOP(mwp);
+ HdlcOutput(PRI_NORMAL, PROTO_COMPD, mwp);
+}
+
+void
+Pred1Input(struct mbuf * bp)
+{
+ u_char *cp, *pp;
+ int len, olen, len1;
+ struct mbuf *wp;
+ u_char *bufp;
+ u_short fcs, proto;
+
+ wp = mballoc(MAX_MTU + 2, MB_IPIN);
+ cp = MBUF_CTOP(bp);
+ olen = plength(bp);
+ pp = bufp = MBUF_CTOP(wp);
+ *pp++ = *cp & 0177;
+ len = *cp++ << 8;
+ *pp++ = *cp;
+ len += *cp++;
+ CcpInfo.orgin += len & 0x7fff;
+ if (len & 0x8000) {
+ len1 = decompress(cp, pp, olen - 4);
+ CcpInfo.compin += olen;
+ len &= 0x7fff;
+ if (len != len1) { /* Error is detected. Send reset request */
+ LogPrintf(LogLCP, "%s: Length Error\n", CcpFsm.name);
+ CcpSendResetReq(&CcpFsm);
+ pfree(bp);
+ pfree(wp);
+ return;
+ }
+ cp += olen - 4;
+ pp += len1;
+ } else {
+ CcpInfo.compin += len;
+ SyncTable(cp, pp, len);
+ cp += len;
+ pp += len;
+ }
+ *pp++ = *cp++; /* CRC */
+ *pp++ = *cp++;
+ fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp);
+ if (fcs != GOODFCS)
+ LogPrintf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x,"
+ " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad",
+ len, olen);
+ if (fcs == GOODFCS) {
+ wp->offset += 2; /* skip length */
+ wp->cnt -= 4; /* skip length & CRC */
+ pp = MBUF_CTOP(wp);
+ proto = *pp++;
+ if (proto & 1) {
+ wp->offset++;
+ wp->cnt--;
+ } else {
+ wp->offset += 2;
+ wp->cnt -= 2;
+ proto = (proto << 8) | *pp++;
+ }
+ DecodePacket(proto, wp);
+ } else {
+ LogDumpBp(LogHDLC, "Bad FCS", wp);
+ CcpSendResetReq(&CcpFsm);
+ pfree(wp);
+ }
+ pfree(bp);
+}
diff --git a/usr.sbin/ppp/pred.h b/usr.sbin/ppp/pred.h
new file mode 100644
index 00000000000..74502d2001b
--- /dev/null
+++ b/usr.sbin/ppp/pred.h
@@ -0,0 +1,25 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pred.h,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ * TODO:
+ */
+
+extern void Pred1Output(int, u_short, struct mbuf *);
+extern void Pred1Input(struct mbuf *);
+extern void Pred1Init(int);
diff --git a/usr.sbin/ppp/route.c b/usr.sbin/ppp/route.c
new file mode 100644
index 00000000000..f86ca6114a1
--- /dev/null
+++ b/usr.sbin/ppp/route.c
@@ -0,0 +1,484 @@
+/*
+ * PPP Routing related Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: route.c,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if_dl.h>
+
+#include <errno.h>
+#include <machine/endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "loadalias.h"
+#include "defs.h"
+#include "vars.h"
+#include "id.h"
+#include "route.h"
+
+static int IfIndex;
+
+struct rtmsg {
+ struct rt_msghdr m_rtm;
+ char m_space[64];
+};
+
+static int seqno;
+
+void
+OsSetRoute(int cmd,
+ struct in_addr dst,
+ struct in_addr gateway,
+ struct in_addr mask)
+{
+ struct rtmsg rtmes;
+ int s, nb, wb;
+ char *cp;
+ const char *cmdstr;
+ u_long *lp;
+ struct sockaddr_in rtdata;
+
+ cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
+ s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
+ return;
+ }
+ memset(&rtmes, '\0', sizeof(rtmes));
+ rtmes.m_rtm.rtm_version = RTM_VERSION;
+ rtmes.m_rtm.rtm_type = cmd;
+ rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
+ rtmes.m_rtm.rtm_seq = ++seqno;
+ rtmes.m_rtm.rtm_pid = getpid();
+ rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
+
+ memset(&rtdata, '\0', sizeof(rtdata));
+ rtdata.sin_len = 16;
+ rtdata.sin_family = AF_INET;
+ rtdata.sin_port = 0;
+ rtdata.sin_addr = dst;
+
+ cp = rtmes.m_space;
+ memcpy(cp, &rtdata, 16);
+ cp += 16;
+ if (gateway.s_addr) {
+ rtdata.sin_addr = gateway;
+ memcpy(cp, &rtdata, 16);
+ cp += 16;
+ rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
+ }
+ if (dst.s_addr == INADDR_ANY)
+ mask.s_addr = INADDR_ANY;
+
+ lp = (u_long *) cp;
+
+ if (mask.s_addr) {
+ *lp++ = 8;
+ cp += sizeof(int);
+ *lp = mask.s_addr;
+ } else
+ *lp = 0;
+ cp += sizeof(u_long);
+
+ nb = cp - (char *) &rtmes;
+ rtmes.m_rtm.rtm_msglen = nb;
+ wb = write(s, &rtmes, nb);
+ if (wb < 0) {
+ LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
+ LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway));
+ LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask));
+ switch (rtmes.m_rtm.rtm_errno) {
+ case EEXIST:
+ LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
+ break;
+ case ESRCH:
+ LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
+ break;
+ case 0:
+ LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno));
+ break;
+ case ENOBUFS:
+ default:
+ LogPrintf(LogTCPIP, "%s route failed: %s\n",
+ cmdstr, strerror(rtmes.m_rtm.rtm_errno));
+ break;
+ }
+ }
+ LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
+ wb, cmdstr, dst.s_addr, gateway.s_addr);
+ close(s);
+}
+
+static void
+p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width)
+{
+ char buf[29];
+ const char *cp;
+ struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
+ struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
+ struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
+
+ switch (phost->sa_family) {
+ case AF_INET:
+ if (!phost)
+ cp = "";
+ else if (ihost->sin_addr.s_addr == INADDR_ANY)
+ cp = "default";
+ else if (!mask)
+ cp = inet_ntoa(ihost->sin_addr);
+ else {
+ u_int msk = ntohl(mask->sin_addr.s_addr);
+ u_int tst;
+ int bits;
+ int len;
+ struct sockaddr_in net;
+
+ for (tst = 1, bits=32; tst; tst <<= 1, bits--)
+ if (msk & tst)
+ break;
+
+ for (tst <<=1; tst; tst <<= 1)
+ if (!(msk & tst))
+ break;
+
+ net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
+ sprintf(buf, "%s", inet_ntoa(net.sin_addr));
+ for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
+ if (strcmp(buf+len-2, ".0"))
+ break;
+
+ if (tst) /* non-contiguous :-( */
+ sprintf(buf+strlen(buf),"&0x%08x", msk);
+ else
+ sprintf(buf+strlen(buf), "/%d", bits);
+ cp = buf;
+ }
+ break;
+
+ case AF_LINK:
+ if (!dl)
+ cp = "";
+ else if (dl->sdl_nlen == 0 && dl->sdl_alen == 0 && dl->sdl_slen == 0) {
+ sprintf(buf, "link#%d", dl->sdl_index);
+ cp = buf;
+ } else if (dl->sdl_type == IFT_ETHER && dl->sdl_alen &&
+ dl->sdl_alen < sizeof(buf)/3) {
+ int f;
+ u_char *MAC;
+
+ MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
+ for (f = 0; f < dl->sdl_alen; f++)
+ sprintf(buf+f*3, "%02x:", MAC[f]);
+ buf[f*3-1] = '\0';
+ cp = buf;
+ } else
+ cp = "???";
+ break;
+
+ default:
+ cp = "???";
+ break;
+ }
+
+ fprintf(VarTerm, "%-*s ", width-1, cp);
+}
+
+struct bits {
+ u_long b_mask;
+ char b_val;
+} bits[] = {
+
+ { RTF_UP, 'U' },
+ { RTF_GATEWAY, 'G' },
+ { RTF_HOST, 'H' },
+ { RTF_REJECT, 'R' },
+ { RTF_DYNAMIC, 'D' },
+ { RTF_MODIFIED, 'M' },
+ { RTF_DONE, 'd' },
+ { RTF_CLONING, 'C' },
+ { RTF_XRESOLVE, 'X' },
+ { RTF_LLINFO, 'L' },
+ { RTF_STATIC, 'S' },
+ { RTF_PROTO1, '1' },
+ { RTF_PROTO2, '2' },
+ { RTF_BLACKHOLE, 'B' },
+#ifdef __FreeBSD__
+ { RTF_WASCLONED, 'W' },
+ { RTF_PRCLONING, 'c' },
+ { RTF_PROTO3, '3' },
+ { RTF_BROADCAST, 'b' },
+#endif
+ { 0, '\0' }
+};
+
+static void
+p_flags(u_long f, const char *format)
+{
+ if (VarTerm) {
+ char name[33], *flags;
+ register struct bits *p = bits;
+
+ for (flags = name; p->b_mask; p++)
+ if (p->b_mask & f)
+ *flags++ = p->b_val;
+ *flags = '\0';
+ fprintf(VarTerm, format, name);
+ }
+}
+
+static const char *
+Index2Nam(int idx)
+{
+ static char ifs[50][6];
+ static int nifs, debug_done;
+
+ if (!nifs) {
+ int mib[6], needed, len;
+ char *buf, *ptr, *end;
+ struct sockaddr_dl *dl;
+ struct if_msghdr *ifm;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
+ return "???";
+ }
+ if ((buf = malloc(needed)) == NULL)
+ return "???";
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ free(buf);
+ return "???";
+ }
+ end = buf + needed;
+
+ for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)ptr;
+ dl = (struct sockaddr_dl *)(ifm + 1);
+ if (ifm->ifm_index > 0 && ifm->ifm_index <= sizeof(ifs)/sizeof(ifs[0])
+ && ifs[ifm->ifm_index-1][0] == '\0') {
+ if ((len = dl->sdl_nlen) > sizeof(ifs[0])-1)
+ len = sizeof(ifs[0])-1;
+ strncpy(ifs[ifm->ifm_index-1], dl->sdl_data, len);
+ ifs[ifm->ifm_index-1][len] = '\0';
+ if (len && nifs < ifm->ifm_index)
+ nifs = ifm->ifm_index;
+ } else if (LogIsKept(LogDEBUG))
+ LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n",
+ ifm->ifm_index);
+ }
+ free(buf);
+ }
+
+ if (LogIsKept(LogDEBUG) && !debug_done) {
+ int f;
+
+ LogPrintf(LogDEBUG, "Found the following interfaces:\n");
+ for (f = 0; f < nifs; f++)
+ if (*ifs[f] != '\0')
+ LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
+ debug_done = 1;
+ }
+
+ if (idx < 1 || idx > nifs || ifs[idx-1][0] == '\0')
+ return "???";
+
+ return ifs[idx-1];
+}
+
+int
+ShowRoute(struct cmdargs const *arg)
+{
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa_dst, *sa_gw, *sa_mask;
+ char *sp, *ep, *cp, *wp;
+ int needed;
+ int mib[6];
+
+ if (!VarTerm)
+ return 1;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
+ return (1);
+ }
+ if (needed < 0)
+ return (1);
+ sp = malloc(needed);
+ if (sp == NULL)
+ return (1);
+ if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
+ LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
+ free(sp);
+ return (1);
+ }
+ ep = sp + needed;
+
+ fprintf(VarTerm, "%-20s%-20sFlags Netif\n", "Destination", "Gateway");
+ for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *) cp;
+ wp = (char *)(rtm+1);
+
+ if (rtm->rtm_addrs & RTA_DST) {
+ sa_dst = (struct sockaddr *)wp;
+ wp += sa_dst->sa_len;
+ } else
+ sa_dst = NULL;
+
+ if (rtm->rtm_addrs & RTA_GATEWAY) {
+ sa_gw = (struct sockaddr *)wp;
+ wp += sa_gw->sa_len;
+ } else
+ sa_gw = NULL;
+
+ if (rtm->rtm_addrs & RTA_NETMASK) {
+ sa_mask = (struct sockaddr *)wp;
+ wp += sa_mask->sa_len;
+ } else
+ sa_mask = NULL;
+
+ p_sockaddr(sa_dst, sa_mask, 20);
+ p_sockaddr(sa_gw, NULL, 20);
+
+ p_flags(rtm->rtm_flags, "%-6.6s ");
+ fprintf(VarTerm, "%s\n", Index2Nam(rtm->rtm_index));
+ }
+ free(sp);
+ return 0;
+}
+
+/*
+ * Delete routes associated with our interface
+ */
+void
+DeleteIfRoutes(int all)
+{
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa;
+ struct in_addr sa_dst, sa_gw, sa_mask;
+ int needed;
+ char *sp, *cp, *ep;
+ u_char *wp;
+ int mib[6];
+
+ LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
+ strerror(errno));
+ return;
+ }
+ if (needed < 0)
+ return;
+
+ sp = malloc(needed);
+ if (sp == NULL)
+ return;
+
+ if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
+ LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
+ strerror(errno));
+ free(sp);
+ return;
+ }
+ ep = sp + needed;
+
+ for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *) cp;
+ sa = (struct sockaddr *) (rtm + 1);
+ LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s), flags: %x,"
+ " dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
+ Index2Nam(rtm->rtm_index), rtm->rtm_flags,
+ inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
+ if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
+ rtm->rtm_index == IfIndex &&
+ (all || (rtm->rtm_flags & RTF_GATEWAY))) {
+ sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ wp = (u_char *) cp + rtm->rtm_msglen;
+ sa = (struct sockaddr *)((char *)sa + sa->sa_len);
+ if (sa->sa_family == AF_INET) {
+ LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
+ sa_gw.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ sa = (struct sockaddr *)((char *)sa + sa->sa_len);
+ if (rtm->rtm_addrs & RTA_NETMASK)
+ sa_mask.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ else
+ sa_mask.s_addr = 0xffffffff;
+ if (sa_dst.s_addr == INADDR_ANY)
+ sa_mask.s_addr = INADDR_ANY;
+ LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(sa_dst));
+ LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(sa_gw));
+ LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
+ OsSetRoute(RTM_DELETE, sa_dst, sa_gw, sa_mask);
+ } else
+ LogPrintf(LogDEBUG, "DeleteIfRoutes: Can't remove an AF_LINK !\n");
+ }
+ }
+ free(sp);
+}
+
+int
+GetIfIndex(char *name)
+{
+ int idx;
+ const char *got;
+
+ idx = 1;
+ while (strcmp(got = Index2Nam(idx), "???"))
+ if (!strcmp(got, name))
+ return IfIndex = idx;
+ else
+ idx++;
+ return -1;
+}
diff --git a/usr.sbin/ppp/route.h b/usr.sbin/ppp/route.h
new file mode 100644
index 00000000000..8a2629042be
--- /dev/null
+++ b/usr.sbin/ppp/route.h
@@ -0,0 +1,27 @@
+/*
+ * User Process PPP
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: route.h,v 1.1 1997/11/23 20:27:35 brian Exp $
+ *
+ */
+
+extern int GetIfIndex(char *);
+extern int ShowRoute(struct cmdargs const *);
+extern void OsSetRoute(int, struct in_addr, struct in_addr, struct in_addr);
+extern void DeleteIfRoutes(int);
diff --git a/usr.sbin/ppp/server.c b/usr.sbin/ppp/server.c
new file mode 100644
index 00000000000..73994726344
--- /dev/null
+++ b/usr.sbin/ppp/server.c
@@ -0,0 +1,145 @@
+/*
+ * $Id: server.c,v 1.1 1997/11/23 20:27:36 brian Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "loadalias.h"
+#include "defs.h"
+#include "vars.h"
+#include "server.h"
+#include "id.h"
+
+int server = -1;
+
+static struct sockaddr_un ifsun;
+static char *rm;
+
+int
+ServerLocalOpen(const char *name, mode_t mask)
+{
+ int s;
+
+ if (VarLocalAuth == LOCAL_DENY) {
+ LogPrintf(LogERROR, "Local: Can't open socket %s: No password "
+ "in ppp.secret\n", name);
+ return 1;
+ }
+
+ if (mode & MODE_INTER) {
+ LogPrintf(LogERROR, "Local: Can't open socket in interactive mode\n");
+ return 1;
+ }
+
+ ifsun.sun_len = strlen(name);
+ if (ifsun.sun_len > sizeof ifsun.sun_path - 1) {
+ LogPrintf(LogERROR, "Local: %s: Path too long\n", name);
+ return 2;
+ }
+ ifsun.sun_family = AF_LOCAL;
+ strcpy(ifsun.sun_path, name);
+
+ s = ID0socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (s < 0) {
+ LogPrintf(LogERROR, "Local: socket: %s\n", strerror(errno));
+ return 3;
+ }
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
+ if (mask != (mode_t)-1)
+ mask = umask(mask);
+ if (bind(s, (struct sockaddr *) & ifsun, sizeof(ifsun)) < 0) {
+ if (mask != (mode_t)-1)
+ umask(mask);
+ LogPrintf(LogERROR, "Local: bind: %s\n", strerror(errno));
+ if (errno == EADDRINUSE && VarTerm)
+ fprintf(VarTerm, "Wait for a while, then try again.\n");
+ close(s);
+ ID0unlink(name);
+ return 4;
+ }
+ if (mask != (mode_t)-1)
+ umask(mask);
+ if (listen(s, 5) != 0) {
+ LogPrintf(LogERROR, "Local: Unable to listen to socket - OS overload?\n");
+ close(s);
+ ID0unlink(name);
+ return 5;
+ }
+ ServerClose();
+ server = s;
+ rm = ifsun.sun_path;
+ LogPrintf(LogPHASE, "Listening at local socket %s.\n", name);
+ return 0;
+}
+
+int
+ServerTcpOpen(int port)
+{
+ struct sockaddr_in ifsin;
+ int s;
+
+ if (VarLocalAuth == LOCAL_DENY) {
+ LogPrintf(LogERROR, "Tcp: Can't open socket %d: No password "
+ "in ppp.secret\n", port);
+ return 6;
+ }
+
+ if (mode & MODE_INTER) {
+ LogPrintf(LogERROR, "Tcp: Can't open socket in interactive mode\n");
+ return 6;
+ }
+
+ s = ID0socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ LogPrintf(LogERROR, "Tcp: socket: %s\n", strerror(errno));
+ return 7;
+ }
+ ifsin.sin_family = AF_INET;
+ ifsin.sin_addr.s_addr = INADDR_ANY;
+ ifsin.sin_port = htons(port);
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
+ if (bind(s, (struct sockaddr *) & ifsin, sizeof(ifsin)) < 0) {
+ LogPrintf(LogERROR, "Tcp: bind: %s\n", strerror(errno));
+ if (errno == EADDRINUSE && VarTerm)
+ fprintf(VarTerm, "Wait for a while, then try again.\n");
+ close(s);
+ return 8;
+ }
+ if (listen(s, 5) != 0) {
+ LogPrintf(LogERROR, "Tcp: Unable to listen to socket - OS overload?\n");
+ close(s);
+ return 9;
+ }
+ ServerClose();
+ server = s;
+ LogPrintf(LogPHASE, "Listening at port %d.\n", port);
+ return 0;
+}
+
+void
+ServerClose()
+{
+ if (server >= 0) {
+ close(server);
+ if (rm) {
+ ID0unlink(rm);
+ rm = 0;
+ }
+ }
+ server = -1;
+}
diff --git a/usr.sbin/ppp/server.h b/usr.sbin/ppp/server.h
new file mode 100644
index 00000000000..347b23fc978
--- /dev/null
+++ b/usr.sbin/ppp/server.h
@@ -0,0 +1,9 @@
+/*
+ * $Id: server.h,v 1.1 1997/11/23 20:27:36 brian Exp $
+ */
+
+extern int server;
+
+extern int ServerLocalOpen(const char *, mode_t);
+extern int ServerTcpOpen(int);
+extern void ServerClose(void);
diff --git a/usr.sbin/ppp/sig.c b/usr.sbin/ppp/sig.c
new file mode 100644
index 00000000000..c7c0dab062e
--- /dev/null
+++ b/usr.sbin/ppp/sig.c
@@ -0,0 +1,73 @@
+/*
+ * $Id: sig.c,v 1.1 1997/11/23 20:27:36 brian Exp $
+ */
+
+#include <sys/types.h>
+
+#include <signal.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "sig.h"
+
+static caused[NSIG]; /* An array of pending signals */
+static sig_type handler[NSIG]; /* all start at SIG_DFL */
+
+
+/* Record a signal in the "caused" array */
+
+static void
+signal_recorder(int sig)
+{
+ caused[sig - 1]++;
+}
+
+
+/*
+ * Set up signal_recorder, and record handler as the function to ultimately
+ * call in handle_signal()
+*/
+
+sig_type
+pending_signal(int sig, sig_type fn)
+{
+ sig_type Result;
+
+ if (sig <= 0 || sig > NSIG) {
+ /* Oops - we must be a bit out of date (too many sigs ?) */
+ LogPrintf(LogALERT, "Eeek! %s:%s: I must be out of date!\n",
+ __FILE__, __LINE__);
+ return signal(sig, fn);
+ }
+ Result = handler[sig - 1];
+ if (fn == SIG_DFL || fn == SIG_IGN) {
+ signal(sig, fn);
+ handler[sig - 1] = (sig_type) 0;
+ } else {
+ handler[sig - 1] = fn;
+ signal(sig, signal_recorder);
+ }
+ caused[sig - 1] = 0;
+ return Result;
+}
+
+
+/* Call the handlers for any pending signals */
+
+void
+handle_signals()
+{
+ int sig;
+ int got;
+
+ do {
+ got = 0;
+ for (sig = 0; sig < NSIG; sig++)
+ if (caused[sig]) {
+ caused[sig]--;
+ got++;
+ (*handler[sig]) (sig + 1);
+ }
+ } while (got);
+}
diff --git a/usr.sbin/ppp/sig.h b/usr.sbin/ppp/sig.h
new file mode 100644
index 00000000000..9d2744dd01c
--- /dev/null
+++ b/usr.sbin/ppp/sig.h
@@ -0,0 +1,11 @@
+/*
+ * $Id: sig.h,v 1.1 1997/11/23 20:27:36 brian Exp $
+ */
+
+typedef void (*sig_type)(int);
+
+/* Call this instead of signal() */
+extern sig_type pending_signal(int, sig_type);
+
+/* Call this when you want things to *actually* happen */
+extern void handle_signals(void);
diff --git a/usr.sbin/ppp/slcompress.c b/usr.sbin/ppp/slcompress.c
new file mode 100644
index 00000000000..391ea214cec
--- /dev/null
+++ b/usr.sbin/ppp/slcompress.c
@@ -0,0 +1,587 @@
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: slcompress.c,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#include <sys/param.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/ip.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "slcompress.h"
+#include "loadalias.h"
+#include "vars.h"
+
+static struct slstat {
+ int sls_packets; /* outbound packets */
+ int sls_compressed; /* outbound compressed packets */
+ int sls_searches; /* searches for connection state */
+ int sls_misses; /* times couldn't find conn. state */
+ int sls_uncompressedin; /* inbound uncompressed packets */
+ int sls_compressedin; /* inbound compressed packets */
+ int sls_errorin; /* inbound unknown type packets */
+ int sls_tossed; /* inbound packets tossed because of error */
+} slstat;
+
+#define INCR(counter) slstat.counter++;
+
+void
+sl_compress_init(struct slcompress * comp, int max_state)
+{
+ register u_int i;
+ register struct cstate *tstate = comp->tstate;
+
+ memset(comp, '\0', sizeof(*comp));
+ for (i = max_state; i > 0; --i) {
+ tstate[i].cs_id = i;
+ tstate[i].cs_next = &tstate[i - 1];
+ }
+ tstate[0].cs_next = &tstate[max_state];
+ tstate[0].cs_id = 0;
+ comp->last_cs = &tstate[0];
+ comp->last_recv = 255;
+ comp->last_xmit = 255;
+ comp->flags = SLF_TOSS;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero. ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+ if ((u_short)(n) >= 256) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+#define ENCODEZ(n) { \
+ if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+
+#define DECODEL(f) { \
+ if (*cp == 0) {\
+ (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
+ cp += 3; \
+ } else { \
+ (f) = htonl(ntohl(f) + (u_long)*cp++); \
+ } \
+}
+
+#define DECODES(f) { \
+ if (*cp == 0) {\
+ (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
+ cp += 3; \
+ } else { \
+ (f) = htons(ntohs(f) + (u_long)*cp++); \
+ } \
+}
+
+#define DECODEU(f) { \
+ if (*cp == 0) {\
+ (f) = htons((cp[1] << 8) | cp[2]); \
+ cp += 3; \
+ } else { \
+ (f) = htons((u_long)*cp++); \
+ } \
+}
+
+
+u_char
+sl_compress_tcp(struct mbuf * m,
+ struct ip * ip,
+ struct slcompress * comp,
+ int compress_cid)
+{
+ register struct cstate *cs = comp->last_cs->cs_next;
+ register u_int hlen = ip->ip_hl;
+ register struct tcphdr *oth;
+ register struct tcphdr *th;
+ register u_int deltaS, deltaA;
+ register u_int changes = 0;
+ u_char new_seq[16];
+ register u_char *cp = new_seq;
+
+ /*
+ * Bail if this is an IP fragment or if the TCP packet isn't `compressible'
+ * (i.e., ACK isn't set or some other control bit is set). (We assume that
+ * the caller has already made sure the packet is IP proto TCP).
+ */
+ if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40) {
+ LogPrintf(LogDEBUG, "??? 1 ip_off = %x, cnt = %d\n",
+ ip->ip_off, m->cnt);
+ LogDumpBp(LogDEBUG, "", m);
+ return (TYPE_IP);
+ }
+ th = (struct tcphdr *) & ((int *) ip)[hlen];
+ if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK) {
+ LogPrintf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags);
+ LogDumpBp(LogDEBUG, "", m);
+ return (TYPE_IP);
+ }
+
+ /*
+ * Packet is compressible -- we're going to send either a COMPRESSED_TCP or
+ * UNCOMPRESSED_TCP packet. Either way we need to locate (or create) the
+ * connection state. Special case the most recently used connection since
+ * it's most likely to be used again & we don't have to do any reordering
+ * if it's used.
+ */
+ INCR(sls_packets)
+ if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+ ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+ *(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) {
+
+ /*
+ * Wasn't the first -- search for it.
+ *
+ * States are kept in a circularly linked list with last_cs pointing to the
+ * end of the list. The list is kept in lru order by moving a state to
+ * the head of the list whenever it is referenced. Since the list is
+ * short and, empirically, the connection we want is almost always near
+ * the front, we locate states via linear search. If we don't find a
+ * state for the datagram, the oldest state is (re-)used.
+ */
+ register struct cstate *lcs;
+ register struct cstate *lastcs = comp->last_cs;
+
+ do {
+ lcs = cs;
+ cs = cs->cs_next;
+ INCR(sls_searches)
+ if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+ && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+ && *(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl])
+ goto found;
+ } while (cs != lastcs);
+
+ /*
+ * Didn't find it -- re-use oldest cstate. Send an uncompressed packet
+ * that tells the other side what connection number we're using for this
+ * conversation. Note that since the state list is circular, the oldest
+ * state points to the newest and we only need to set last_cs to update
+ * the lru linkage.
+ */
+ INCR(sls_misses)
+ comp->last_cs = lcs;
+#define THOFFSET(th) (th->th_off)
+ hlen += th->th_off;
+ hlen <<= 2;
+ if (hlen > m->cnt)
+ return (TYPE_IP);
+ goto uncompressed;
+
+found:
+
+ /*
+ * Found it -- move to the front on the connection list.
+ */
+ if (cs == lastcs)
+ comp->last_cs = lcs;
+ else {
+ lcs->cs_next = cs->cs_next;
+ cs->cs_next = lastcs->cs_next;
+ lastcs->cs_next = cs;
+ }
+ }
+
+ /*
+ * Make sure that only what we expect to change changed. The first line of
+ * the `if' checks the IP protocol version, header length & type of
+ * service. The 2nd line checks the "Don't fragment" bit. The 3rd line
+ * checks the time-to-live and protocol (the protocol check is unnecessary
+ * but costless). The 4th line checks the TCP header length. The 5th line
+ * checks IP options, if any. The 6th line checks TCP options, if any. If
+ * any of these things are different between the previous & current
+ * datagram, we send the current datagram `uncompressed'.
+ */
+ oth = (struct tcphdr *) & ((int *) &cs->cs_ip)[hlen];
+ deltaS = hlen;
+ hlen += th->th_off;
+ hlen <<= 2;
+ if (hlen > m->cnt)
+ return (TYPE_IP);
+
+ if (((u_short *) ip)[0] != ((u_short *) & cs->cs_ip)[0] ||
+ ((u_short *) ip)[3] != ((u_short *) & cs->cs_ip)[3] ||
+ ((u_short *) ip)[4] != ((u_short *) & cs->cs_ip)[4] ||
+ THOFFSET(th) != THOFFSET(oth) ||
+ (deltaS > 5 &&
+ memcmp(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
+ (THOFFSET(th) > 5 &&
+ memcmp(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) {
+ goto uncompressed;
+ }
+
+ /*
+ * Figure out which of the changing fields changed. The receiver expects
+ * changes in the order: urgent, window, ack, seq (the order minimizes the
+ * number of temporaries needed in this section of code).
+ */
+ if (th->th_flags & TH_URG) {
+ deltaS = ntohs(th->th_urp);
+ ENCODEZ(deltaS);
+ changes |= NEW_U;
+ } else if (th->th_urp != oth->th_urp) {
+
+ /*
+ * argh! URG not set but urp changed -- a sensible implementation should
+ * never do this but RFC793 doesn't prohibit the change so we have to
+ * deal with it.
+ */
+ goto uncompressed;
+ }
+ deltaS = (u_short) (ntohs(th->th_win) - ntohs(oth->th_win));
+ if (deltaS) {
+ ENCODE(deltaS);
+ changes |= NEW_W;
+ }
+ deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
+ if (deltaA) {
+ if (deltaA > 0xffff) {
+ goto uncompressed;
+ }
+ ENCODE(deltaA);
+ changes |= NEW_A;
+ }
+ deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
+ if (deltaS) {
+ if (deltaS > 0xffff) {
+ goto uncompressed;
+ }
+ ENCODE(deltaS);
+ changes |= NEW_S;
+ }
+ switch (changes) {
+
+ case 0:
+
+ /*
+ * Nothing changed. If this packet contains data and the last one didn't,
+ * this is probably a data packet following an ack (normal on an
+ * interactive connection) and we send it compressed. Otherwise it's
+ * probably a retransmit, retransmitted ack or window probe. Send it
+ * uncompressed in case the other side missed the compressed version.
+ */
+ if (ip->ip_len != cs->cs_ip.ip_len &&
+ ntohs(cs->cs_ip.ip_len) == hlen)
+ break;
+
+ /* (fall through) */
+
+ case SPECIAL_I:
+ case SPECIAL_D:
+
+ /*
+ * actual changes match one of our special case encodings -- send packet
+ * uncompressed.
+ */
+ goto uncompressed;
+
+ case NEW_S | NEW_A:
+ if (deltaS == deltaA &&
+ deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for echoed terminal traffic */
+ changes = SPECIAL_I;
+ cp = new_seq;
+ }
+ break;
+
+ case NEW_S:
+ if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for data xfer */
+ changes = SPECIAL_D;
+ cp = new_seq;
+ }
+ break;
+ }
+
+ deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+ if (deltaS != 1) {
+ ENCODEZ(deltaS);
+ changes |= NEW_I;
+ }
+ if (th->th_flags & TH_PUSH)
+ changes |= TCP_PUSH_BIT;
+
+ /*
+ * Grab the cksum before we overwrite it below. Then update our state with
+ * this packet's header.
+ */
+ deltaA = ntohs(th->th_sum);
+ memcpy(&cs->cs_ip, ip, hlen);
+
+ /*
+ * We want to use the original packet as our compressed packet. (cp -
+ * new_seq) is the number of bytes we need for compressed sequence numbers.
+ * In addition we need one byte for the change mask, one for the connection
+ * id and two for the tcp checksum. So, (cp - new_seq) + 4 bytes of header
+ * are needed. hlen is how many bytes of the original packet to toss so
+ * subtract the two to get the new packet size.
+ */
+ deltaS = cp - new_seq;
+ cp = (u_char *) ip;
+
+ /*
+ * Since fastq traffic can jump ahead of the background traffic, we don't
+ * know what order packets will go on the line. In this case, we always
+ * send a "new" connection id so the receiver state stays synchronized.
+ */
+ if (comp->last_xmit == cs->cs_id && compress_cid) {
+ hlen -= deltaS + 3;
+ cp += hlen;
+ *cp++ = changes;
+ } else {
+ comp->last_xmit = cs->cs_id;
+ hlen -= deltaS + 4;
+ cp += hlen;
+ *cp++ = changes | NEW_C;
+ *cp++ = cs->cs_id;
+ }
+ m->cnt -= hlen;
+ m->offset += hlen;
+ *cp++ = deltaA >> 8;
+ *cp++ = deltaA;
+ memcpy(cp, new_seq, deltaS);
+ INCR(sls_compressed)
+ return (TYPE_COMPRESSED_TCP);
+
+ /*
+ * Update connection state cs & send uncompressed packet ('uncompressed'
+ * means a regular ip/tcp packet but with the 'conversation id' we hope to
+ * use on future compressed packets in the protocol field).
+ */
+uncompressed:
+ memcpy(&cs->cs_ip, ip, hlen);
+ ip->ip_p = cs->cs_id;
+ comp->last_xmit = cs->cs_id;
+ return (TYPE_UNCOMPRESSED_TCP);
+}
+
+
+int
+sl_uncompress_tcp(u_char ** bufp,
+ int len,
+ u_int type,
+ struct slcompress * comp)
+{
+ register u_char *cp;
+ register u_int hlen, changes;
+ register struct tcphdr *th;
+ register struct cstate *cs;
+ register struct ip *ip;
+
+ switch (type) {
+
+ case TYPE_UNCOMPRESSED_TCP:
+ ip = (struct ip *) * bufp;
+ if (ip->ip_p >= MAX_STATES)
+ goto bad;
+ cs = &comp->rstate[comp->last_recv = ip->ip_p];
+ comp->flags &= ~SLF_TOSS;
+ ip->ip_p = IPPROTO_TCP;
+
+ /*
+ * Calculate the size of the TCP/IP header and make sure that we don't
+ * overflow the space we have available for it.
+ */
+ hlen = ip->ip_hl << 2;
+ if (hlen + sizeof(struct tcphdr) > len)
+ goto bad;
+ th = (struct tcphdr *) & ((char *) ip)[hlen];
+ hlen += THOFFSET(th) << 2;
+ if (hlen > MAX_HDR)
+ goto bad;
+ memcpy(&cs->cs_ip, ip, hlen);
+ cs->cs_ip.ip_sum = 0;
+ cs->cs_hlen = hlen;
+ INCR(sls_uncompressedin)
+ return (len);
+
+ default:
+ goto bad;
+
+ case TYPE_COMPRESSED_TCP:
+ break;
+ }
+ /* We've got a compressed packet. */
+ INCR(sls_compressedin)
+ cp = *bufp;
+ changes = *cp++;
+ LogPrintf(LogDEBUG, "compressed: changes = %02x\n", changes);
+ if (changes & NEW_C) {
+
+ /*
+ * Make sure the state index is in range, then grab the state. If we have
+ * a good state index, clear the 'discard' flag.
+ */
+ if (*cp >= MAX_STATES || comp->last_recv == 255)
+ goto bad;
+
+ comp->flags &= ~SLF_TOSS;
+ comp->last_recv = *cp++;
+ } else {
+
+ /*
+ * this packet has an implicit state index. If we've had a line error
+ * since the last time we got an explicit state index, we have to toss
+ * the packet.
+ */
+ if (comp->flags & SLF_TOSS) {
+ INCR(sls_tossed)
+ return (0);
+ }
+ }
+ cs = &comp->rstate[comp->last_recv];
+ hlen = cs->cs_ip.ip_hl << 2;
+ th = (struct tcphdr *) & ((u_char *) & cs->cs_ip)[hlen];
+ th->th_sum = htons((*cp << 8) | cp[1]);
+ cp += 2;
+ if (changes & TCP_PUSH_BIT)
+ th->th_flags |= TH_PUSH;
+ else
+ th->th_flags &= ~TH_PUSH;
+
+ switch (changes & SPECIALS_MASK) {
+ case SPECIAL_I:
+ {
+ register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+
+ th->th_ack = htonl(ntohl(th->th_ack) + i);
+ th->th_seq = htonl(ntohl(th->th_seq) + i);
+ }
+ break;
+
+ case SPECIAL_D:
+ th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
+ - cs->cs_hlen);
+ break;
+
+ default:
+ if (changes & NEW_U) {
+ th->th_flags |= TH_URG;
+ DECODEU(th->th_urp)
+ } else
+ th->th_flags &= ~TH_URG;
+ if (changes & NEW_W)
+ DECODES(th->th_win)
+ if (changes & NEW_A)
+ DECODEL(th->th_ack)
+ if (changes & NEW_S) {
+ LogPrintf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n",
+ *cp, cp[1], cp[2]);
+ DECODEL(th->th_seq)
+ }
+ break;
+ }
+ if (changes & NEW_I) {
+ DECODES(cs->cs_ip.ip_id)
+ } else
+ cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
+
+ LogPrintf(LogDEBUG, "Uncompress: id = %04x, seq = %08x\n",
+ cs->cs_ip.ip_id, ntohl(th->th_seq));
+
+ /*
+ * At this point, cp points to the first byte of data in the packet. If
+ * we're not aligned on a 4-byte boundary, copy the data down so the ip &
+ * tcp headers will be aligned. Then back up cp by the tcp/ip header
+ * length to make room for the reconstructed header (we assume the packet
+ * we were handed has enough space to prepend 128 bytes of header). Adjust
+ * the length to account for the new header & fill in the IP total length.
+ */
+ len -= (cp - *bufp);
+ if (len < 0)
+
+ /*
+ * we must have dropped some characters (crc should detect this but the
+ * old slip framing won't)
+ */
+ goto bad;
+
+#ifdef notdef
+ if ((int) cp & 3) {
+ if (len > 0)
+ (void) bcopy(cp, (caddr_t) ((int) cp & ~3), len);
+ cp = (u_char *) ((int) cp & ~3);
+ }
+#endif
+
+ cp -= cs->cs_hlen;
+ len += cs->cs_hlen;
+ cs->cs_ip.ip_len = htons(len);
+ memcpy(cp, &cs->cs_ip, cs->cs_hlen);
+ *bufp = cp;
+
+ /* recompute the ip header checksum */
+ {
+ register u_short *bp = (u_short *) cp;
+
+ for (changes = 0; hlen > 0; hlen -= 2)
+ changes += *bp++;
+ changes = (changes & 0xffff) + (changes >> 16);
+ changes = (changes & 0xffff) + (changes >> 16);
+ ((struct ip *) cp)->ip_sum = ~changes;
+ }
+ return (len);
+bad:
+ comp->flags |= SLF_TOSS;
+ INCR(sls_errorin)
+ return (0);
+}
+
+int
+ReportCompress(struct cmdargs const *arg)
+{
+ if (!VarTerm)
+ return 1;
+
+ fprintf(VarTerm, "Out: %d (compress) / %d (total)",
+ slstat.sls_compressed, slstat.sls_packets);
+ fprintf(VarTerm, " %d (miss) / %d (search)\n",
+ slstat.sls_misses, slstat.sls_searches);
+ fprintf(VarTerm, "In: %d (compress), %d (uncompress)",
+ slstat.sls_compressedin, slstat.sls_uncompressedin);
+ fprintf(VarTerm, " %d (error), %d (tossed)\n",
+ slstat.sls_errorin, slstat.sls_tossed);
+ return 0;
+}
diff --git a/usr.sbin/ppp/slcompress.h b/usr.sbin/ppp/slcompress.h
new file mode 100644
index 00000000000..17658efca26
--- /dev/null
+++ b/usr.sbin/ppp/slcompress.h
@@ -0,0 +1,134 @@
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Header: /cvs/OpenBSD/src/usr.sbin/ppp/Attic/slcompress.h,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: slcompress.h,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#define MAX_STATES 16 /* must be > 2 and < 256 */
+#define MAX_HDR 128 /* XXX 4bsd-ism: should really be 128 */
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID. (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.) Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ struct cstate *cs_next; /* next most recently used cstate (xmit only) */
+ u_short cs_hlen; /* size of hdr (receive only) */
+ u_char cs_id; /* connection # associated with this state */
+ u_char cs_filler;
+ union {
+ char csu_hdr[MAX_HDR];
+ struct ip csu_ip; /* ip/tcp hdr from most recent packet */
+ } slcs_u;
+};
+
+#define cs_ip slcs_u.csu_ip
+#define cs_hdr slcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these
+ * per line).
+ */
+struct slcompress {
+ struct cstate *last_cs; /* most recently used tstate */
+ u_char last_recv; /* last rcvd conn. id */
+ u_char last_xmit; /* last sent conn. id */
+ u_short flags;
+ struct cstate tstate[MAX_STATES]; /* xmit connection states */
+ struct cstate rstate[MAX_STATES]; /* receive connection states */
+};
+
+/* flag values */
+#define SLF_TOSS 1 /* tossing rcvd frames because of input err */
+
+extern void sl_compress_init(struct slcompress *, int);
+extern u_char sl_compress_tcp
+ (struct mbuf *, struct ip *, struct slcompress *, int);
+extern int sl_uncompress_tcp(u_char **, int, u_int, struct slcompress *);
+extern int ReportCompress(struct cmdargs const *);
diff --git a/usr.sbin/ppp/systems.c b/usr.sbin/ppp/systems.c
new file mode 100644
index 00000000000..a19ca4e1e07
--- /dev/null
+++ b/usr.sbin/ppp/systems.c
@@ -0,0 +1,368 @@
+/*
+ * System configuration routines
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: systems.c,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ * TODO:
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "id.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "loadalias.h"
+#include "ipcp.h"
+#include "pathnames.h"
+#include "vars.h"
+#include "server.h"
+#include "chat.h"
+#include "systems.h"
+
+#define issep(ch) ((ch) == ' ' || (ch) == '\t')
+
+FILE *
+OpenSecret(const char *file)
+{
+ FILE *fp;
+ char line[100];
+
+ snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
+ fp = ID0fopen(line, "r");
+ if (fp == NULL)
+ LogPrintf(LogWARN, "OpenSecret: Can't open %s.\n", line);
+ return (fp);
+}
+
+void
+CloseSecret(FILE * fp)
+{
+ fclose(fp);
+}
+
+/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
+static void
+InterpretArg(char *from, char *to)
+{
+ const char *env;
+ char *ptr, *startto, *endto;
+ int len;
+
+ startto = to;
+ endto = to + LINE_LEN - 1;
+
+ while(issep(*from))
+ from++;
+ if (*from == '~') {
+ ptr = strchr(++from, '/');
+ len = ptr ? ptr - from : strlen(from);
+ if (len == 0) {
+ if ((env = getenv("HOME")) == NULL)
+ env = _PATH_PPP;
+ strncpy(to, env, endto - to);
+ } else {
+ struct passwd *pwd;
+
+ strncpy(to, from, len);
+ to[len] = '\0';
+ pwd = getpwnam(to);
+ if (pwd)
+ strncpy(to, pwd->pw_dir, endto-to);
+ else
+ strncpy(to, _PATH_PPP, endto - to);
+ endpwent();
+ }
+ *endto = '\0';
+ to += strlen(to);
+ from += len;
+ }
+
+ while (to < endto && *from != '\0') {
+ if (*from == '$') {
+ if (from[1] == '$') {
+ *to = '\0'; /* For an empty var name below */
+ from += 2;
+ } else if (from[1] == '{') {
+ ptr = strchr(from+2, '}');
+ if (ptr) {
+ len = ptr - from - 2;
+ if (endto - to < len )
+ len = endto - to;
+ if (len) {
+ strncpy(to, from+2, len);
+ to[len] = '\0';
+ from = ptr+1;
+ } else {
+ *to++ = *from++;
+ continue;
+ }
+ } else {
+ *to++ = *from++;
+ continue;
+ }
+ } else {
+ ptr = to;
+ for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
+ *ptr++ = *from;
+ *ptr = '\0';
+ }
+ if (*to == '\0')
+ *to++ = '$';
+ else if ((env = getenv(to)) != NULL) {
+ strncpy(to, env, endto - to);
+ *endto = '\0';
+ to += strlen(to);
+ }
+ } else
+ *to++ = *from++;
+ }
+ while (to > startto) {
+ to--;
+ if (!issep(*to)) {
+ to++;
+ break;
+ }
+ }
+ *to = '\0';
+}
+
+#define CTRL_UNKNOWN (0)
+#define CTRL_INCLUDE (1)
+
+static int
+DecodeCtrlCommand(char *line, char *arg)
+{
+ if (!strncasecmp(line, "include", 7) && issep(line[7])) {
+ InterpretArg(line+8, arg);
+ return CTRL_INCLUDE;
+ }
+ return CTRL_UNKNOWN;
+}
+
+static int userok;
+
+int
+AllowUsers(struct cmdargs const *arg)
+{
+ int f;
+ char *user;
+
+ userok = 0;
+ user = getlogin();
+ if (user && *user)
+ for (f = 0; f < arg->argc; f++)
+ if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
+ userok = 1;
+ break;
+ }
+
+ return 0;
+}
+
+static struct {
+ int mode;
+ const char *name;
+} modes[] = {
+ { MODE_INTER, "interactive" },
+ { MODE_AUTO, "auto" },
+ { MODE_DIRECT, "direct" },
+ { MODE_DEDICATED, "dedicated" },
+ { MODE_DDIAL, "ddial" },
+ { MODE_BACKGROUND, "background" },
+ { ~0, "*" },
+ { 0, 0 }
+};
+
+static int modeok;
+
+int
+AllowModes(struct cmdargs const *arg)
+{
+ int f;
+ int m;
+ int allowed;
+
+ allowed = 0;
+ for (f = 0; f < arg->argc; f++) {
+ for (m = 0; modes[m].mode; m++)
+ if (!strcasecmp(modes[m].name, arg->argv[f])) {
+ allowed |= modes[m].mode;
+ break;
+ }
+ if (modes[m].mode == 0)
+ LogPrintf(LogWARN, "%s: Invalid mode\n", arg->argv[f]);
+ }
+
+ modeok = (mode | allowed) == allowed ? 1 : 0;
+ return 0;
+}
+
+static int
+ReadSystem(const char *name, const char *file, int doexec)
+{
+ FILE *fp;
+ char *cp, *wp;
+ int n, len;
+ u_char olauth;
+ char line[LINE_LEN];
+ char filename[200];
+ int linenum;
+ int argc;
+ char **argv;
+ int allowcmd;
+
+ if (*file == '/')
+ snprintf(filename, sizeof filename, "%s", file);
+ else
+ snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
+ fp = ID0fopen(filename, "r");
+ if (fp == NULL) {
+ LogPrintf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
+ return (-1);
+ }
+ LogPrintf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
+
+ linenum = 0;
+ while (fgets(line, sizeof(line), fp)) {
+ linenum++;
+ cp = line;
+ switch (*cp) {
+ case '#': /* comment */
+ break;
+ case ' ':
+ case '\t':
+ break;
+ default:
+ wp = strpbrk(cp, ":\n");
+ if (wp == NULL) {
+ LogPrintf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
+ filename, linenum);
+ ServerClose();
+ exit(1);
+ }
+ *wp = '\0';
+ if (*cp == '!') {
+ char arg[LINE_LEN];
+ switch (DecodeCtrlCommand(cp+1, arg)) {
+ case CTRL_INCLUDE:
+ LogPrintf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
+ n = ReadSystem(name, arg, doexec);
+ LogPrintf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
+ if (!n)
+ return 0; /* got it */
+ break;
+ default:
+ LogPrintf(LogCOMMAND, "%s: %s: Invalid command\n", name, cp);
+ break;
+ }
+ } else if (strcmp(cp, name) == 0) {
+ while (fgets(line, sizeof(line), fp)) {
+ cp = line;
+ if (issep(*cp)) {
+ n = strspn(cp, " \t");
+ cp += n;
+ len = strlen(cp);
+ if (!len)
+ continue;
+ if (cp[len-1] == '\n')
+ cp[--len] = '\0';
+ if (!len)
+ continue;
+ InterpretCommand(cp, len, &argc, &argv);
+ allowcmd = argc > 0 && !strcasecmp(*argv, "allow");
+ if ((!doexec && allowcmd) || (doexec && !allowcmd)) {
+ olauth = VarLocalAuth;
+ if (VarLocalAuth == LOCAL_NO_AUTH)
+ VarLocalAuth = LOCAL_AUTH;
+ RunCommand(argc, (char const *const *)argv, name);
+ VarLocalAuth = olauth;
+ }
+ } else if (*cp == '#' || *cp == '\n' || *cp == '\0') {
+ continue;
+ } else
+ break;
+ }
+ fclose(fp);
+ return (0);
+ }
+ break;
+ }
+ }
+ fclose(fp);
+ return -1;
+}
+
+int
+ValidSystem(const char *name)
+{
+ if (ID0realuid() == 0)
+ return userok = modeok = 1;
+ userok = 0;
+ modeok = 1;
+ ReadSystem("default", CONFFILE, 0);
+ if (name != NULL)
+ ReadSystem(name, CONFFILE, 0);
+ return userok && modeok;
+}
+
+int
+SelectSystem(const char *name, const char *file)
+{
+ userok = modeok = 1;
+ return ReadSystem(name, file, 1);
+}
+
+int
+LoadCommand(struct cmdargs const *arg)
+{
+ const char *name;
+
+ if (arg->argc > 0)
+ name = *arg->argv;
+ else
+ name = "default";
+
+ if (!ValidSystem(name)) {
+ LogPrintf(LogERROR, "%s: Label not allowed\n", name);
+ return 1;
+ } else if (SelectSystem(name, CONFFILE) < 0) {
+ LogPrintf(LogWARN, "%s: not found.\n", name);
+ return -1;
+ } else
+ SetLabel(arg->argc ? name : NULL);
+ return 0;
+}
+
+int
+SaveCommand(struct cmdargs const *arg)
+{
+ LogPrintf(LogWARN, "save command is not implemented (yet).\n");
+ return 1;
+}
diff --git a/usr.sbin/ppp/systems.h b/usr.sbin/ppp/systems.h
new file mode 100644
index 00000000000..cf75015f987
--- /dev/null
+++ b/usr.sbin/ppp/systems.h
@@ -0,0 +1,31 @@
+/*
+ * User Process PPP
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: systems.h,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ */
+
+extern int SelectSystem(const char *, const char *);
+extern int ValidSystem(const char *);
+extern FILE *OpenSecret(const char *);
+extern void CloseSecret(FILE *);
+extern int AllowUsers(struct cmdargs const *);
+extern int AllowModes(struct cmdargs const *);
+extern int LoadCommand(struct cmdargs const *);
+extern int SaveCommand(struct cmdargs const *);
diff --git a/usr.sbin/ppp/throughput.c b/usr.sbin/ppp/throughput.c
new file mode 100644
index 00000000000..da0311fb2d9
--- /dev/null
+++ b/usr.sbin/ppp/throughput.c
@@ -0,0 +1,127 @@
+/*
+ * $Id: throughput.c,v 1.1 1997/11/23 20:27:37 brian Exp $
+ */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <netinet/in.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "timer.h"
+#include "throughput.h"
+#include "defs.h"
+#include "loadalias.h"
+#include "vars.h"
+
+void
+throughput_init(struct pppThroughput *t)
+{
+ int f;
+
+ t->OctetsIn = t->OctetsOut = 0;
+ for (f = 0; f < SAMPLE_PERIOD; f++)
+ t->SampleOctets[f] = 0;
+ t->OctetsPerSecond = t->BestOctetsPerSecond = t->nSample = 0;
+ throughput_stop(t);
+}
+
+void
+throughput_disp(struct pppThroughput *t, FILE *f)
+{
+ int secs_up;
+
+ secs_up = time(NULL) - t->uptime;
+ fprintf(f, "Connect time: %d secs\n", secs_up);
+ if (secs_up == 0)
+ secs_up = 1;
+ fprintf(f, "%ld octets in, %ld octets out\n", t->OctetsIn, t->OctetsOut);
+ if (Enabled(ConfThroughput)) {
+ fprintf(f, " overall %5ld bytes/sec\n",
+ (t->OctetsIn+t->OctetsOut)/secs_up);
+ fprintf(f, " currently %5d bytes/sec\n", t->OctetsPerSecond);
+ fprintf(f, " peak %5d bytes/sec\n", t->BestOctetsPerSecond);
+ } else
+ fprintf(f, "Overall %ld bytes/sec\n", (t->OctetsIn+t->OctetsOut)/secs_up);
+}
+
+
+void
+throughput_log(struct pppThroughput *t, int level, const char *title)
+{
+ if (t->uptime) {
+ int secs_up;
+
+ secs_up = time(NULL) - t->uptime;
+ if (title)
+ LogPrintf(level, "%s: Connect time: %d secs: %ld octets in, %ld octets"
+ " out\n", title, secs_up, t->OctetsIn, t->OctetsOut);
+ else
+ LogPrintf(level, "Connect time: %d secs: %ld octets in, %ld octets out\n",
+ secs_up, t->OctetsIn, t->OctetsOut);
+ if (secs_up == 0)
+ secs_up = 1;
+ if (Enabled(ConfThroughput))
+ LogPrintf(level, " total %ld bytes/sec, peak %d bytes/sec\n",
+ (t->OctetsIn+t->OctetsOut)/secs_up, t->BestOctetsPerSecond);
+ else
+ LogPrintf(level, " total %ld bytes/sec\n",
+ (t->OctetsIn+t->OctetsOut)/secs_up);
+ }
+}
+
+static void
+throughput_sampler(void *v)
+{
+ struct pppThroughput *t = (struct pppThroughput *)v;
+ u_long old;
+
+ StopTimer(&t->Timer);
+ t->Timer.state = TIMER_STOPPED;
+
+ old = t->SampleOctets[t->nSample];
+ t->SampleOctets[t->nSample] = t->OctetsIn + t->OctetsOut;
+ t->OctetsPerSecond = (t->SampleOctets[t->nSample] - old) / SAMPLE_PERIOD;
+ if (t->BestOctetsPerSecond < t->OctetsPerSecond)
+ t->BestOctetsPerSecond = t->OctetsPerSecond;
+ if (++t->nSample == SAMPLE_PERIOD)
+ t->nSample = 0;
+
+ StartTimer(&t->Timer);
+}
+
+void
+throughput_start(struct pppThroughput *t)
+{
+ throughput_init(t);
+ time(&t->uptime);
+ if (Enabled(ConfThroughput)) {
+ t->Timer.state = TIMER_STOPPED;
+ t->Timer.load = SECTICKS;
+ t->Timer.func = throughput_sampler;
+ t->Timer.arg = t;
+ StartTimer(&t->Timer);
+ }
+}
+
+void
+throughput_stop(struct pppThroughput *t)
+{
+ if (Enabled(ConfThroughput))
+ StopTimer(&t->Timer);
+}
+
+void
+throughput_addin(struct pppThroughput *t, int n)
+{
+ t->OctetsIn += n;
+}
+
+void
+throughput_addout(struct pppThroughput *t, int n)
+{
+ t->OctetsOut += n;
+}
diff --git a/usr.sbin/ppp/throughput.h b/usr.sbin/ppp/throughput.h
new file mode 100644
index 00000000000..d255c15bcbe
--- /dev/null
+++ b/usr.sbin/ppp/throughput.h
@@ -0,0 +1,24 @@
+/*
+ * $Id: throughput.h,v 1.1 1997/11/23 20:27:37 brian Exp $
+ */
+
+#define SAMPLE_PERIOD 5
+
+struct pppThroughput {
+ time_t uptime;
+ u_long OctetsIn;
+ u_long OctetsOut;
+ u_long SampleOctets[SAMPLE_PERIOD];
+ int OctetsPerSecond;
+ int BestOctetsPerSecond;
+ int nSample;
+ struct pppTimer Timer;
+};
+
+extern void throughput_init(struct pppThroughput *);
+extern void throughput_disp(struct pppThroughput *, FILE *);
+extern void throughput_log(struct pppThroughput *, int, const char *);
+extern void throughput_start(struct pppThroughput *);
+extern void throughput_stop(struct pppThroughput *);
+extern void throughput_addin(struct pppThroughput *, int);
+extern void throughput_addout(struct pppThroughput *, int);
diff --git a/usr.sbin/ppp/timer.c b/usr.sbin/ppp/timer.c
new file mode 100644
index 00000000000..ebb4cd4453b
--- /dev/null
+++ b/usr.sbin/ppp/timer.c
@@ -0,0 +1,296 @@
+/*
+ * PPP Timer Processing Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: timer.c,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ * TODO:
+ */
+
+#include <signal.h>
+#ifdef SIGALRM
+#include <errno.h>
+#endif
+#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "sig.h"
+#include "timer.h"
+
+struct pppTimer *TimerList = NULL;
+
+static void StopTimerNoBlock(struct pppTimer *);
+static void InitTimerService(void);
+
+void
+StopTimer(struct pppTimer * tp)
+{
+#ifdef SIGALRM
+ int omask;
+
+ omask = sigblock(sigmask(SIGALRM));
+#endif
+ StopTimerNoBlock(tp);
+#ifdef SIGALRM
+ sigsetmask(omask);
+#endif
+}
+
+void
+StartTimer(struct pppTimer * tp)
+{
+ struct pppTimer *t, *pt;
+ u_long ticks = 0;
+
+#ifdef SIGALRM
+ int omask;
+
+ omask = sigblock(sigmask(SIGALRM));
+#endif
+
+ if (tp->state != TIMER_STOPPED) {
+ StopTimerNoBlock(tp);
+ }
+ if (tp->load == 0) {
+ LogPrintf(LogDEBUG, "timer %x has 0 load!\n", tp);
+ sigsetmask(omask);
+ return;
+ }
+ pt = NULL;
+ for (t = TimerList; t; t = t->next) {
+ LogPrintf(LogDEBUG, "StartTimer: %x(%d): ticks: %d, rest: %d\n",
+ t, t->state, ticks, t->rest);
+ if (ticks + t->rest >= tp->load)
+ break;
+ ticks += t->rest;
+ pt = t;
+ }
+
+ tp->state = TIMER_RUNNING;
+ tp->rest = tp->load - ticks;
+ LogPrintf(LogDEBUG, "StartTimer: Inserting %x before %x, rest = %d\n",
+ tp, t, tp->rest);
+ /* Insert given *tp just before *t */
+ tp->next = t;
+ if (pt) {
+ pt->next = tp;
+ } else {
+ InitTimerService();
+ TimerList = tp;
+ }
+ if (t)
+ t->rest -= tp->rest;
+
+#ifdef SIGALRM
+ sigsetmask(omask);
+#endif
+}
+
+static void
+StopTimerNoBlock(struct pppTimer * tp)
+{
+ struct pppTimer *t, *pt;
+
+ /*
+ * A Running Timer should be removing TimerList, But STOPPED/EXPIRED is
+ * already removing TimerList. So just marked as TIMER_STOPPED. Do not
+ * change tp->enext!! (Might be Called by expired proc)
+ */
+ LogPrintf(LogDEBUG, "StopTimer: %x, next = %x state=%x\n",
+ tp, tp->next, tp->state);
+ if (tp->state != TIMER_RUNNING) {
+ tp->next = NULL;
+ tp->state = TIMER_STOPPED;
+ return;
+ }
+ pt = NULL;
+ for (t = TimerList; t != tp && t != NULL; t = t->next)
+ pt = t;
+ if (t) {
+ if (pt) {
+ pt->next = t->next;
+ } else {
+ TimerList = t->next;
+ if (TimerList == NULL) /* Last one ? */
+ TermTimerService(); /* Terminate Timer Service */
+ }
+ if (t->next)
+ t->next->rest += tp->rest;
+ } else
+ LogPrintf(LogERROR, "Oops, timer not found!!\n");
+
+ tp->next = NULL;
+ tp->state = TIMER_STOPPED;
+}
+
+void
+TimerService()
+{
+ struct pppTimer *tp, *exp, *wt;
+
+ if (LogIsKept(LogDEBUG))
+ ShowTimers();
+ tp = TimerList;
+ if (tp) {
+ tp->rest--;
+ if (tp->rest == 0) {
+
+ /*
+ * Multiple timers may expires at once. Create list of expired timers.
+ */
+ exp = NULL;
+ do {
+ tp->state = TIMER_EXPIRED;
+ wt = tp->next;
+ tp->enext = exp;
+ exp = tp;
+ LogPrintf(LogDEBUG, "TimerService: Add %x to exp\n", tp);
+ tp = wt;
+ } while (tp && (tp->rest == 0));
+
+ TimerList = tp;
+ if (TimerList == NULL) /* No timers ? */
+ TermTimerService(); /* Terminate Timer Service */
+ LogPrintf(LogDEBUG, "TimerService: next is %x(%d)\n",
+ TimerList, TimerList ? TimerList->rest : 0);
+
+ /*
+ * Process all expired timers.
+ */
+ while (exp) {
+#ifdef notdef
+ StopTimer(exp);
+#endif
+ if (exp->func)
+ (*exp->func) (exp->arg);
+
+ /*
+ * Just Removing each item from expired list And exp->enext will be
+ * intialized at next expire in this funtion.
+ */
+ exp = exp->enext;
+ }
+ }
+ }
+}
+
+void
+ShowTimers()
+{
+ struct pppTimer *pt;
+
+ LogPrintf(LogDEBUG, "---- Begin of Timer Service List---\n");
+ for (pt = TimerList; pt; pt = pt->next)
+ LogPrintf(LogDEBUG, "%x: load = %d, rest = %d, state =%x\n",
+ pt, pt->load, pt->rest, pt->state);
+ LogPrintf(LogDEBUG, "---- End of Timer Service List ---\n");
+}
+
+#ifdef SIGALRM
+u_int
+nointr_sleep(u_int sec)
+{
+ struct timeval to, st, et;
+ long sld, nwd, std;
+
+ gettimeofday(&st, NULL);
+ to.tv_sec = sec;
+ to.tv_usec = 0;
+ std = st.tv_sec * 1000000 + st.tv_usec;
+ for (;;) {
+ if (select(0, NULL, NULL, NULL, &to) == 0 ||
+ errno != EINTR) {
+ break;
+ } else {
+ gettimeofday(&et, NULL);
+ sld = to.tv_sec * 1000000 + to.tv_sec;
+ nwd = et.tv_sec * 1000000 + et.tv_usec - std;
+ if (sld > nwd)
+ sld -= nwd;
+ else
+ sld = 1; /* Avoid both tv_sec/usec is 0 */
+
+ /* Calculate timeout value for select */
+ to.tv_sec = sld / 1000000;
+ to.tv_usec = sld % 1000000;
+ }
+ }
+ return (0L);
+}
+
+void
+nointr_usleep(u_int usec)
+{
+ struct timeval to, st, et;
+ long sld, nwd, std;
+
+ gettimeofday(&st, NULL);
+ to.tv_sec = 0;
+ to.tv_usec = usec;
+ std = st.tv_sec * 1000000 + st.tv_usec;
+ for (;;) {
+ if (select(0, NULL, NULL, NULL, &to) == 0 ||
+ errno != EINTR) {
+ break;
+ } else {
+ gettimeofday(&et, NULL);
+ sld = to.tv_sec * 1000000 + to.tv_sec;
+ nwd = et.tv_sec * 1000000 + et.tv_usec - std;
+ if (sld > nwd)
+ sld -= nwd;
+ else
+ sld = 1; /* Avoid both tv_sec/usec is 0 */
+
+ /* Calculate timeout value for select */
+ to.tv_sec = sld / 1000000;
+ to.tv_usec = sld % 1000000;
+
+ }
+ }
+}
+
+static void
+InitTimerService()
+{
+ struct itimerval itimer;
+
+ pending_signal(SIGALRM, (void (*) (int)) TimerService);
+ itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
+ itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
+ if (setitimer(ITIMER_REAL, &itimer, NULL) == -1)
+ LogPrintf(LogERROR, "Unable to set itimer.\n");
+}
+
+void
+TermTimerService(void)
+{
+ struct itimerval itimer;
+
+ itimer.it_interval.tv_usec = itimer.it_interval.tv_sec = 0;
+ itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
+ if (setitimer(ITIMER_REAL, &itimer, NULL) == -1)
+ LogPrintf(LogERROR, "Unable to set itimer.\n");
+ pending_signal(SIGALRM, SIG_IGN);
+}
+
+#endif
diff --git a/usr.sbin/ppp/timer.h b/usr.sbin/ppp/timer.h
new file mode 100644
index 00000000000..cf11adbe104
--- /dev/null
+++ b/usr.sbin/ppp/timer.h
@@ -0,0 +1,51 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: timer.h,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ * TODO:
+ */
+
+#define TICKUNIT 100000 /* Unit in usec */
+#define SECTICKS (1000000/TICKUNIT)
+
+struct pppTimer {
+ int state;
+ u_long rest; /* Ticks to expire */
+ u_long load; /* Initial load value */
+ void (*func)(void *); /* Function called when timer is expired */
+ void *arg; /* Argument passed to timeout function */
+ struct pppTimer *next; /* Link to next timer */
+ struct pppTimer *enext; /* Link to next expired timer */
+};
+
+#define TIMER_STOPPED 0
+#define TIMER_RUNNING 1
+#define TIMER_EXPIRED 2
+
+extern struct pppTimer *TimerList;
+
+extern void StartTimer(struct pppTimer *);
+extern void StopTimer(struct pppTimer *);
+extern void TimerService(void);
+extern void TermTimerService(void);
+extern void ShowTimers(void);
+
+#ifdef SIGALRM
+extern u_int nointr_sleep(u_int);
+extern void nointr_usleep(u_int);
+#endif
diff --git a/usr.sbin/ppp/tun.c b/usr.sbin/ppp/tun.c
new file mode 100644
index 00000000000..2cf21ca4dd1
--- /dev/null
+++ b/usr.sbin/ppp/tun.c
@@ -0,0 +1,46 @@
+/*
+ * $Id: tun.c,v 1.1 1997/11/23 20:27:37 brian Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#ifdef __FreeBSD__
+#include <net/if_var.h>
+#endif
+#include <net/if_tun.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "hdlc.h"
+#include "defs.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "tun.h"
+
+void
+tun_configure(int mtu, int speed)
+{
+ struct tuninfo info;
+
+ info.type = 23;
+ info.mtu = mtu;
+ if (VarPrefMTU != 0 && VarPrefMTU < mtu)
+ info.mtu = VarPrefMTU;
+ info.baudrate = speed;
+#ifdef __OpenBSD__
+ info.flags = IFF_UP|IFF_POINTOPOINT;
+#endif
+ if (ioctl(tun_out, TUNSIFINFO, &info) < 0)
+ LogPrintf(LogERROR, "tun_configure: ioctl(TUNSIFINFO): %s\n",
+ strerror(errno));
+}
diff --git a/usr.sbin/ppp/tun.h b/usr.sbin/ppp/tun.h
new file mode 100644
index 00000000000..ca31c8f66d6
--- /dev/null
+++ b/usr.sbin/ppp/tun.h
@@ -0,0 +1,20 @@
+/*
+ * $Id: tun.h,v 1.1 1997/11/23 20:27:36 brian Exp $
+ */
+
+struct tun_data {
+#ifdef __OpenBSD__
+ struct tunnel_header head;
+#endif
+ u_char data[MAX_MRU];
+};
+
+#ifdef __OpenBSD__
+#define tun_fill_header(f,proto) do { (f).head.tun_af = (proto); } while (0)
+#define tun_check_header(f,proto) ((f).head.tun_af == (proto))
+#else
+#define tun_fill_header(f,proto) do { } while (0)
+#define tun_check_header(f,proto) (1)
+#endif
+
+extern void tun_configure(int, int);
diff --git a/usr.sbin/ppp/vars.c b/usr.sbin/ppp/vars.c
new file mode 100644
index 00000000000..b7d6fcc88ea
--- /dev/null
+++ b/usr.sbin/ppp/vars.c
@@ -0,0 +1,194 @@
+/*
+ * PPP configuration variables
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: vars.c,v 1.1 1997/11/23 20:27:36 brian Exp $
+ *
+ */
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "hdlc.h"
+#include "termios.h"
+#include "loadalias.h"
+#include "vars.h"
+#include "auth.h"
+
+char VarVersion[] = "PPP Version 1.5";
+char VarLocalVersion[] = "$Date: 1997/11/23 20:27:36 $";
+int Utmp = 0;
+int ipInOctets = 0;
+int ipOutOctets = 0;
+int ipKeepAlive = 0;
+int ipConnectSecs = 0;
+int ipIdleSecs = 0;
+int reconnectState = RECON_UNKNOWN;
+int reconnectCount = 0;
+
+/*
+ * Order of conf option is important. See vars.h.
+ */
+struct confdesc pppConfs[] = {
+ {"vjcomp", CONF_ENABLE, CONF_ACCEPT},
+ {"lqr", CONF_DISABLE, CONF_ACCEPT},
+ {"chap", CONF_DISABLE, CONF_ACCEPT},
+ {"pap", CONF_DISABLE, CONF_ACCEPT},
+ {"acfcomp", CONF_ENABLE, CONF_ACCEPT},
+ {"protocomp", CONF_ENABLE, CONF_ACCEPT},
+ {"pred1", CONF_ENABLE, CONF_ACCEPT},
+ {"proxy", CONF_DISABLE, CONF_NONE},
+ {"msext", CONF_DISABLE, CONF_NONE},
+ {"passwdauth", CONF_DISABLE, CONF_NONE},
+ {"utmp", CONF_ENABLE, CONF_NONE},
+ {"throughput", CONF_DISABLE, CONF_NONE},
+ {NULL},
+};
+
+struct pppvars pppVars = {
+ DEF_MRU, DEF_MTU, 0, MODEM_SPEED, CS8, MODEM_CTSRTS, 180, 30, 3,
+ RECONNECT_TIMER, RECONNECT_TRIES, REDIAL_PERIOD,
+ NEXT_REDIAL_PERIOD, 1, 1, MODEM_DEV, BASE_MODEM_DEV,
+ OPEN_ACTIVE, LOCAL_NO_AUTH, 0
+};
+
+int
+DisplayCommand(struct cmdargs const *arg)
+{
+ struct confdesc *vp;
+
+ if (!VarTerm)
+ return 1;
+
+ fprintf(VarTerm, "Current configuration option settings..\n\n");
+ fprintf(VarTerm, "Name\t\tMy Side\t\tHis Side\n");
+ fprintf(VarTerm, "----------------------------------------\n");
+ for (vp = pppConfs; vp->name; vp++)
+ fprintf(VarTerm, "%-10s\t%s\t\t%s\n", vp->name,
+ (vp->myside == CONF_ENABLE) ? "enable" :
+ (vp->myside == CONF_DISABLE ? "disable" : "N/A"),
+ (vp->hisside == CONF_ACCEPT) ? "accept" :
+ (vp->hisside == CONF_DENY ? "deny" : "N/A"));
+
+ return 0;
+}
+
+static int
+ConfigCommand(struct cmdargs const *arg, int mine, int val)
+{
+ struct confdesc *vp;
+ int err;
+ int narg = 0;
+
+ if (arg->argc < 1)
+ return -1;
+
+ err = 0;
+ do {
+ for (vp = pppConfs; vp->name; vp++)
+ if (strcasecmp(vp->name, arg->argv[narg]) == 0) {
+ if (mine) {
+ if (vp->myside == CONF_NONE) {
+ LogPrintf(LogWARN, "Config: %s cannot be enabled or disabled\n",
+ vp->name);
+ err++;
+ } else
+ vp->myside = val;
+ } else {
+ if (vp->hisside == CONF_NONE) {
+ LogPrintf(LogWARN, "Config: %s cannot be accepted or denied\n",
+ vp->name);
+ err++;
+ } else
+ vp->hisside = val;
+ }
+ break;
+ }
+ if (!vp->name) {
+ LogPrintf(LogWARN, "Config: %s: No such key word\n", arg->argv[narg]);
+ err++;
+ }
+ } while (++narg < arg->argc);
+
+ return err;
+}
+
+int
+EnableCommand(struct cmdargs const *arg)
+{
+ return ConfigCommand(arg, 1, CONF_ENABLE);
+}
+
+int
+DisableCommand(struct cmdargs const *arg)
+{
+ return ConfigCommand(arg, 1, CONF_DISABLE);
+}
+
+int
+AcceptCommand(struct cmdargs const *arg)
+{
+ return ConfigCommand(arg, 0, CONF_ACCEPT);
+}
+
+int
+DenyCommand(struct cmdargs const *arg)
+{
+ return ConfigCommand(arg, 0, CONF_DENY);
+}
+
+int
+LocalAuthCommand(struct cmdargs const *arg)
+{
+ const char *pass;
+ if (arg->argc == 0)
+ pass = "";
+ else if (arg->argc > 1)
+ return -1;
+ else
+ pass = *arg->argv;
+
+ if (VarHaveLocalAuthKey)
+ VarLocalAuth = strcmp(VarLocalAuthKey, pass) ? LOCAL_NO_AUTH : LOCAL_AUTH;
+ else
+ switch (LocalAuthValidate(SECRETFILE, VarShortHost, pass)) {
+ case INVALID:
+ VarLocalAuth = LOCAL_NO_AUTH;
+ break;
+ case VALID:
+ VarLocalAuth = LOCAL_AUTH;
+ break;
+ case NOT_FOUND:
+ VarLocalAuth = LOCAL_AUTH;
+ LogPrintf(LogWARN, "WARNING: No Entry for this system\n");
+ break;
+ default:
+ VarLocalAuth = LOCAL_NO_AUTH;
+ LogPrintf(LogERROR, "LocalAuthCommand: Ooops?\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/usr.sbin/ppp/vars.h b/usr.sbin/ppp/vars.h
new file mode 100644
index 00000000000..018be321b2f
--- /dev/null
+++ b/usr.sbin/ppp/vars.h
@@ -0,0 +1,204 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: vars.h,v 1.1 1997/11/23 20:27:37 brian Exp $
+ *
+ * TODO:
+ */
+
+struct confdesc {
+ const char *name;
+ int myside, hisside;
+};
+
+#define CONF_NONE -1
+#define CONF_DISABLE 0
+#define CONF_ENABLE 1
+
+#define CONF_DENY 0
+#define CONF_ACCEPT 1
+
+#define ConfVjcomp 0
+#define ConfLqr 1
+#define ConfChap 2
+#define ConfPap 3
+#define ConfAcfcomp 4
+#define ConfProtocomp 5
+#define ConfPred1 6
+#define ConfProxy 7
+#define ConfMSExt 8
+#define ConfPasswdAuth 9
+#define ConfUtmp 10
+#define ConfThroughput 11
+#define MAXCONFS 12
+
+#define Enabled(x) (pppConfs[x].myside & CONF_ENABLE)
+#define Acceptable(x) (pppConfs[x].hisside & CONF_ACCEPT)
+
+extern struct confdesc pppConfs[MAXCONFS + 1];
+
+struct pppvars {
+ u_long var_mru; /* Initial MRU value */
+ u_long pref_mtu; /* Preferred MTU value */
+ int var_accmap; /* Initial ACCMAP value */
+ int modem_speed; /* Current modem speed */
+ int modem_parity; /* Parity setting */
+ int modem_ctsrts; /* Use CTS/RTS on modem port? (boolean) */
+ int idle_timeout; /* Idle timeout value */
+ int lqr_timeout; /* LQR timeout value */
+ int retry_timeout; /* Retry timeout value */
+ int reconnect_timer; /* Timeout before reconnect on carrier loss */
+ int reconnect_tries; /* Attempt reconnect on carrier loss */
+ int redial_timeout; /* Redial timeout value */
+ int redial_next_timeout; /* Redial next timeout value */
+ int dial_tries; /* Dial attempts before giving up, 0 == inf */
+ int loopback; /* Turn around packets addressed to me */
+ char modem_dev[40]; /* Name of device / host:port */
+ const char *base_modem_dev; /* Pointer to base of modem_dev */
+ int open_mode; /* LCP open mode */
+#define LOCAL_AUTH 0x01
+#define LOCAL_NO_AUTH 0x02
+#define LOCAL_DENY 0x03
+ u_char lauth; /* Local Authorized status */
+ FILE *termfp; /* The terminal */
+#define DIALUP_REQ 0x01
+#define DIALUP_DONE 0x02
+ char dial_script[SCRIPT_LEN]; /* Dial script */
+ char login_script[SCRIPT_LEN]; /* Login script */
+ char auth_key[50]; /* PAP/CHAP key */
+ char auth_name[50]; /* PAP/CHAP system name */
+ char local_auth_key[50]; /* Local auth passwd */
+ int have_local_auth_key; /* Local auth passwd specified ? */
+#ifdef HAVE_DES
+ int use_MSChap; /* Use MSCHAP encryption */
+#endif
+ char phone_numbers[200]; /* Telephone Numbers */
+ char phone_copy[200]; /* copy for strsep() */
+ char *next_phone; /* Next phone from the list */
+ char *alt_phone; /* Next phone from the list */
+ char shostname[MAXHOSTNAMELEN]; /* Local short Host Name */
+ char hangup_script[SCRIPT_LEN]; /* Hangup script before modem is closed */
+ struct aliasHandlers handler; /* Alias function pointers */
+};
+
+#define VarAccmap pppVars.var_accmap
+#define VarMRU pppVars.var_mru
+#define VarPrefMTU pppVars.pref_mtu
+#define VarDevice pppVars.modem_dev
+#define VarBaseDevice pppVars.base_modem_dev
+#define VarSpeed pppVars.modem_speed
+#define VarParity pppVars.modem_parity
+#define VarCtsRts pppVars.modem_ctsrts
+#define VarOpenMode pppVars.open_mode
+#define VarLocalAuth pppVars.lauth
+#define VarDialScript pppVars.dial_script
+#define VarHangupScript pppVars.hangup_script
+#define VarLoginScript pppVars.login_script
+#define VarIdleTimeout pppVars.idle_timeout
+#define VarLqrTimeout pppVars.lqr_timeout
+#define VarRetryTimeout pppVars.retry_timeout
+#define VarAuthKey pppVars.auth_key
+#define VarAuthName pppVars.auth_name
+#define VarLocalAuthKey pppVars.local_auth_key
+#define VarHaveLocalAuthKey pppVars.have_local_auth_key
+#ifdef HAVE_DES
+#define VarMSChap pppVars.use_MSChap
+#endif
+#define VarPhoneList pppVars.phone_numbers
+#define VarPhoneCopy pppVars.phone_copy
+#define VarNextPhone pppVars.next_phone
+#define VarAltPhone pppVars.alt_phone
+#define VarShortHost pppVars.shostname
+#define VarReconnectTimer pppVars.reconnect_timer
+#define VarReconnectTries pppVars.reconnect_tries
+#define VarRedialTimeout pppVars.redial_timeout
+#define VarRedialNextTimeout pppVars.redial_next_timeout
+#define VarDialTries pppVars.dial_tries
+#define VarLoopback pppVars.loopback
+#define VarTerm pppVars.termfp
+
+#define VarAliasHandlers pppVars.handler
+#define VarPacketAliasGetFragment (*pppVars.handler.PacketAliasGetFragment)
+#define VarPacketAliasGetFragment (*pppVars.handler.PacketAliasGetFragment)
+#define VarPacketAliasInit (*pppVars.handler.PacketAliasInit)
+#define VarPacketAliasIn (*pppVars.handler.PacketAliasIn)
+#define VarPacketAliasOut (*pppVars.handler.PacketAliasOut)
+#define VarPacketAliasRedirectAddr (*pppVars.handler.PacketAliasRedirectAddr)
+#define VarPacketAliasRedirectPort (*pppVars.handler.PacketAliasRedirectPort)
+#define VarPacketAliasSaveFragment (*pppVars.handler.PacketAliasSaveFragment)
+#define VarPacketAliasSetAddress (*pppVars.handler.PacketAliasSetAddress)
+#define VarPacketAliasSetMode (*pppVars.handler.PacketAliasSetMode)
+#define VarPacketAliasFragmentIn (*pppVars.handler.PacketAliasFragmentIn)
+
+#define DEV_IS_SYNC (VarSpeed == 0)
+
+extern struct pppvars pppVars;
+extern char VarVersion[];
+extern char VarLocalVersion[];
+
+extern int Utmp; /* Are we in /etc/utmp ? */
+extern int ipInOctets;
+extern int ipOutOctets;
+extern int ipKeepAlive;
+extern int ipConnectSecs;
+extern int ipIdleSecs;
+extern int reconnectState;
+extern int reconnectCount;
+
+#define RECON_TRUE (1)
+#define RECON_FALSE (2)
+#define RECON_UNKNOWN (3)
+#define RECON_ENVOKED (4)
+#define reconnect(x) \
+ do \
+ if (reconnectState == RECON_UNKNOWN) { \
+ reconnectState = x; \
+ if (x == RECON_FALSE) \
+ reconnectCount = 0; \
+ } \
+ while(0)
+
+
+/*
+ * This is the logic behind the reconnect variables:
+ * We have four reconnect "states". We start off not requiring anything
+ * from the reconnect code (reconnectState == RECON_UNKNOWN). If the
+ * line is brought down (via LcpClose() or LcpDown()), we have to decide
+ * whether to set to RECON_TRUE or RECON_FALSE. It's only here that we
+ * know the correct action. Once we've decided, we don't want that
+ * decision to be overridden (hence the above reconnect() macro) - If we
+ * call LcpClose, the ModemTimeout() still gets to "notice" that the line
+ * is down. When it "notice"s, it should only set RECON_TRUE if a decision
+ * hasn't already been made.
+ *
+ * In main.c, when we notice we have RECON_TRUE, we must only action
+ * it once. The fourth "state" is where we're bringing the line up,
+ * but if we call LcpClose for any reason (failed PAP/CHAP etc) we
+ * don't want to set to RECON_{TRUE,FALSE}.
+ *
+ * If we get a connection or give up dialing, we go back to RECON_UNKNOWN.
+ * If we get give up dialing or reconnecting or if we chose to down the
+ * connection, we set reconnectCount back to zero.
+ *
+ */
+
+extern int EnableCommand(struct cmdargs const *);
+extern int DisableCommand(struct cmdargs const *);
+extern int AcceptCommand(struct cmdargs const *);
+extern int DenyCommand(struct cmdargs const *);
+extern int LocalAuthCommand(struct cmdargs const *);
+extern int DisplayCommand(struct cmdargs const *);
diff --git a/usr.sbin/ppp/vjcomp.c b/usr.sbin/ppp/vjcomp.c
new file mode 100644
index 00000000000..cf476040fc6
--- /dev/null
+++ b/usr.sbin/ppp/vjcomp.c
@@ -0,0 +1,155 @@
+/*
+ * Input/Output VJ Compressed packets
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: vjcomp.c,v 1.1 1997/11/23 20:27:37 brian Exp $
+ *
+ * TODO:
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "command.h"
+#include "mbuf.h"
+#include "log.h"
+#include "defs.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lcpproto.h"
+#include "slcompress.h"
+#include "hdlc.h"
+#include "ipcp.h"
+#include "vjcomp.h"
+
+#define MAX_VJHEADER 16 /* Maximum size of compressed header */
+
+struct slcompress cslc;
+
+void
+VjInit(int max_state)
+{
+ sl_compress_init(&cslc, max_state);
+}
+
+void
+SendPppFrame(struct mbuf * bp)
+{
+ int type;
+ int proto;
+ int cproto = IpcpInfo.his_compproto >> 16;
+
+ LogPrintf(LogDEBUG, "SendPppFrame: proto = %x\n", IpcpInfo.his_compproto);
+ if (((struct ip *) MBUF_CTOP(bp))->ip_p == IPPROTO_TCP
+ && cproto == PROTO_VJCOMP) {
+ type = sl_compress_tcp(bp, (struct ip *) MBUF_CTOP(bp), &cslc, IpcpInfo.his_compproto & 0xff);
+
+ LogPrintf(LogDEBUG, "SendPppFrame: type = %x\n", type);
+ switch (type) {
+ case TYPE_IP:
+ proto = PROTO_IP;
+ break;
+ case TYPE_UNCOMPRESSED_TCP:
+ proto = PROTO_VJUNCOMP;
+ break;
+ case TYPE_COMPRESSED_TCP:
+ proto = PROTO_VJCOMP;
+ break;
+ default:
+ LogPrintf(LogERROR, "Unknown frame type %x\n", type);
+ pfree(bp);
+ return;
+ }
+ } else
+ proto = PROTO_IP;
+ HdlcOutput(PRI_NORMAL, proto, bp);
+}
+
+static struct mbuf *
+VjUncompressTcp(struct mbuf * bp, u_char type)
+{
+ u_char *bufp;
+ int len, olen, rlen;
+ struct mbuf *nbp;
+ u_char work[MAX_HDR + MAX_VJHEADER]; /* enough to hold TCP/IP header */
+
+ olen = len = plength(bp);
+ if (type == TYPE_UNCOMPRESSED_TCP) {
+
+ /*
+ * Uncompressed packet does NOT change its size, so that we can use mbuf
+ * space for uncompression job.
+ */
+ bufp = MBUF_CTOP(bp);
+ len = sl_uncompress_tcp(&bufp, len, type, &cslc);
+ if (len <= 0) {
+ pfree(bp);
+ bp = NULLBUFF;
+ }
+ return (bp);
+ }
+
+ /*
+ * Handle compressed packet. 1) Read upto MAX_VJHEADER bytes into work
+ * space. 2) Try to uncompress it. 3) Compute amount of necesary space. 4)
+ * Copy unread data info there.
+ */
+ if (len > MAX_VJHEADER)
+ len = MAX_VJHEADER;
+ rlen = len;
+ bufp = work + MAX_HDR;
+ bp = mbread(bp, bufp, rlen);
+ len = sl_uncompress_tcp(&bufp, olen, type, &cslc);
+ if (len <= 0) {
+ pfree(bp);
+ return NULLBUFF;
+ }
+ len -= olen;
+ len += rlen;
+ nbp = mballoc(len, MB_VJCOMP);
+ memcpy(MBUF_CTOP(nbp), bufp, len);
+ nbp->next = bp;
+ return (nbp);
+}
+
+struct mbuf *
+VjCompInput(struct mbuf * bp, int proto)
+{
+ u_char type;
+
+ LogPrintf(LogDEBUG, "VjCompInput: proto %02x\n", proto);
+ LogDumpBp(LogDEBUG, "Raw packet info:", bp);
+
+ switch (proto) {
+ case PROTO_VJCOMP:
+ type = TYPE_COMPRESSED_TCP;
+ break;
+ case PROTO_VJUNCOMP:
+ type = TYPE_UNCOMPRESSED_TCP;
+ break;
+ default:
+ LogPrintf(LogERROR, "VjCompInput...???\n");
+ return (bp);
+ }
+ bp = VjUncompressTcp(bp, type);
+ return (bp);
+}
diff --git a/usr.sbin/ppp/vjcomp.h b/usr.sbin/ppp/vjcomp.h
new file mode 100644
index 00000000000..4cc27aaf593
--- /dev/null
+++ b/usr.sbin/ppp/vjcomp.h
@@ -0,0 +1,7 @@
+/*
+ * $Id: vjcomp.h,v 1.1 1997/11/23 20:27:37 brian Exp $
+ */
+
+extern void VjInit(int);
+extern void SendPppFrame(struct mbuf *);
+extern struct mbuf *VjCompInput(struct mbuf *, int);