if_spppsubr.c revision 25944
14910Swollman/*
24910Swollman * Synchronous PPP/Cisco link level subroutines.
34910Swollman * Keepalive protocol implemented in both Cisco and PPP modes.
44910Swollman *
54910Swollman * Copyright (C) 1994 Cronyx Ltd.
625944Sjoerg * Author: Serge Vakulenko, <vak@cronyx.ru>
74910Swollman *
825944Sjoerg * Heavily revamped to conform to RFC 1661.
925944Sjoerg * Copyright (C) 1997, Joerg Wunsch.
1025944Sjoerg *
114910Swollman * This software is distributed with NO WARRANTIES, not even the implied
124910Swollman * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
134910Swollman *
144910Swollman * Authors grant any other persons or organisations permission to use
154910Swollman * or modify this software as long as this message is kept with the software,
164910Swollman * all derivative works or modified versions.
174910Swollman *
1825944Sjoerg * From: Version 1.9, Wed Oct  4 18:58:15 MSK 1995
1916288Sgpalmer *
2025944Sjoerg * $Id: if_spppsubr.c,v 1.18 1997/05/11 10:04:24 joerg Exp $
214910Swollman */
224910Swollman
234910Swollman#include <sys/param.h>
244952Sbde#include <sys/systm.h>
254952Sbde#include <sys/kernel.h>
2624204Sbde#include <sys/sockio.h>
274910Swollman#include <sys/socket.h>
2825706Sjoerg#include <sys/syslog.h>
294910Swollman#include <sys/mbuf.h>
304910Swollman
314910Swollman#include <net/if.h>
324910Swollman#include <net/netisr.h>
334910Swollman#include <net/if_types.h>
344910Swollman
354910Swollman#ifdef INET
364910Swollman#include <netinet/in.h>
374910Swollman#include <netinet/in_systm.h>
384910Swollman#include <netinet/in_var.h>
394910Swollman#include <netinet/ip.h>
404910Swollman#include <netinet/tcp.h>
414910Swollman#include <netinet/if_ether.h>
424910Swollman#endif
434910Swollman
4411819Sjulian#ifdef IPX
4511819Sjulian#include <netipx/ipx.h>
4611819Sjulian#include <netipx/ipx_if.h>
4711819Sjulian#endif
4811819Sjulian
494910Swollman#ifdef NS
504910Swollman#include <netns/ns.h>
514910Swollman#include <netns/ns_if.h>
524910Swollman#endif
534910Swollman
544910Swollman#ifdef ISO
554910Swollman#include <netiso/argo_debug.h>
564910Swollman#include <netiso/iso.h>
574910Swollman#include <netiso/iso_var.h>
584910Swollman#include <netiso/iso_snpac.h>
594910Swollman#endif
604910Swollman
614910Swollman#include <net/if_sppp.h>
624910Swollman
634910Swollman#define MAXALIVECNT     3               /* max. alive packets */
644910Swollman
6525944Sjoerg/*
6625944Sjoerg * Interface flags that can be set in an ifconfig command.
6725944Sjoerg *
6825944Sjoerg * Setting link0 will cause the link to auto-dial only as packets
6925944Sjoerg * arrive to be sent.
7025944Sjoerg *
7125944Sjoerg * Setting link1 will make the link passive, i.e. it will be marked
7225944Sjoerg * as being administrative openable, but won't be opened to begin
7325944Sjoerg * with.  Incoming calls will be answered, or subsequent calls with
7425944Sjoerg * -link1 will cause the administrative open of the LCP layer.
7525944Sjoerg */
7625944Sjoerg
7725944Sjoerg#define IFF_AUTO	IFF_LINK0	/* auto-dial on output */
7825944Sjoerg#define IFF_PASSIVE	IFF_LINK1	/* wait passively for connection */
7925944Sjoerg
804910Swollman#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
814910Swollman#define PPP_UI          0x03            /* Unnumbered Information */
824910Swollman#define PPP_IP          0x0021          /* Internet Protocol */
834910Swollman#define PPP_ISO         0x0023          /* ISO OSI Protocol */
844910Swollman#define PPP_XNS         0x0025          /* Xerox NS Protocol */
8512495Speter#define PPP_IPX         0x002b          /* Novell IPX Protocol */
864910Swollman#define PPP_LCP         0xc021          /* Link Control Protocol */
874910Swollman#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
884910Swollman
8925944Sjoerg#define CONF_REQ	1		/* PPP configure request */
9025944Sjoerg#define CONF_ACK	2		/* PPP configure acknowledge */
9125944Sjoerg#define CONF_NAK	3		/* PPP configure negative ack */
9225944Sjoerg#define CONF_REJ	4		/* PPP configure reject */
9325944Sjoerg#define TERM_REQ	5		/* PPP terminate request */
9425944Sjoerg#define TERM_ACK	6		/* PPP terminate acknowledge */
9525944Sjoerg#define CODE_REJ	7		/* PPP code reject */
9625944Sjoerg#define PROTO_REJ	8		/* PPP protocol reject */
9725944Sjoerg#define ECHO_REQ	9		/* PPP echo request */
9825944Sjoerg#define ECHO_REPLY	10		/* PPP echo reply */
9925944Sjoerg#define DISC_REQ	11		/* PPP discard request */
1004910Swollman
1014910Swollman#define LCP_OPT_MRU             1       /* maximum receive unit */
1024910Swollman#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
1034910Swollman#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
1044910Swollman#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
1054910Swollman#define LCP_OPT_MAGIC           5       /* magic number */
1064910Swollman#define LCP_OPT_RESERVED        6       /* reserved */
1074910Swollman#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
1084910Swollman#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
1094910Swollman
11025944Sjoerg#define IPCP_OPT_ADDRESSES	1	/* both IP addresses; deprecated */
11125944Sjoerg#define IPCP_OPT_COMPRESSION	2	/* IP compression protocol (VJ) */
11225944Sjoerg#define IPCP_OPT_ADDRESS	3	/* local IP address */
1134910Swollman
1144910Swollman#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
1154910Swollman#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
1164910Swollman#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
1174910Swollman#define CISCO_ADDR_REQ          0       /* Cisco address request */
1184910Swollman#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
1194910Swollman#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
1204910Swollman
12125944Sjoerg/* states are named and numbered according to RFC 1661 */
12225944Sjoerg#define STATE_INITIAL	0
12325944Sjoerg#define STATE_STARTING	1
12425944Sjoerg#define STATE_CLOSED	2
12525944Sjoerg#define STATE_STOPPED	3
12625944Sjoerg#define STATE_CLOSING	4
12725944Sjoerg#define STATE_STOPPING	5
12825944Sjoerg#define STATE_REQ_SENT	6
12925944Sjoerg#define STATE_ACK_RCVD	7
13025944Sjoerg#define STATE_ACK_SENT	8
13125944Sjoerg#define STATE_OPENED	9
13225944Sjoerg
1334910Swollmanstruct ppp_header {
13411189Sjkh	u_char address;
13511189Sjkh	u_char control;
13611189Sjkh	u_short protocol;
1374910Swollman};
1384910Swollman#define PPP_HEADER_LEN          sizeof (struct ppp_header)
1394910Swollman
1404910Swollmanstruct lcp_header {
14111189Sjkh	u_char type;
14211189Sjkh	u_char ident;
14311189Sjkh	u_short len;
1444910Swollman};
1454910Swollman#define LCP_HEADER_LEN          sizeof (struct lcp_header)
1464910Swollman
1474910Swollmanstruct cisco_packet {
14811189Sjkh	u_long type;
14911189Sjkh	u_long par1;
15011189Sjkh	u_long par2;
15111189Sjkh	u_short rel;
15211189Sjkh	u_short time0;
15311189Sjkh	u_short time1;
1544910Swollman};
1554910Swollman#define CISCO_PACKET_LEN 18
1564910Swollman
15725944Sjoerg/*
15825944Sjoerg * We follow the spelling and capitalization of RFC 1661 here, to make
15925944Sjoerg * it easier comparing with the standard.  Please refer to this RFC in
16025944Sjoerg * case you can't make sense out of these abbreviation; it will also
16125944Sjoerg * explain the semantics related to the various events and actions.
16225944Sjoerg */
16325944Sjoergstruct cp {
16425944Sjoerg	u_short	proto;		/* PPP control protocol number */
16525944Sjoerg	u_char protoidx;	/* index into state table in struct sppp */
16625944Sjoerg	u_char flags;
16725944Sjoerg#define CP_LCP		0x01	/* this is the LCP */
16825944Sjoerg#define CP_AUTH		0x02	/* this is an authentication protocol */
16925944Sjoerg#define CP_NCP		0x04	/* this is a NCP */
17025944Sjoerg#define CP_QUAL		0x08	/* this is a quality reporting protocol */
17125944Sjoerg	const char *name;	/* name of this control protocol */
17225944Sjoerg	/* event handlers */
17325944Sjoerg	void	(*Up)(struct sppp *sp);
17425944Sjoerg	void	(*Down)(struct sppp *sp);
17525944Sjoerg	void	(*Open)(struct sppp *sp);
17625944Sjoerg	void	(*Close)(struct sppp *sp);
17725944Sjoerg	void	(*TO)(void *sp);
17825944Sjoerg	int	(*RCR)(struct sppp *sp, struct lcp_header *h, int len);
17925944Sjoerg	void	(*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len);
18025944Sjoerg	void	(*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len);
18125944Sjoerg	/* actions */
18225944Sjoerg	void	(*tlu)(struct sppp *sp);
18325944Sjoerg	void	(*tld)(struct sppp *sp);
18425944Sjoerg	void	(*tls)(struct sppp *sp);
18525944Sjoerg	void	(*tlf)(struct sppp *sp);
18625944Sjoerg	void	(*scr)(struct sppp *sp);
18725944Sjoerg};
18825944Sjoerg
18912820Sphkstatic struct sppp *spppq;
1904910Swollman
1914910Swollman/*
1924910Swollman * The following disgusting hack gets around the problem that IP TOS
1934910Swollman * can't be set yet.  We want to put "interactive" traffic on a high
1944910Swollman * priority queue.  To decide if traffic is interactive, we check that
1954910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
1964910Swollman */
19711189Sjkhstatic u_short interactive_ports[8] = {
1984910Swollman	0,	513,	0,	0,
1994910Swollman	0,	21,	0,	23,
2004910Swollman};
2014910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
2024910Swollman
20325944Sjoerg/* almost every function needs these */
20425944Sjoerg#define STDDCL							\
20525944Sjoerg	struct ifnet *ifp = &sp->pp_if;				\
20625944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG
20711189Sjkh
20825944Sjoergstatic int sppp_output(struct ifnet *ifp, struct mbuf *m,
20925944Sjoerg		       struct sockaddr *dst, struct rtentry *rt);
2104910Swollman
21125944Sjoergstatic void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2);
21225944Sjoergstatic void sppp_cisco_input(struct sppp *sp, struct mbuf *m);
21325944Sjoerg
21425944Sjoergstatic void sppp_cp_input(const struct cp *cp, struct sppp *sp,
21525944Sjoerg			  struct mbuf *m);
21625944Sjoergstatic void sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
21725944Sjoerg			 u_char ident, u_short len, void *data);
21825944Sjoergstatic void sppp_cp_timeout(void *arg);
21925944Sjoergstatic void sppp_cp_change_state(const struct cp *cp, struct sppp *sp,
22025944Sjoerg				 int newstate);
22125944Sjoerg
22225944Sjoergstatic void sppp_up_event(const struct cp *cp, struct sppp *sp);
22325944Sjoergstatic void sppp_down_event(const struct cp *cp, struct sppp *sp);
22425944Sjoergstatic void sppp_open_event(const struct cp *cp, struct sppp *sp);
22525944Sjoergstatic void sppp_close_event(const struct cp *cp, struct sppp *sp);
22625944Sjoergstatic void sppp_to_event(const struct cp *cp, struct sppp *sp);
22725944Sjoerg
22825944Sjoergstatic void sppp_lcp_init(struct sppp *sp);
22925944Sjoergstatic void sppp_lcp_up(struct sppp *sp);
23025944Sjoergstatic void sppp_lcp_down(struct sppp *sp);
23125944Sjoergstatic void sppp_lcp_open(struct sppp *sp);
23225944Sjoergstatic void sppp_lcp_close(struct sppp *sp);
23325944Sjoergstatic void sppp_lcp_TO(void *sp);
23425944Sjoergstatic int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
23525944Sjoergstatic void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
23625944Sjoergstatic void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
23725944Sjoergstatic void sppp_lcp_tlu(struct sppp *sp);
23825944Sjoergstatic void sppp_lcp_tld(struct sppp *sp);
23925944Sjoergstatic void sppp_lcp_tls(struct sppp *sp);
24025944Sjoergstatic void sppp_lcp_tlf(struct sppp *sp);
24125944Sjoergstatic void sppp_lcp_scr(struct sppp *sp);
24225944Sjoergstatic void sppp_lcp_check(struct sppp *sp);
24325944Sjoerg
24425944Sjoergstatic void sppp_ipcp_init(struct sppp *sp);
24525944Sjoergstatic void sppp_ipcp_up(struct sppp *sp);
24625944Sjoergstatic void sppp_ipcp_down(struct sppp *sp);
24725944Sjoergstatic void sppp_ipcp_open(struct sppp *sp);
24825944Sjoergstatic void sppp_ipcp_close(struct sppp *sp);
24925944Sjoergstatic void sppp_ipcp_TO(void *sp);
25025944Sjoergstatic int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
25125944Sjoergstatic void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
25225944Sjoergstatic void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
25325944Sjoergstatic void sppp_ipcp_tlu(struct sppp *sp);
25425944Sjoergstatic void sppp_ipcp_tld(struct sppp *sp);
25525944Sjoergstatic void sppp_ipcp_tls(struct sppp *sp);
25625944Sjoergstatic void sppp_ipcp_tlf(struct sppp *sp);
25725944Sjoergstatic void sppp_ipcp_scr(struct sppp *sp);
25825944Sjoerg
25925944Sjoergstatic const char *sppp_cp_type_name(u_char type);
26025944Sjoergstatic const char *sppp_lcp_opt_name(u_char opt);
26125944Sjoergstatic const char *sppp_ipcp_opt_name(u_char opt);
26225944Sjoergstatic const char *sppp_state_name(int state);
26325944Sjoergstatic const char *sppp_phase_name(enum ppp_phase phase);
26425944Sjoergstatic const char *sppp_proto_name(u_short proto);
26525944Sjoerg
26625944Sjoergstatic void sppp_keepalive(void *dummy);
26725944Sjoergstatic void sppp_qflush(struct ifqueue *ifq);
26825944Sjoerg
26925944Sjoergstatic void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst);
27025944Sjoergstatic void sppp_set_ip_addr(struct sppp *sp, u_long src);
27125944Sjoerg
27225944Sjoergstatic void sppp_print_bytes(u_char *p, u_short len);
27325944Sjoerg
27425944Sjoerg/* our control protocol descriptors */
27525944Sjoergconst struct cp lcp = {
27625944Sjoerg	PPP_LCP, IDX_LCP, CP_LCP, "lcp",
27725944Sjoerg	sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close,
27825944Sjoerg	sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak,
27925944Sjoerg	sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf,
28025944Sjoerg	sppp_lcp_scr
28125944Sjoerg};
28225944Sjoerg
28325944Sjoergconst struct cp ipcp = {
28425944Sjoerg	PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp",
28525944Sjoerg	sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close,
28625944Sjoerg	sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak,
28725944Sjoerg	sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf,
28825944Sjoerg	sppp_ipcp_scr
28925944Sjoerg};
29025944Sjoerg
29125944Sjoergconst struct cp *cps[IDX_COUNT] = {
29225944Sjoerg	&lcp,			/* IDX_LCP */
29325944Sjoerg	&ipcp,			/* IDX_IPCP */
29425944Sjoerg};
29525944Sjoerg
29625944Sjoerg
29725944Sjoerg/*
29825944Sjoerg * Exported functions, comprising our interface to the lower layer.
2994910Swollman */
3004910Swollman
3014910Swollman/*
3024910Swollman * Process the received packet.
3034910Swollman */
30425706Sjoergvoid
30525706Sjoergsppp_input(struct ifnet *ifp, struct mbuf *m)
3064910Swollman{
3074910Swollman	struct ppp_header *h;
3084910Swollman	struct ifqueue *inq = 0;
30911189Sjkh	int s;
31025944Sjoerg	struct sppp *sp = (struct sppp *)ifp;
31125944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
3124910Swollman
3134910Swollman	if (ifp->if_flags & IFF_UP)
3144910Swollman		/* Count received bytes, add FCS and one flag */
3154910Swollman		ifp->if_ibytes += m->m_pkthdr.len + 3;
3164910Swollman
3174910Swollman	if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
3184910Swollman		/* Too small packet, drop it. */
31925944Sjoerg		if (debug)
32025706Sjoerg			log(LOG_DEBUG,
32125706Sjoerg			    "%s%d: input packet is too small, %d bytes\n",
32225706Sjoerg			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
32325944Sjoerg	  drop:
32425944Sjoerg		++ifp->if_ierrors;
32525944Sjoerg		++ifp->if_iqdrops;
3264910Swollman		m_freem (m);
3274910Swollman		return;
3284910Swollman	}
3294910Swollman
3304910Swollman	/* Get PPP header. */
3314910Swollman	h = mtod (m, struct ppp_header*);
3324910Swollman	m_adj (m, PPP_HEADER_LEN);
3334910Swollman
3344910Swollman	switch (h->address) {
3354910Swollman	case PPP_ALLSTATIONS:
3364910Swollman		if (h->control != PPP_UI)
3374910Swollman			goto invalid;
33811189Sjkh		if (sp->pp_flags & PP_CISCO) {
33925944Sjoerg			if (debug)
34025706Sjoerg				log(LOG_DEBUG,
34125706Sjoerg				    "%s%d: PPP packet in Cisco mode "
34225706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
34325706Sjoerg				    ifp->if_name, ifp->if_unit,
34425706Sjoerg				    h->address, h->control, ntohs(h->protocol));
34511189Sjkh			goto drop;
34611189Sjkh		}
3474910Swollman		switch (ntohs (h->protocol)) {
3484910Swollman		default:
34925944Sjoerg			if (sp->state[IDX_LCP] == STATE_OPENED)
35025944Sjoerg				sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
35111189Sjkh					++sp->pp_seq, m->m_pkthdr.len + 2,
3524910Swollman					&h->protocol);
35325944Sjoerg			if (debug)
35425706Sjoerg				log(LOG_DEBUG,
35525706Sjoerg				    "%s%d: invalid input protocol "
35625706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
35725706Sjoerg				    ifp->if_name, ifp->if_unit,
35825706Sjoerg				    h->address, h->control, ntohs(h->protocol));
3594910Swollman			++ifp->if_noproto;
3604910Swollman			goto drop;
3614910Swollman		case PPP_LCP:
36225944Sjoerg			sppp_cp_input(&lcp, (struct sppp*)ifp, m);
3634910Swollman			m_freem (m);
3644910Swollman			return;
3654910Swollman#ifdef INET
3664910Swollman		case PPP_IPCP:
36725944Sjoerg			if (sp->pp_phase == PHASE_NETWORK)
36825944Sjoerg				sppp_cp_input(&ipcp, (struct sppp*) ifp, m);
3694910Swollman			m_freem (m);
3704910Swollman			return;
3714910Swollman		case PPP_IP:
37225944Sjoerg			if (sp->state[IDX_IPCP] == STATE_OPENED) {
3734910Swollman				schednetisr (NETISR_IP);
3744910Swollman				inq = &ipintrq;
3754910Swollman			}
3764910Swollman			break;
3774910Swollman#endif
37812495Speter#ifdef IPX
37912495Speter		case PPP_IPX:
38012495Speter			/* IPX IPXCP not implemented yet */
38125944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
38212495Speter				schednetisr (NETISR_IPX);
38312495Speter				inq = &ipxintrq;
38412495Speter			}
38512495Speter			break;
38612495Speter#endif
3874910Swollman#ifdef NS
3884910Swollman		case PPP_XNS:
3894910Swollman			/* XNS IDPCP not implemented yet */
39025944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
3914910Swollman				schednetisr (NETISR_NS);
3924910Swollman				inq = &nsintrq;
3934910Swollman			}
3944910Swollman			break;
3954910Swollman#endif
3964910Swollman#ifdef ISO
3974910Swollman		case PPP_ISO:
3984910Swollman			/* OSI NLCP not implemented yet */
39925944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
4004910Swollman				schednetisr (NETISR_ISO);
4014910Swollman				inq = &clnlintrq;
4024910Swollman			}
4034910Swollman			break;
4044910Swollman#endif
4054910Swollman		}
4064910Swollman		break;
4074910Swollman	case CISCO_MULTICAST:
4084910Swollman	case CISCO_UNICAST:
4094910Swollman		/* Don't check the control field here (RFC 1547). */
41011189Sjkh		if (! (sp->pp_flags & PP_CISCO)) {
41125944Sjoerg			if (debug)
41225706Sjoerg				log(LOG_DEBUG,
41325706Sjoerg				    "%s%d: Cisco packet in PPP mode "
41425706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
41525706Sjoerg				    ifp->if_name, ifp->if_unit,
41625706Sjoerg				    h->address, h->control, ntohs(h->protocol));
41711189Sjkh			goto drop;
41811189Sjkh		}
4194910Swollman		switch (ntohs (h->protocol)) {
4204910Swollman		default:
4214910Swollman			++ifp->if_noproto;
4224910Swollman			goto invalid;
4234910Swollman		case CISCO_KEEPALIVE:
4244910Swollman			sppp_cisco_input ((struct sppp*) ifp, m);
4254910Swollman			m_freem (m);
4264910Swollman			return;
4274910Swollman#ifdef INET
4284910Swollman		case ETHERTYPE_IP:
4294910Swollman			schednetisr (NETISR_IP);
4304910Swollman			inq = &ipintrq;
4314910Swollman			break;
4324910Swollman#endif
43312495Speter#ifdef IPX
43412495Speter		case ETHERTYPE_IPX:
43512495Speter			schednetisr (NETISR_IPX);
43612495Speter			inq = &ipxintrq;
43712495Speter			break;
43812495Speter#endif
4394910Swollman#ifdef NS
4404910Swollman		case ETHERTYPE_NS:
4414910Swollman			schednetisr (NETISR_NS);
4424910Swollman			inq = &nsintrq;
4434910Swollman			break;
4444910Swollman#endif
4454910Swollman		}
4464910Swollman		break;
44725944Sjoerg	default:        /* Invalid PPP packet. */
44825944Sjoerg	  invalid:
44925944Sjoerg		if (debug)
45025944Sjoerg			log(LOG_DEBUG,
45125944Sjoerg			    "%s%d: invalid input packet "
45225944Sjoerg			    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
45325944Sjoerg			    ifp->if_name, ifp->if_unit,
45425944Sjoerg			    h->address, h->control, ntohs(h->protocol));
45525944Sjoerg		goto drop;
4564910Swollman	}
4574910Swollman
4584910Swollman	if (! (ifp->if_flags & IFF_UP) || ! inq)
4594910Swollman		goto drop;
4604910Swollman
4614910Swollman	/* Check queue. */
46225944Sjoerg	s = splimp();
4634910Swollman	if (IF_QFULL (inq)) {
4644910Swollman		/* Queue overflow. */
46525944Sjoerg		IF_DROP(inq);
46625944Sjoerg		splx(s);
46725944Sjoerg		if (debug)
46825706Sjoerg			log(LOG_DEBUG, "%s%d: protocol queue overflow\n",
4694910Swollman				ifp->if_name, ifp->if_unit);
4704910Swollman		goto drop;
4714910Swollman	}
47225944Sjoerg	IF_ENQUEUE(inq, m);
47325944Sjoerg	splx(s);
4744910Swollman}
4754910Swollman
4764910Swollman/*
4774910Swollman * Enqueue transmit packet.
4784910Swollman */
47912820Sphkstatic int
48025706Sjoergsppp_output(struct ifnet *ifp, struct mbuf *m,
48125706Sjoerg	    struct sockaddr *dst, struct rtentry *rt)
4824910Swollman{
4834910Swollman	struct sppp *sp = (struct sppp*) ifp;
4844910Swollman	struct ppp_header *h;
4854910Swollman	struct ifqueue *ifq;
48625944Sjoerg	int s;
4874910Swollman
48825944Sjoerg	s = splimp();
48925944Sjoerg
49025944Sjoerg	if ((ifp->if_flags & IFF_UP) == 0 ||
49125944Sjoerg	    (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) {
4924910Swollman		m_freem (m);
4934910Swollman		splx (s);
4944910Swollman		return (ENETDOWN);
4954910Swollman	}
4964910Swollman
49725944Sjoerg	if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) {
49825944Sjoerg		/*
49925944Sjoerg		 * Interface is not yet running, but auto-dial.  Need
50025944Sjoerg		 * to start LCP for it.
50125944Sjoerg		 */
50225944Sjoerg		ifp->if_flags |= IFF_RUNNING;
50325944Sjoerg		splx(s);
50425944Sjoerg		lcp.Open(sp);
50525944Sjoerg		s = splimp();
50625944Sjoerg	}
50725944Sjoerg
5084910Swollman	ifq = &ifp->if_snd;
5094910Swollman#ifdef INET
5104910Swollman	/*
5114910Swollman	 * Put low delay, telnet, rlogin and ftp control packets
5124910Swollman	 * in front of the queue.
5134910Swollman	 */
51412436Speter	if (dst->sa_family == AF_INET) {
51512436Speter		struct ip *ip = mtod (m, struct ip*);
51612436Speter		struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
5174910Swollman
51812436Speter		if (! IF_QFULL (&sp->pp_fastq) &&
51912436Speter		    ((ip->ip_tos & IPTOS_LOWDELAY) ||
52012436Speter	    	    ip->ip_p == IPPROTO_TCP &&
52112436Speter	    	    m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) &&
52212436Speter	    	    (INTERACTIVE (ntohs (tcp->th_sport)) ||
52312436Speter	    	    INTERACTIVE (ntohs (tcp->th_dport)))))
52412436Speter			ifq = &sp->pp_fastq;
5254910Swollman	}
5264910Swollman#endif
5274910Swollman
5284910Swollman	/*
5294910Swollman	 * Prepend general data packet PPP header. For now, IP only.
5304910Swollman	 */
5314910Swollman	M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT);
5324910Swollman	if (! m) {
5334910Swollman		if (ifp->if_flags & IFF_DEBUG)
53425706Sjoerg			log(LOG_DEBUG, "%s%d: no memory for transmit header\n",
5354910Swollman				ifp->if_name, ifp->if_unit);
53625944Sjoerg		++ifp->if_oerrors;
5374910Swollman		splx (s);
5384910Swollman		return (ENOBUFS);
5394910Swollman	}
5404910Swollman	h = mtod (m, struct ppp_header*);
5414910Swollman	if (sp->pp_flags & PP_CISCO) {
5424910Swollman		h->address = CISCO_MULTICAST;        /* broadcast address */
5434910Swollman		h->control = 0;
5444910Swollman	} else {
5454910Swollman		h->address = PPP_ALLSTATIONS;        /* broadcast address */
5464910Swollman		h->control = PPP_UI;                 /* Unnumbered Info */
5474910Swollman	}
5484910Swollman
5494910Swollman	switch (dst->sa_family) {
5504910Swollman#ifdef INET
5514910Swollman	case AF_INET:   /* Internet Protocol */
55211189Sjkh		if (sp->pp_flags & PP_CISCO)
55311189Sjkh			h->protocol = htons (ETHERTYPE_IP);
55425944Sjoerg		else if (sp->state[IDX_IPCP] == STATE_OPENED)
55511189Sjkh			h->protocol = htons (PPP_IP);
55611189Sjkh		else {
55711189Sjkh			m_freem (m);
55825944Sjoerg			++ifp->if_oerrors;
55911189Sjkh			splx (s);
56011189Sjkh			return (ENETDOWN);
56111189Sjkh		}
5624910Swollman		break;
5634910Swollman#endif
5644910Swollman#ifdef NS
5654910Swollman	case AF_NS:     /* Xerox NS Protocol */
5664910Swollman		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
5674910Swollman			ETHERTYPE_NS : PPP_XNS);
5684910Swollman		break;
5694910Swollman#endif
57011819Sjulian#ifdef IPX
57112495Speter	case AF_IPX:     /* Novell IPX Protocol */
57211819Sjulian		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
57312495Speter			ETHERTYPE_IPX : PPP_IPX);
57411819Sjulian		break;
57511819Sjulian#endif
5764910Swollman#ifdef ISO
5774910Swollman	case AF_ISO:    /* ISO OSI Protocol */
5784910Swollman		if (sp->pp_flags & PP_CISCO)
5794910Swollman			goto nosupport;
5804910Swollman		h->protocol = htons (PPP_ISO);
5814910Swollman		break;
58212820Sphknosupport:
5834910Swollman#endif
5844910Swollman	default:
5854910Swollman		m_freem (m);
58625944Sjoerg		++ifp->if_oerrors;
5874910Swollman		splx (s);
5884910Swollman		return (EAFNOSUPPORT);
5894910Swollman	}
5904910Swollman
5914910Swollman	/*
5924910Swollman	 * Queue message on interface, and start output if interface
5934910Swollman	 * not yet active.
5944910Swollman	 */
5954910Swollman	if (IF_QFULL (ifq)) {
5964910Swollman		IF_DROP (&ifp->if_snd);
5974910Swollman		m_freem (m);
59825944Sjoerg		++ifp->if_oerrors;
5994910Swollman		splx (s);
6004910Swollman		return (ENOBUFS);
6014910Swollman	}
6024910Swollman	IF_ENQUEUE (ifq, m);
6034910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
6044910Swollman		(*ifp->if_start) (ifp);
6054910Swollman
6064910Swollman	/*
6074910Swollman	 * Count output packets and bytes.
6084910Swollman	 * The packet length includes header, FCS and 1 flag,
6094910Swollman	 * according to RFC 1333.
6104910Swollman	 */
6114910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
6124910Swollman	splx (s);
6134910Swollman	return (0);
6144910Swollman}
6154910Swollman
61625706Sjoergvoid
61725706Sjoergsppp_attach(struct ifnet *ifp)
6184910Swollman{
6194910Swollman	struct sppp *sp = (struct sppp*) ifp;
6204910Swollman
6214910Swollman	/* Initialize keepalive handler. */
6224910Swollman	if (! spppq)
62311189Sjkh		timeout (sppp_keepalive, 0, hz * 10);
6244910Swollman
6254910Swollman	/* Insert new entry into the keepalive list. */
6264910Swollman	sp->pp_next = spppq;
6274910Swollman	spppq = sp;
6284910Swollman
6294910Swollman	sp->pp_if.if_type = IFT_PPP;
6304910Swollman	sp->pp_if.if_output = sppp_output;
6314910Swollman	sp->pp_fastq.ifq_maxlen = 32;
6324910Swollman	sp->pp_loopcnt = 0;
6334910Swollman	sp->pp_alivecnt = 0;
63411189Sjkh	sp->pp_seq = 0;
6354910Swollman	sp->pp_rseq = 0;
63625944Sjoerg	sp->pp_phase = PHASE_DEAD;
63725944Sjoerg	sp->pp_up = lcp.Up;
63825944Sjoerg	sp->pp_down = lcp.Down;
63925944Sjoerg
64025944Sjoerg	sppp_lcp_init(sp);
64125944Sjoerg	sppp_ipcp_init(sp);
6424910Swollman}
6434910Swollman
64412820Sphkvoid
64525706Sjoergsppp_detach(struct ifnet *ifp)
6464910Swollman{
6474910Swollman	struct sppp **q, *p, *sp = (struct sppp*) ifp;
64825944Sjoerg	int i;
6494910Swollman
6504910Swollman	/* Remove the entry from the keepalive list. */
6514910Swollman	for (q = &spppq; (p = *q); q = &p->pp_next)
6524910Swollman		if (p == sp) {
6534910Swollman			*q = p->pp_next;
6544910Swollman			break;
6554910Swollman		}
6564910Swollman
6574910Swollman	/* Stop keepalive handler. */
6584910Swollman	if (! spppq)
65911189Sjkh		untimeout (sppp_keepalive, 0);
66025944Sjoerg
66125944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
66225944Sjoerg		untimeout((cps[i])->TO, (void *)sp);
6634910Swollman}
6644910Swollman
6654910Swollman/*
6664910Swollman * Flush the interface output queue.
6674910Swollman */
66825706Sjoergvoid
66925706Sjoergsppp_flush(struct ifnet *ifp)
6704910Swollman{
6714910Swollman	struct sppp *sp = (struct sppp*) ifp;
6724910Swollman
67325944Sjoerg	sppp_qflush (&sp->pp_if.if_snd);
67425944Sjoerg	sppp_qflush (&sp->pp_fastq);
6754910Swollman}
6764910Swollman
6774910Swollman/*
67811189Sjkh * Check if the output queue is empty.
67911189Sjkh */
68012820Sphkint
68125706Sjoergsppp_isempty(struct ifnet *ifp)
68211189Sjkh{
68311189Sjkh	struct sppp *sp = (struct sppp*) ifp;
68425944Sjoerg	int empty, s;
68511189Sjkh
68625944Sjoerg	s = splimp();
68711189Sjkh	empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head;
68825944Sjoerg	splx(s);
68911189Sjkh	return (empty);
69011189Sjkh}
69111189Sjkh
69211189Sjkh/*
6934910Swollman * Get next packet to send.
6944910Swollman */
69525706Sjoergstruct mbuf *
69625706Sjoergsppp_dequeue(struct ifnet *ifp)
6974910Swollman{
6984910Swollman	struct sppp *sp = (struct sppp*) ifp;
6994910Swollman	struct mbuf *m;
70025944Sjoerg	int s;
7014910Swollman
70225944Sjoerg	s = splimp();
7034910Swollman	IF_DEQUEUE (&sp->pp_fastq, m);
7044910Swollman	if (! m)
7054910Swollman		IF_DEQUEUE (&sp->pp_if.if_snd, m);
7064910Swollman	splx (s);
7074910Swollman	return (m);
7084910Swollman}
7094910Swollman
7104910Swollman/*
71125944Sjoerg * Process an ioctl request.  Called on low priority level.
7124910Swollman */
71325944Sjoergint
71425944Sjoergsppp_ioctl(struct ifnet *ifp, int cmd, void *data)
7154910Swollman{
71625944Sjoerg	struct ifreq *ifr = (struct ifreq*) data;
71725944Sjoerg	struct sppp *sp = (struct sppp*) ifp;
71825944Sjoerg	int s, going_up, going_down, newmode;
7194910Swollman
72025944Sjoerg	s = splimp();
72125944Sjoerg	switch (cmd) {
72225944Sjoerg	case SIOCAIFADDR:
72325944Sjoerg	case SIOCSIFDSTADDR:
72425944Sjoerg		break;
7254910Swollman
72625944Sjoerg	case SIOCSIFADDR:
72725944Sjoerg		if_up(ifp);
72825944Sjoerg		/* fall through... */
72911189Sjkh
73025944Sjoerg	case SIOCSIFFLAGS:
73125944Sjoerg		going_up = ifp->if_flags & IFF_UP &&
73225944Sjoerg			(ifp->if_flags & IFF_RUNNING) == 0;
73325944Sjoerg		going_down = (ifp->if_flags & IFF_UP) == 0 &&
73425944Sjoerg			ifp->if_flags & IFF_RUNNING;
73525944Sjoerg		newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE);
73625944Sjoerg		if (newmode == (IFF_AUTO | IFF_PASSIVE)) {
73725944Sjoerg			/* sanity */
73825944Sjoerg			newmode = IFF_PASSIVE;
73925944Sjoerg			ifp->if_flags &= ~IFF_AUTO;
7404910Swollman		}
7414910Swollman
74225944Sjoerg		if (going_up || going_down)
74325944Sjoerg			lcp.Close(sp);
74425944Sjoerg		if (going_up && newmode == 0) {
74525944Sjoerg			/* neither auto-dial nor passive */
74625944Sjoerg			ifp->if_flags |= IFF_RUNNING;
74725944Sjoerg			if (!(sp->pp_flags & PP_CISCO))
74825944Sjoerg				lcp.Open(sp);
74925944Sjoerg		} else if (going_down)
75025944Sjoerg			ifp->if_flags &= ~IFF_RUNNING;
7514910Swollman
7524910Swollman		break;
75311189Sjkh
75425944Sjoerg#ifdef SIOCSIFMTU
75525944Sjoerg#ifndef ifr_mtu
75625944Sjoerg#define ifr_mtu ifr_metric
75725944Sjoerg#endif
75825944Sjoerg	case SIOCSIFMTU:
75925944Sjoerg		if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru)
76025944Sjoerg			return (EINVAL);
76125944Sjoerg		ifp->if_mtu = ifr->ifr_mtu;
7624910Swollman		break;
76325944Sjoerg#endif
76425944Sjoerg#ifdef SLIOCSETMTU
76525944Sjoerg	case SLIOCSETMTU:
76625944Sjoerg		if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru)
76725944Sjoerg			return (EINVAL);
76825944Sjoerg		ifp->if_mtu = *(short*)data;
7694910Swollman		break;
77025944Sjoerg#endif
77125944Sjoerg#ifdef SIOCGIFMTU
77225944Sjoerg	case SIOCGIFMTU:
77325944Sjoerg		ifr->ifr_mtu = ifp->if_mtu;
77411189Sjkh		break;
77525944Sjoerg#endif
77625944Sjoerg#ifdef SLIOCGETMTU
77725944Sjoerg	case SLIOCGETMTU:
77825944Sjoerg		*(short*)data = ifp->if_mtu;
7794910Swollman		break;
78025944Sjoerg#endif
78125944Sjoerg	case SIOCADDMULTI:
78225944Sjoerg	case SIOCDELMULTI:
7834910Swollman		break;
78411189Sjkh
78525944Sjoerg	default:
78625944Sjoerg		splx(s);
78725944Sjoerg		return (ENOTTY);
7884910Swollman	}
78925944Sjoerg	splx(s);
79025944Sjoerg	return (0);
7914910Swollman}
7924910Swollman
79325944Sjoerg
79425944Sjoerg/*
79525944Sjoerg * Cisco framing implementation.
79625944Sjoerg */
79725944Sjoerg
7984910Swollman/*
7994910Swollman * Handle incoming Cisco keepalive protocol packets.
8004910Swollman */
80112820Sphkstatic void
80225706Sjoergsppp_cisco_input(struct sppp *sp, struct mbuf *m)
8034910Swollman{
80425944Sjoerg	STDDCL;
8054910Swollman	struct cisco_packet *h;
8064910Swollman	struct ifaddr *ifa;
8074910Swollman
8084910Swollman	if (m->m_pkthdr.len != CISCO_PACKET_LEN) {
80925706Sjoerg		if (debug)
81025706Sjoerg			log(LOG_DEBUG,
81125706Sjoerg			    "%s%d: invalid cisco packet length: %d bytes\n",
81225706Sjoerg			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
8134910Swollman		return;
8144910Swollman	}
8154910Swollman	h = mtod (m, struct cisco_packet*);
81625706Sjoerg	if (debug)
81725706Sjoerg		log(LOG_DEBUG,
81825706Sjoerg		    "%s%d: cisco input: %d bytes "
81925706Sjoerg		    "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
82025706Sjoerg		    ifp->if_name, ifp->if_unit, m->m_pkthdr.len,
82125706Sjoerg		    ntohl (h->type), h->par1, h->par2, h->rel,
82225706Sjoerg		    h->time0, h->time1);
8234910Swollman	switch (ntohl (h->type)) {
8244910Swollman	default:
82525706Sjoerg		if (debug)
82625706Sjoerg			addlog("%s%d: unknown cisco packet type: 0x%lx\n",
82725706Sjoerg			       ifp->if_name, ifp->if_unit, ntohl (h->type));
8284910Swollman		break;
8294910Swollman	case CISCO_ADDR_REPLY:
8304910Swollman		/* Reply on address request, ignore */
8314910Swollman		break;
8324910Swollman	case CISCO_KEEPALIVE_REQ:
8334910Swollman		sp->pp_alivecnt = 0;
8344910Swollman		sp->pp_rseq = ntohl (h->par1);
8354910Swollman		if (sp->pp_seq == sp->pp_rseq) {
8364910Swollman			/* Local and remote sequence numbers are equal.
8374910Swollman			 * Probably, the line is in loopback mode. */
83811189Sjkh			if (sp->pp_loopcnt >= MAXALIVECNT) {
83911189Sjkh				printf ("%s%d: loopback\n",
84011189Sjkh					ifp->if_name, ifp->if_unit);
84111189Sjkh				sp->pp_loopcnt = 0;
84211189Sjkh				if (ifp->if_flags & IFF_UP) {
84311189Sjkh					if_down (ifp);
84425944Sjoerg					sppp_qflush (&sp->pp_fastq);
84511189Sjkh				}
84611189Sjkh			}
8474910Swollman			++sp->pp_loopcnt;
8484910Swollman
8494910Swollman			/* Generate new local sequence number */
8504910Swollman			sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
85111189Sjkh			break;
85211189Sjkh		}
8534910Swollman			sp->pp_loopcnt = 0;
85411189Sjkh		if (! (ifp->if_flags & IFF_UP) &&
85511189Sjkh		    (ifp->if_flags & IFF_RUNNING)) {
85611189Sjkh			ifp->if_flags |= IFF_UP;
85711189Sjkh			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
85811189Sjkh		}
8594910Swollman		break;
8604910Swollman	case CISCO_ADDR_REQ:
86120407Swollman		for (ifa=ifp->if_addrhead.tqh_first; ifa;
86220407Swollman		     ifa=ifa->ifa_link.tqe_next)
8634910Swollman			if (ifa->ifa_addr->sa_family == AF_INET)
8644910Swollman				break;
8654910Swollman		if (! ifa) {
86625706Sjoerg			if (debug)
86725706Sjoerg				addlog("%s%d: unknown address for cisco request\n",
86825706Sjoerg				       ifp->if_name, ifp->if_unit);
8694910Swollman			return;
8704910Swollman		}
8714910Swollman		sppp_cisco_send (sp, CISCO_ADDR_REPLY,
8724910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr),
8734910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr));
8744910Swollman		break;
8754910Swollman	}
8764910Swollman}
8774910Swollman
8784910Swollman/*
87925944Sjoerg * Send Cisco keepalive packet.
8804910Swollman */
88112820Sphkstatic void
88225944Sjoergsppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
88325944Sjoerg{
88425944Sjoerg	STDDCL;
88525944Sjoerg	struct ppp_header *h;
88625944Sjoerg	struct cisco_packet *ch;
88725944Sjoerg	struct mbuf *m;
88825944Sjoerg	u_long t = (time.tv_sec - boottime.tv_sec) * 1000;
88925944Sjoerg
89025944Sjoerg	MGETHDR (m, M_DONTWAIT, MT_DATA);
89125944Sjoerg	if (! m)
89225944Sjoerg		return;
89325944Sjoerg	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
89425944Sjoerg	m->m_pkthdr.rcvif = 0;
89525944Sjoerg
89625944Sjoerg	h = mtod (m, struct ppp_header*);
89725944Sjoerg	h->address = CISCO_MULTICAST;
89825944Sjoerg	h->control = 0;
89925944Sjoerg	h->protocol = htons (CISCO_KEEPALIVE);
90025944Sjoerg
90125944Sjoerg	ch = (struct cisco_packet*) (h + 1);
90225944Sjoerg	ch->type = htonl (type);
90325944Sjoerg	ch->par1 = htonl (par1);
90425944Sjoerg	ch->par2 = htonl (par2);
90525944Sjoerg	ch->rel = -1;
90625944Sjoerg	ch->time0 = htons ((u_short) (t >> 16));
90725944Sjoerg	ch->time1 = htons ((u_short) t);
90825944Sjoerg
90925944Sjoerg	if (debug)
91025944Sjoerg		log(LOG_DEBUG,
91125944Sjoerg		    "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
91225944Sjoerg			ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
91325944Sjoerg			ch->par2, ch->rel, ch->time0, ch->time1);
91425944Sjoerg
91525944Sjoerg	if (IF_QFULL (&sp->pp_fastq)) {
91625944Sjoerg		IF_DROP (&ifp->if_snd);
91725944Sjoerg		m_freem (m);
91825944Sjoerg	} else
91925944Sjoerg		IF_ENQUEUE (&sp->pp_fastq, m);
92025944Sjoerg	if (! (ifp->if_flags & IFF_OACTIVE))
92125944Sjoerg		(*ifp->if_start) (ifp);
92225944Sjoerg	ifp->if_obytes += m->m_pkthdr.len + 3;
92325944Sjoerg}
92425944Sjoerg
92525944Sjoerg/*
92625944Sjoerg * PPP protocol implementation.
92725944Sjoerg */
92825944Sjoerg
92925944Sjoerg/*
93025944Sjoerg * Send PPP control protocol packet.
93125944Sjoerg */
93225944Sjoergstatic void
93325706Sjoergsppp_cp_send(struct sppp *sp, u_short proto, u_char type,
93425706Sjoerg	     u_char ident, u_short len, void *data)
9354910Swollman{
93625944Sjoerg	STDDCL;
9374910Swollman	struct ppp_header *h;
9384910Swollman	struct lcp_header *lh;
9394910Swollman	struct mbuf *m;
9404910Swollman
9414910Swollman	if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
9424910Swollman		len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
9434910Swollman	MGETHDR (m, M_DONTWAIT, MT_DATA);
9444910Swollman	if (! m)
9454910Swollman		return;
9464910Swollman	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
9474910Swollman	m->m_pkthdr.rcvif = 0;
9484910Swollman
9494910Swollman	h = mtod (m, struct ppp_header*);
9504910Swollman	h->address = PPP_ALLSTATIONS;        /* broadcast address */
9514910Swollman	h->control = PPP_UI;                 /* Unnumbered Info */
9524910Swollman	h->protocol = htons (proto);         /* Link Control Protocol */
9534910Swollman
9544910Swollman	lh = (struct lcp_header*) (h + 1);
9554910Swollman	lh->type = type;
9564910Swollman	lh->ident = ident;
9574910Swollman	lh->len = htons (LCP_HEADER_LEN + len);
9584910Swollman	if (len)
9594910Swollman		bcopy (data, lh+1, len);
9604910Swollman
96125706Sjoerg	if (debug) {
96225944Sjoerg		log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d",
96325944Sjoerg		    ifp->if_name, ifp->if_unit,
96425944Sjoerg		    sppp_proto_name(proto),
96525944Sjoerg		    sppp_cp_type_name (lh->type), lh->ident,
96625944Sjoerg		    ntohs (lh->len));
9674910Swollman		if (len)
96811189Sjkh			sppp_print_bytes ((u_char*) (lh+1), len);
96925706Sjoerg		addlog(">\n");
9704910Swollman	}
9714910Swollman	if (IF_QFULL (&sp->pp_fastq)) {
9724910Swollman		IF_DROP (&ifp->if_snd);
9734910Swollman		m_freem (m);
97425944Sjoerg		++ifp->if_oerrors;
9754910Swollman	} else
9764910Swollman		IF_ENQUEUE (&sp->pp_fastq, m);
9774910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
9784910Swollman		(*ifp->if_start) (ifp);
9794910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
9804910Swollman}
9814910Swollman
9824910Swollman/*
98325944Sjoerg * Handle incoming PPP control protocol packets.
9844910Swollman */
98512820Sphkstatic void
98625944Sjoergsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
9874910Swollman{
98825944Sjoerg	STDDCL;
98925944Sjoerg	struct lcp_header *h;
99025944Sjoerg	int len = m->m_pkthdr.len;
99125944Sjoerg	int rv;
99225944Sjoerg	u_char *p;
9934910Swollman
99425944Sjoerg	if (len < 4) {
99525944Sjoerg		if (debug)
99625944Sjoerg			log(LOG_DEBUG,
99725944Sjoerg			    "%s%d: %s invalid packet length: %d bytes\n",
99825944Sjoerg			    ifp->if_name, ifp->if_unit, cp->name, len);
9994910Swollman		return;
100025944Sjoerg	}
100125944Sjoerg	h = mtod (m, struct lcp_header*);
100225944Sjoerg	if (debug) {
100325944Sjoerg		log(LOG_DEBUG,
100425944Sjoerg		    "%s%d: %s input(%s): <%s id=0x%x len=%d",
100525944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
100625944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
100725944Sjoerg		    sppp_cp_type_name (h->type), h->ident, ntohs (h->len));
100825944Sjoerg		if (len > 4)
100925944Sjoerg			sppp_print_bytes ((u_char*) (h+1), len-4);
101025944Sjoerg		addlog(">\n");
101125944Sjoerg	}
101225944Sjoerg	if (len > ntohs (h->len))
101325944Sjoerg		len = ntohs (h->len);
101425944Sjoerg	switch (h->type) {
101525944Sjoerg	case CONF_REQ:
101625944Sjoerg		if (len < 4) {
101725944Sjoerg			if (debug)
101825944Sjoerg				addlog("%s%d: %s invalid conf-req length %d\n",
101925944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
102025944Sjoerg				       len);
102125944Sjoerg			++ifp->if_ierrors;
102225944Sjoerg			break;
102325944Sjoerg		}
102425944Sjoerg		rv = (cp->RCR)(sp, h, len);
102525944Sjoerg		switch (sp->state[cp->protoidx]) {
102625944Sjoerg		case STATE_OPENED:
102725944Sjoerg			(cp->tld)(sp);
102825944Sjoerg			(cp->scr)(sp);
102925944Sjoerg			/* fall through... */
103025944Sjoerg		case STATE_ACK_SENT:
103125944Sjoerg		case STATE_REQ_SENT:
103225944Sjoerg			sppp_cp_change_state(cp, sp, rv?
103325944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
103425944Sjoerg			break;
103525944Sjoerg		case STATE_CLOSING:
103625944Sjoerg		case STATE_STOPPING:
103725944Sjoerg			break;
103825944Sjoerg		case STATE_STOPPED:
103925944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
104025944Sjoerg			(cp->scr)(sp);
104125944Sjoerg			sppp_cp_change_state(cp, sp, rv?
104225944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
104325944Sjoerg			break;
104425944Sjoerg		case STATE_CLOSED:
104525944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
104625944Sjoerg				     0, 0);
104725944Sjoerg			break;
104825944Sjoerg		case STATE_ACK_RCVD:
104925944Sjoerg			if (rv) {
105025944Sjoerg				sppp_cp_change_state(cp, sp, STATE_OPENED);
105125944Sjoerg				if (debug)
105225944Sjoerg					addlog("%s%d: %s tlu\n",
105325944Sjoerg					       ifp->if_name, ifp->if_unit,
105425944Sjoerg					       cp->name);
105525944Sjoerg				(cp->tlu)(sp);
105625944Sjoerg			} else
105725944Sjoerg				sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
105825944Sjoerg			break;
105925944Sjoerg		default:
106025944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
106125944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
106225944Sjoerg			       sppp_cp_type_name(h->type),
106325944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
106425944Sjoerg			++ifp->if_ierrors;
106525944Sjoerg		}
106625944Sjoerg		break;
106725944Sjoerg	case CONF_ACK:
106825944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
106925944Sjoerg			if (debug)
107025944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
107125944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
107225944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
107325944Sjoerg			++ifp->if_ierrors;
107425944Sjoerg			break;
107525944Sjoerg		}
107625944Sjoerg		switch (sp->state[cp->protoidx]) {
107725944Sjoerg		case STATE_CLOSED:
107825944Sjoerg		case STATE_STOPPED:
107925944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
108025944Sjoerg			break;
108125944Sjoerg		case STATE_CLOSING:
108225944Sjoerg		case STATE_STOPPING:
108325944Sjoerg			break;
108425944Sjoerg		case STATE_REQ_SENT:
108525944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
108625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
108725944Sjoerg			break;
108825944Sjoerg		case STATE_OPENED:
108925944Sjoerg			(cp->tld)(sp);
109025944Sjoerg			/* fall through */
109125944Sjoerg		case STATE_ACK_RCVD:
109225944Sjoerg			(cp->scr)(sp);
109325944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
109425944Sjoerg			break;
109525944Sjoerg		case STATE_ACK_SENT:
109625944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
109725944Sjoerg			sppp_cp_change_state(cp, sp, STATE_OPENED);
109825944Sjoerg			if (debug)
109925944Sjoerg				addlog("%s%d: %s tlu\n",
110025944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name);
110125944Sjoerg			(cp->tlu)(sp);
110225944Sjoerg			break;
110325944Sjoerg		default:
110425944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
110525944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
110625944Sjoerg			       sppp_cp_type_name(h->type),
110725944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
110825944Sjoerg			++ifp->if_ierrors;
110925944Sjoerg		}
111025944Sjoerg		break;
111125944Sjoerg	case CONF_NAK:
111225944Sjoerg	case CONF_REJ:
111325944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
111425944Sjoerg			if (debug)
111525944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
111625944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
111725944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
111825944Sjoerg			++ifp->if_ierrors;
111925944Sjoerg			break;
112025944Sjoerg		}
112125944Sjoerg		if (h->type == CONF_NAK)
112225944Sjoerg			(cp->RCN_nak)(sp, h, len);
112325944Sjoerg		else /* CONF_REJ */
112425944Sjoerg			(cp->RCN_rej)(sp, h, len);
11254910Swollman
112625944Sjoerg		switch (sp->state[cp->protoidx]) {
112725944Sjoerg		case STATE_CLOSED:
112825944Sjoerg		case STATE_STOPPED:
112925944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
113025944Sjoerg			break;
113125944Sjoerg		case STATE_REQ_SENT:
113225944Sjoerg		case STATE_ACK_SENT:
113325944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
113425944Sjoerg			(cp->scr)(sp);
113525944Sjoerg			break;
113625944Sjoerg		case STATE_OPENED:
113725944Sjoerg			(cp->tld)(sp);
113825944Sjoerg			/* fall through */
113925944Sjoerg		case STATE_ACK_RCVD:
114025944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_SENT);
114125944Sjoerg			(cp->scr)(sp);
114225944Sjoerg			break;
114325944Sjoerg		case STATE_CLOSING:
114425944Sjoerg		case STATE_STOPPING:
114525944Sjoerg			break;
114625944Sjoerg		default:
114725944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
114825944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
114925944Sjoerg			       sppp_cp_type_name(h->type),
115025944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
115125944Sjoerg			++ifp->if_ierrors;
115225944Sjoerg		}
115325944Sjoerg		break;
11544910Swollman
115525944Sjoerg	case TERM_REQ:
115625944Sjoerg		switch (sp->state[cp->protoidx]) {
115725944Sjoerg		case STATE_ACK_RCVD:
115825944Sjoerg		case STATE_ACK_SENT:
115925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
116025944Sjoerg			/* fall through */
116125944Sjoerg		case STATE_CLOSED:
116225944Sjoerg		case STATE_STOPPED:
116325944Sjoerg		case STATE_CLOSING:
116425944Sjoerg		case STATE_STOPPING:
116525944Sjoerg		case STATE_REQ_SENT:
116625944Sjoerg		  sta:
116725944Sjoerg			/* Send Terminate-Ack packet. */
116825944Sjoerg			if (debug)
116925944Sjoerg				log(LOG_DEBUG, "%s%d: %s send terminate-ack\n",
117025944Sjoerg				    ifp->if_name, ifp->if_unit, cp->name);
117125944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
117225944Sjoerg			break;
117325944Sjoerg		case STATE_OPENED:
117425944Sjoerg			(cp->tld)(sp);
117525944Sjoerg			sp->rst_counter[cp->protoidx] = 0;
117625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPING);
117725944Sjoerg			goto sta;
117825944Sjoerg			break;
117925944Sjoerg		default:
118025944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
118125944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
118225944Sjoerg			       sppp_cp_type_name(h->type),
118325944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
118425944Sjoerg			++ifp->if_ierrors;
118525944Sjoerg		}
118625944Sjoerg		break;
118725944Sjoerg	case TERM_ACK:
118825944Sjoerg		switch (sp->state[cp->protoidx]) {
118925944Sjoerg		case STATE_CLOSED:
119025944Sjoerg		case STATE_STOPPED:
119125944Sjoerg		case STATE_REQ_SENT:
119225944Sjoerg		case STATE_ACK_SENT:
119325944Sjoerg			break;
119425944Sjoerg		case STATE_CLOSING:
119525944Sjoerg			(cp->tlf)(sp);
119625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
119725944Sjoerg			break;
119825944Sjoerg		case STATE_STOPPING:
119925944Sjoerg			(cp->tlf)(sp);
120025944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
120125944Sjoerg			break;
120225944Sjoerg		case STATE_ACK_RCVD:
120325944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
120425944Sjoerg			break;
120525944Sjoerg		case STATE_OPENED:
120625944Sjoerg			(cp->tld)(sp);
120725944Sjoerg			(cp->scr)(sp);
120825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
120925944Sjoerg			break;
121025944Sjoerg		default:
121125944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
121225944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
121325944Sjoerg			       sppp_cp_type_name(h->type),
121425944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
121525944Sjoerg			++ifp->if_ierrors;
121625944Sjoerg		}
121725944Sjoerg		break;
121825944Sjoerg	case CODE_REJ:
121925944Sjoerg	case PROTO_REJ:
122025944Sjoerg		/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
122125944Sjoerg		switch (sp->state[cp->protoidx]) {
122225944Sjoerg		case STATE_CLOSED:
122325944Sjoerg		case STATE_STOPPED:
122425944Sjoerg		case STATE_REQ_SENT:
122525944Sjoerg		case STATE_ACK_SENT:
122625944Sjoerg		case STATE_CLOSING:
122725944Sjoerg		case STATE_STOPPING:
122825944Sjoerg		case STATE_OPENED:
122925944Sjoerg			break;
123025944Sjoerg		case STATE_ACK_RCVD:
123125944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
123225944Sjoerg			break;
123325944Sjoerg		default:
123425944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
123525944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
123625944Sjoerg			       sppp_cp_type_name(h->type),
123725944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
123825944Sjoerg			++ifp->if_ierrors;
123925944Sjoerg		}
124025944Sjoerg		break;
124125944Sjoerg	case DISC_REQ:
124225944Sjoerg		if (cp->proto != PPP_LCP)
124325944Sjoerg			goto illegal;
124425944Sjoerg		/* Discard the packet. */
124525944Sjoerg		break;
124625944Sjoerg	case ECHO_REQ:
124725944Sjoerg		if (cp->proto != PPP_LCP)
124825944Sjoerg			goto illegal;
124925944Sjoerg		if (sp->state[cp->protoidx] != STATE_OPENED) {
125025944Sjoerg			if (debug)
125125944Sjoerg				addlog("%s%d: lcp echo req but lcp closed\n",
125225944Sjoerg				       ifp->if_name, ifp->if_unit);
125325944Sjoerg			++ifp->if_ierrors;
125425944Sjoerg			break;
125525944Sjoerg		}
125625944Sjoerg		if (len < 8) {
125725944Sjoerg			if (debug)
125825944Sjoerg				addlog("%s%d: invalid lcp echo request "
125925944Sjoerg				       "packet length: %d bytes\n",
126025944Sjoerg				       ifp->if_name, ifp->if_unit, len);
126125944Sjoerg			break;
126225944Sjoerg		}
126325944Sjoerg		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
126425944Sjoerg			/* Line loopback mode detected. */
126525944Sjoerg			printf("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
126625944Sjoerg			if_down (ifp);
126725944Sjoerg			sppp_qflush (&sp->pp_fastq);
12684910Swollman
126925944Sjoerg			/* Shut down the PPP link. */
127025944Sjoerg			/* XXX */
127125944Sjoerg			lcp.Down(sp);
127225944Sjoerg			lcp.Up(sp);
127325944Sjoerg			break;
127425944Sjoerg		}
127525944Sjoerg		*(long*)(h+1) = htonl (sp->lcp.magic);
127625944Sjoerg		if (debug)
127725944Sjoerg			addlog("%s%d: got lcp echo req, sending echo rep\n",
127825944Sjoerg			       ifp->if_name, ifp->if_unit);
127925944Sjoerg		sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1);
128025944Sjoerg		break;
128125944Sjoerg	case ECHO_REPLY:
128225944Sjoerg		if (cp->proto != PPP_LCP)
128325944Sjoerg			goto illegal;
128425944Sjoerg		if (h->ident != sp->lcp.echoid) {
128525944Sjoerg			++ifp->if_ierrors;
128625944Sjoerg			break;
128725944Sjoerg		}
128825944Sjoerg		if (len < 8) {
128925944Sjoerg			if (debug)
129025944Sjoerg				addlog("%s%d: lcp invalid echo reply "
129125944Sjoerg				       "packet length: %d bytes\n",
129225944Sjoerg				       ifp->if_name, ifp->if_unit, len);
129325944Sjoerg			break;
129425944Sjoerg		}
129525944Sjoerg		if (debug)
129625944Sjoerg			addlog("%s%d: lcp got echo rep\n",
129725944Sjoerg			       ifp->if_name, ifp->if_unit);
129825944Sjoerg		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
129925944Sjoerg			sp->pp_alivecnt = 0;
130025944Sjoerg		break;
130125944Sjoerg	default:
130225944Sjoerg		/* Unknown packet type -- send Code-Reject packet. */
130325944Sjoerg	  illegal:
130425944Sjoerg		if (debug)
130525944Sjoerg			addlog("%s%d: %c send code-rej for 0x%x\n",
130625944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name, h->type);
130725944Sjoerg		sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq,
130825944Sjoerg			     m->m_pkthdr.len, h);
130925944Sjoerg		++ifp->if_ierrors;
131025944Sjoerg	}
13114910Swollman}
13124910Swollman
131325944Sjoerg
13144910Swollman/*
131525944Sjoerg * The generic part of all Up/Down/Open/Close/TO event handlers.
131625944Sjoerg * Basically, the state transition handling in the automaton.
13174910Swollman */
131825944Sjoergstatic void
131925944Sjoergsppp_up_event(const struct cp *cp, struct sppp *sp)
13204910Swollman{
132125944Sjoerg	STDDCL;
13224910Swollman
132325944Sjoerg	if (debug)
132425944Sjoerg		log(LOG_DEBUG, "%s%d: %s up(%s)\n",
132525944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
132625944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
132725944Sjoerg
132825944Sjoerg	switch (sp->state[cp->protoidx]) {
132925944Sjoerg	case STATE_INITIAL:
133025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
133125944Sjoerg		break;
133225944Sjoerg	case STATE_STARTING:
133325944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
133425944Sjoerg		(cp->scr)(sp);
133525944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
133625944Sjoerg		break;
13374910Swollman	default:
133825944Sjoerg		printf("%s%d: %s illegal up in state %s\n",
133925944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
134025944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
134125944Sjoerg	}
134225944Sjoerg}
13434910Swollman
134425944Sjoergstatic void
134525944Sjoergsppp_down_event(const struct cp *cp, struct sppp *sp)
134625944Sjoerg{
134725944Sjoerg	STDDCL;
134825944Sjoerg
134925944Sjoerg	if (debug)
135025944Sjoerg		log(LOG_DEBUG, "%s%d: %s down(%s)\n",
135125944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
135225944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
135325944Sjoerg
135425944Sjoerg	switch (sp->state[cp->protoidx]) {
135525944Sjoerg	case STATE_CLOSED:
135625944Sjoerg	case STATE_CLOSING:
135725944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
13584910Swollman		break;
135925944Sjoerg	case STATE_STOPPED:
136025944Sjoerg		(cp->tls)(sp);
136125944Sjoerg		/* fall through */
136225944Sjoerg	case STATE_STOPPING:
136325944Sjoerg	case STATE_REQ_SENT:
136425944Sjoerg	case STATE_ACK_RCVD:
136525944Sjoerg	case STATE_ACK_SENT:
136625944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
136725944Sjoerg		break;
136825944Sjoerg	case STATE_OPENED:
136925944Sjoerg		(cp->tld)(sp);
137025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
137125944Sjoerg		break;
137225944Sjoerg	default:
137325944Sjoerg		printf("%s%d: %s illegal down in state %s\n",
137425944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
137525944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
137625944Sjoerg	}
137725944Sjoerg}
13784910Swollman
137911189Sjkh
138025944Sjoergstatic void
138125944Sjoergsppp_open_event(const struct cp *cp, struct sppp *sp)
138225944Sjoerg{
138325944Sjoerg	STDDCL;
138425944Sjoerg
138525944Sjoerg	if (debug)
138625944Sjoerg		log(LOG_DEBUG, "%s%d: %s open(%s)\n",
138725944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
138825944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
138925944Sjoerg
139025944Sjoerg	switch (sp->state[cp->protoidx]) {
139125944Sjoerg	case STATE_INITIAL:
139225944Sjoerg		(cp->tls)(sp);
139325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
13944910Swollman		break;
139525944Sjoerg	case STATE_STARTING:
139625944Sjoerg		break;
139725944Sjoerg	case STATE_CLOSED:
139825944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
139925944Sjoerg		(cp->scr)(sp);
140025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
140125944Sjoerg		break;
140225944Sjoerg	case STATE_STOPPED:
140325944Sjoerg	case STATE_STOPPING:
140425944Sjoerg	case STATE_REQ_SENT:
140525944Sjoerg	case STATE_ACK_RCVD:
140625944Sjoerg	case STATE_ACK_SENT:
140725944Sjoerg	case STATE_OPENED:
140825944Sjoerg		break;
140925944Sjoerg	case STATE_CLOSING:
141025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STOPPING);
141125944Sjoerg		break;
141225944Sjoerg	}
141325944Sjoerg}
14144910Swollman
141525944Sjoerg
141625944Sjoergstatic void
141725944Sjoergsppp_close_event(const struct cp *cp, struct sppp *sp)
141825944Sjoerg{
141925944Sjoerg	STDDCL;
142025944Sjoerg
142125944Sjoerg	if (debug)
142225944Sjoerg		log(LOG_DEBUG, "%s%d: %s close(%s)\n",
142325944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
142425944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
142525944Sjoerg
142625944Sjoerg	switch (sp->state[cp->protoidx]) {
142725944Sjoerg	case STATE_INITIAL:
142825944Sjoerg	case STATE_CLOSED:
142925944Sjoerg	case STATE_CLOSING:
14304910Swollman		break;
143125944Sjoerg	case STATE_STARTING:
143225944Sjoerg		(cp->tlf)(sp);
143325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
14344910Swollman		break;
143525944Sjoerg	case STATE_STOPPED:
143625944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
14374910Swollman		break;
143825944Sjoerg	case STATE_STOPPING:
143925944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
14404910Swollman		break;
144125944Sjoerg	case STATE_OPENED:
144225944Sjoerg		(cp->tld)(sp);
144325944Sjoerg		/* fall through */
144425944Sjoerg	case STATE_REQ_SENT:
144525944Sjoerg	case STATE_ACK_RCVD:
144625944Sjoerg	case STATE_ACK_SENT:
144725944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
144825944Sjoerg		sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0);
144925944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
14504910Swollman		break;
14514910Swollman	}
14524910Swollman}
14534910Swollman
145425944Sjoergstatic void
145525944Sjoergsppp_to_event(const struct cp *cp, struct sppp *sp)
145625944Sjoerg{
145725944Sjoerg	STDDCL;
145825944Sjoerg	int s;
145925944Sjoerg
146025944Sjoerg	s = splimp();
146125944Sjoerg	if (debug)
146225944Sjoerg		log(LOG_DEBUG, "%s%d: %s TO(%s) rst_counter = %d\n",
146325944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
146425944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
146525944Sjoerg		    sp->rst_counter[cp->protoidx]);
146625944Sjoerg
146725944Sjoerg	if (--sp->rst_counter[cp->protoidx] < 0)
146825944Sjoerg		/* TO- event */
146925944Sjoerg		switch (sp->state[cp->protoidx]) {
147025944Sjoerg		case STATE_CLOSING:
147125944Sjoerg			(cp->tlf)(sp);
147225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
147325944Sjoerg			break;
147425944Sjoerg		case STATE_STOPPING:
147525944Sjoerg			(cp->tlf)(sp);
147625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
147725944Sjoerg			break;
147825944Sjoerg		case STATE_REQ_SENT:
147925944Sjoerg		case STATE_ACK_RCVD:
148025944Sjoerg		case STATE_ACK_SENT:
148125944Sjoerg			(cp->tlf)(sp);
148225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
148325944Sjoerg			break;
148425944Sjoerg		}
148525944Sjoerg	else
148625944Sjoerg		/* TO+ event */
148725944Sjoerg		switch (sp->state[cp->protoidx]) {
148825944Sjoerg		case STATE_CLOSING:
148925944Sjoerg		case STATE_STOPPING:
149025944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
149125944Sjoerg				     0, 0);
149225944Sjoerg			timeout(cp->TO, (void *)sp, sp->lcp.timeout);
149325944Sjoerg			break;
149425944Sjoerg		case STATE_REQ_SENT:
149525944Sjoerg		case STATE_ACK_RCVD:
149625944Sjoerg			(cp->scr)(sp);
149725944Sjoerg			/* sppp_cp_change_state() will restart the timer */
149825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
149925944Sjoerg			break;
150025944Sjoerg		case STATE_ACK_SENT:
150125944Sjoerg			(cp->scr)(sp);
150225944Sjoerg			timeout(cp->TO, (void *)sp, sp->lcp.timeout);
150325944Sjoerg			break;
150425944Sjoerg		}
150525944Sjoerg
150625944Sjoerg	splx(s);
150725944Sjoerg}
150825944Sjoerg
150911189Sjkh/*
151025944Sjoerg * Change the state of a control protocol in the state automaton.
151125944Sjoerg * Takes care of starting/stopping the restart timer.
151211189Sjkh */
151325944Sjoergvoid
151425944Sjoergsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
151525944Sjoerg{
151625944Sjoerg	sp->state[cp->protoidx] = newstate;
151725944Sjoerg
151825944Sjoerg	untimeout(cp->TO, (void *)sp);
151925944Sjoerg	switch (newstate) {
152025944Sjoerg	case STATE_INITIAL:
152125944Sjoerg	case STATE_STARTING:
152225944Sjoerg	case STATE_CLOSED:
152325944Sjoerg	case STATE_STOPPED:
152425944Sjoerg	case STATE_OPENED:
152525944Sjoerg		break;
152625944Sjoerg	case STATE_CLOSING:
152725944Sjoerg	case STATE_STOPPING:
152825944Sjoerg	case STATE_REQ_SENT:
152925944Sjoerg	case STATE_ACK_RCVD:
153025944Sjoerg	case STATE_ACK_SENT:
153125944Sjoerg		timeout(cp->TO, (void *)sp, sp->lcp.timeout);
153225944Sjoerg		break;
153325944Sjoerg	}
153425944Sjoerg}
153525944Sjoerg/*
153625944Sjoerg *--------------------------------------------------------------------------*
153725944Sjoerg *                                                                          *
153825944Sjoerg *                         The LCP implementation.                          *
153925944Sjoerg *                                                                          *
154025944Sjoerg *--------------------------------------------------------------------------*
154125944Sjoerg */
154225944Sjoergstatic void
154325944Sjoergsppp_lcp_init(struct sppp *sp)
154425944Sjoerg{
154525944Sjoerg	sp->lcp.opts = (1 << LCP_OPT_MAGIC);
154625944Sjoerg	sp->lcp.magic = 0;
154725944Sjoerg	sp->state[IDX_LCP] = STATE_INITIAL;
154825944Sjoerg	sp->fail_counter[IDX_LCP] = 0;
154925944Sjoerg	sp->lcp.protos = 0;
155025944Sjoerg	sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
155125944Sjoerg
155225944Sjoerg	/*
155325944Sjoerg	 * Initialize counters and timeout values.  Note that we don't
155425944Sjoerg	 * use the 3 seconds suggested in RFC 1661 since we are likely
155525944Sjoerg	 * running on a fast link.  XXX We should probably implement
155625944Sjoerg	 * the exponential backoff option.  Note that these values are
155725944Sjoerg	 * relevant for all control protocols, not just LCP only.
155825944Sjoerg	 */
155925944Sjoerg	sp->lcp.timeout = 1 * hz;
156025944Sjoerg	sp->lcp.max_terminate = 2;
156125944Sjoerg	sp->lcp.max_configure = 10;
156225944Sjoerg	sp->lcp.max_failure = 10;
156325944Sjoerg}
156425944Sjoerg
156525944Sjoergstatic void
156625944Sjoergsppp_lcp_up(struct sppp *sp)
156725944Sjoerg{
156825944Sjoerg	STDDCL;
156925944Sjoerg
157025944Sjoerg	/*
157125944Sjoerg	 * If this interface is passive or dial-on-demand, it means
157225944Sjoerg	 * we've got in incoming call.  Activate the interface.
157325944Sjoerg	 */
157425944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) {
157525944Sjoerg		if (debug)
157625944Sjoerg			log(LOG_DEBUG,
157725944Sjoerg			    "%s%d: Up event (incoming call)\n",
157825944Sjoerg			    ifp->if_name, ifp->if_unit);
157925944Sjoerg		ifp->if_flags |= IFF_RUNNING;
158025944Sjoerg		lcp.Open(sp);
158125944Sjoerg	}
158225944Sjoerg
158325944Sjoerg	sppp_up_event(&lcp, sp);
158425944Sjoerg}
158525944Sjoerg
158625944Sjoergstatic void
158725944Sjoergsppp_lcp_down(struct sppp *sp)
158825944Sjoerg{
158925944Sjoerg	STDDCL;
159025944Sjoerg
159125944Sjoerg	sppp_down_event(&lcp, sp);
159225944Sjoerg
159325944Sjoerg	/*
159425944Sjoerg	 * If this is neither a dial-on-demand nor a passive
159525944Sjoerg	 * interface, simulate an ``ifconfig down'' action, so the
159625944Sjoerg	 * administrator can force a redial by another ``ifconfig
159725944Sjoerg	 * up''.  XXX For leased line operation, should we immediately
159825944Sjoerg	 * try to reopen the connection here?
159925944Sjoerg	 */
160025944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
160125944Sjoerg		log(LOG_INFO,
160225944Sjoerg		    "%s%d: Down event (carrier loss), taking interface down.\n",
160325944Sjoerg		    ifp->if_name, ifp->if_unit);
160425944Sjoerg		if_down(ifp);
160525944Sjoerg	} else {
160625944Sjoerg		if (debug)
160725944Sjoerg			log(LOG_DEBUG,
160825944Sjoerg			    "%s%d: Down event (carrier loss)\n",
160925944Sjoerg			    ifp->if_name, ifp->if_unit);
161025944Sjoerg	}
161125944Sjoerg	lcp.Close(sp);
161225944Sjoerg	ifp->if_flags &= ~IFF_RUNNING;
161325944Sjoerg}
161425944Sjoerg
161525944Sjoergstatic void
161625944Sjoergsppp_lcp_open(struct sppp *sp)
161725944Sjoerg{
161825944Sjoerg	sppp_open_event(&lcp, sp);
161925944Sjoerg}
162025944Sjoerg
162125944Sjoergstatic void
162225944Sjoergsppp_lcp_close(struct sppp *sp)
162325944Sjoerg{
162425944Sjoerg	sppp_close_event(&lcp, sp);
162525944Sjoerg}
162625944Sjoerg
162725944Sjoergstatic void
162825944Sjoergsppp_lcp_TO(void *cookie)
162925944Sjoerg{
163025944Sjoerg	sppp_to_event(&lcp, (struct sppp *)cookie);
163125944Sjoerg}
163225944Sjoerg
163325944Sjoerg/*
163425944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
163525944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
163625944Sjoerg * caused action scn.  (The return value is used to make the state
163725944Sjoerg * transition decision in the state automaton.)
163825944Sjoerg */
163912820Sphkstatic int
164025944Sjoergsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
16414910Swollman{
164225944Sjoerg	STDDCL;
164311189Sjkh	u_char *buf, *r, *p;
164425944Sjoerg	int origlen, rlen;
164525944Sjoerg	u_long nmagic;
16464910Swollman
164711189Sjkh	len -= 4;
164825944Sjoerg	origlen = len;
164911189Sjkh	buf = r = malloc (len, M_TEMP, M_NOWAIT);
165011189Sjkh	if (! buf)
165111189Sjkh		return (0);
16524910Swollman
165325706Sjoerg	if (debug)
165425944Sjoerg		log(LOG_DEBUG, "%s%d: lcp parse opts: ",
165525944Sjoerg		    ifp->if_name, ifp->if_unit);
165625706Sjoerg
165725944Sjoerg	/* pass 1: check for things that need to be rejected */
165811189Sjkh	p = (void*) (h+1);
165911189Sjkh	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
166025944Sjoerg		if (debug)
166125944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
166211189Sjkh		switch (*p) {
166311189Sjkh		case LCP_OPT_MAGIC:
166425944Sjoerg			/* Magic number. */
166525944Sjoerg			/* fall through, both are same length */
166625944Sjoerg		case LCP_OPT_ASYNC_MAP:
166725944Sjoerg			/* Async control character map. */
166825944Sjoerg			if (len >= 6 || p[1] == 6)
166925944Sjoerg				continue;
167025944Sjoerg			if (debug)
167125944Sjoerg				addlog("[invalid] ");
167225944Sjoerg			break;
167325944Sjoerg		case LCP_OPT_MRU:
167425944Sjoerg			/* Maximum receive unit. */
167525944Sjoerg			if (len >= 4 && p[1] == 4)
167625944Sjoerg				continue;
167725944Sjoerg			if (debug)
167825944Sjoerg				addlog("[invalid] ");
167925944Sjoerg			break;
168025944Sjoerg		default:
168125944Sjoerg			/* Others not supported. */
168225944Sjoerg			if (debug)
168325944Sjoerg				addlog("[rej] ");
168425944Sjoerg			break;
168525944Sjoerg		}
168625944Sjoerg		/* Add the option to rejected list. */
168725944Sjoerg		bcopy (p, r, p[1]);
168825944Sjoerg		r += p[1];
168925944Sjoerg		rlen += p[1];
169025944Sjoerg	}
169125944Sjoerg	if (rlen) {
169225944Sjoerg		if (debug)
169325944Sjoerg			addlog(" send conf-rej\n");
169425944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
169525944Sjoerg		return 0;
169625944Sjoerg	} else if (debug)
169725944Sjoerg		addlog("\n");
169825944Sjoerg
169925944Sjoerg	/*
170025944Sjoerg	 * pass 2: check for option values that are unacceptable and
170125944Sjoerg	 * thus require to be nak'ed.
170225944Sjoerg	 */
170325944Sjoerg	if (debug)
170425944Sjoerg		addlog("%s%d: lcp parse opt values: ",
170525944Sjoerg		       ifp->if_name, ifp->if_unit);
170625944Sjoerg
170725944Sjoerg	p = (void*) (h+1);
170825944Sjoerg	len = origlen;
170925944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
171025944Sjoerg		if (debug)
171125944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
171225944Sjoerg		switch (*p) {
171325944Sjoerg		case LCP_OPT_MAGIC:
171411189Sjkh			/* Magic number -- extract. */
171525944Sjoerg			nmagic = (u_long)p[2] << 24 |
171625944Sjoerg				(u_long)p[3] << 16 | p[4] << 8 | p[5];
171725944Sjoerg			if (nmagic != sp->lcp.magic) {
171825706Sjoerg				if (debug)
171925944Sjoerg					addlog("0x%x ", nmagic);
172011189Sjkh				continue;
172111189Sjkh			}
172225944Sjoerg			/*
172325944Sjoerg			 * Local and remote magics equal -- loopback?
172425944Sjoerg			 */
172525944Sjoerg			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
172625944Sjoerg				printf ("\n%s%d: loopback\n",
172725944Sjoerg					ifp->if_name, ifp->if_unit);
172825944Sjoerg				sp->pp_loopcnt = 0;
172925944Sjoerg				if (ifp->if_flags & IFF_UP) {
173025944Sjoerg					if_down(ifp);
173125944Sjoerg					sppp_qflush(&sp->pp_fastq);
173225944Sjoerg					/* XXX ? */
173325944Sjoerg					lcp.Down(sp);
173425944Sjoerg					lcp.Up(sp);
173525944Sjoerg				}
173625944Sjoerg			} else if (debug)
173725944Sjoerg				addlog("[glitch] ");
173825944Sjoerg			++sp->pp_loopcnt;
173925944Sjoerg			/*
174025944Sjoerg			 * We negate our magic here, and NAK it.  If
174125944Sjoerg			 * we see it later in an NAK packet, we
174225944Sjoerg			 * suggest a new one.
174325944Sjoerg			 */
174425944Sjoerg			nmagic = ~sp->lcp.magic;
174525944Sjoerg			/* Gonna NAK it. */
174625944Sjoerg			p[2] = nmagic >> 24;
174725944Sjoerg			p[3] = nmagic >> 16;
174825944Sjoerg			p[4] = nmagic >> 8;
174925944Sjoerg			p[5] = nmagic;
175011189Sjkh			break;
175125944Sjoerg
175211189Sjkh		case LCP_OPT_ASYNC_MAP:
175311189Sjkh			/* Async control character map -- check to be zero. */
175425944Sjoerg			if (! p[2] && ! p[3] && ! p[4] && ! p[5]) {
175525706Sjoerg				if (debug)
175625944Sjoerg					addlog("[empty] ");
175711189Sjkh				continue;
175825706Sjoerg			}
175925706Sjoerg			if (debug)
176025944Sjoerg				addlog("[non-empty] ");
176125944Sjoerg			/* suggest a zero one */
176225944Sjoerg			p[2] = p[3] = p[4] = p[5] = 0;
176311189Sjkh			break;
176425944Sjoerg
176511189Sjkh		case LCP_OPT_MRU:
176625944Sjoerg			/*
176725944Sjoerg			 * Maximum receive unit.  Always agreeable,
176825944Sjoerg			 * but ignored by now.
176925944Sjoerg			 */
177025944Sjoerg			sp->lcp.their_mru = p[2] * 256 + p[3];
177125706Sjoerg			if (debug)
177225944Sjoerg				addlog("%d ", sp->lcp.their_mru);
177311189Sjkh			continue;
177411189Sjkh		}
177525944Sjoerg		/* Add the option to nak'ed list. */
177625706Sjoerg		bcopy (p, r, p[1]);
177725706Sjoerg		r += p[1];
177811189Sjkh		rlen += p[1];
177912436Speter	}
178025706Sjoerg	if (rlen) {
178125706Sjoerg		if (debug)
178225944Sjoerg			addlog(" send conf-nak\n");
178325944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
178425944Sjoerg		return 0;
178525944Sjoerg	} else {
178625944Sjoerg		if (debug)
178725944Sjoerg			addlog(" send conf-ack\n");
178825944Sjoerg		sp->pp_loopcnt = 0;
178925944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_ACK,
179025944Sjoerg			      h->ident, origlen, h+1);
179125944Sjoerg	}
179225944Sjoerg
179311189Sjkh	free (buf, M_TEMP);
179411189Sjkh	return (rlen == 0);
17954910Swollman}
17964910Swollman
179725944Sjoerg/*
179825944Sjoerg * Analyze the LCP Configure-Reject option list, and adjust our
179925944Sjoerg * negotiation.
180025944Sjoerg */
180112820Sphkstatic void
180225944Sjoergsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
18034910Swollman{
180425944Sjoerg	STDDCL;
180525944Sjoerg	u_char *buf, *p;
18064910Swollman
180725944Sjoerg	len -= 4;
180825944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
180925944Sjoerg	if (!buf)
18104910Swollman		return;
181125944Sjoerg
181225944Sjoerg	if (debug)
181325944Sjoerg		log(LOG_DEBUG, "%s%d: lcp rej opts: ",
181425944Sjoerg		    ifp->if_name, ifp->if_unit);
181525944Sjoerg
181625944Sjoerg	p = (void*) (h+1);
181725944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
181825944Sjoerg		if (debug)
181925944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
182025944Sjoerg		switch (*p) {
182125944Sjoerg		case LCP_OPT_MAGIC:
182225944Sjoerg			/* Magic number -- can't use it, use 0 */
182325944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC);
182425944Sjoerg			sp->lcp.magic = 0;
182525944Sjoerg			break;
182625944Sjoerg		case LCP_OPT_MRU:
182725944Sjoerg			/*
182825944Sjoerg			 * Should not be rejected anyway, since we only
182925944Sjoerg			 * negotiate a MRU if explicitly requested by
183025944Sjoerg			 * peer.
183125944Sjoerg			 */
183225944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
183325944Sjoerg			break;
183425944Sjoerg		}
18354910Swollman	}
183625944Sjoerg	if (debug)
183725944Sjoerg		addlog("\n");
183825944Sjoerg	free (buf, M_TEMP);
183925944Sjoerg	return;
184025944Sjoerg}
184125944Sjoerg
184225944Sjoerg/*
184325944Sjoerg * Analyze the LCP Configure-NAK option list, and adjust our
184425944Sjoerg * negotiation.
184525944Sjoerg */
184625944Sjoergstatic void
184725944Sjoergsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
184825944Sjoerg{
184925944Sjoerg	STDDCL;
185025944Sjoerg	u_char *buf, *p;
185125944Sjoerg	u_long magic;
185225944Sjoerg
185325944Sjoerg	len -= 4;
185425944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
185525944Sjoerg	if (!buf)
185625944Sjoerg		return;
185725944Sjoerg
185825944Sjoerg	if (debug)
185925944Sjoerg		log(LOG_DEBUG, "%s%d: lcp nak opts: ",
186025944Sjoerg		    ifp->if_name, ifp->if_unit);
186125944Sjoerg
186225944Sjoerg	p = (void*) (h+1);
186325944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
186425706Sjoerg		if (debug)
186525944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
186625944Sjoerg		switch (*p) {
186725944Sjoerg		case LCP_OPT_MAGIC:
186825944Sjoerg			/* Magic number -- renegotiate */
186925944Sjoerg			if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
187025944Sjoerg			    len >= 6 && p[1] == 6) {
187125944Sjoerg				magic = (u_long)p[2] << 24 |
187225944Sjoerg					(u_long)p[3] << 16 | p[4] << 8 | p[5];
187325944Sjoerg				/*
187425944Sjoerg				 * If the remote magic is our negated one,
187525944Sjoerg				 * this looks like a loopback problem.
187625944Sjoerg				 * Suggest a new magic to make sure.
187725944Sjoerg				 */
187825944Sjoerg				if (magic == ~sp->lcp.magic) {
187925944Sjoerg					if (debug)
188025944Sjoerg						addlog("magic glitch ");
188125944Sjoerg					sp->lcp.magic += time.tv_sec + time.tv_usec;
188225944Sjoerg				} else {
188325944Sjoerg					sp->lcp.magic = magic;
188425944Sjoerg					if (debug)
188525944Sjoerg						addlog("%d ");
188625944Sjoerg				}
188725944Sjoerg			}
188825944Sjoerg			break;
188925944Sjoerg		case LCP_OPT_MRU:
189025944Sjoerg			/*
189125944Sjoerg			 * Peer wants to advise us to negotiate an MRU.
189225944Sjoerg			 * Agree on it if it's reasonable, or use
189325944Sjoerg			 * default otherwise.
189425944Sjoerg			 */
189525944Sjoerg			if (len >= 4 && p[1] == 4) {
189625944Sjoerg				u_int mru = p[2] * 256 + p[3];
189725944Sjoerg				if (debug)
189825944Sjoerg					addlog("%d ", mru);
189925944Sjoerg				if (mru < PP_MTU || mru > PP_MAX_MRU)
190025944Sjoerg					mru = PP_MTU;
190125944Sjoerg				sp->lcp.mru = mru;
190225944Sjoerg				sp->lcp.opts |= (1 << LCP_OPT_MRU);
190325944Sjoerg			}
190425944Sjoerg			break;
19054910Swollman		}
190625944Sjoerg	}
190725944Sjoerg	if (debug)
190825944Sjoerg		addlog("\n");
190925944Sjoerg	free (buf, M_TEMP);
191025944Sjoerg	return;
191125944Sjoerg}
191211189Sjkh
191325944Sjoergstatic void
191425944Sjoergsppp_lcp_tlu(struct sppp *sp)
191525944Sjoerg{
191625944Sjoerg	STDDCL;
191725944Sjoerg	int i;
191825944Sjoerg	u_long mask;
191925944Sjoerg
192025944Sjoerg	/* XXX ? */
192125944Sjoerg	if (! (ifp->if_flags & IFF_UP) &&
192225944Sjoerg	    (ifp->if_flags & IFF_RUNNING)) {
192325944Sjoerg		/* Coming out of loopback mode. */
192425944Sjoerg		if_up(ifp);
192525944Sjoerg		printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
192625944Sjoerg	}
192725944Sjoerg
192825944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
192925944Sjoerg		if ((cps[i])->flags & CP_QUAL)
193025944Sjoerg			(cps[i])->Open(sp);
193125944Sjoerg
193225944Sjoerg	if (/* require authentication XXX */ 0)
193325944Sjoerg		sp->pp_phase = PHASE_AUTHENTICATE;
193425944Sjoerg	else
193525944Sjoerg		sp->pp_phase = PHASE_NETWORK;
193625944Sjoerg
193725944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
193825944Sjoerg	    sppp_phase_name(sp->pp_phase));
193925944Sjoerg
194025944Sjoerg	if (sp->pp_phase == PHASE_AUTHENTICATE) {
194125944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
194225944Sjoerg			if ((cps[i])->flags & CP_AUTH)
194325944Sjoerg				(cps[i])->Open(sp);
194425944Sjoerg	} else {
194525944Sjoerg		/* Notify all NCPs. */
194625944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
194725944Sjoerg			if ((cps[i])->flags & CP_NCP)
194825944Sjoerg				(cps[i])->Open(sp);
194925944Sjoerg	}
195025944Sjoerg
195125944Sjoerg	/* Send Up events to all started protos. */
195225944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
195325944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0)
195425944Sjoerg			(cps[i])->Up(sp);
195525944Sjoerg
195625944Sjoerg	if (sp->pp_phase == PHASE_NETWORK)
195725944Sjoerg		/* if no NCP is starting, close down */
195825944Sjoerg		sppp_lcp_check(sp);
195925944Sjoerg}
196025944Sjoerg
196125944Sjoergstatic void
196225944Sjoergsppp_lcp_tld(struct sppp *sp)
196325944Sjoerg{
196425944Sjoerg	STDDCL;
196525944Sjoerg	int i;
196625944Sjoerg	u_long mask;
196725944Sjoerg
196825944Sjoerg	sp->pp_phase = PHASE_TERMINATE;
196925944Sjoerg
197025944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
197125944Sjoerg	    sppp_phase_name(sp->pp_phase));
197225944Sjoerg
197325944Sjoerg	/*
197425944Sjoerg	 * Take upper layers down.  We send the Down event first and
197525944Sjoerg	 * the Close second to prevent the upper layers from sending
197625944Sjoerg	 * ``a flurry of terminate-request packets'', as the RFC
197725944Sjoerg	 * describes it.
197825944Sjoerg	 */
197925944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
198025944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) {
198125944Sjoerg			(cps[i])->Down(sp);
198225944Sjoerg			(cps[i])->Close(sp);
198325944Sjoerg		}
198425944Sjoerg}
198525944Sjoerg
198625944Sjoergstatic void
198725944Sjoergsppp_lcp_tls(struct sppp *sp)
198825944Sjoerg{
198925944Sjoerg	STDDCL;
199025944Sjoerg
199125944Sjoerg	sp->pp_phase = PHASE_ESTABLISH;
199225944Sjoerg
199325944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
199425944Sjoerg	    sppp_phase_name(sp->pp_phase));
199525944Sjoerg
199625944Sjoerg	/* Notify lower layer if desired. */
199725944Sjoerg	if (sp->pp_tls)
199825944Sjoerg		(sp->pp_tls)(sp);
199925944Sjoerg}
200025944Sjoerg
200125944Sjoergstatic void
200225944Sjoergsppp_lcp_tlf(struct sppp *sp)
200325944Sjoerg{
200425944Sjoerg	STDDCL;
200525944Sjoerg
200625944Sjoerg	sp->pp_phase = PHASE_DEAD;
200725944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
200825944Sjoerg	    sppp_phase_name(sp->pp_phase));
200925944Sjoerg
201025944Sjoerg	/* Notify lower layer if desired. */
201125944Sjoerg	if (sp->pp_tlf)
201225944Sjoerg		(sp->pp_tlf)(sp);
201325944Sjoerg}
201425944Sjoerg
201525944Sjoergstatic void
201625944Sjoergsppp_lcp_scr(struct sppp *sp)
201725944Sjoerg{
201825944Sjoerg	char opt[6 /* magicnum */ + 4 /* mru */];
201925944Sjoerg	int i = 0;
202025944Sjoerg
202125944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
202225944Sjoerg		if (! sp->lcp.magic)
202325944Sjoerg			sp->lcp.magic = time.tv_sec + time.tv_usec;
202425944Sjoerg		opt[i++] = LCP_OPT_MAGIC;
202525944Sjoerg		opt[i++] = 6;
202625944Sjoerg		opt[i++] = sp->lcp.magic >> 24;
202725944Sjoerg		opt[i++] = sp->lcp.magic >> 16;
202825944Sjoerg		opt[i++] = sp->lcp.magic >> 8;
202925944Sjoerg		opt[i++] = sp->lcp.magic;
203025944Sjoerg	}
203125944Sjoerg
203225944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MRU)) {
203325944Sjoerg		opt[i++] = LCP_OPT_MRU;
203425944Sjoerg		opt[i++] = 4;
203525944Sjoerg		opt[i++] = sp->lcp.mru >> 8;
203625944Sjoerg		opt[i++] = sp->lcp.mru;
203725944Sjoerg	}
203825944Sjoerg
203925944Sjoerg	sp->confid[IDX_LCP] = ++sp->pp_seq;
204025944Sjoerg	sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
204125944Sjoerg}
204225944Sjoerg
204325944Sjoerg/*
204425944Sjoerg * Re-check the open NCPs and see if we should terminate the link.
204525944Sjoerg * Called by the NCPs during their tlf action handling.
204625944Sjoerg */
204725944Sjoergstatic void
204825944Sjoergsppp_lcp_check(struct sppp *sp)
204925944Sjoerg{
205025944Sjoerg	int i, mask;
205125944Sjoerg
205225944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
205325944Sjoerg		if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP)
205425944Sjoerg			return;
205525944Sjoerg	lcp.Close(sp);
205625944Sjoerg}
205725944Sjoerg/*
205825944Sjoerg *--------------------------------------------------------------------------*
205925944Sjoerg *                                                                          *
206025944Sjoerg *                        The IPCP implementation.                          *
206125944Sjoerg *                                                                          *
206225944Sjoerg *--------------------------------------------------------------------------*
206325944Sjoerg */
206425944Sjoerg
206525944Sjoergstatic void
206625944Sjoergsppp_ipcp_init(struct sppp *sp)
206725944Sjoerg{
206825944Sjoerg	sp->ipcp.opts = 0;
206925944Sjoerg	sp->ipcp.flags = 0;
207025944Sjoerg	sp->state[IDX_IPCP] = STATE_INITIAL;
207125944Sjoerg	sp->fail_counter[IDX_IPCP] = 0;
207225944Sjoerg}
207325944Sjoerg
207425944Sjoergstatic void
207525944Sjoergsppp_ipcp_up(struct sppp *sp)
207625944Sjoerg{
207725944Sjoerg	sppp_up_event(&ipcp, sp);
207825944Sjoerg}
207925944Sjoerg
208025944Sjoergstatic void
208125944Sjoergsppp_ipcp_down(struct sppp *sp)
208225944Sjoerg{
208325944Sjoerg	sppp_down_event(&ipcp, sp);
208425944Sjoerg}
208525944Sjoerg
208625944Sjoergstatic void
208725944Sjoergsppp_ipcp_open(struct sppp *sp)
208825944Sjoerg{
208925944Sjoerg	STDDCL;
209025944Sjoerg	u_long myaddr, hisaddr;
209125944Sjoerg
209225944Sjoerg	sppp_get_ip_addrs(sp, &myaddr, &hisaddr);
209325944Sjoerg	/*
209425944Sjoerg	 * If we don't have his address, this probably means our
209525944Sjoerg	 * interface doesn't want to talk IP at all.  (This could
209625944Sjoerg	 * be the case if somebody wants to speak only IPX, for
209725944Sjoerg	 * example.)  Don't open IPCP in this case.
209825944Sjoerg	 */
209925944Sjoerg	if (hisaddr == 0L) {
210025944Sjoerg		/* XXX this message should go away */
210125944Sjoerg		if (debug)
210225944Sjoerg			log(LOG_DEBUG, "%s%d: ipcp_open(): no IP interface\n",
210325944Sjoerg			    ifp->if_name, ifp->if_unit);
210425944Sjoerg		return;
210525944Sjoerg	}
210625944Sjoerg
210725944Sjoerg	if (myaddr == 0L) {
210825944Sjoerg		/*
210925944Sjoerg		 * I don't have an assigned address, so i need to
211025944Sjoerg		 * negotiate my address.
211125944Sjoerg		 */
211225944Sjoerg		sp->ipcp.flags |= IPCP_MYADDR_DYN;
211325944Sjoerg		sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
211425944Sjoerg	}
211525944Sjoerg	sppp_open_event(&ipcp, sp);
211625944Sjoerg}
211725944Sjoerg
211825944Sjoergstatic void
211925944Sjoergsppp_ipcp_close(struct sppp *sp)
212025944Sjoerg{
212125944Sjoerg	sppp_close_event(&ipcp, sp);
212225944Sjoerg	if (sp->ipcp.flags & IPCP_MYADDR_DYN)
212325944Sjoerg		/*
212425944Sjoerg		 * My address was dynamic, clear it again.
212525944Sjoerg		 */
212625944Sjoerg		sppp_set_ip_addr(sp, 0L);
212725944Sjoerg}
212825944Sjoerg
212925944Sjoergstatic void
213025944Sjoergsppp_ipcp_TO(void *cookie)
213125944Sjoerg{
213225944Sjoerg	sppp_to_event(&ipcp, (struct sppp *)cookie);
213325944Sjoerg}
213425944Sjoerg
213525944Sjoerg/*
213625944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
213725944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
213825944Sjoerg * caused action scn.  (The return value is used to make the state
213925944Sjoerg * transition decision in the state automaton.)
214025944Sjoerg */
214125944Sjoergstatic int
214225944Sjoergsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
214325944Sjoerg{
214425944Sjoerg	u_char *buf, *r, *p;
214525944Sjoerg	struct ifnet *ifp = &sp->pp_if;
214625944Sjoerg	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
214725944Sjoerg	u_long hisaddr, desiredaddr;
214825944Sjoerg
214925944Sjoerg	len -= 4;
215025944Sjoerg	origlen = len;
215125944Sjoerg	/*
215225944Sjoerg	 * Make sure to allocate a buf that can at least hold a
215325944Sjoerg	 * conf-nak with an `address' option.  We might need it below.
215425944Sjoerg	 */
215525944Sjoerg	buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
215625944Sjoerg	if (! buf)
215725944Sjoerg		return (0);
215825944Sjoerg
215925944Sjoerg	/* pass 1: see if we can recognize them */
216025944Sjoerg	if (debug)
216125944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp parse opts: ",
216225944Sjoerg		    ifp->if_name, ifp->if_unit);
216325944Sjoerg	p = (void*) (h+1);
216425944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
216525944Sjoerg		if (debug)
216625944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
216725944Sjoerg		switch (*p) {
216825944Sjoerg#ifdef notyet
216925944Sjoerg		case IPCP_OPT_COMPRESSION:
217025944Sjoerg			if (len >= 6 && p[1] >= 6) {
217125944Sjoerg				/* correctly formed compress option */
217225944Sjoerg				continue;
217311189Sjkh			}
217425706Sjoerg			if (debug)
217525944Sjoerg				addlog("[invalid] ");
217625944Sjoerg			break;
217725944Sjoerg#endif
217825944Sjoerg		case IPCP_OPT_ADDRESS:
217925944Sjoerg			if (len >= 6 && p[1] == 6) {
218025944Sjoerg				/* correctly formed address option */
218125944Sjoerg				continue;
218225944Sjoerg			}
218325706Sjoerg			if (debug)
218425944Sjoerg				addlog("[invalid] ");
218511189Sjkh			break;
218625944Sjoerg		default:
218725944Sjoerg			/* Others not supported. */
218825944Sjoerg			if (debug)
218925944Sjoerg				addlog("[rej] ");
21904910Swollman			break;
21914910Swollman		}
219225944Sjoerg		/* Add the option to rejected list. */
219325944Sjoerg		bcopy (p, r, p[1]);
219425944Sjoerg		r += p[1];
219525944Sjoerg		rlen += p[1];
219625944Sjoerg	}
219725944Sjoerg	if (rlen) {
219825944Sjoerg		if (debug)
219925944Sjoerg			addlog(" send conf-rej\n");
220025944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf);
220125944Sjoerg		return 0;
220225944Sjoerg	} else if (debug)
220325944Sjoerg		addlog("\n");
220425944Sjoerg
220525944Sjoerg	/* pass 2: parse option values */
220625944Sjoerg	sppp_get_ip_addrs(sp, 0, &hisaddr);
220725944Sjoerg	if (debug)
220825944Sjoerg		addlog("%s%d: ipcp parse opt values: ", ifp->if_name, ifp->if_unit);
220925944Sjoerg	p = (void*) (h+1);
221025944Sjoerg	len = origlen;
221125944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
221225944Sjoerg		if (debug)
221325944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
221425944Sjoerg		switch (*p) {
221525944Sjoerg#ifdef notyet
221625944Sjoerg		case IPCP_OPT_COMPRESSION:
221725944Sjoerg			continue;
221825944Sjoerg#endif
221925944Sjoerg		case IPCP_OPT_ADDRESS:
222025944Sjoerg			desiredaddr = p[2] << 24 | p[3] << 16 |
222125944Sjoerg				p[4] << 8 | p[5];
222225944Sjoerg			if (desiredaddr == hisaddr) {
222325944Sjoerg				/*
222425944Sjoerg				 * Peer's address is same as our value,
222525944Sjoerg				 * this is agreeable.  Gonna conf-ack
222625944Sjoerg				 * it.
222725944Sjoerg				 */
222825944Sjoerg				if (debug)
222925944Sjoerg					addlog("0x%x [ack] ", hisaddr);
223025944Sjoerg				/* record that we've seen it already */
223125944Sjoerg				sp->ipcp.flags |= IPCP_HISADDR_SEEN;
223225944Sjoerg				continue;
223325944Sjoerg			}
223425944Sjoerg			/*
223525944Sjoerg			 * The address wasn't agreeable.  This is either
223625944Sjoerg			 * he sent us 0.0.0.0, asking to assign him an
223725944Sjoerg			 * address, or he send us another address not
223825944Sjoerg			 * matching our value.  Either case, we gonna
223925944Sjoerg			 * conf-nak it with our value.
224025944Sjoerg			 */
224125944Sjoerg			if (debug) {
224225944Sjoerg				if (desiredaddr == 0)
224325944Sjoerg					addlog("[addr requested] ");
224425944Sjoerg				else
224525944Sjoerg					addlog("0x%x [not agreed] ",
224625944Sjoerg					       desiredaddr);
224725944Sjoerg
224825944Sjoerg				p[2] = hisaddr >> 24;
224925944Sjoerg				p[3] = hisaddr >> 16;
225025944Sjoerg				p[4] = hisaddr >> 8;
225125944Sjoerg				p[5] = hisaddr;
225225944Sjoerg			}
225311189Sjkh			break;
225425706Sjoerg		}
225525944Sjoerg		/* Add the option to nak'ed list. */
225625944Sjoerg		bcopy (p, r, p[1]);
225725944Sjoerg		r += p[1];
225825944Sjoerg		rlen += p[1];
225925944Sjoerg	}
226025944Sjoerg
226125944Sjoerg	/*
226225944Sjoerg	 * If we are about to conf-ack the request, but haven't seen
226325944Sjoerg	 * his address so far, gonna conf-nak it instead, with the
226425944Sjoerg	 * `address' option present and our idea of his address being
226525944Sjoerg	 * filled in there, to request negotiation of both addresses.
226625944Sjoerg	 *
226725944Sjoerg	 * XXX This can result in an endless req - nak loop if peer
226825944Sjoerg	 * doesn't want to send us his address.  Q: What should we do
226925944Sjoerg	 * about it?  XXX  A: implement the max-failure counter.
227025944Sjoerg	 */
227125944Sjoerg	if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) {
227225944Sjoerg		buf[0] = IPCP_OPT_ADDRESS;
227325944Sjoerg		buf[1] = 6;
227425944Sjoerg		buf[2] = hisaddr >> 24;
227525944Sjoerg		buf[3] = hisaddr >> 16;
227625944Sjoerg		buf[4] = hisaddr >> 8;
227725944Sjoerg		buf[5] = hisaddr;
227825944Sjoerg		rlen = 6;
227925706Sjoerg		if (debug)
228025944Sjoerg			addlog("still need hisaddr ");
228125944Sjoerg	}
228225944Sjoerg
228325944Sjoerg	if (rlen) {
228425706Sjoerg		if (debug)
228525944Sjoerg			addlog(" send conf-nak\n");
228625944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf);
228725944Sjoerg	} else {
228825706Sjoerg		if (debug)
228925944Sjoerg			addlog(" send conf-ack\n");
229025944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_ACK,
229125944Sjoerg			      h->ident, origlen, h+1);
229225944Sjoerg	}
229325944Sjoerg
229425944Sjoerg	free (buf, M_TEMP);
229525944Sjoerg	return (rlen == 0);
229625944Sjoerg}
229725944Sjoerg
229825944Sjoerg/*
229925944Sjoerg * Analyze the IPCP Configure-Reject option list, and adjust our
230025944Sjoerg * negotiation.
230125944Sjoerg */
230225944Sjoergstatic void
230325944Sjoergsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
230425944Sjoerg{
230525944Sjoerg	u_char *buf, *p;
230625944Sjoerg	struct ifnet *ifp = &sp->pp_if;
230725944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
230825944Sjoerg
230925944Sjoerg	len -= 4;
231025944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
231125944Sjoerg	if (!buf)
231225944Sjoerg		return;
231325944Sjoerg
231425944Sjoerg	if (debug)
231525944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp rej opts: ",
231625944Sjoerg		    ifp->if_name, ifp->if_unit);
231725944Sjoerg
231825944Sjoerg	p = (void*) (h+1);
231925944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
232025706Sjoerg		if (debug)
232125944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
232225944Sjoerg		switch (*p) {
232325944Sjoerg		case IPCP_OPT_ADDRESS:
232425944Sjoerg			/*
232525944Sjoerg			 * Peer doesn't grok address option.  This is
232625944Sjoerg			 * bad.  XXX  Should we better give up here?
232725944Sjoerg			 */
232825944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS);
232925944Sjoerg			break;
233025944Sjoerg#ifdef notyet
233125944Sjoerg		case IPCP_OPT_COMPRESS:
233225944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS);
233325944Sjoerg			break;
233425944Sjoerg#endif
233525944Sjoerg		}
23364910Swollman	}
233725944Sjoerg	if (debug)
233825944Sjoerg		addlog("\n");
233925944Sjoerg	free (buf, M_TEMP);
234025944Sjoerg	return;
23414910Swollman}
23424910Swollman
234325944Sjoerg/*
234425944Sjoerg * Analyze the IPCP Configure-NAK option list, and adjust our
234525944Sjoerg * negotiation.
234625944Sjoerg */
234712820Sphkstatic void
234825944Sjoergsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
23494910Swollman{
235025944Sjoerg	u_char *buf, *p;
235125944Sjoerg	struct ifnet *ifp = &sp->pp_if;
235225944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
235325944Sjoerg	u_long wantaddr;
23544910Swollman
235525944Sjoerg	len -= 4;
235625944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
235725944Sjoerg	if (!buf)
235825944Sjoerg		return;
235925944Sjoerg
236025944Sjoerg	if (debug)
236125944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp nak opts: ",
236225944Sjoerg		    ifp->if_name, ifp->if_unit);
236325944Sjoerg
236425944Sjoerg	p = (void*) (h+1);
236525944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
236625944Sjoerg		if (debug)
236725944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
236825944Sjoerg		switch (*p) {
236925944Sjoerg		case IPCP_OPT_ADDRESS:
237025944Sjoerg			/*
237125944Sjoerg			 * Peer doesn't like our local IP address.  See
237225944Sjoerg			 * if we can do something for him.  We'll drop
237325944Sjoerg			 * him our address then.
237425944Sjoerg			 */
237525944Sjoerg			if (len >= 6 && p[1] == 6) {
237625944Sjoerg				wantaddr = p[2] << 24 | p[3] << 16 |
237725944Sjoerg					p[4] << 8 | p[5];
237825944Sjoerg				sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
237925944Sjoerg				if (debug)
238025944Sjoerg					addlog("[wantaddr 0x%x] ", wantaddr);
238125944Sjoerg				/*
238225944Sjoerg				 * When doing dynamic address assignment,
238325944Sjoerg				 * we accept his offer.  Otherwise, we
238425944Sjoerg				 * ignore it and thus continue to negotiate
238525944Sjoerg				 * our already existing value.
238625944Sjoerg				 */
238725944Sjoerg				if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
238825944Sjoerg					sppp_set_ip_addr(sp, wantaddr);
238925944Sjoerg					if (debug)
239025944Sjoerg						addlog("[agree] ");
239125944Sjoerg				}
239225944Sjoerg			}
239325944Sjoerg			break;
239425944Sjoerg#ifdef notyet
239525944Sjoerg		case IPCP_OPT_COMPRESS:
239625944Sjoerg			/*
239725944Sjoerg			 * Peer wants different compression parameters.
239825944Sjoerg			 */
239925944Sjoerg			break;
240025944Sjoerg#endif
240125944Sjoerg		}
240225944Sjoerg	}
240325944Sjoerg	if (debug)
240425944Sjoerg		addlog("\n");
240525944Sjoerg	free (buf, M_TEMP);
240625944Sjoerg	return;
24074910Swollman}
24084910Swollman
240912820Sphkstatic void
241025944Sjoergsppp_ipcp_tlu(struct sppp *sp)
24114910Swollman{
24124910Swollman}
24134910Swollman
241425944Sjoergstatic void
241525944Sjoergsppp_ipcp_tld(struct sppp *sp)
241625944Sjoerg{
241725944Sjoerg}
241825944Sjoerg
241925944Sjoergstatic void
242025944Sjoergsppp_ipcp_tls(struct sppp *sp)
242125944Sjoerg{
242225944Sjoerg	/* indicate to LCP that it must stay alive */
242325944Sjoerg	sp->lcp.protos |= (1 << IDX_IPCP);
242425944Sjoerg}
242525944Sjoerg
242625944Sjoergstatic void
242725944Sjoergsppp_ipcp_tlf(struct sppp *sp)
242825944Sjoerg{
242925944Sjoerg	/* we no longer need LCP */
243025944Sjoerg	sp->lcp.protos &= ~(1 << IDX_IPCP);
243125944Sjoerg	sppp_lcp_check(sp);
243225944Sjoerg}
243325944Sjoerg
243425944Sjoergstatic void
243525944Sjoergsppp_ipcp_scr(struct sppp *sp)
243625944Sjoerg{
243725944Sjoerg	char opt[6 /* compression */ + 6 /* address */];
243825944Sjoerg	u_long ouraddr;
243925944Sjoerg	int i = 0;
244025944Sjoerg
244125944Sjoerg#ifdef notyet
244225944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
244325944Sjoerg		opt[i++] = IPCP_OPT_COMPRESSION;
244425944Sjoerg		opt[i++] = 6;
244525944Sjoerg		opt[i++] = 0;	/* VJ header compression */
244625944Sjoerg		opt[i++] = 0x2d; /* VJ header compression */
244725944Sjoerg		opt[i++] = max_slot_id;
244825944Sjoerg		opt[i++] = comp_slot_id;
244925944Sjoerg	}
245025944Sjoerg#endif
245125944Sjoerg
245225944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
245325944Sjoerg		sppp_get_ip_addrs(sp, &ouraddr, 0);
245425944Sjoerg		opt[i++] = IPCP_OPT_ADDRESS;
245525944Sjoerg		opt[i++] = 6;
245625944Sjoerg		opt[i++] = ouraddr >> 24;
245725944Sjoerg		opt[i++] = ouraddr >> 16;
245825944Sjoerg		opt[i++] = ouraddr >> 8;
245925944Sjoerg		opt[i++] = ouraddr;
246025944Sjoerg	}
246125944Sjoerg
246225944Sjoerg	sp->confid[IDX_IPCP] = ++sp->pp_seq;
246325944Sjoerg	sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
246425944Sjoerg}
246525944Sjoerg
246625944Sjoerg
246725944Sjoerg/*
246825944Sjoerg * Random miscellaneous functions.
246925944Sjoerg */
247025944Sjoerg
24714910Swollman/*
247225944Sjoerg * Flush interface queue.
24734910Swollman */
247412820Sphkstatic void
247525944Sjoergsppp_qflush(struct ifqueue *ifq)
24764910Swollman{
247725944Sjoerg	struct mbuf *m, *n;
24784910Swollman
247925944Sjoerg	n = ifq->ifq_head;
248025944Sjoerg	while ((m = n)) {
248125944Sjoerg		n = m->m_act;
248225944Sjoerg		m_freem (m);
248311189Sjkh	}
248425944Sjoerg	ifq->ifq_head = 0;
248525944Sjoerg	ifq->ifq_tail = 0;
248625944Sjoerg	ifq->ifq_len = 0;
248725944Sjoerg}
248825944Sjoerg
248925944Sjoerg/*
249025944Sjoerg * Send keepalive packets, every 10 seconds.
249125944Sjoerg */
249225944Sjoergstatic void
249325944Sjoergsppp_keepalive(void *dummy)
249425944Sjoerg{
249525944Sjoerg	struct sppp *sp;
249625944Sjoerg	int s;
249725944Sjoerg
249825944Sjoerg	s = splimp();
249925944Sjoerg	for (sp=spppq; sp; sp=sp->pp_next) {
250025944Sjoerg		struct ifnet *ifp = &sp->pp_if;
250125944Sjoerg
250225944Sjoerg		/* Keepalive mode disabled or channel down? */
250325944Sjoerg		if (! (sp->pp_flags & PP_KEEPALIVE) ||
250425944Sjoerg		    ! (ifp->if_flags & IFF_RUNNING))
250525944Sjoerg			continue;
250625944Sjoerg
250725944Sjoerg		/* No keepalive in PPP mode if LCP not opened yet. */
250825944Sjoerg		if (! (sp->pp_flags & PP_CISCO) &&
250925944Sjoerg		    sp->pp_phase < PHASE_AUTHENTICATE)
251025944Sjoerg			continue;
251125944Sjoerg
251225944Sjoerg		if (sp->pp_alivecnt == MAXALIVECNT) {
251325944Sjoerg			/* No keepalive packets got.  Stop the interface. */
251425944Sjoerg			printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
251525944Sjoerg			if_down (ifp);
251625944Sjoerg			sppp_qflush (&sp->pp_fastq);
251725944Sjoerg			if (! (sp->pp_flags & PP_CISCO)) {
251825944Sjoerg				/* XXX */
251925944Sjoerg				/* Shut down the PPP link. */
252025944Sjoerg				lcp.Down(sp);
252125944Sjoerg				/* Initiate negotiation. XXX */
252225944Sjoerg				lcp.Up(sp);
252325944Sjoerg			}
25244910Swollman		}
252525944Sjoerg		if (sp->pp_alivecnt <= MAXALIVECNT)
252625944Sjoerg			++sp->pp_alivecnt;
252725944Sjoerg		if (sp->pp_flags & PP_CISCO)
252825944Sjoerg			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
252925944Sjoerg				sp->pp_rseq);
253025944Sjoerg		else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
253125944Sjoerg			long nmagic = htonl (sp->lcp.magic);
253225944Sjoerg			sp->lcp.echoid = ++sp->pp_seq;
253325944Sjoerg			sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
253425944Sjoerg				sp->lcp.echoid, 4, &nmagic);
253525944Sjoerg		}
25364910Swollman	}
253725944Sjoerg	splx(s);
253825944Sjoerg	timeout(sppp_keepalive, 0, hz * 10);
25394910Swollman}
25404910Swollman
254125944Sjoerg/*
254225944Sjoerg * Get both IP addresses.
254325944Sjoerg */
254425944Sjoergstatic void
254525944Sjoergsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst)
254625944Sjoerg{
254725944Sjoerg	struct ifnet *ifp = &sp->pp_if;
254825944Sjoerg	struct ifaddr *ifa;
254925944Sjoerg	struct sockaddr_in *si;
255025944Sjoerg	u_long ssrc, ddst;
255125944Sjoerg
255225944Sjoerg	ssrc = ddst = 0L;
255325944Sjoerg	/*
255425944Sjoerg	 * Pick the first AF_INET address from the list,
255525944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
255625944Sjoerg	 */
255725944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
255825944Sjoerg	     ifa;
255925944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
256025944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
256125944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
256225944Sjoerg			if (si)
256325944Sjoerg				break;
256425944Sjoerg		}
256525944Sjoerg	if (ifa) {
256625944Sjoerg		if (si && si->sin_addr.s_addr)
256725944Sjoerg			ssrc = si->sin_addr.s_addr;
256825944Sjoerg
256925944Sjoerg		si = (struct sockaddr_in *)ifa->ifa_dstaddr;
257025944Sjoerg		if (si && si->sin_addr.s_addr)
257125944Sjoerg			ddst = si->sin_addr.s_addr;
257225944Sjoerg	}
257325944Sjoerg
257425944Sjoerg	if (dst) *dst = ntohl(ddst);
257525944Sjoerg	if (src) *src = ntohl(ssrc);
257625944Sjoerg}
257725944Sjoerg
257825944Sjoerg/*
257925944Sjoerg * Set my IP address.  Must be called at splimp.
258025944Sjoerg */
258125944Sjoergstatic void
258225944Sjoergsppp_set_ip_addr(struct sppp *sp, u_long src)
258325944Sjoerg{
258425944Sjoerg	struct ifnet *ifp = &sp->pp_if;
258525944Sjoerg	struct ifaddr *ifa;
258625944Sjoerg	struct sockaddr_in *si;
258725944Sjoerg	u_long ssrc, ddst;
258825944Sjoerg
258925944Sjoerg	/*
259025944Sjoerg	 * Pick the first AF_INET address from the list,
259125944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
259225944Sjoerg	 */
259325944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
259425944Sjoerg	     ifa;
259525944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
259625944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
259725944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
259825944Sjoerg			if (si)
259925944Sjoerg				break;
260025944Sjoerg		}
260125944Sjoerg	if (ifa && si)
260225944Sjoerg		si->sin_addr.s_addr = htonl(src);
260325944Sjoerg}
260425944Sjoerg
260525706Sjoergstatic const char *
260625944Sjoergsppp_cp_type_name(u_char type)
26074910Swollman{
260825706Sjoerg	static char buf [12];
26094910Swollman	switch (type) {
261025944Sjoerg	case CONF_REQ:   return ("conf-req");
261125944Sjoerg	case CONF_ACK:   return ("conf-ack");
261225944Sjoerg	case CONF_NAK:   return ("conf-nak");
261325944Sjoerg	case CONF_REJ:   return ("conf-rej");
261425944Sjoerg	case TERM_REQ:   return ("term-req");
261525944Sjoerg	case TERM_ACK:   return ("term-ack");
261625944Sjoerg	case CODE_REJ:   return ("code-rej");
261725944Sjoerg	case PROTO_REJ:  return ("proto-rej");
261825944Sjoerg	case ECHO_REQ:   return ("echo-req");
261925944Sjoerg	case ECHO_REPLY: return ("echo-reply");
262025944Sjoerg	case DISC_REQ:   return ("discard-req");
26214910Swollman	}
262225706Sjoerg	sprintf (buf, "0x%x", type);
26234910Swollman	return (buf);
26244910Swollman}
26254910Swollman
262625706Sjoergstatic const char *
262725944Sjoergsppp_lcp_opt_name(u_char opt)
26284910Swollman{
262925706Sjoerg	static char buf [12];
263025944Sjoerg	switch (opt) {
263125944Sjoerg	case LCP_OPT_MRU:		return ("mru");
263225944Sjoerg	case LCP_OPT_ASYNC_MAP:		return ("async-map");
263325944Sjoerg	case LCP_OPT_AUTH_PROTO:	return ("auth-proto");
263425944Sjoerg	case LCP_OPT_QUAL_PROTO:	return ("qual-proto");
263525944Sjoerg	case LCP_OPT_MAGIC:		return ("magic");
263625944Sjoerg	case LCP_OPT_PROTO_COMP:	return ("proto-comp");
263725944Sjoerg	case LCP_OPT_ADDR_COMP:		return ("addr-comp");
26384910Swollman	}
263925944Sjoerg	sprintf (buf, "0x%x", opt);
26404910Swollman	return (buf);
26414910Swollman}
26424910Swollman
264325944Sjoergstatic const char *
264425944Sjoergsppp_ipcp_opt_name(u_char opt)
264525944Sjoerg{
264625944Sjoerg	static char buf [12];
264725944Sjoerg	switch (opt) {
264825944Sjoerg	case IPCP_OPT_ADDRESSES:	return ("addresses");
264925944Sjoerg	case IPCP_OPT_COMPRESSION:	return ("compression");
265025944Sjoerg	case IPCP_OPT_ADDRESS:		return ("address");
265125944Sjoerg	}
265225944Sjoerg	sprintf (buf, "0x%x", opt);
265325944Sjoerg	return (buf);
265425944Sjoerg}
265525944Sjoerg
265625944Sjoergstatic const char *
265725944Sjoergsppp_state_name(int state)
265825944Sjoerg{
265925944Sjoerg	switch (state) {
266025944Sjoerg	case STATE_INITIAL:	return "initial";
266125944Sjoerg	case STATE_STARTING:	return "starting";
266225944Sjoerg	case STATE_CLOSED:	return "closed";
266325944Sjoerg	case STATE_STOPPED:	return "stopped";
266425944Sjoerg	case STATE_CLOSING:	return "closing";
266525944Sjoerg	case STATE_STOPPING:	return "stopping";
266625944Sjoerg	case STATE_REQ_SENT:	return "req-sent";
266725944Sjoerg	case STATE_ACK_RCVD:	return "ack-rcvd";
266825944Sjoerg	case STATE_ACK_SENT:	return "ack-sent";
266925944Sjoerg	case STATE_OPENED:	return "opened";
267025944Sjoerg	}
267125944Sjoerg	return "illegal";
267225944Sjoerg}
267325944Sjoerg
267425944Sjoergstatic const char *
267525944Sjoergsppp_phase_name(enum ppp_phase phase)
267625944Sjoerg{
267725944Sjoerg	switch (phase) {
267825944Sjoerg	case PHASE_DEAD:	return "dead";
267925944Sjoerg	case PHASE_ESTABLISH:	return "establish";
268025944Sjoerg	case PHASE_TERMINATE:	return "terminate";
268125944Sjoerg	case PHASE_AUTHENTICATE: return "authenticate";
268225944Sjoerg	case PHASE_NETWORK:	return "network";
268325944Sjoerg	}
268425944Sjoerg	return "illegal";
268525944Sjoerg}
268625944Sjoerg
268725944Sjoergstatic const char *
268825944Sjoergsppp_proto_name(u_short proto)
268925944Sjoerg{
269025944Sjoerg	static char buf[12];
269125944Sjoerg	switch (proto) {
269225944Sjoerg	case PPP_LCP:	return "lcp";
269325944Sjoerg	case PPP_IPCP:	return "ipcp";
269425944Sjoerg	}
269525944Sjoerg	sprintf(buf, "0x%x", (unsigned)proto);
269625944Sjoerg	return buf;
269725944Sjoerg}
269825944Sjoerg
269912820Sphkstatic void
270025706Sjoergsppp_print_bytes(u_char *p, u_short len)
27014910Swollman{
270225706Sjoerg	addlog(" %x", *p++);
27034910Swollman	while (--len > 0)
270425706Sjoerg		addlog("-%x", *p++);
27054910Swollman}
270625944Sjoerg
270725944Sjoerg/*
270825944Sjoerg * This file is large.  Tell emacs to highlight it nevertheless.
270925944Sjoerg *
271025944Sjoerg * Local Variables:
271125944Sjoerg * hilit-auto-highlight-maxout: 100000
271225944Sjoerg * End:
271325944Sjoerg */
2714