summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1997-05-19 22:03:09 +0000
committerjoerg <joerg@FreeBSD.org>1997-05-19 22:03:09 +0000
commit27ddec53f718ea168a222ceed081cd1a101b23a1 (patch)
treedfad88c2b1e9c2e4a0cded65e393e30e7e9ceffc /sys
parent13206dfe736ae31106bbaba0db80a492b5b38e67 (diff)
downloadFreeBSD-src-27ddec53f718ea168a222ceed081cd1a101b23a1.zip
FreeBSD-src-27ddec53f718ea168a222ceed081cd1a101b23a1.tar.gz
Major overhaul of the SyncPPP layer. Basically, this comprises now a
full implementation of the sate machine as described in RFC1661, and provides support for plugging in various control protocols. I needed this to provide PPP support for the BISDN project (right now). Unfortunatley, while the existing API was almost up to the point, i needed one minor API change in order to decouple the this-layer- started and this-layer-finished actions from the respective Up and Down events of the lower layer. This requires two additional lines in the attach routines of all existing lower layer interface drivers that are using syncPPP (shortcutting these actions and events). Apart from this, i believe i didn't change the API of all this, so everything should plug in without too many hassles. Please report if i broke something in the existing drivers. For a list of features (including new ones like dial-on-demand), and things still to be done, please refer to the man page i'll commit asap. Encouraged by: Serge Vakulenko <vak@cronyx.ru>
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ar/if_ar.c9
-rw-r--r--sys/dev/ar/if_ar_isa.c9
-rw-r--r--sys/dev/sr/if_sr.c20
-rw-r--r--sys/dev/sr/if_sr_isa.c20
-rw-r--r--sys/i386/isa/if_ar.c9
-rw-r--r--sys/i386/isa/if_cx.c8
-rw-r--r--sys/i386/isa/if_sr.c20
-rw-r--r--sys/net/if_sppp.h80
-rw-r--r--sys/net/if_spppsubr.c2730
9 files changed, 2119 insertions, 786 deletions
diff --git a/sys/dev/ar/if_ar.c b/sys/dev/ar/if_ar.c
index a0fad0f..8e5c384 100644
--- a/sys/dev/ar/if_ar.c
+++ b/sys/dev/ar/if_ar.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: if_ar.c,v 1.14 1997/02/22 09:36:15 peter Exp $
*/
/*
@@ -349,6 +349,13 @@ arattach(struct isa_device *id)
sppp_attach((struct ifnet *)&sc->ifsppp);
if_attach(ifp);
+ /*
+ * Shortcut the sppp tls/tlf actions to up/down events
+ * since our lower layer is always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
+
#if NBPFILTER > 0
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
#endif
diff --git a/sys/dev/ar/if_ar_isa.c b/sys/dev/ar/if_ar_isa.c
index a0fad0f..8e5c384 100644
--- a/sys/dev/ar/if_ar_isa.c
+++ b/sys/dev/ar/if_ar_isa.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: if_ar.c,v 1.14 1997/02/22 09:36:15 peter Exp $
*/
/*
@@ -349,6 +349,13 @@ arattach(struct isa_device *id)
sppp_attach((struct ifnet *)&sc->ifsppp);
if_attach(ifp);
+ /*
+ * Shortcut the sppp tls/tlf actions to up/down events
+ * since our lower layer is always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
+
#if NBPFILTER > 0
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
#endif
diff --git a/sys/dev/sr/if_sr.c b/sys/dev/sr/if_sr.c
index 21c0f48..a9abd8f 100644
--- a/sys/dev/sr/if_sr.c
+++ b/sys/dev/sr/if_sr.c
@@ -27,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: if_sr.c,v 1.6 1997/02/22 09:36:35 peter Exp $
*/
/*
@@ -1304,6 +1304,14 @@ srioctl(struct ifnet *ifp, int cmd, caddr_t data)
default:
sc->ifsppp.pp_flags = PP_KEEPALIVE;
sppp_attach(&sc->ifsppp.pp_if);
+
+ /*
+ * Shortcut the sppp tls/tlf actions to
+ * up/down events since our lower layer is
+ * always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
}
sc->attached = sc->protocol;
@@ -1487,7 +1495,15 @@ sr_up(struct sr_softc *sc)
default:
sc->ifsppp.pp_flags = PP_KEEPALIVE;
sppp_attach(&sc->ifsppp.pp_if);
- }
+
+ /*
+ * Shortcut the sppp tls/tlf actions to
+ * up/down events since our lower layer is
+ * always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
+ }
sc->attached = sc->protocol;
}
diff --git a/sys/dev/sr/if_sr_isa.c b/sys/dev/sr/if_sr_isa.c
index 21c0f48..a9abd8f 100644
--- a/sys/dev/sr/if_sr_isa.c
+++ b/sys/dev/sr/if_sr_isa.c
@@ -27,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: if_sr.c,v 1.6 1997/02/22 09:36:35 peter Exp $
*/
/*
@@ -1304,6 +1304,14 @@ srioctl(struct ifnet *ifp, int cmd, caddr_t data)
default:
sc->ifsppp.pp_flags = PP_KEEPALIVE;
sppp_attach(&sc->ifsppp.pp_if);
+
+ /*
+ * Shortcut the sppp tls/tlf actions to
+ * up/down events since our lower layer is
+ * always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
}
sc->attached = sc->protocol;
@@ -1487,7 +1495,15 @@ sr_up(struct sr_softc *sc)
default:
sc->ifsppp.pp_flags = PP_KEEPALIVE;
sppp_attach(&sc->ifsppp.pp_if);
- }
+
+ /*
+ * Shortcut the sppp tls/tlf actions to
+ * up/down events since our lower layer is
+ * always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
+ }
sc->attached = sc->protocol;
}
diff --git a/sys/i386/isa/if_ar.c b/sys/i386/isa/if_ar.c
index a0fad0f..8e5c384 100644
--- a/sys/i386/isa/if_ar.c
+++ b/sys/i386/isa/if_ar.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: if_ar.c,v 1.14 1997/02/22 09:36:15 peter Exp $
*/
/*
@@ -349,6 +349,13 @@ arattach(struct isa_device *id)
sppp_attach((struct ifnet *)&sc->ifsppp);
if_attach(ifp);
+ /*
+ * Shortcut the sppp tls/tlf actions to up/down events
+ * since our lower layer is always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
+
#if NBPFILTER > 0
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
#endif
diff --git a/sys/i386/isa/if_cx.c b/sys/i386/isa/if_cx.c
index d57480b..c7dd4e4 100644
--- a/sys/i386/isa/if_cx.c
+++ b/sys/i386/isa/if_cx.c
@@ -224,6 +224,7 @@ cxattach (struct isa_device *id)
int drq = id->id_drq;
cx_board_t *b = cxboard + unit;
int i;
+ struct sppp *sp;
/* Initialize the board structure. */
cx_init (b, unit, iobase, ffs(irq)-1, drq);
@@ -276,6 +277,13 @@ cxattach (struct isa_device *id)
/* Init routine is never called by upper level? */
sppp_attach (c->ifp);
if_attach (c->ifp);
+ /*
+ * Shortcut the sppp tls/tlf actions to up/down
+ * events since our lower layer is always ready.
+ */
+ sp = (struct sppp*) c->ifp;
+ sp->pp_tls = sp->pp_up;
+ sp->pp_tlf = sp->pp_down;
#if NBPFILTER > 0
/* If BPF is in the kernel, call the attach for it. */
bpfattach (c->ifp, DLT_PPP, PPP_HEADER_LEN);
diff --git a/sys/i386/isa/if_sr.c b/sys/i386/isa/if_sr.c
index 21c0f48..a9abd8f 100644
--- a/sys/i386/isa/if_sr.c
+++ b/sys/i386/isa/if_sr.c
@@ -27,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: if_sr.c,v 1.6 1997/02/22 09:36:35 peter Exp $
*/
/*
@@ -1304,6 +1304,14 @@ srioctl(struct ifnet *ifp, int cmd, caddr_t data)
default:
sc->ifsppp.pp_flags = PP_KEEPALIVE;
sppp_attach(&sc->ifsppp.pp_if);
+
+ /*
+ * Shortcut the sppp tls/tlf actions to
+ * up/down events since our lower layer is
+ * always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
}
sc->attached = sc->protocol;
@@ -1487,7 +1495,15 @@ sr_up(struct sr_softc *sc)
default:
sc->ifsppp.pp_flags = PP_KEEPALIVE;
sppp_attach(&sc->ifsppp.pp_if);
- }
+
+ /*
+ * Shortcut the sppp tls/tlf actions to
+ * up/down events since our lower layer is
+ * always ready.
+ */
+ sc->ifsppp.pp_tls = sc->ifsppp.pp_up;
+ sc->ifsppp.pp_tlf = sc->ifsppp.pp_down;
+ }
sc->attached = sc->protocol;
}
diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h
index 378fdd3..d40b591 100644
--- a/sys/net/if_sppp.h
+++ b/sys/net/if_sppp.h
@@ -2,7 +2,10 @@
* Defines for synchronous PPP/Cisco link level subroutines.
*
* Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ * Author: Serge Vakulenko, <vak@cronyx.ru>
+ *
+ * Heavily revamped to conform to RFC 1661.
+ * Copyright (C) 1997, Joerg Wunsch.
*
* This software is distributed with NO WARRANTIES, not even the implied
* warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -11,25 +14,53 @@
* or modify this software as long as this message is kept with the software,
* all derivative works or modified versions.
*
- * Version 1.7, Wed Jun 7 22:12:02 MSD 1995
+ * From: Version 1.7, Wed Jun 7 22:12:02 MSD 1995
+ *
+ * $Id$
*/
#ifndef _NET_IF_HDLC_H_
#define _NET_IF_HDLC_H_ 1
+#define IDX_LCP 0 /* idx into state table */
+
struct slcp {
- u_short state; /* state machine */
+ u_long opts; /* LCP options to send (bitfield) */
u_long magic; /* local magic number */
+ u_long mru; /* our max receive unit */
+ u_long their_mru; /* their max receive unit */
+ u_long protos; /* bitmask of protos that are started */
u_char echoid; /* id of last keepalive echo request */
- u_char confid; /* id of last configuration request */
+ /* restart max values, see RFC 1661 */
+ int timeout;
+ int max_terminate;
+ int max_configure;
+ int max_failure;
};
+#define IDX_IPCP 1 /* idx into state table */
+
struct sipcp {
- u_short state; /* state machine */
- u_char confid; /* id of last configuration request */
+ u_long opts; /* IPCP options to send (bitfield) */
+ u_int flags;
+#define IPCP_HISADDR_SEEN 1 /* have seen his address already */
+#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */
+};
+
+#define IDX_COUNT (IDX_IPCP + 1) /* bump this when adding cp's! */
+
+/*
+ * Don't change the order of this. Ordering the phases this way allows
+ * for a comparision of ``pp_phase >= PHASE_AUTHENTICATE'' in order to
+ * know whether LCP is up.
+ */
+enum ppp_phase {
+ PHASE_DEAD, PHASE_ESTABLISH, PHASE_TERMINATE,
+ PHASE_AUTHENTICATE, PHASE_NETWORK
};
struct sppp {
+ /* NB: pp_if _must_ be first */
struct ifnet pp_if; /* network interface data */
struct ifqueue pp_fastq; /* fast output queue */
struct sppp *pp_next; /* next interface in keepalive list */
@@ -38,25 +69,38 @@ struct sppp {
u_short pp_loopcnt; /* loopback detection counter */
u_long pp_seq; /* local sequence number */
u_long pp_rseq; /* remote sequence number */
+ enum ppp_phase pp_phase; /* phase we're currently in */
+ int state[IDX_COUNT]; /* state machine */
+ u_char confid[IDX_COUNT]; /* id of last configuration request */
+ int rst_counter[IDX_COUNT]; /* restart counter */
+ int fail_counter[IDX_COUNT]; /* negotiation failure counter */
struct slcp lcp; /* LCP params */
struct sipcp ipcp; /* IPCP params */
+ /*
+ * These functions are filled in by sppp_attach(), and are
+ * expected to be used by the lower layer (hardware) drivers
+ * in order to communicate the (un)availability of the
+ * communication link. Lower layer drivers that are always
+ * ready to communicate (like hardware HDLC) can shortcut
+ * pp_up from pp_tls, and pp_down from pp_tlf.
+ */
+ void (*pp_up)(struct sppp *sp);
+ void (*pp_down)(struct sppp *sp);
+ /*
+ * These functions need to be filled in by the lower layer
+ * (hardware) drivers if they request notification from the
+ * PPP layer whether the link is actually required. They
+ * correspond to the tls and tlf actions.
+ */
+ void (*pp_tls)(struct sppp *sp);
+ void (*pp_tlf)(struct sppp *sp);
};
#define PP_KEEPALIVE 0x01 /* use keepalive protocol */
#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */
-#define PP_TIMO 0x04 /* cp_timeout routine active */
-
-#define PP_MTU 1500 /* max. transmit unit */
-
-#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */
-#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */
-#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */
-#define LCP_STATE_OPENED 3 /* LCP state: opened */
-#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */
-#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */
-#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */
-#define IPCP_STATE_OPENED 3 /* IPCP state: opened */
+#define PP_MTU 1500 /* default/minimal MRU */
+#define PP_MAX_MRU 2048 /* maximal MRU we want to negotiate */
#ifdef KERNEL
void sppp_attach (struct ifnet *ifp);
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index bc40e32..5b10f3a 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -3,7 +3,10 @@
* Keepalive protocol implemented in both Cisco and PPP modes.
*
* Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ * Author: Serge Vakulenko, <vak@cronyx.ru>
+ *
+ * Heavily revamped to conform to RFC 1661.
+ * Copyright (C) 1997, Joerg Wunsch.
*
* This software is distributed with NO WARRANTIES, not even the implied
* warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -12,9 +15,9 @@
* or modify this software as long as this message is kept with the software,
* all derivative works or modified versions.
*
- * Version 1.9, Wed Oct 4 18:58:15 MSK 1995
+ * From: Version 1.9, Wed Oct 4 18:58:15 MSK 1995
*
- * $Id: if_spppsubr.c,v 1.17 1997/03/24 11:33:16 bde Exp $
+ * $Id: if_spppsubr.c,v 1.18 1997/05/11 10:04:24 joerg Exp $
*/
#include <sys/param.h>
@@ -59,6 +62,21 @@
#define MAXALIVECNT 3 /* max. alive packets */
+/*
+ * Interface flags that can be set in an ifconfig command.
+ *
+ * Setting link0 will cause the link to auto-dial only as packets
+ * arrive to be sent.
+ *
+ * Setting link1 will make the link passive, i.e. it will be marked
+ * as being administrative openable, but won't be opened to begin
+ * with. Incoming calls will be answered, or subsequent calls with
+ * -link1 will cause the administrative open of the LCP layer.
+ */
+
+#define IFF_AUTO IFF_LINK0 /* auto-dial on output */
+#define IFF_PASSIVE IFF_LINK1 /* wait passively for connection */
+
#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
#define PPP_UI 0x03 /* Unnumbered Information */
#define PPP_IP 0x0021 /* Internet Protocol */
@@ -68,17 +86,17 @@
#define PPP_LCP 0xc021 /* Link Control Protocol */
#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */
-#define LCP_CONF_REQ 1 /* PPP LCP configure request */
-#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */
-#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */
-#define LCP_CONF_REJ 4 /* PPP LCP configure reject */
-#define LCP_TERM_REQ 5 /* PPP LCP terminate request */
-#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */
-#define LCP_CODE_REJ 7 /* PPP LCP code reject */
-#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */
-#define LCP_ECHO_REQ 9 /* PPP LCP echo request */
-#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */
-#define LCP_DISC_REQ 11 /* PPP LCP discard request */
+#define CONF_REQ 1 /* PPP configure request */
+#define CONF_ACK 2 /* PPP configure acknowledge */
+#define CONF_NAK 3 /* PPP configure negative ack */
+#define CONF_REJ 4 /* PPP configure reject */
+#define TERM_REQ 5 /* PPP terminate request */
+#define TERM_ACK 6 /* PPP terminate acknowledge */
+#define CODE_REJ 7 /* PPP code reject */
+#define PROTO_REJ 8 /* PPP protocol reject */
+#define ECHO_REQ 9 /* PPP echo request */
+#define ECHO_REPLY 10 /* PPP echo reply */
+#define DISC_REQ 11 /* PPP discard request */
#define LCP_OPT_MRU 1 /* maximum receive unit */
#define LCP_OPT_ASYNC_MAP 2 /* async control character map */
@@ -89,13 +107,9 @@
#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */
#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */
-#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */
-#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */
-#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */
-#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */
-#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */
-#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */
-#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */
+#define IPCP_OPT_ADDRESSES 1 /* both IP addresses; deprecated */
+#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */
+#define IPCP_OPT_ADDRESS 3 /* local IP address */
#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
#define CISCO_UNICAST 0x0f /* Cisco unicast address */
@@ -104,6 +118,18 @@
#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+/* states are named and numbered according to RFC 1661 */
+#define STATE_INITIAL 0
+#define STATE_STARTING 1
+#define STATE_CLOSED 2
+#define STATE_STOPPED 3
+#define STATE_CLOSING 4
+#define STATE_STOPPING 5
+#define STATE_REQ_SENT 6
+#define STATE_ACK_RCVD 7
+#define STATE_ACK_SENT 8
+#define STATE_OPENED 9
+
struct ppp_header {
u_char address;
u_char control;
@@ -128,6 +154,38 @@ struct cisco_packet {
};
#define CISCO_PACKET_LEN 18
+/*
+ * We follow the spelling and capitalization of RFC 1661 here, to make
+ * it easier comparing with the standard. Please refer to this RFC in
+ * case you can't make sense out of these abbreviation; it will also
+ * explain the semantics related to the various events and actions.
+ */
+struct cp {
+ u_short proto; /* PPP control protocol number */
+ u_char protoidx; /* index into state table in struct sppp */
+ u_char flags;
+#define CP_LCP 0x01 /* this is the LCP */
+#define CP_AUTH 0x02 /* this is an authentication protocol */
+#define CP_NCP 0x04 /* this is a NCP */
+#define CP_QUAL 0x08 /* this is a quality reporting protocol */
+ const char *name; /* name of this control protocol */
+ /* event handlers */
+ void (*Up)(struct sppp *sp);
+ void (*Down)(struct sppp *sp);
+ void (*Open)(struct sppp *sp);
+ void (*Close)(struct sppp *sp);
+ void (*TO)(void *sp);
+ int (*RCR)(struct sppp *sp, struct lcp_header *h, int len);
+ void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len);
+ void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len);
+ /* actions */
+ void (*tlu)(struct sppp *sp);
+ void (*tld)(struct sppp *sp);
+ void (*tls)(struct sppp *sp);
+ void (*tlf)(struct sppp *sp);
+ void (*scr)(struct sppp *sp);
+};
+
static struct sppp *spppq;
/*
@@ -142,51 +200,103 @@ static u_short interactive_ports[8] = {
};
#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
-/*
- * Timeout routine activation macros.
- */
-#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \
- timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \
- (p)->pp_flags |= PP_TIMO; }
-#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \
- untimeout (sppp_cp_timeout, (void*) (p)); \
- (p)->pp_flags &= ~PP_TIMO; }
-
-static void sppp_keepalive (void *dummy);
-static void sppp_cp_send (struct sppp *sp, u_short proto, u_char type,
- u_char ident, u_short len, void *data);
-static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
-static void sppp_lcp_input (struct sppp *sp, struct mbuf *m);
-static void sppp_cisco_input (struct sppp *sp, struct mbuf *m);
-static void sppp_ipcp_input (struct sppp *sp, struct mbuf *m);
-static void sppp_lcp_open (struct sppp *sp);
-static void sppp_ipcp_open (struct sppp *sp);
-static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
- int len, u_long *magic);
-static void sppp_cp_timeout (void *arg);
-static const char *sppp_lcp_type_name (u_char type);
-static const char *sppp_ipcp_type_name (u_char type);
-static void sppp_print_bytes (u_char *p, u_short len);
-static int sppp_output (struct ifnet *ifp, struct mbuf *m,
- struct sockaddr *dst, struct rtentry *rt);
+/* almost every function needs these */
+#define STDDCL \
+ struct ifnet *ifp = &sp->pp_if; \
+ int debug = ifp->if_flags & IFF_DEBUG
+
+static int sppp_output(struct ifnet *ifp, struct mbuf *m,
+ struct sockaddr *dst, struct rtentry *rt);
+
+static void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2);
+static void sppp_cisco_input(struct sppp *sp, struct mbuf *m);
+
+static void sppp_cp_input(const struct cp *cp, struct sppp *sp,
+ struct mbuf *m);
+static void sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
+ u_char ident, u_short len, void *data);
+static void sppp_cp_timeout(void *arg);
+static void sppp_cp_change_state(const struct cp *cp, struct sppp *sp,
+ int newstate);
+
+static void sppp_up_event(const struct cp *cp, struct sppp *sp);
+static void sppp_down_event(const struct cp *cp, struct sppp *sp);
+static void sppp_open_event(const struct cp *cp, struct sppp *sp);
+static void sppp_close_event(const struct cp *cp, struct sppp *sp);
+static void sppp_to_event(const struct cp *cp, struct sppp *sp);
+
+static void sppp_lcp_init(struct sppp *sp);
+static void sppp_lcp_up(struct sppp *sp);
+static void sppp_lcp_down(struct sppp *sp);
+static void sppp_lcp_open(struct sppp *sp);
+static void sppp_lcp_close(struct sppp *sp);
+static void sppp_lcp_TO(void *sp);
+static int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_lcp_tlu(struct sppp *sp);
+static void sppp_lcp_tld(struct sppp *sp);
+static void sppp_lcp_tls(struct sppp *sp);
+static void sppp_lcp_tlf(struct sppp *sp);
+static void sppp_lcp_scr(struct sppp *sp);
+static void sppp_lcp_check(struct sppp *sp);
+
+static void sppp_ipcp_init(struct sppp *sp);
+static void sppp_ipcp_up(struct sppp *sp);
+static void sppp_ipcp_down(struct sppp *sp);
+static void sppp_ipcp_open(struct sppp *sp);
+static void sppp_ipcp_close(struct sppp *sp);
+static void sppp_ipcp_TO(void *sp);
+static int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipcp_tlu(struct sppp *sp);
+static void sppp_ipcp_tld(struct sppp *sp);
+static void sppp_ipcp_tls(struct sppp *sp);
+static void sppp_ipcp_tlf(struct sppp *sp);
+static void sppp_ipcp_scr(struct sppp *sp);
+
+static const char *sppp_cp_type_name(u_char type);
+static const char *sppp_lcp_opt_name(u_char opt);
+static const char *sppp_ipcp_opt_name(u_char opt);
+static const char *sppp_state_name(int state);
+static const char *sppp_phase_name(enum ppp_phase phase);
+static const char *sppp_proto_name(u_short proto);
+
+static void sppp_keepalive(void *dummy);
+static void sppp_qflush(struct ifqueue *ifq);
+
+static void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst);
+static void sppp_set_ip_addr(struct sppp *sp, u_long src);
+
+static void sppp_print_bytes(u_char *p, u_short len);
+
+/* our control protocol descriptors */
+const struct cp lcp = {
+ PPP_LCP, IDX_LCP, CP_LCP, "lcp",
+ sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close,
+ sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak,
+ sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf,
+ sppp_lcp_scr
+};
-/*
- * Flush interface queue.
- */
-static void
-qflush(struct ifqueue *ifq)
-{
- struct mbuf *m, *n;
+const struct cp ipcp = {
+ PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp",
+ sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close,
+ sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak,
+ sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf,
+ sppp_ipcp_scr
+};
- n = ifq->ifq_head;
- while ((m = n)) {
- n = m->m_act;
- m_freem (m);
- }
- ifq->ifq_head = 0;
- ifq->ifq_tail = 0;
- ifq->ifq_len = 0;
-}
+const struct cp *cps[IDX_COUNT] = {
+ &lcp, /* IDX_LCP */
+ &ipcp, /* IDX_IPCP */
+};
+
+
+ /*
+ * Exported functions, comprising our interface to the lower layer.
+ */
/*
* Process the received packet.
@@ -195,9 +305,10 @@ void
sppp_input(struct ifnet *ifp, struct mbuf *m)
{
struct ppp_header *h;
- struct sppp *sp = (struct sppp*) ifp;
struct ifqueue *inq = 0;
int s;
+ struct sppp *sp = (struct sppp *)ifp;
+ int debug = ifp->if_flags & IFF_DEBUG;
if (ifp->if_flags & IFF_UP)
/* Count received bytes, add FCS and one flag */
@@ -205,11 +316,13 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
/* Too small packet, drop it. */
- if (ifp->if_flags & IFF_DEBUG)
+ if (debug)
log(LOG_DEBUG,
"%s%d: input packet is too small, %d bytes\n",
ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
-drop: ++ifp->if_iqdrops;
+ drop:
+ ++ifp->if_ierrors;
+ ++ifp->if_iqdrops;
m_freem (m);
return;
}
@@ -219,19 +332,11 @@ drop: ++ifp->if_iqdrops;
m_adj (m, PPP_HEADER_LEN);
switch (h->address) {
- default: /* Invalid PPP packet. */
-invalid: if (ifp->if_flags & IFF_DEBUG)
- log(LOG_DEBUG,
- "%s%d: invalid input packet "
- "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
- ifp->if_name, ifp->if_unit,
- h->address, h->control, ntohs(h->protocol));
- goto drop;
case PPP_ALLSTATIONS:
if (h->control != PPP_UI)
goto invalid;
if (sp->pp_flags & PP_CISCO) {
- if (ifp->if_flags & IFF_DEBUG)
+ if (debug)
log(LOG_DEBUG,
"%s%d: PPP packet in Cisco mode "
"<addr=0x%x ctrl=0x%x proto=0x%x>\n",
@@ -241,11 +346,11 @@ invalid: if (ifp->if_flags & IFF_DEBUG)
}
switch (ntohs (h->protocol)) {
default:
- if (sp->lcp.state == LCP_STATE_OPENED)
- sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
+ if (sp->state[IDX_LCP] == STATE_OPENED)
+ sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
++sp->pp_seq, m->m_pkthdr.len + 2,
&h->protocol);
- if (ifp->if_flags & IFF_DEBUG)
+ if (debug)
log(LOG_DEBUG,
"%s%d: invalid input protocol "
"<addr=0x%x ctrl=0x%x proto=0x%x>\n",
@@ -254,17 +359,17 @@ invalid: if (ifp->if_flags & IFF_DEBUG)
++ifp->if_noproto;
goto drop;
case PPP_LCP:
- sppp_lcp_input ((struct sppp*) ifp, m);
+ sppp_cp_input(&lcp, (struct sppp*)ifp, m);
m_freem (m);
return;
#ifdef INET
case PPP_IPCP:
- if (sp->lcp.state == LCP_STATE_OPENED)
- sppp_ipcp_input ((struct sppp*) ifp, m);
+ if (sp->pp_phase == PHASE_NETWORK)
+ sppp_cp_input(&ipcp, (struct sppp*) ifp, m);
m_freem (m);
return;
case PPP_IP:
- if (sp->ipcp.state == IPCP_STATE_OPENED) {
+ if (sp->state[IDX_IPCP] == STATE_OPENED) {
schednetisr (NETISR_IP);
inq = &ipintrq;
}
@@ -273,7 +378,7 @@ invalid: if (ifp->if_flags & IFF_DEBUG)
#ifdef IPX
case PPP_IPX:
/* IPX IPXCP not implemented yet */
- if (sp->lcp.state == LCP_STATE_OPENED) {
+ if (sp->pp_phase == PHASE_NETWORK) {
schednetisr (NETISR_IPX);
inq = &ipxintrq;
}
@@ -282,7 +387,7 @@ invalid: if (ifp->if_flags & IFF_DEBUG)
#ifdef NS
case PPP_XNS:
/* XNS IDPCP not implemented yet */
- if (sp->lcp.state == LCP_STATE_OPENED) {
+ if (sp->pp_phase == PHASE_NETWORK) {
schednetisr (NETISR_NS);
inq = &nsintrq;
}
@@ -291,7 +396,7 @@ invalid: if (ifp->if_flags & IFF_DEBUG)
#ifdef ISO
case PPP_ISO:
/* OSI NLCP not implemented yet */
- if (sp->lcp.state == LCP_STATE_OPENED) {
+ if (sp->pp_phase == PHASE_NETWORK) {
schednetisr (NETISR_ISO);
inq = &clnlintrq;
}
@@ -303,7 +408,7 @@ invalid: if (ifp->if_flags & IFF_DEBUG)
case CISCO_UNICAST:
/* Don't check the control field here (RFC 1547). */
if (! (sp->pp_flags & PP_CISCO)) {
- if (ifp->if_flags & IFF_DEBUG)
+ if (debug)
log(LOG_DEBUG,
"%s%d: Cisco packet in PPP mode "
"<addr=0x%x ctrl=0x%x proto=0x%x>\n",
@@ -339,24 +444,33 @@ invalid: if (ifp->if_flags & IFF_DEBUG)
#endif
}
break;
+ default: /* Invalid PPP packet. */
+ invalid:
+ if (debug)
+ log(LOG_DEBUG,
+ "%s%d: invalid input packet "
+ "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
+ ifp->if_name, ifp->if_unit,
+ h->address, h->control, ntohs(h->protocol));
+ goto drop;
}
if (! (ifp->if_flags & IFF_UP) || ! inq)
goto drop;
/* Check queue. */
- s = splimp ();
+ s = splimp();
if (IF_QFULL (inq)) {
/* Queue overflow. */
- IF_DROP (inq);
- splx (s);
- if (ifp->if_flags & IFF_DEBUG)
+ IF_DROP(inq);
+ splx(s);
+ if (debug)
log(LOG_DEBUG, "%s%d: protocol queue overflow\n",
ifp->if_name, ifp->if_unit);
goto drop;
}
- IF_ENQUEUE (inq, m);
- splx (s);
+ IF_ENQUEUE(inq, m);
+ splx(s);
}
/*
@@ -369,14 +483,28 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
struct sppp *sp = (struct sppp*) ifp;
struct ppp_header *h;
struct ifqueue *ifq;
- int s = splimp ();
+ int s;
+
+ s = splimp();
- if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) {
+ if ((ifp->if_flags & IFF_UP) == 0 ||
+ (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) {
m_freem (m);
splx (s);
return (ENETDOWN);
}
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) {
+ /*
+ * Interface is not yet running, but auto-dial. Need
+ * to start LCP for it.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ splx(s);
+ lcp.Open(sp);
+ s = splimp();
+ }
+
ifq = &ifp->if_snd;
#ifdef INET
/*
@@ -405,6 +533,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
if (ifp->if_flags & IFF_DEBUG)
log(LOG_DEBUG, "%s%d: no memory for transmit header\n",
ifp->if_name, ifp->if_unit);
+ ++ifp->if_oerrors;
splx (s);
return (ENOBUFS);
}
@@ -422,10 +551,11 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
case AF_INET: /* Internet Protocol */
if (sp->pp_flags & PP_CISCO)
h->protocol = htons (ETHERTYPE_IP);
- else if (sp->ipcp.state == IPCP_STATE_OPENED)
+ else if (sp->state[IDX_IPCP] == STATE_OPENED)
h->protocol = htons (PPP_IP);
else {
m_freem (m);
+ ++ifp->if_oerrors;
splx (s);
return (ENETDOWN);
}
@@ -453,6 +583,7 @@ nosupport:
#endif
default:
m_freem (m);
+ ++ifp->if_oerrors;
splx (s);
return (EAFNOSUPPORT);
}
@@ -464,6 +595,7 @@ nosupport:
if (IF_QFULL (ifq)) {
IF_DROP (&ifp->if_snd);
m_freem (m);
+ ++ifp->if_oerrors;
splx (s);
return (ENOBUFS);
}
@@ -501,15 +633,19 @@ sppp_attach(struct ifnet *ifp)
sp->pp_alivecnt = 0;
sp->pp_seq = 0;
sp->pp_rseq = 0;
- sp->lcp.magic = 0;
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
+ sp->pp_phase = PHASE_DEAD;
+ sp->pp_up = lcp.Up;
+ sp->pp_down = lcp.Down;
+
+ sppp_lcp_init(sp);
+ sppp_ipcp_init(sp);
}
void
sppp_detach(struct ifnet *ifp)
{
struct sppp **q, *p, *sp = (struct sppp*) ifp;
+ int i;
/* Remove the entry from the keepalive list. */
for (q = &spppq; (p = *q); q = &p->pp_next)
@@ -521,7 +657,9 @@ sppp_detach(struct ifnet *ifp)
/* Stop keepalive handler. */
if (! spppq)
untimeout (sppp_keepalive, 0);
- UNTIMO (sp);
+
+ for (i = 0; i < IDX_COUNT; i++)
+ untimeout((cps[i])->TO, (void *)sp);
}
/*
@@ -532,8 +670,8 @@ sppp_flush(struct ifnet *ifp)
{
struct sppp *sp = (struct sppp*) ifp;
- qflush (&sp->pp_if.if_snd);
- qflush (&sp->pp_fastq);
+ sppp_qflush (&sp->pp_if.if_snd);
+ sppp_qflush (&sp->pp_fastq);
}
/*
@@ -543,10 +681,11 @@ int
sppp_isempty(struct ifnet *ifp)
{
struct sppp *sp = (struct sppp*) ifp;
- int empty, s = splimp ();
+ int empty, s;
+ s = splimp();
empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head;
- splx (s);
+ splx(s);
return (empty);
}
@@ -558,8 +697,9 @@ sppp_dequeue(struct ifnet *ifp)
{
struct sppp *sp = (struct sppp*) ifp;
struct mbuf *m;
- int s = splimp ();
+ int s;
+ s = splimp();
IF_DEQUEUE (&sp->pp_fastq, m);
if (! m)
IF_DEQUEUE (&sp->pp_if.if_snd, m);
@@ -568,349 +708,102 @@ sppp_dequeue(struct ifnet *ifp)
}
/*
- * Send keepalive packets, every 10 seconds.
+ * Process an ioctl request. Called on low priority level.
*/
-static void
-sppp_keepalive(void *dummy)
+int
+sppp_ioctl(struct ifnet *ifp, int cmd, void *data)
{
- struct sppp *sp;
- int s = splimp ();
-
- for (sp=spppq; sp; sp=sp->pp_next) {
- struct ifnet *ifp = &sp->pp_if;
+ struct ifreq *ifr = (struct ifreq*) data;
+ struct sppp *sp = (struct sppp*) ifp;
+ int s, going_up, going_down, newmode;
- /* Keepalive mode disabled or channel down? */
- if (! (sp->pp_flags & PP_KEEPALIVE) ||
- ! (ifp->if_flags & IFF_RUNNING))
- continue;
+ s = splimp();
+ switch (cmd) {
+ case SIOCAIFADDR:
+ case SIOCSIFDSTADDR:
+ break;
- /* No keepalive in PPP mode if LCP not opened yet. */
- if (! (sp->pp_flags & PP_CISCO) &&
- sp->lcp.state != LCP_STATE_OPENED)
- continue;
+ case SIOCSIFADDR:
+ if_up(ifp);
+ /* fall through... */
- if (sp->pp_alivecnt == MAXALIVECNT) {
- /* No keepalive packets got. Stop the interface. */
- printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
- if_down (ifp);
- qflush (&sp->pp_fastq);
- if (! (sp->pp_flags & PP_CISCO)) {
- /* Shut down the PPP link. */
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- UNTIMO (sp);
- /* Initiate negotiation. */
- sppp_lcp_open (sp);
- }
- }
- if (sp->pp_alivecnt <= MAXALIVECNT)
- ++sp->pp_alivecnt;
- if (sp->pp_flags & PP_CISCO)
- sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
- sp->pp_rseq);
- else if (sp->lcp.state == LCP_STATE_OPENED) {
- long nmagic = htonl (sp->lcp.magic);
- sp->lcp.echoid = ++sp->pp_seq;
- sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
- sp->lcp.echoid, 4, &nmagic);
+ case SIOCSIFFLAGS:
+ going_up = ifp->if_flags & IFF_UP &&
+ (ifp->if_flags & IFF_RUNNING) == 0;
+ going_down = (ifp->if_flags & IFF_UP) == 0 &&
+ ifp->if_flags & IFF_RUNNING;
+ newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE);
+ if (newmode == (IFF_AUTO | IFF_PASSIVE)) {
+ /* sanity */
+ newmode = IFF_PASSIVE;
+ ifp->if_flags &= ~IFF_AUTO;
}
- }
- splx (s);
- timeout (sppp_keepalive, 0, hz * 10);
-}
-/*
- * Handle incoming PPP Link Control Protocol packets.
- */
-static void
-sppp_lcp_input(struct sppp *sp, struct mbuf *m)
-{
- struct lcp_header *h;
- struct ifnet *ifp = &sp->pp_if;
- int len = m->m_pkthdr.len, debug = ifp->if_flags & IFF_DEBUG;
- u_char *p, opt[6];
- u_long rmagic;
+ if (going_up || going_down)
+ lcp.Close(sp);
+ if (going_up && newmode == 0) {
+ /* neither auto-dial nor passive */
+ ifp->if_flags |= IFF_RUNNING;
+ if (!(sp->pp_flags & PP_CISCO))
+ lcp.Open(sp);
+ } else if (going_down)
+ ifp->if_flags &= ~IFF_RUNNING;
- if (len < 4) {
- if (debug)
- log(LOG_DEBUG,
- "%s%d: invalid lcp packet length: %d bytes\n",
- ifp->if_name, ifp->if_unit, len);
- return;
- }
- h = mtod (m, struct lcp_header*);
- if (debug) {
- const char *state = "unknown";
- switch (sp->lcp.state) {
- case LCP_STATE_CLOSED: state = "closed"; break;
- case LCP_STATE_ACK_RCVD: state = "ack-rcvd"; break;
- case LCP_STATE_ACK_SENT: state = "ack-sent"; break;
- case LCP_STATE_OPENED: state = "opened"; break;
- }
- log(LOG_DEBUG,
- "%s%d: lcp input(%s): %d bytes <%s id=0x%x len=0x%x",
- ifp->if_name, ifp->if_unit, state, len,
- sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
- if (len > 4)
- sppp_print_bytes ((u_char*) (h+1), len-4);
- addlog(">\n");
- }
- if (len > ntohs (h->len))
- len = ntohs (h->len);
- switch (h->type) {
- default:
- /* Unknown packet type -- send Code-Reject packet. */
- if (debug)
- addlog("%s%d: sending lcp code rej\n",
- ifp->if_name, ifp->if_unit);
- sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq,
- m->m_pkthdr.len, h);
break;
- case LCP_CONF_REQ:
- if (len < 4) {
- if (debug)
- addlog("%s%d: invalid lcp configure request "
- "packet length: %d bytes\n",
- ifp->if_name, ifp->if_unit, len);
- break;
- }
- rmagic = 0xd00ddeed; /* in case LCP fails */
- if (len > 4 &&
- !sppp_lcp_conf_parse_options (sp, h, len, &rmagic))
- goto badreq;
- if (rmagic == sp->lcp.magic) {
- /* Local and remote magics equal -- loopback? */
- if (sp->pp_loopcnt >= MAXALIVECNT*5) {
- printf ("%s%d: loopback\n",
- ifp->if_name, ifp->if_unit);
- sp->pp_loopcnt = 0;
- if (ifp->if_flags & IFF_UP) {
- if_down (ifp);
- qflush (&sp->pp_fastq);
- }
- } else if (debug) {
- addlog("%s%d: conf req: magic glitch, "
- "sending config nak\n",
- ifp->if_name, ifp->if_unit);
- }
- ++sp->pp_loopcnt;
- /* MUST send Conf-Nack packet. */
- rmagic = ~sp->lcp.magic;
- opt[0] = LCP_OPT_MAGIC;
- opt[1] = sizeof (opt);
- opt[2] = rmagic >> 24;
- opt[3] = rmagic >> 16;
- opt[4] = rmagic >> 8;
- opt[5] = rmagic;
- sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
- h->ident, sizeof (opt), &opt);
- badreq:
- switch (sp->lcp.state) {
- case LCP_STATE_OPENED:
- /* Initiate renegotiation. */
- sppp_lcp_open (sp);
- /* fall through... */
- case LCP_STATE_ACK_SENT:
- /* Go to closed state. */
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- }
- break;
- }
- /* Send Configure-Ack packet. */
- if (debug)
- addlog("%s%d: sending configure ack\n",
- ifp->if_name, ifp->if_unit);
- sp->pp_loopcnt = 0;
- sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
- h->ident, len-4, h+1);
- /* Change the state. */
- switch (sp->lcp.state) {
- case LCP_STATE_CLOSED:
- sp->lcp.state = LCP_STATE_ACK_SENT;
- break;
- case LCP_STATE_ACK_RCVD:
- sp->lcp.state = LCP_STATE_OPENED;
- sppp_ipcp_open (sp);
- break;
- case LCP_STATE_OPENED:
- /* Remote magic changed -- close session. */
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- /* Initiate renegotiation. */
- sppp_lcp_open (sp);
- /* An ACK has already been sent. */
- sp->lcp.state = LCP_STATE_ACK_SENT;
- break;
- }
- break;
- case LCP_CONF_ACK:
- if (h->ident != sp->lcp.confid) {
- if (debug)
- addlog("%s%d: lcp id mismatch 0x%x != 0x%x\n",
- ifp->if_name, ifp->if_unit,
- h->ident, sp->lcp.confid);
- break;
- }
- UNTIMO (sp);
- if (! (ifp->if_flags & IFF_UP) &&
- (ifp->if_flags & IFF_RUNNING)) {
- /* Coming out of loopback mode. */
- ifp->if_flags |= IFF_UP;
- printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
- }
- switch (sp->lcp.state) {
- case LCP_STATE_CLOSED:
- sp->lcp.state = LCP_STATE_ACK_RCVD;
- TIMO (sp, 5);
- break;
- case LCP_STATE_ACK_SENT:
- sp->lcp.state = LCP_STATE_OPENED;
- sppp_ipcp_open (sp);
- break;
- }
- break;
- case LCP_CONF_NAK:
- if (h->ident != sp->lcp.confid) {
- if (debug)
- addlog("%s%d: lcp id mismatch 0x%x != 0x%x\n",
- ifp->if_name, ifp->if_unit,
- h->ident, sp->lcp.confid);
- break;
- }
- p = (u_char*) (h+1);
- if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
- rmagic = (u_long)p[2] << 24 |
- (u_long)p[3] << 16 | p[4] << 8 | p[5];
- if (rmagic == ~sp->lcp.magic) {
- if (debug)
- addlog("%s%d: conf nak: magic glitch\n",
- ifp->if_name, ifp->if_unit);
- sp->lcp.magic += time.tv_sec + time.tv_usec;
- } else
- sp->lcp.magic = rmagic;
- }
- if (sp->lcp.state != LCP_STATE_ACK_SENT) {
- /* Go to closed state. */
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- }
- /* The link will be renegotiated after timeout,
- * to avoid endless req-nack loop. */
- if (debug)
- addlog("%s%d: sleeping due to nak\n",
- ifp->if_name, ifp->if_unit);
- UNTIMO (sp);
- TIMO (sp, 2);
+#ifdef SIOCSIFMTU
+#ifndef ifr_mtu
+#define ifr_mtu ifr_metric
+#endif
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru)
+ return (EINVAL);
+ ifp->if_mtu = ifr->ifr_mtu;
break;
- case LCP_CONF_REJ:
- if (h->ident != sp->lcp.confid) {
- if (debug)
- addlog("%s%d: lcp id mismatch 0x%x != 0x%x\n",
- ifp->if_name, ifp->if_unit,
- h->ident, sp->lcp.confid);
- break;
- }
- UNTIMO (sp);
- /* Initiate renegotiation. */
- if (debug)
- addlog("%s%d: reopening lcp\n",
- ifp->if_name, ifp->if_unit);
- sppp_lcp_open (sp);
- if (sp->lcp.state != LCP_STATE_ACK_SENT) {
- /* Go to closed state. */
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- }
+#endif
+#ifdef SLIOCSETMTU
+ case SLIOCSETMTU:
+ if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru)
+ return (EINVAL);
+ ifp->if_mtu = *(short*)data;
break;
- case LCP_TERM_REQ:
- UNTIMO (sp);
- /* Send Terminate-Ack packet. */
- if (debug)
- addlog("%s%d: sending terminate-ack\n",
- ifp->if_name, ifp->if_unit);
- sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0);
- /* Go to closed state. */
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- /* Initiate renegotiation. */
- sppp_lcp_open (sp);
+#endif
+#ifdef SIOCGIFMTU
+ case SIOCGIFMTU:
+ ifr->ifr_mtu = ifp->if_mtu;
break;
- case LCP_TERM_ACK:
- case LCP_CODE_REJ:
- case LCP_PROTO_REJ:
- if (debug)
- addlog("%s%d: ignoring lcp code 0x%x\n",
- ifp->if_name, ifp->if_unit, h->type);
- /* Ignore for now. */
+#endif
+#ifdef SLIOCGETMTU
+ case SLIOCGETMTU:
+ *(short*)data = ifp->if_mtu;
break;
- case LCP_DISC_REQ:
- /* Discard the packet. */
+#endif
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
break;
- case LCP_ECHO_REQ:
- if (sp->lcp.state != LCP_STATE_OPENED) {
- if (debug)
- addlog("%s%d: lcp echo req but lcp close\n",
- ifp->if_name, ifp->if_unit);
- break;
- }
- if (len < 8) {
- if (debug)
- addlog("%s%d: invalid lcp echo request "
- "packet length: %d bytes\n",
- ifp->if_name, ifp->if_unit, len);
- break;
- }
- if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
- /* Line loopback mode detected. */
- printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
- if_down (ifp);
- qflush (&sp->pp_fastq);
- /* Shut down the PPP link. */
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- UNTIMO (sp);
- /* Initiate negotiation. */
- sppp_lcp_open (sp);
- break;
- }
- *(long*)(h+1) = htonl (sp->lcp.magic);
- if (debug)
- addlog("%s%d: got lcp echo req, sending echo rep\n",
- ifp->if_name, ifp->if_unit);
- sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
- break;
- case LCP_ECHO_REPLY:
- if (h->ident != sp->lcp.echoid)
- break;
- if (len < 8) {
- if (debug)
- addlog("%s%d: invalid lcp echo reply "
- "packet length: %d bytes\n",
- ifp->if_name, ifp->if_unit, len);
- break;
- }
- if (debug)
- addlog("%s%d: got lcp echo rep\n",
- ifp->if_name, ifp->if_unit);
- if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
- sp->pp_alivecnt = 0;
- break;
+ default:
+ splx(s);
+ return (ENOTTY);
}
+ splx(s);
+ return (0);
}
+
+ /*
+ * Cisco framing implementation.
+ */
+
/*
* Handle incoming Cisco keepalive protocol packets.
*/
static void
sppp_cisco_input(struct sppp *sp, struct mbuf *m)
{
+ STDDCL;
struct cisco_packet *h;
struct ifaddr *ifa;
- struct ifnet *ifp = &sp->pp_if;
- int debug = ifp->if_flags & IFF_DEBUG;
if (m->m_pkthdr.len != CISCO_PACKET_LEN) {
if (debug)
@@ -948,7 +841,7 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m)
sp->pp_loopcnt = 0;
if (ifp->if_flags & IFF_UP) {
if_down (ifp);
- qflush (&sp->pp_fastq);
+ sppp_qflush (&sp->pp_fastq);
}
}
++sp->pp_loopcnt;
@@ -983,17 +876,67 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m)
}
/*
- * Send PPP LCP packet.
+ * Send Cisco keepalive packet.
+ */
+static void
+sppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
+{
+ STDDCL;
+ struct ppp_header *h;
+ struct cisco_packet *ch;
+ struct mbuf *m;
+ u_long t = (time.tv_sec - boottime.tv_sec) * 1000;
+
+ MGETHDR (m, M_DONTWAIT, MT_DATA);
+ if (! m)
+ return;
+ m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
+ m->m_pkthdr.rcvif = 0;
+
+ h = mtod (m, struct ppp_header*);
+ h->address = CISCO_MULTICAST;
+ h->control = 0;
+ h->protocol = htons (CISCO_KEEPALIVE);
+
+ ch = (struct cisco_packet*) (h + 1);
+ ch->type = htonl (type);
+ ch->par1 = htonl (par1);
+ ch->par2 = htonl (par2);
+ ch->rel = -1;
+ ch->time0 = htons ((u_short) (t >> 16));
+ ch->time1 = htons ((u_short) t);
+
+ if (debug)
+ log(LOG_DEBUG,
+ "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
+ ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
+ ch->par2, ch->rel, ch->time0, ch->time1);
+
+ if (IF_QFULL (&sp->pp_fastq)) {
+ IF_DROP (&ifp->if_snd);
+ m_freem (m);
+ } else
+ IF_ENQUEUE (&sp->pp_fastq, m);
+ if (! (ifp->if_flags & IFF_OACTIVE))
+ (*ifp->if_start) (ifp);
+ ifp->if_obytes += m->m_pkthdr.len + 3;
+}
+
+ /*
+ * PPP protocol implementation.
+ */
+
+/*
+ * Send PPP control protocol packet.
*/
static void
sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
u_char ident, u_short len, void *data)
{
+ STDDCL;
struct ppp_header *h;
struct lcp_header *lh;
struct mbuf *m;
- struct ifnet *ifp = &sp->pp_if;
- int debug = ifp->if_flags & IFF_DEBUG;
if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
@@ -1016,12 +959,11 @@ sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
bcopy (data, lh+1, len);
if (debug) {
- log(LOG_DEBUG, "%s%d: %s output <%s id=%xh len=%xh",
- ifp->if_name, ifp->if_unit,
- proto==PPP_LCP ? "lcp" : "ipcp",
- proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
- sppp_ipcp_type_name (lh->type), lh->ident,
- ntohs (lh->len));
+ log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d",
+ ifp->if_name, ifp->if_unit,
+ sppp_proto_name(proto),
+ sppp_cp_type_name (lh->type), lh->ident,
+ ntohs (lh->len));
if (len)
sppp_print_bytes ((u_char*) (lh+1), len);
addlog(">\n");
@@ -1029,6 +971,7 @@ sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
if (IF_QFULL (&sp->pp_fastq)) {
IF_DROP (&ifp->if_snd);
m_freem (m);
+ ++ifp->if_oerrors;
} else
IF_ENQUEUE (&sp->pp_fastq, m);
if (! (ifp->if_flags & IFF_OACTIVE))
@@ -1037,461 +980,1722 @@ sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
}
/*
- * Send Cisco keepalive packet.
+ * Handle incoming PPP control protocol packets.
*/
static void
-sppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
+sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
{
- struct ppp_header *h;
- struct cisco_packet *ch;
- struct mbuf *m;
- struct ifnet *ifp = &sp->pp_if;
- u_long t = (time.tv_sec - boottime.tv_sec) * 1000;
- int debug = ifp->if_flags & IFF_DEBUG;
+ STDDCL;
+ struct lcp_header *h;
+ int len = m->m_pkthdr.len;
+ int rv;
+ u_char *p;
- MGETHDR (m, M_DONTWAIT, MT_DATA);
- if (! m)
+ if (len < 4) {
+ if (debug)
+ log(LOG_DEBUG,
+ "%s%d: %s invalid packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, cp->name, len);
return;
- m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
- m->m_pkthdr.rcvif = 0;
-
- h = mtod (m, struct ppp_header*);
- h->address = CISCO_MULTICAST;
- h->control = 0;
- h->protocol = htons (CISCO_KEEPALIVE);
-
- ch = (struct cisco_packet*) (h + 1);
- ch->type = htonl (type);
- ch->par1 = htonl (par1);
- ch->par2 = htonl (par2);
- ch->rel = -1;
- ch->time0 = htons ((u_short) (t >> 16));
- ch->time1 = htons ((u_short) t);
-
- if (debug)
+ }
+ h = mtod (m, struct lcp_header*);
+ if (debug) {
log(LOG_DEBUG,
- "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
- ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
- ch->par2, ch->rel, ch->time0, ch->time1);
+ "%s%d: %s input(%s): <%s id=0x%x len=%d",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]),
+ sppp_cp_type_name (h->type), h->ident, ntohs (h->len));
+ if (len > 4)
+ sppp_print_bytes ((u_char*) (h+1), len-4);
+ addlog(">\n");
+ }
+ if (len > ntohs (h->len))
+ len = ntohs (h->len);
+ switch (h->type) {
+ case CONF_REQ:
+ if (len < 4) {
+ if (debug)
+ addlog("%s%d: %s invalid conf-req length %d\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ len);
+ ++ifp->if_ierrors;
+ break;
+ }
+ rv = (cp->RCR)(sp, h, len);
+ switch (sp->state[cp->protoidx]) {
+ case STATE_OPENED:
+ (cp->tld)(sp);
+ (cp->scr)(sp);
+ /* fall through... */
+ case STATE_ACK_SENT:
+ case STATE_REQ_SENT:
+ sppp_cp_change_state(cp, sp, rv?
+ STATE_ACK_SENT: STATE_REQ_SENT);
+ break;
+ case STATE_CLOSING:
+ case STATE_STOPPING:
+ break;
+ case STATE_STOPPED:
+ sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
+ (cp->scr)(sp);
+ sppp_cp_change_state(cp, sp, rv?
+ STATE_ACK_SENT: STATE_REQ_SENT);
+ break;
+ case STATE_CLOSED:
+ sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
+ 0, 0);
+ break;
+ case STATE_ACK_RCVD:
+ if (rv) {
+ sppp_cp_change_state(cp, sp, STATE_OPENED);
+ if (debug)
+ addlog("%s%d: %s tlu\n",
+ ifp->if_name, ifp->if_unit,
+ cp->name);
+ (cp->tlu)(sp);
+ } else
+ sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
+ break;
+ default:
+ printf("%s%d: %s illegal %s in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_cp_type_name(h->type),
+ sppp_state_name(sp->state[cp->protoidx]));
+ ++ifp->if_ierrors;
+ }
+ break;
+ case CONF_ACK:
+ if (h->ident != sp->confid[cp->protoidx]) {
+ if (debug)
+ addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ h->ident, sp->confid[cp->protoidx]);
+ ++ifp->if_ierrors;
+ break;
+ }
+ switch (sp->state[cp->protoidx]) {
+ case STATE_CLOSED:
+ case STATE_STOPPED:
+ sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
+ break;
+ case STATE_CLOSING:
+ case STATE_STOPPING:
+ break;
+ case STATE_REQ_SENT:
+ sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
+ sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
+ break;
+ case STATE_OPENED:
+ (cp->tld)(sp);
+ /* fall through */
+ case STATE_ACK_RCVD:
+ (cp->scr)(sp);
+ sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
+ break;
+ case STATE_ACK_SENT:
+ sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
+ sppp_cp_change_state(cp, sp, STATE_OPENED);
+ if (debug)
+ addlog("%s%d: %s tlu\n",
+ ifp->if_name, ifp->if_unit, cp->name);
+ (cp->tlu)(sp);
+ break;
+ default:
+ printf("%s%d: %s illegal %s in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_cp_type_name(h->type),
+ sppp_state_name(sp->state[cp->protoidx]));
+ ++ifp->if_ierrors;
+ }
+ break;
+ case CONF_NAK:
+ case CONF_REJ:
+ if (h->ident != sp->confid[cp->protoidx]) {
+ if (debug)
+ addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ h->ident, sp->confid[cp->protoidx]);
+ ++ifp->if_ierrors;
+ break;
+ }
+ if (h->type == CONF_NAK)
+ (cp->RCN_nak)(sp, h, len);
+ else /* CONF_REJ */
+ (cp->RCN_rej)(sp, h, len);
+
+ switch (sp->state[cp->protoidx]) {
+ case STATE_CLOSED:
+ case STATE_STOPPED:
+ sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
+ break;
+ case STATE_REQ_SENT:
+ case STATE_ACK_SENT:
+ sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
+ (cp->scr)(sp);
+ break;
+ case STATE_OPENED:
+ (cp->tld)(sp);
+ /* fall through */
+ case STATE_ACK_RCVD:
+ sppp_cp_change_state(cp, sp, STATE_ACK_SENT);
+ (cp->scr)(sp);
+ break;
+ case STATE_CLOSING:
+ case STATE_STOPPING:
+ break;
+ default:
+ printf("%s%d: %s illegal %s in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_cp_type_name(h->type),
+ sppp_state_name(sp->state[cp->protoidx]));
+ ++ifp->if_ierrors;
+ }
+ break;
- if (IF_QFULL (&sp->pp_fastq)) {
- IF_DROP (&ifp->if_snd);
- m_freem (m);
- } else
- IF_ENQUEUE (&sp->pp_fastq, m);
- if (! (ifp->if_flags & IFF_OACTIVE))
- (*ifp->if_start) (ifp);
- ifp->if_obytes += m->m_pkthdr.len + 3;
+ case TERM_REQ:
+ switch (sp->state[cp->protoidx]) {
+ case STATE_ACK_RCVD:
+ case STATE_ACK_SENT:
+ sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
+ /* fall through */
+ case STATE_CLOSED:
+ case STATE_STOPPED:
+ case STATE_CLOSING:
+ case STATE_STOPPING:
+ case STATE_REQ_SENT:
+ sta:
+ /* Send Terminate-Ack packet. */
+ if (debug)
+ log(LOG_DEBUG, "%s%d: %s send terminate-ack\n",
+ ifp->if_name, ifp->if_unit, cp->name);
+ sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
+ break;
+ case STATE_OPENED:
+ (cp->tld)(sp);
+ sp->rst_counter[cp->protoidx] = 0;
+ sppp_cp_change_state(cp, sp, STATE_STOPPING);
+ goto sta;
+ break;
+ default:
+ printf("%s%d: %s illegal %s in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_cp_type_name(h->type),
+ sppp_state_name(sp->state[cp->protoidx]));
+ ++ifp->if_ierrors;
+ }
+ break;
+ case TERM_ACK:
+ switch (sp->state[cp->protoidx]) {
+ case STATE_CLOSED:
+ case STATE_STOPPED:
+ case STATE_REQ_SENT:
+ case STATE_ACK_SENT:
+ break;
+ case STATE_CLOSING:
+ (cp->tlf)(sp);
+ sppp_cp_change_state(cp, sp, STATE_CLOSED);
+ break;
+ case STATE_STOPPING:
+ (cp->tlf)(sp);
+ sppp_cp_change_state(cp, sp, STATE_STOPPED);
+ break;
+ case STATE_ACK_RCVD:
+ sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
+ break;
+ case STATE_OPENED:
+ (cp->tld)(sp);
+ (cp->scr)(sp);
+ sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
+ break;
+ default:
+ printf("%s%d: %s illegal %s in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_cp_type_name(h->type),
+ sppp_state_name(sp->state[cp->protoidx]));
+ ++ifp->if_ierrors;
+ }
+ break;
+ case CODE_REJ:
+ case PROTO_REJ:
+ /* XXX catastrophic rejects (RXJ-) aren't handled yet. */
+ switch (sp->state[cp->protoidx]) {
+ case STATE_CLOSED:
+ case STATE_STOPPED:
+ case STATE_REQ_SENT:
+ case STATE_ACK_SENT:
+ case STATE_CLOSING:
+ case STATE_STOPPING:
+ case STATE_OPENED:
+ break;
+ case STATE_ACK_RCVD:
+ sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
+ break;
+ default:
+ printf("%s%d: %s illegal %s in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_cp_type_name(h->type),
+ sppp_state_name(sp->state[cp->protoidx]));
+ ++ifp->if_ierrors;
+ }
+ break;
+ case DISC_REQ:
+ if (cp->proto != PPP_LCP)
+ goto illegal;
+ /* Discard the packet. */
+ break;
+ case ECHO_REQ:
+ if (cp->proto != PPP_LCP)
+ goto illegal;
+ if (sp->state[cp->protoidx] != STATE_OPENED) {
+ if (debug)
+ addlog("%s%d: lcp echo req but lcp closed\n",
+ ifp->if_name, ifp->if_unit);
+ ++ifp->if_ierrors;
+ break;
+ }
+ if (len < 8) {
+ if (debug)
+ addlog("%s%d: invalid lcp echo request "
+ "packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ break;
+ }
+ if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
+ /* Line loopback mode detected. */
+ printf("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
+ if_down (ifp);
+ sppp_qflush (&sp->pp_fastq);
+
+ /* Shut down the PPP link. */
+ /* XXX */
+ lcp.Down(sp);
+ lcp.Up(sp);
+ break;
+ }
+ *(long*)(h+1) = htonl (sp->lcp.magic);
+ if (debug)
+ addlog("%s%d: got lcp echo req, sending echo rep\n",
+ ifp->if_name, ifp->if_unit);
+ sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1);
+ break;
+ case ECHO_REPLY:
+ if (cp->proto != PPP_LCP)
+ goto illegal;
+ if (h->ident != sp->lcp.echoid) {
+ ++ifp->if_ierrors;
+ break;
+ }
+ if (len < 8) {
+ if (debug)
+ addlog("%s%d: lcp invalid echo reply "
+ "packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ break;
+ }
+ if (debug)
+ addlog("%s%d: lcp got echo rep\n",
+ ifp->if_name, ifp->if_unit);
+ if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
+ sp->pp_alivecnt = 0;
+ break;
+ default:
+ /* Unknown packet type -- send Code-Reject packet. */
+ illegal:
+ if (debug)
+ addlog("%s%d: %c send code-rej for 0x%x\n",
+ ifp->if_name, ifp->if_unit, cp->name, h->type);
+ sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq,
+ m->m_pkthdr.len, h);
+ ++ifp->if_ierrors;
+ }
}
+
/*
- * Process an ioctl request. Called on low priority level.
+ * The generic part of all Up/Down/Open/Close/TO event handlers.
+ * Basically, the state transition handling in the automaton.
*/
-int
-sppp_ioctl(struct ifnet *ifp, int cmd, void *data)
+static void
+sppp_up_event(const struct cp *cp, struct sppp *sp)
{
- struct ifreq *ifr = (struct ifreq*) data;
- struct sppp *sp = (struct sppp*) ifp;
- int s, going_up, going_down;
+ STDDCL;
- switch (cmd) {
+ if (debug)
+ log(LOG_DEBUG, "%s%d: %s up(%s)\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]));
+
+ switch (sp->state[cp->protoidx]) {
+ case STATE_INITIAL:
+ sppp_cp_change_state(cp, sp, STATE_CLOSED);
+ break;
+ case STATE_STARTING:
+ sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
+ (cp->scr)(sp);
+ sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
+ break;
default:
- return (ENOTTY);
+ printf("%s%d: %s illegal up in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]));
+ }
+}
- case SIOCAIFADDR:
- case SIOCSIFDSTADDR:
+static void
+sppp_down_event(const struct cp *cp, struct sppp *sp)
+{
+ STDDCL;
+
+ if (debug)
+ log(LOG_DEBUG, "%s%d: %s down(%s)\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]));
+
+ switch (sp->state[cp->protoidx]) {
+ case STATE_CLOSED:
+ case STATE_CLOSING:
+ sppp_cp_change_state(cp, sp, STATE_INITIAL);
+ break;
+ case STATE_STOPPED:
+ (cp->tls)(sp);
+ /* fall through */
+ case STATE_STOPPING:
+ case STATE_REQ_SENT:
+ case STATE_ACK_RCVD:
+ case STATE_ACK_SENT:
+ sppp_cp_change_state(cp, sp, STATE_STARTING);
+ break;
+ case STATE_OPENED:
+ (cp->tld)(sp);
+ sppp_cp_change_state(cp, sp, STATE_STARTING);
break;
+ default:
+ printf("%s%d: %s illegal down in state %s\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]));
+ }
+}
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
- /* fall through... */
- case SIOCSIFFLAGS:
- s = splimp ();
- going_up = (ifp->if_flags & IFF_UP) &&
- ! (ifp->if_flags & IFF_RUNNING);
- going_down = ! (ifp->if_flags & IFF_UP) &&
- (ifp->if_flags & IFF_RUNNING);
- if (going_up || going_down) {
- /* Shut down the PPP link. */
- ifp->if_flags &= ~IFF_RUNNING;
- sp->lcp.state = LCP_STATE_CLOSED;
- sp->ipcp.state = IPCP_STATE_CLOSED;
- UNTIMO (sp);
- }
- if (going_up) {
- /* Interface is starting -- initiate negotiation. */
- ifp->if_flags |= IFF_RUNNING;
- if (!(sp->pp_flags & PP_CISCO))
- sppp_lcp_open (sp);
- }
- splx (s);
+static void
+sppp_open_event(const struct cp *cp, struct sppp *sp)
+{
+ STDDCL;
+
+ if (debug)
+ log(LOG_DEBUG, "%s%d: %s open(%s)\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]));
+
+ switch (sp->state[cp->protoidx]) {
+ case STATE_INITIAL:
+ (cp->tls)(sp);
+ sppp_cp_change_state(cp, sp, STATE_STARTING);
+ break;
+ case STATE_STARTING:
+ break;
+ case STATE_CLOSED:
+ sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
+ (cp->scr)(sp);
+ sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
+ break;
+ case STATE_STOPPED:
+ case STATE_STOPPING:
+ case STATE_REQ_SENT:
+ case STATE_ACK_RCVD:
+ case STATE_ACK_SENT:
+ case STATE_OPENED:
+ break;
+ case STATE_CLOSING:
+ sppp_cp_change_state(cp, sp, STATE_STOPPING);
break;
+ }
+}
-#ifdef SIOCSIFMTU
-#ifndef ifr_mtu
-#define ifr_mtu ifr_metric
-#endif
- case SIOCSIFMTU:
- if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > PP_MTU)
- return (EINVAL);
- ifp->if_mtu = ifr->ifr_mtu;
+
+static void
+sppp_close_event(const struct cp *cp, struct sppp *sp)
+{
+ STDDCL;
+
+ if (debug)
+ log(LOG_DEBUG, "%s%d: %s close(%s)\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]));
+
+ switch (sp->state[cp->protoidx]) {
+ case STATE_INITIAL:
+ case STATE_CLOSED:
+ case STATE_CLOSING:
break;
-#endif
-#ifdef SLIOCSETMTU
- case SLIOCSETMTU:
- if (*(short*)data < 128 || *(short*)data > PP_MTU)
- return (EINVAL);
- ifp->if_mtu = *(short*)data;
+ case STATE_STARTING:
+ (cp->tlf)(sp);
+ sppp_cp_change_state(cp, sp, STATE_INITIAL);
break;
-#endif
-#ifdef SIOCGIFMTU
- case SIOCGIFMTU:
- ifr->ifr_mtu = ifp->if_mtu;
+ case STATE_STOPPED:
+ sppp_cp_change_state(cp, sp, STATE_CLOSED);
break;
-#endif
-#ifdef SLIOCGETMTU
- case SLIOCGETMTU:
- *(short*)data = ifp->if_mtu;
+ case STATE_STOPPING:
+ sppp_cp_change_state(cp, sp, STATE_CLOSING);
break;
-#endif
- case SIOCADDMULTI:
- case SIOCDELMULTI:
+ case STATE_OPENED:
+ (cp->tld)(sp);
+ /* fall through */
+ case STATE_REQ_SENT:
+ case STATE_ACK_RCVD:
+ case STATE_ACK_SENT:
+ sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
+ sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0);
+ sppp_cp_change_state(cp, sp, STATE_CLOSING);
break;
}
- return (0);
+}
+
+static void
+sppp_to_event(const struct cp *cp, struct sppp *sp)
+{
+ STDDCL;
+ int s;
+
+ s = splimp();
+ if (debug)
+ log(LOG_DEBUG, "%s%d: %s TO(%s) rst_counter = %d\n",
+ ifp->if_name, ifp->if_unit, cp->name,
+ sppp_state_name(sp->state[cp->protoidx]),
+ sp->rst_counter[cp->protoidx]);
+
+ if (--sp->rst_counter[cp->protoidx] < 0)
+ /* TO- event */
+ switch (sp->state[cp->protoidx]) {
+ case STATE_CLOSING:
+ (cp->tlf)(sp);
+ sppp_cp_change_state(cp, sp, STATE_CLOSED);
+ break;
+ case STATE_STOPPING:
+ (cp->tlf)(sp);
+ sppp_cp_change_state(cp, sp, STATE_STOPPED);
+ break;
+ case STATE_REQ_SENT:
+ case STATE_ACK_RCVD:
+ case STATE_ACK_SENT:
+ (cp->tlf)(sp);
+ sppp_cp_change_state(cp, sp, STATE_STOPPED);
+ break;
+ }
+ else
+ /* TO+ event */
+ switch (sp->state[cp->protoidx]) {
+ case STATE_CLOSING:
+ case STATE_STOPPING:
+ sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
+ 0, 0);
+ timeout(cp->TO, (void *)sp, sp->lcp.timeout);
+ break;
+ case STATE_REQ_SENT:
+ case STATE_ACK_RCVD:
+ (cp->scr)(sp);
+ /* sppp_cp_change_state() will restart the timer */
+ sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
+ break;
+ case STATE_ACK_SENT:
+ (cp->scr)(sp);
+ timeout(cp->TO, (void *)sp, sp->lcp.timeout);
+ break;
+ }
+
+ splx(s);
}
/*
- * Analyze the LCP Configure-Request options list
- * for the presence of unknown options.
- * If the request contains unknown options, build and
- * send Configure-reject packet, containing only unknown options.
+ * Change the state of a control protocol in the state automaton.
+ * Takes care of starting/stopping the restart timer.
+ */
+void
+sppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
+{
+ sp->state[cp->protoidx] = newstate;
+
+ untimeout(cp->TO, (void *)sp);
+ switch (newstate) {
+ case STATE_INITIAL:
+ case STATE_STARTING:
+ case STATE_CLOSED:
+ case STATE_STOPPED:
+ case STATE_OPENED:
+ break;
+ case STATE_CLOSING:
+ case STATE_STOPPING:
+ case STATE_REQ_SENT:
+ case STATE_ACK_RCVD:
+ case STATE_ACK_SENT:
+ timeout(cp->TO, (void *)sp, sp->lcp.timeout);
+ break;
+ }
+}
+ /*
+ *--------------------------------------------------------------------------*
+ * *
+ * The LCP implementation. *
+ * *
+ *--------------------------------------------------------------------------*
+ */
+static void
+sppp_lcp_init(struct sppp *sp)
+{
+ sp->lcp.opts = (1 << LCP_OPT_MAGIC);
+ sp->lcp.magic = 0;
+ sp->state[IDX_LCP] = STATE_INITIAL;
+ sp->fail_counter[IDX_LCP] = 0;
+ sp->lcp.protos = 0;
+ sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
+
+ /*
+ * Initialize counters and timeout values. Note that we don't
+ * use the 3 seconds suggested in RFC 1661 since we are likely
+ * running on a fast link. XXX We should probably implement
+ * the exponential backoff option. Note that these values are
+ * relevant for all control protocols, not just LCP only.
+ */
+ sp->lcp.timeout = 1 * hz;
+ sp->lcp.max_terminate = 2;
+ sp->lcp.max_configure = 10;
+ sp->lcp.max_failure = 10;
+}
+
+static void
+sppp_lcp_up(struct sppp *sp)
+{
+ STDDCL;
+
+ /*
+ * If this interface is passive or dial-on-demand, it means
+ * we've got in incoming call. Activate the interface.
+ */
+ if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) {
+ if (debug)
+ log(LOG_DEBUG,
+ "%s%d: Up event (incoming call)\n",
+ ifp->if_name, ifp->if_unit);
+ ifp->if_flags |= IFF_RUNNING;
+ lcp.Open(sp);
+ }
+
+ sppp_up_event(&lcp, sp);
+}
+
+static void
+sppp_lcp_down(struct sppp *sp)
+{
+ STDDCL;
+
+ sppp_down_event(&lcp, sp);
+
+ /*
+ * If this is neither a dial-on-demand nor a passive
+ * interface, simulate an ``ifconfig down'' action, so the
+ * administrator can force a redial by another ``ifconfig
+ * up''. XXX For leased line operation, should we immediately
+ * try to reopen the connection here?
+ */
+ if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
+ log(LOG_INFO,
+ "%s%d: Down event (carrier loss), taking interface down.\n",
+ ifp->if_name, ifp->if_unit);
+ if_down(ifp);
+ } else {
+ if (debug)
+ log(LOG_DEBUG,
+ "%s%d: Down event (carrier loss)\n",
+ ifp->if_name, ifp->if_unit);
+ }
+ lcp.Close(sp);
+ ifp->if_flags &= ~IFF_RUNNING;
+}
+
+static void
+sppp_lcp_open(struct sppp *sp)
+{
+ sppp_open_event(&lcp, sp);
+}
+
+static void
+sppp_lcp_close(struct sppp *sp)
+{
+ sppp_close_event(&lcp, sp);
+}
+
+static void
+sppp_lcp_TO(void *cookie)
+{
+ sppp_to_event(&lcp, (struct sppp *)cookie);
+}
+
+/*
+ * Analyze a configure request. Return true if it was agreeable, and
+ * caused action sca, false if it has been rejected or nak'ed, and
+ * caused action scn. (The return value is used to make the state
+ * transition decision in the state automaton.)
*/
static int
-sppp_lcp_conf_parse_options(struct sppp *sp, struct lcp_header *h,
- int len, u_long *magic)
+sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
{
+ STDDCL;
u_char *buf, *r, *p;
- struct ifnet *ifp = &sp->pp_if;
- int rlen, debug = ifp->if_flags & IFF_DEBUG;
+ int origlen, rlen;
+ u_long nmagic;
len -= 4;
+ origlen = len;
buf = r = malloc (len, M_TEMP, M_NOWAIT);
if (! buf)
return (0);
if (debug)
- addlog("%s%d: lcp parse opts: ", ifp->if_name, ifp->if_unit);
+ log(LOG_DEBUG, "%s%d: lcp parse opts: ",
+ ifp->if_name, ifp->if_unit);
+ /* pass 1: check for things that need to be rejected */
p = (void*) (h+1);
for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s ", sppp_lcp_opt_name(*p));
switch (*p) {
case LCP_OPT_MAGIC:
- /* Magic number -- extract. */
+ /* Magic number. */
+ /* fall through, both are same length */
+ case LCP_OPT_ASYNC_MAP:
+ /* Async control character map. */
+ if (len >= 6 || p[1] == 6)
+ continue;
if (debug)
- addlog(" magicnum: ");
- if (len >= 6 && p[1] == 6) {
- *magic = (u_long)p[2] << 24 |
- (u_long)p[3] << 16 | p[4] << 8 | p[5];
+ addlog("[invalid] ");
+ break;
+ case LCP_OPT_MRU:
+ /* Maximum receive unit. */
+ if (len >= 4 && p[1] == 4)
+ continue;
+ if (debug)
+ addlog("[invalid] ");
+ break;
+ default:
+ /* Others not supported. */
+ if (debug)
+ addlog("[rej] ");
+ break;
+ }
+ /* Add the option to rejected list. */
+ bcopy (p, r, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+ if (rlen) {
+ if (debug)
+ addlog(" send conf-rej\n");
+ sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
+ return 0;
+ } else if (debug)
+ addlog("\n");
+
+ /*
+ * pass 2: check for option values that are unacceptable and
+ * thus require to be nak'ed.
+ */
+ if (debug)
+ addlog("%s%d: lcp parse opt values: ",
+ ifp->if_name, ifp->if_unit);
+
+ p = (void*) (h+1);
+ len = origlen;
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s ", sppp_lcp_opt_name(*p));
+ switch (*p) {
+ case LCP_OPT_MAGIC:
+ /* Magic number -- extract. */
+ nmagic = (u_long)p[2] << 24 |
+ (u_long)p[3] << 16 | p[4] << 8 | p[5];
+ if (nmagic != sp->lcp.magic) {
if (debug)
- addlog("0x%x", *magic);
+ addlog("0x%x ", nmagic);
continue;
}
- if (debug)
- addlog("invalid");
+ /*
+ * Local and remote magics equal -- loopback?
+ */
+ if (sp->pp_loopcnt >= MAXALIVECNT*5) {
+ printf ("\n%s%d: loopback\n",
+ ifp->if_name, ifp->if_unit);
+ sp->pp_loopcnt = 0;
+ if (ifp->if_flags & IFF_UP) {
+ if_down(ifp);
+ sppp_qflush(&sp->pp_fastq);
+ /* XXX ? */
+ lcp.Down(sp);
+ lcp.Up(sp);
+ }
+ } else if (debug)
+ addlog("[glitch] ");
+ ++sp->pp_loopcnt;
+ /*
+ * We negate our magic here, and NAK it. If
+ * we see it later in an NAK packet, we
+ * suggest a new one.
+ */
+ nmagic = ~sp->lcp.magic;
+ /* Gonna NAK it. */
+ p[2] = nmagic >> 24;
+ p[3] = nmagic >> 16;
+ p[4] = nmagic >> 8;
+ p[5] = nmagic;
break;
+
case LCP_OPT_ASYNC_MAP:
/* Async control character map -- check to be zero. */
- if (debug)
- addlog(" asyncmap: ");
- if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&
- ! p[4] && ! p[5]) {
+ if (! p[2] && ! p[3] && ! p[4] && ! p[5]) {
if (debug)
- addlog("empty (ack)");
+ addlog("[empty] ");
continue;
}
if (debug)
- addlog("non-empty (rej)");
+ addlog("[non-empty] ");
+ /* suggest a zero one */
+ p[2] = p[3] = p[4] = p[5] = 0;
break;
+
case LCP_OPT_MRU:
- /* Maximum receive unit -- always OK. */
+ /*
+ * Maximum receive unit. Always agreeable,
+ * but ignored by now.
+ */
+ sp->lcp.their_mru = p[2] * 256 + p[3];
if (debug)
- addlog(" mru (ignored)");
+ addlog("%d ", sp->lcp.their_mru);
continue;
- default:
- /* Others not supported. */
- if (debug)
- addlog(" unknown 0x%x", *p);
- break;
}
- /* Add the option to rejected list. */
+ /* Add the option to nak'ed list. */
bcopy (p, r, p[1]);
r += p[1];
rlen += p[1];
}
if (rlen) {
if (debug)
- addlog(", send lcp configure nak\n");
- sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, h->ident, rlen, buf);
- } else if (debug)
- addlog("\n");
+ addlog(" send conf-nak\n");
+ sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
+ return 0;
+ } else {
+ if (debug)
+ addlog(" send conf-ack\n");
+ sp->pp_loopcnt = 0;
+ sppp_cp_send (sp, PPP_LCP, CONF_ACK,
+ h->ident, origlen, h+1);
+ }
+
free (buf, M_TEMP);
return (rlen == 0);
}
+/*
+ * Analyze the LCP Configure-Reject option list, and adjust our
+ * negotiation.
+ */
static void
-sppp_ipcp_input(struct sppp *sp, struct mbuf *m)
+sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
{
- struct lcp_header *h;
- struct ifnet *ifp = &sp->pp_if;
- int len = m->m_pkthdr.len, debug = ifp->if_flags & IFF_DEBUG;;
+ STDDCL;
+ u_char *buf, *p;
- if (len < 4) {
- printf ("%s%d: invalid ipcp packet length: %d bytes\n",
- ifp->if_name, ifp->if_unit, len);
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
return;
- }
- h = mtod (m, struct lcp_header*);
- if (debug) {
- log(LOG_DEBUG,
- "%s%d: ipcp input: %d bytes <%s id=0x%x len=0x%x",
- ifp->if_name, ifp->if_unit, len,
- sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
- if (len > 4)
- sppp_print_bytes ((u_char*) (h+1), len-4);
- addlog(">\n");
- }
- if (len > ntohs (h->len))
- len = ntohs (h->len);
- switch (h->type) {
- default:
- /* Unknown packet type -- send Code-Reject packet. */
+
+ if (debug)
+ log(LOG_DEBUG, "%s%d: lcp rej opts: ",
+ ifp->if_name, ifp->if_unit);
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
if (debug)
- addlog("%s%d: ipcp unknown type 0x%x, sending code rej\n",
- ifp->if_name, ifp->if_unit, h->type);
- sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
- break;
- case IPCP_CONF_REQ:
- if (len < 4) {
- if (debug)
- addlog("%s%d: invalid ipcp configure "
- "request packet length: %d bytes\n",
- ifp->if_name, ifp->if_unit, len);
- return;
+ addlog(" %s ", sppp_lcp_opt_name(*p));
+ switch (*p) {
+ case LCP_OPT_MAGIC:
+ /* Magic number -- can't use it, use 0 */
+ sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC);
+ sp->lcp.magic = 0;
+ break;
+ case LCP_OPT_MRU:
+ /*
+ * Should not be rejected anyway, since we only
+ * negotiate a MRU if explicitly requested by
+ * peer.
+ */
+ sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
+ break;
}
- if (len > 4) {
- if (debug)
- addlog("%s%d: rejecting ipcp conf req len=%d\n",
- ifp->if_name, ifp->if_unit, len);
- sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
- len-4, h+1);
-
- switch (sp->ipcp.state) {
- case IPCP_STATE_OPENED:
- /* Initiate renegotiation. */
- sppp_ipcp_open (sp);
- /* fall through... */
- case IPCP_STATE_ACK_SENT:
- /* Go to closed state. */
- sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
+}
+
+/*
+ * Analyze the LCP Configure-NAK option list, and adjust our
+ * negotiation.
+ */
+static void
+sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
+{
+ STDDCL;
+ u_char *buf, *p;
+ u_long magic;
+
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return;
+
+ if (debug)
+ log(LOG_DEBUG, "%s%d: lcp nak opts: ",
+ ifp->if_name, ifp->if_unit);
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ if (debug)
+ addlog(" %s ", sppp_lcp_opt_name(*p));
+ switch (*p) {
+ case LCP_OPT_MAGIC:
+ /* Magic number -- renegotiate */
+ if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
+ len >= 6 && p[1] == 6) {
+ magic = (u_long)p[2] << 24 |
+ (u_long)p[3] << 16 | p[4] << 8 | p[5];
+ /*
+ * If the remote magic is our negated one,
+ * this looks like a loopback problem.
+ * Suggest a new magic to make sure.
+ */
+ if (magic == ~sp->lcp.magic) {
+ if (debug)
+ addlog("magic glitch ");
+ sp->lcp.magic += time.tv_sec + time.tv_usec;
+ } else {
+ sp->lcp.magic = magic;
+ if (debug)
+ addlog("%d ");
+ }
}
- } else {
- if (debug)
- addlog("%s%d: sending ipcp conf ack\n",
- ifp->if_name, ifp->if_unit);
- /* Send Configure-Ack packet. */
- sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
- 0, 0);
- /* Change the state. */
- if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)
- sp->ipcp.state = IPCP_STATE_OPENED;
- else
- sp->ipcp.state = IPCP_STATE_ACK_SENT;
+ break;
+ case LCP_OPT_MRU:
+ /*
+ * Peer wants to advise us to negotiate an MRU.
+ * Agree on it if it's reasonable, or use
+ * default otherwise.
+ */
+ if (len >= 4 && p[1] == 4) {
+ u_int mru = p[2] * 256 + p[3];
+ if (debug)
+ addlog("%d ", mru);
+ if (mru < PP_MTU || mru > PP_MAX_MRU)
+ mru = PP_MTU;
+ sp->lcp.mru = mru;
+ sp->lcp.opts |= (1 << LCP_OPT_MRU);
+ }
+ break;
}
- break;
- case IPCP_CONF_ACK:
- if (h->ident != sp->ipcp.confid) {
+ }
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
+}
+
+static void
+sppp_lcp_tlu(struct sppp *sp)
+{
+ STDDCL;
+ int i;
+ u_long mask;
+
+ /* XXX ? */
+ if (! (ifp->if_flags & IFF_UP) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ /* Coming out of loopback mode. */
+ if_up(ifp);
+ printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
+ }
+
+ for (i = 0; i < IDX_COUNT; i++)
+ if ((cps[i])->flags & CP_QUAL)
+ (cps[i])->Open(sp);
+
+ if (/* require authentication XXX */ 0)
+ sp->pp_phase = PHASE_AUTHENTICATE;
+ else
+ sp->pp_phase = PHASE_NETWORK;
+
+ log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
+ sppp_phase_name(sp->pp_phase));
+
+ if (sp->pp_phase == PHASE_AUTHENTICATE) {
+ for (i = 0; i < IDX_COUNT; i++)
+ if ((cps[i])->flags & CP_AUTH)
+ (cps[i])->Open(sp);
+ } else {
+ /* Notify all NCPs. */
+ for (i = 0; i < IDX_COUNT; i++)
+ if ((cps[i])->flags & CP_NCP)
+ (cps[i])->Open(sp);
+ }
+
+ /* Send Up events to all started protos. */
+ for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
+ if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0)
+ (cps[i])->Up(sp);
+
+ if (sp->pp_phase == PHASE_NETWORK)
+ /* if no NCP is starting, close down */
+ sppp_lcp_check(sp);
+}
+
+static void
+sppp_lcp_tld(struct sppp *sp)
+{
+ STDDCL;
+ int i;
+ u_long mask;
+
+ sp->pp_phase = PHASE_TERMINATE;
+
+ log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
+ sppp_phase_name(sp->pp_phase));
+
+ /*
+ * Take upper layers down. We send the Down event first and
+ * the Close second to prevent the upper layers from sending
+ * ``a flurry of terminate-request packets'', as the RFC
+ * describes it.
+ */
+ for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
+ if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) {
+ (cps[i])->Down(sp);
+ (cps[i])->Close(sp);
+ }
+}
+
+static void
+sppp_lcp_tls(struct sppp *sp)
+{
+ STDDCL;
+
+ sp->pp_phase = PHASE_ESTABLISH;
+
+ log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
+ sppp_phase_name(sp->pp_phase));
+
+ /* Notify lower layer if desired. */
+ if (sp->pp_tls)
+ (sp->pp_tls)(sp);
+}
+
+static void
+sppp_lcp_tlf(struct sppp *sp)
+{
+ STDDCL;
+
+ sp->pp_phase = PHASE_DEAD;
+ log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
+ sppp_phase_name(sp->pp_phase));
+
+ /* Notify lower layer if desired. */
+ if (sp->pp_tlf)
+ (sp->pp_tlf)(sp);
+}
+
+static void
+sppp_lcp_scr(struct sppp *sp)
+{
+ char opt[6 /* magicnum */ + 4 /* mru */];
+ int i = 0;
+
+ if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
+ if (! sp->lcp.magic)
+ sp->lcp.magic = time.tv_sec + time.tv_usec;
+ opt[i++] = LCP_OPT_MAGIC;
+ opt[i++] = 6;
+ opt[i++] = sp->lcp.magic >> 24;
+ opt[i++] = sp->lcp.magic >> 16;
+ opt[i++] = sp->lcp.magic >> 8;
+ opt[i++] = sp->lcp.magic;
+ }
+
+ if (sp->lcp.opts & (1 << LCP_OPT_MRU)) {
+ opt[i++] = LCP_OPT_MRU;
+ opt[i++] = 4;
+ opt[i++] = sp->lcp.mru >> 8;
+ opt[i++] = sp->lcp.mru;
+ }
+
+ sp->confid[IDX_LCP] = ++sp->pp_seq;
+ sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
+}
+
+/*
+ * Re-check the open NCPs and see if we should terminate the link.
+ * Called by the NCPs during their tlf action handling.
+ */
+static void
+sppp_lcp_check(struct sppp *sp)
+{
+ int i, mask;
+
+ for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
+ if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP)
+ return;
+ lcp.Close(sp);
+}
+ /*
+ *--------------------------------------------------------------------------*
+ * *
+ * The IPCP implementation. *
+ * *
+ *--------------------------------------------------------------------------*
+ */
+
+static void
+sppp_ipcp_init(struct sppp *sp)
+{
+ sp->ipcp.opts = 0;
+ sp->ipcp.flags = 0;
+ sp->state[IDX_IPCP] = STATE_INITIAL;
+ sp->fail_counter[IDX_IPCP] = 0;
+}
+
+static void
+sppp_ipcp_up(struct sppp *sp)
+{
+ sppp_up_event(&ipcp, sp);
+}
+
+static void
+sppp_ipcp_down(struct sppp *sp)
+{
+ sppp_down_event(&ipcp, sp);
+}
+
+static void
+sppp_ipcp_open(struct sppp *sp)
+{
+ STDDCL;
+ u_long myaddr, hisaddr;
+
+ sppp_get_ip_addrs(sp, &myaddr, &hisaddr);
+ /*
+ * If we don't have his address, this probably means our
+ * interface doesn't want to talk IP at all. (This could
+ * be the case if somebody wants to speak only IPX, for
+ * example.) Don't open IPCP in this case.
+ */
+ if (hisaddr == 0L) {
+ /* XXX this message should go away */
+ if (debug)
+ log(LOG_DEBUG, "%s%d: ipcp_open(): no IP interface\n",
+ ifp->if_name, ifp->if_unit);
+ return;
+ }
+
+ if (myaddr == 0L) {
+ /*
+ * I don't have an assigned address, so i need to
+ * negotiate my address.
+ */
+ sp->ipcp.flags |= IPCP_MYADDR_DYN;
+ sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
+ }
+ sppp_open_event(&ipcp, sp);
+}
+
+static void
+sppp_ipcp_close(struct sppp *sp)
+{
+ sppp_close_event(&ipcp, sp);
+ if (sp->ipcp.flags & IPCP_MYADDR_DYN)
+ /*
+ * My address was dynamic, clear it again.
+ */
+ sppp_set_ip_addr(sp, 0L);
+}
+
+static void
+sppp_ipcp_TO(void *cookie)
+{
+ sppp_to_event(&ipcp, (struct sppp *)cookie);
+}
+
+/*
+ * Analyze a configure request. Return true if it was agreeable, and
+ * caused action sca, false if it has been rejected or nak'ed, and
+ * caused action scn. (The return value is used to make the state
+ * transition decision in the state automaton.)
+ */
+static int
+sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *r, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
+ u_long hisaddr, desiredaddr;
+
+ len -= 4;
+ origlen = len;
+ /*
+ * Make sure to allocate a buf that can at least hold a
+ * conf-nak with an `address' option. We might need it below.
+ */
+ buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
+ if (! buf)
+ return (0);
+
+ /* pass 1: see if we can recognize them */
+ if (debug)
+ log(LOG_DEBUG, "%s%d: ipcp parse opts: ",
+ ifp->if_name, ifp->if_unit);
+ p = (void*) (h+1);
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s ", sppp_ipcp_opt_name(*p));
+ switch (*p) {
+#ifdef notyet
+ case IPCP_OPT_COMPRESSION:
+ if (len >= 6 && p[1] >= 6) {
+ /* correctly formed compress option */
+ continue;
+ }
if (debug)
- addlog("%s%d: ipcp id mismatch 0x%x != 0x%x\n",
- ifp->if_name, ifp->if_unit,
- h->ident, sp->ipcp.confid);
+ addlog("[invalid] ");
break;
- }
- UNTIMO (sp);
- switch (sp->ipcp.state) {
- case IPCP_STATE_CLOSED:
- sp->ipcp.state = IPCP_STATE_ACK_RCVD;
- TIMO (sp, 5);
+#endif
+ case IPCP_OPT_ADDRESS:
+ if (len >= 6 && p[1] == 6) {
+ /* correctly formed address option */
+ continue;
+ }
+ if (debug)
+ addlog("[invalid] ");
break;
- case IPCP_STATE_ACK_SENT:
- sp->ipcp.state = IPCP_STATE_OPENED;
+ default:
+ /* Others not supported. */
+ if (debug)
+ addlog("[rej] ");
break;
}
- break;
- case IPCP_CONF_NAK:
- case IPCP_CONF_REJ:
- if (h->ident != sp->ipcp.confid) {
- if (debug)
- addlog("%s%d: ipcp id mismatch 0x%x != 0x%x\n",
- ifp->if_name, ifp->if_unit,
- h->ident, sp->ipcp.confid);
+ /* Add the option to rejected list. */
+ bcopy (p, r, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+ if (rlen) {
+ if (debug)
+ addlog(" send conf-rej\n");
+ sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf);
+ return 0;
+ } else if (debug)
+ addlog("\n");
+
+ /* pass 2: parse option values */
+ sppp_get_ip_addrs(sp, 0, &hisaddr);
+ if (debug)
+ addlog("%s%d: ipcp parse opt values: ", ifp->if_name, ifp->if_unit);
+ p = (void*) (h+1);
+ len = origlen;
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s ", sppp_ipcp_opt_name(*p));
+ switch (*p) {
+#ifdef notyet
+ case IPCP_OPT_COMPRESSION:
+ continue;
+#endif
+ case IPCP_OPT_ADDRESS:
+ desiredaddr = p[2] << 24 | p[3] << 16 |
+ p[4] << 8 | p[5];
+ if (desiredaddr == hisaddr) {
+ /*
+ * Peer's address is same as our value,
+ * this is agreeable. Gonna conf-ack
+ * it.
+ */
+ if (debug)
+ addlog("0x%x [ack] ", hisaddr);
+ /* record that we've seen it already */
+ sp->ipcp.flags |= IPCP_HISADDR_SEEN;
+ continue;
+ }
+ /*
+ * The address wasn't agreeable. This is either
+ * he sent us 0.0.0.0, asking to assign him an
+ * address, or he send us another address not
+ * matching our value. Either case, we gonna
+ * conf-nak it with our value.
+ */
+ if (debug) {
+ if (desiredaddr == 0)
+ addlog("[addr requested] ");
+ else
+ addlog("0x%x [not agreed] ",
+ desiredaddr);
+
+ p[2] = hisaddr >> 24;
+ p[3] = hisaddr >> 16;
+ p[4] = hisaddr >> 8;
+ p[5] = hisaddr;
+ }
break;
}
+ /* Add the option to nak'ed list. */
+ bcopy (p, r, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+
+ /*
+ * If we are about to conf-ack the request, but haven't seen
+ * his address so far, gonna conf-nak it instead, with the
+ * `address' option present and our idea of his address being
+ * filled in there, to request negotiation of both addresses.
+ *
+ * XXX This can result in an endless req - nak loop if peer
+ * doesn't want to send us his address. Q: What should we do
+ * about it? XXX A: implement the max-failure counter.
+ */
+ if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) {
+ buf[0] = IPCP_OPT_ADDRESS;
+ buf[1] = 6;
+ buf[2] = hisaddr >> 24;
+ buf[3] = hisaddr >> 16;
+ buf[4] = hisaddr >> 8;
+ buf[5] = hisaddr;
+ rlen = 6;
if (debug)
- addlog("%s%d: got ipcp conf %s, reopening ipcp\n",
- ifp->if_name, ifp->if_unit,
- (h->type == IPCP_CONF_NAK? "nak": "rej"));
- UNTIMO (sp);
- /* Initiate renegotiation. */
- sppp_ipcp_open (sp);
- if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
- /* Go to closed state. */
- sp->ipcp.state = IPCP_STATE_CLOSED;
- break;
- case IPCP_TERM_REQ:
- /* Send Terminate-Ack packet. */
+ addlog("still need hisaddr ");
+ }
+
+ if (rlen) {
if (debug)
- addlog("%s%d: got ipcp term req\n",
- ifp->if_name, ifp->if_unit);
- sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0);
- /* Go to closed state. */
- sp->ipcp.state = IPCP_STATE_CLOSED;
- /* Initiate renegotiation. */
- sppp_ipcp_open (sp);
- break;
- case IPCP_TERM_ACK:
- /* Ignore for now. */
+ addlog(" send conf-nak\n");
+ sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf);
+ } else {
if (debug)
- addlog("%s%d: ignoring ipcp term ack\n",
- ifp->if_name, ifp->if_unit);
- case IPCP_CODE_REJ:
- /* Ignore for now. */
+ addlog(" send conf-ack\n");
+ sppp_cp_send (sp, PPP_IPCP, CONF_ACK,
+ h->ident, origlen, h+1);
+ }
+
+ free (buf, M_TEMP);
+ return (rlen == 0);
+}
+
+/*
+ * Analyze the IPCP Configure-Reject option list, and adjust our
+ * negotiation.
+ */
+static void
+sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int debug = ifp->if_flags & IFF_DEBUG;
+
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return;
+
+ if (debug)
+ log(LOG_DEBUG, "%s%d: ipcp rej opts: ",
+ ifp->if_name, ifp->if_unit);
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
if (debug)
- addlog("%s%d: ignoring ipcp code rej\n",
- ifp->if_name, ifp->if_unit);
- break;
+ addlog(" %s ", sppp_ipcp_opt_name(*p));
+ switch (*p) {
+ case IPCP_OPT_ADDRESS:
+ /*
+ * Peer doesn't grok address option. This is
+ * bad. XXX Should we better give up here?
+ */
+ sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS);
+ break;
+#ifdef notyet
+ case IPCP_OPT_COMPRESS:
+ sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS);
+ break;
+#endif
+ }
}
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
}
+/*
+ * Analyze the IPCP Configure-NAK option list, and adjust our
+ * negotiation.
+ */
static void
-sppp_lcp_open(struct sppp *sp)
+sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int debug = ifp->if_flags & IFF_DEBUG;
+ u_long wantaddr;
+
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return;
+
+ if (debug)
+ log(LOG_DEBUG, "%s%d: ipcp nak opts: ",
+ ifp->if_name, ifp->if_unit);
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ if (debug)
+ addlog(" %s ", sppp_ipcp_opt_name(*p));
+ switch (*p) {
+ case IPCP_OPT_ADDRESS:
+ /*
+ * Peer doesn't like our local IP address. See
+ * if we can do something for him. We'll drop
+ * him our address then.
+ */
+ if (len >= 6 && p[1] == 6) {
+ wantaddr = p[2] << 24 | p[3] << 16 |
+ p[4] << 8 | p[5];
+ sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
+ if (debug)
+ addlog("[wantaddr 0x%x] ", wantaddr);
+ /*
+ * When doing dynamic address assignment,
+ * we accept his offer. Otherwise, we
+ * ignore it and thus continue to negotiate
+ * our already existing value.
+ */
+ if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
+ sppp_set_ip_addr(sp, wantaddr);
+ if (debug)
+ addlog("[agree] ");
+ }
+ }
+ break;
+#ifdef notyet
+ case IPCP_OPT_COMPRESS:
+ /*
+ * Peer wants different compression parameters.
+ */
+ break;
+#endif
+ }
+ }
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
+}
+
+static void
+sppp_ipcp_tlu(struct sppp *sp)
{
- char opt[6];
-
- if (! sp->lcp.magic)
- sp->lcp.magic = time.tv_sec + time.tv_usec;
- opt[0] = LCP_OPT_MAGIC;
- opt[1] = sizeof (opt);
- opt[2] = sp->lcp.magic >> 24;
- opt[3] = sp->lcp.magic >> 16;
- opt[4] = sp->lcp.magic >> 8;
- opt[5] = sp->lcp.magic;
- sp->lcp.confid = ++sp->pp_seq;
- sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,
- sizeof (opt), &opt);
- TIMO (sp, 2);
}
static void
-sppp_ipcp_open(struct sppp *sp)
+sppp_ipcp_tld(struct sppp *sp)
{
- sp->ipcp.confid = ++sp->pp_seq;
- sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0);
- TIMO (sp, 2);
}
+static void
+sppp_ipcp_tls(struct sppp *sp)
+{
+ /* indicate to LCP that it must stay alive */
+ sp->lcp.protos |= (1 << IDX_IPCP);
+}
+
+static void
+sppp_ipcp_tlf(struct sppp *sp)
+{
+ /* we no longer need LCP */
+ sp->lcp.protos &= ~(1 << IDX_IPCP);
+ sppp_lcp_check(sp);
+}
+
+static void
+sppp_ipcp_scr(struct sppp *sp)
+{
+ char opt[6 /* compression */ + 6 /* address */];
+ u_long ouraddr;
+ int i = 0;
+
+#ifdef notyet
+ if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
+ opt[i++] = IPCP_OPT_COMPRESSION;
+ opt[i++] = 6;
+ opt[i++] = 0; /* VJ header compression */
+ opt[i++] = 0x2d; /* VJ header compression */
+ opt[i++] = max_slot_id;
+ opt[i++] = comp_slot_id;
+ }
+#endif
+
+ if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
+ sppp_get_ip_addrs(sp, &ouraddr, 0);
+ opt[i++] = IPCP_OPT_ADDRESS;
+ opt[i++] = 6;
+ opt[i++] = ouraddr >> 24;
+ opt[i++] = ouraddr >> 16;
+ opt[i++] = ouraddr >> 8;
+ opt[i++] = ouraddr;
+ }
+
+ sp->confid[IDX_IPCP] = ++sp->pp_seq;
+ sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
+}
+
+
+ /*
+ * Random miscellaneous functions.
+ */
+
/*
- * Process PPP control protocol timeouts.
+ * Flush interface queue.
*/
static void
-sppp_cp_timeout(void *arg)
+sppp_qflush(struct ifqueue *ifq)
{
- struct sppp *sp = (struct sppp*) arg;
- int s = splimp ();
+ struct mbuf *m, *n;
- sp->pp_flags &= ~PP_TIMO;
- if (! (sp->pp_if.if_flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) {
- splx (s);
- return;
+ n = ifq->ifq_head;
+ while ((m = n)) {
+ n = m->m_act;
+ m_freem (m);
}
- switch (sp->lcp.state) {
- case LCP_STATE_CLOSED:
- /* No ACK for Configure-Request, retry. */
- sppp_lcp_open (sp);
- break;
- case LCP_STATE_ACK_RCVD:
- /* ACK got, but no Configure-Request for peer, retry. */
- sppp_lcp_open (sp);
- sp->lcp.state = LCP_STATE_CLOSED;
- break;
- case LCP_STATE_ACK_SENT:
- /* ACK sent but no ACK for Configure-Request, retry. */
- sppp_lcp_open (sp);
- break;
- case LCP_STATE_OPENED:
- /* LCP is already OK, try IPCP. */
- switch (sp->ipcp.state) {
- case IPCP_STATE_CLOSED:
- /* No ACK for Configure-Request, retry. */
- sppp_ipcp_open (sp);
- break;
- case IPCP_STATE_ACK_RCVD:
- /* ACK got, but no Configure-Request for peer, retry. */
- sppp_ipcp_open (sp);
- sp->ipcp.state = IPCP_STATE_CLOSED;
- break;
- case IPCP_STATE_ACK_SENT:
- /* ACK sent but no ACK for Configure-Request, retry. */
- sppp_ipcp_open (sp);
- break;
- case IPCP_STATE_OPENED:
- /* IPCP is OK. */
- break;
+ ifq->ifq_head = 0;
+ ifq->ifq_tail = 0;
+ ifq->ifq_len = 0;
+}
+
+/*
+ * Send keepalive packets, every 10 seconds.
+ */
+static void
+sppp_keepalive(void *dummy)
+{
+ struct sppp *sp;
+ int s;
+
+ s = splimp();
+ for (sp=spppq; sp; sp=sp->pp_next) {
+ struct ifnet *ifp = &sp->pp_if;
+
+ /* Keepalive mode disabled or channel down? */
+ if (! (sp->pp_flags & PP_KEEPALIVE) ||
+ ! (ifp->if_flags & IFF_RUNNING))
+ continue;
+
+ /* No keepalive in PPP mode if LCP not opened yet. */
+ if (! (sp->pp_flags & PP_CISCO) &&
+ sp->pp_phase < PHASE_AUTHENTICATE)
+ continue;
+
+ if (sp->pp_alivecnt == MAXALIVECNT) {
+ /* No keepalive packets got. Stop the interface. */
+ printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
+ if_down (ifp);
+ sppp_qflush (&sp->pp_fastq);
+ if (! (sp->pp_flags & PP_CISCO)) {
+ /* XXX */
+ /* Shut down the PPP link. */
+ lcp.Down(sp);
+ /* Initiate negotiation. XXX */
+ lcp.Up(sp);
+ }
+ }
+ if (sp->pp_alivecnt <= MAXALIVECNT)
+ ++sp->pp_alivecnt;
+ if (sp->pp_flags & PP_CISCO)
+ sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
+ sp->pp_rseq);
+ else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
+ long nmagic = htonl (sp->lcp.magic);
+ sp->lcp.echoid = ++sp->pp_seq;
+ sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
+ sp->lcp.echoid, 4, &nmagic);
}
- break;
}
- splx (s);
+ splx(s);
+ timeout(sppp_keepalive, 0, hz * 10);
+}
+
+/*
+ * Get both IP addresses.
+ */
+static void
+sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst)
+{
+ struct ifnet *ifp = &sp->pp_if;
+ struct ifaddr *ifa;
+ struct sockaddr_in *si;
+ u_long ssrc, ddst;
+
+ ssrc = ddst = 0L;
+ /*
+ * Pick the first AF_INET address from the list,
+ * aliases don't make any sense on a p2p link anyway.
+ */
+ for (ifa = ifp->if_addrhead.tqh_first, si = 0;
+ ifa;
+ ifa = ifa->ifa_link.tqe_next)
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ si = (struct sockaddr_in *)ifa->ifa_addr;
+ if (si)
+ break;
+ }
+ if (ifa) {
+ if (si && si->sin_addr.s_addr)
+ ssrc = si->sin_addr.s_addr;
+
+ si = (struct sockaddr_in *)ifa->ifa_dstaddr;
+ if (si && si->sin_addr.s_addr)
+ ddst = si->sin_addr.s_addr;
+ }
+
+ if (dst) *dst = ntohl(ddst);
+ if (src) *src = ntohl(ssrc);
+}
+
+/*
+ * Set my IP address. Must be called at splimp.
+ */
+static void
+sppp_set_ip_addr(struct sppp *sp, u_long src)
+{
+ struct ifnet *ifp = &sp->pp_if;
+ struct ifaddr *ifa;
+ struct sockaddr_in *si;
+ u_long ssrc, ddst;
+
+ /*
+ * Pick the first AF_INET address from the list,
+ * aliases don't make any sense on a p2p link anyway.
+ */
+ for (ifa = ifp->if_addrhead.tqh_first, si = 0;
+ ifa;
+ ifa = ifa->ifa_link.tqe_next)
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ si = (struct sockaddr_in *)ifa->ifa_addr;
+ if (si)
+ break;
+ }
+ if (ifa && si)
+ si->sin_addr.s_addr = htonl(src);
}
static const char *
-sppp_lcp_type_name(u_char type)
+sppp_cp_type_name(u_char type)
{
static char buf [12];
switch (type) {
- case LCP_CONF_REQ: return ("conf-req");
- case LCP_CONF_ACK: return ("conf-ack");
- case LCP_CONF_NAK: return ("conf-nack");
- case LCP_CONF_REJ: return ("conf-rej");
- case LCP_TERM_REQ: return ("term-req");
- case LCP_TERM_ACK: return ("term-ack");
- case LCP_CODE_REJ: return ("code-rej");
- case LCP_PROTO_REJ: return ("proto-rej");
- case LCP_ECHO_REQ: return ("echo-req");
- case LCP_ECHO_REPLY: return ("echo-reply");
- case LCP_DISC_REQ: return ("discard-req");
+ case CONF_REQ: return ("conf-req");
+ case CONF_ACK: return ("conf-ack");
+ case CONF_NAK: return ("conf-nak");
+ case CONF_REJ: return ("conf-rej");
+ case TERM_REQ: return ("term-req");
+ case TERM_ACK: return ("term-ack");
+ case CODE_REJ: return ("code-rej");
+ case PROTO_REJ: return ("proto-rej");
+ case ECHO_REQ: return ("echo-req");
+ case ECHO_REPLY: return ("echo-reply");
+ case DISC_REQ: return ("discard-req");
}
sprintf (buf, "0x%x", type);
return (buf);
}
static const char *
-sppp_ipcp_type_name(u_char type)
+sppp_lcp_opt_name(u_char opt)
{
static char buf [12];
- switch (type) {
- case IPCP_CONF_REQ: return ("conf-req");
- case IPCP_CONF_ACK: return ("conf-ack");
- case IPCP_CONF_NAK: return ("conf-nack");
- case IPCP_CONF_REJ: return ("conf-rej");
- case IPCP_TERM_REQ: return ("term-req");
- case IPCP_TERM_ACK: return ("term-ack");
- case IPCP_CODE_REJ: return ("code-rej");
+ switch (opt) {
+ case LCP_OPT_MRU: return ("mru");
+ case LCP_OPT_ASYNC_MAP: return ("async-map");
+ case LCP_OPT_AUTH_PROTO: return ("auth-proto");
+ case LCP_OPT_QUAL_PROTO: return ("qual-proto");
+ case LCP_OPT_MAGIC: return ("magic");
+ case LCP_OPT_PROTO_COMP: return ("proto-comp");
+ case LCP_OPT_ADDR_COMP: return ("addr-comp");
}
- sprintf (buf, "0x%x", type);
+ sprintf (buf, "0x%x", opt);
return (buf);
}
+static const char *
+sppp_ipcp_opt_name(u_char opt)
+{
+ static char buf [12];
+ switch (opt) {
+ case IPCP_OPT_ADDRESSES: return ("addresses");
+ case IPCP_OPT_COMPRESSION: return ("compression");
+ case IPCP_OPT_ADDRESS: return ("address");
+ }
+ sprintf (buf, "0x%x", opt);
+ return (buf);
+}
+
+static const char *
+sppp_state_name(int state)
+{
+ switch (state) {
+ case STATE_INITIAL: return "initial";
+ case STATE_STARTING: return "starting";
+ case STATE_CLOSED: return "closed";
+ case STATE_STOPPED: return "stopped";
+ case STATE_CLOSING: return "closing";
+ case STATE_STOPPING: return "stopping";
+ case STATE_REQ_SENT: return "req-sent";
+ case STATE_ACK_RCVD: return "ack-rcvd";
+ case STATE_ACK_SENT: return "ack-sent";
+ case STATE_OPENED: return "opened";
+ }
+ return "illegal";
+}
+
+static const char *
+sppp_phase_name(enum ppp_phase phase)
+{
+ switch (phase) {
+ case PHASE_DEAD: return "dead";
+ case PHASE_ESTABLISH: return "establish";
+ case PHASE_TERMINATE: return "terminate";
+ case PHASE_AUTHENTICATE: return "authenticate";
+ case PHASE_NETWORK: return "network";
+ }
+ return "illegal";
+}
+
+static const char *
+sppp_proto_name(u_short proto)
+{
+ static char buf[12];
+ switch (proto) {
+ case PPP_LCP: return "lcp";
+ case PPP_IPCP: return "ipcp";
+ }
+ sprintf(buf, "0x%x", (unsigned)proto);
+ return buf;
+}
+
static void
sppp_print_bytes(u_char *p, u_short len)
{
@@ -1499,3 +2703,11 @@ sppp_print_bytes(u_char *p, u_short len)
while (--len > 0)
addlog("-%x", *p++);
}
+
+/*
+ * This file is large. Tell emacs to highlight it nevertheless.
+ *
+ * Local Variables:
+ * hilit-auto-highlight-maxout: 100000
+ * End:
+ */
OpenPOWER on IntegriCloud