if_spppsubr.c revision 27929
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 *
2027929Sitojun * $Id: if_spppsubr.c,v 1.22 1997/05/23 20:40:15 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 *
6825955Sjoerg * Setting link0 will make the link passive, i.e. it will be marked
6925944Sjoerg * as being administrative openable, but won't be opened to begin
7025944Sjoerg * with.  Incoming calls will be answered, or subsequent calls with
7125944Sjoerg * -link1 will cause the administrative open of the LCP layer.
7225955Sjoerg *
7325955Sjoerg * Setting link1 will cause the link to auto-dial only as packets
7425955Sjoerg * arrive to be sent.
7525944Sjoerg */
7625944Sjoerg
7725955Sjoerg#define IFF_PASSIVE	IFF_LINK0	/* wait passively for connection */
7825955Sjoerg#define IFF_AUTO	IFF_LINK1	/* auto-dial on output */
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;
48625955Sjoerg	int s, rv = 0;
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);
55411189Sjkh		else {
55525955Sjoerg			/*
55625955Sjoerg			 * Don't choke with an ENETDOWN early.  It's
55725955Sjoerg			 * possible that we just started dialing out,
55825955Sjoerg			 * so don't drop the packet immediately.  If
55925955Sjoerg			 * we notice that we run out of buffer space
56025955Sjoerg			 * below, we will however remember that we are
56125955Sjoerg			 * not ready to carry IP packets, and return
56225955Sjoerg			 * ENETDOWN, as opposed to ENOBUFS.
56325955Sjoerg			 */
56425955Sjoerg			h->protocol = htons(PPP_IP);
56525955Sjoerg			if (sp->state[IDX_IPCP] != STATE_OPENED)
56625955Sjoerg				rv = ENETDOWN;
56711189Sjkh		}
5684910Swollman		break;
5694910Swollman#endif
5704910Swollman#ifdef NS
5714910Swollman	case AF_NS:     /* Xerox NS Protocol */
5724910Swollman		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
5734910Swollman			ETHERTYPE_NS : PPP_XNS);
5744910Swollman		break;
5754910Swollman#endif
57611819Sjulian#ifdef IPX
57712495Speter	case AF_IPX:     /* Novell IPX Protocol */
57811819Sjulian		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
57912495Speter			ETHERTYPE_IPX : PPP_IPX);
58011819Sjulian		break;
58111819Sjulian#endif
5824910Swollman#ifdef ISO
5834910Swollman	case AF_ISO:    /* ISO OSI Protocol */
5844910Swollman		if (sp->pp_flags & PP_CISCO)
5854910Swollman			goto nosupport;
5864910Swollman		h->protocol = htons (PPP_ISO);
5874910Swollman		break;
58812820Sphknosupport:
5894910Swollman#endif
5904910Swollman	default:
5914910Swollman		m_freem (m);
59225944Sjoerg		++ifp->if_oerrors;
5934910Swollman		splx (s);
5944910Swollman		return (EAFNOSUPPORT);
5954910Swollman	}
5964910Swollman
5974910Swollman	/*
5984910Swollman	 * Queue message on interface, and start output if interface
5994910Swollman	 * not yet active.
6004910Swollman	 */
6014910Swollman	if (IF_QFULL (ifq)) {
6024910Swollman		IF_DROP (&ifp->if_snd);
6034910Swollman		m_freem (m);
60425944Sjoerg		++ifp->if_oerrors;
6054910Swollman		splx (s);
60625955Sjoerg		return (rv? rv: ENOBUFS);
6074910Swollman	}
6084910Swollman	IF_ENQUEUE (ifq, m);
6094910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
6104910Swollman		(*ifp->if_start) (ifp);
6114910Swollman
6124910Swollman	/*
6134910Swollman	 * Count output packets and bytes.
6144910Swollman	 * The packet length includes header, FCS and 1 flag,
6154910Swollman	 * according to RFC 1333.
6164910Swollman	 */
6174910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
6184910Swollman	splx (s);
6194910Swollman	return (0);
6204910Swollman}
6214910Swollman
62225706Sjoergvoid
62325706Sjoergsppp_attach(struct ifnet *ifp)
6244910Swollman{
6254910Swollman	struct sppp *sp = (struct sppp*) ifp;
6264910Swollman
6274910Swollman	/* Initialize keepalive handler. */
6284910Swollman	if (! spppq)
62911189Sjkh		timeout (sppp_keepalive, 0, hz * 10);
6304910Swollman
6314910Swollman	/* Insert new entry into the keepalive list. */
6324910Swollman	sp->pp_next = spppq;
6334910Swollman	spppq = sp;
6344910Swollman
6354910Swollman	sp->pp_if.if_type = IFT_PPP;
6364910Swollman	sp->pp_if.if_output = sppp_output;
6374910Swollman	sp->pp_fastq.ifq_maxlen = 32;
63826018Sjoerg	sp->pp_cpq.ifq_maxlen = 20;
6394910Swollman	sp->pp_loopcnt = 0;
6404910Swollman	sp->pp_alivecnt = 0;
64111189Sjkh	sp->pp_seq = 0;
6424910Swollman	sp->pp_rseq = 0;
64325944Sjoerg	sp->pp_phase = PHASE_DEAD;
64425944Sjoerg	sp->pp_up = lcp.Up;
64525944Sjoerg	sp->pp_down = lcp.Down;
64625944Sjoerg
64725944Sjoerg	sppp_lcp_init(sp);
64825944Sjoerg	sppp_ipcp_init(sp);
6494910Swollman}
6504910Swollman
65112820Sphkvoid
65225706Sjoergsppp_detach(struct ifnet *ifp)
6534910Swollman{
6544910Swollman	struct sppp **q, *p, *sp = (struct sppp*) ifp;
65525944Sjoerg	int i;
6564910Swollman
6574910Swollman	/* Remove the entry from the keepalive list. */
6584910Swollman	for (q = &spppq; (p = *q); q = &p->pp_next)
6594910Swollman		if (p == sp) {
6604910Swollman			*q = p->pp_next;
6614910Swollman			break;
6624910Swollman		}
6634910Swollman
6644910Swollman	/* Stop keepalive handler. */
6654910Swollman	if (! spppq)
66611189Sjkh		untimeout (sppp_keepalive, 0);
66725944Sjoerg
66825944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
66925944Sjoerg		untimeout((cps[i])->TO, (void *)sp);
6704910Swollman}
6714910Swollman
6724910Swollman/*
6734910Swollman * Flush the interface output queue.
6744910Swollman */
67525706Sjoergvoid
67625706Sjoergsppp_flush(struct ifnet *ifp)
6774910Swollman{
6784910Swollman	struct sppp *sp = (struct sppp*) ifp;
6794910Swollman
68025944Sjoerg	sppp_qflush (&sp->pp_if.if_snd);
68125944Sjoerg	sppp_qflush (&sp->pp_fastq);
68226018Sjoerg	sppp_qflush (&sp->pp_cpq);
6834910Swollman}
6844910Swollman
6854910Swollman/*
68611189Sjkh * Check if the output queue is empty.
68711189Sjkh */
68812820Sphkint
68925706Sjoergsppp_isempty(struct ifnet *ifp)
69011189Sjkh{
69111189Sjkh	struct sppp *sp = (struct sppp*) ifp;
69225944Sjoerg	int empty, s;
69311189Sjkh
69425944Sjoerg	s = splimp();
69526018Sjoerg	empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head &&
69626018Sjoerg		!sp->pp_if.if_snd.ifq_head;
69725944Sjoerg	splx(s);
69811189Sjkh	return (empty);
69911189Sjkh}
70011189Sjkh
70111189Sjkh/*
7024910Swollman * Get next packet to send.
7034910Swollman */
70425706Sjoergstruct mbuf *
70525706Sjoergsppp_dequeue(struct ifnet *ifp)
7064910Swollman{
7074910Swollman	struct sppp *sp = (struct sppp*) ifp;
7084910Swollman	struct mbuf *m;
70925944Sjoerg	int s;
7104910Swollman
71125944Sjoerg	s = splimp();
71226018Sjoerg	/*
71326018Sjoerg	 * Process only the control protocol queue until we are in
71426018Sjoerg	 * network phase.
71526018Sjoerg	 *
71626018Sjoerg	 * XXX Network phase itself is still not a sufficient test, we
71726018Sjoerg	 * normally should keep a separate queue for each supported
71826018Sjoerg	 * protocol family, and only serve these queues as the
71926018Sjoerg	 * respective NCPs were opened.  The simplistic logic used
72026018Sjoerg	 * here might cause some loss of network traffic while the
72126018Sjoerg	 * NCPs are being negotiated, in particular if the NCPs take a
72226018Sjoerg	 * long time to negotiate.
72326018Sjoerg	 *
72426018Sjoerg	 * Do always serve all three queues in Cisco mode.
72526018Sjoerg	 */
72626018Sjoerg	IF_DEQUEUE(&sp->pp_cpq, m);
72726018Sjoerg	if (m == NULL &&
72826018Sjoerg	    (sp->pp_phase == PHASE_NETWORK ||
72926018Sjoerg	     (sp->pp_flags & PP_CISCO) != 0)) {
73026018Sjoerg		IF_DEQUEUE(&sp->pp_fastq, m);
73126018Sjoerg		if (m == NULL)
73226018Sjoerg			IF_DEQUEUE (&sp->pp_if.if_snd, m);
73326018Sjoerg	}
73426018Sjoerg	splx(s);
73526018Sjoerg	return m;
7364910Swollman}
7374910Swollman
7384910Swollman/*
73925944Sjoerg * Process an ioctl request.  Called on low priority level.
7404910Swollman */
74125944Sjoergint
74225944Sjoergsppp_ioctl(struct ifnet *ifp, int cmd, void *data)
7434910Swollman{
74425944Sjoerg	struct ifreq *ifr = (struct ifreq*) data;
74525944Sjoerg	struct sppp *sp = (struct sppp*) ifp;
74625944Sjoerg	int s, going_up, going_down, newmode;
7474910Swollman
74825944Sjoerg	s = splimp();
74925944Sjoerg	switch (cmd) {
75025944Sjoerg	case SIOCAIFADDR:
75125944Sjoerg	case SIOCSIFDSTADDR:
75225944Sjoerg		break;
7534910Swollman
75425944Sjoerg	case SIOCSIFADDR:
75525944Sjoerg		if_up(ifp);
75625944Sjoerg		/* fall through... */
75711189Sjkh
75825944Sjoerg	case SIOCSIFFLAGS:
75925944Sjoerg		going_up = ifp->if_flags & IFF_UP &&
76025944Sjoerg			(ifp->if_flags & IFF_RUNNING) == 0;
76125944Sjoerg		going_down = (ifp->if_flags & IFF_UP) == 0 &&
76225944Sjoerg			ifp->if_flags & IFF_RUNNING;
76325944Sjoerg		newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE);
76425944Sjoerg		if (newmode == (IFF_AUTO | IFF_PASSIVE)) {
76525944Sjoerg			/* sanity */
76625944Sjoerg			newmode = IFF_PASSIVE;
76725944Sjoerg			ifp->if_flags &= ~IFF_AUTO;
7684910Swollman		}
7694910Swollman
77025944Sjoerg		if (going_up || going_down)
77125944Sjoerg			lcp.Close(sp);
77225944Sjoerg		if (going_up && newmode == 0) {
77325944Sjoerg			/* neither auto-dial nor passive */
77425944Sjoerg			ifp->if_flags |= IFF_RUNNING;
77525944Sjoerg			if (!(sp->pp_flags & PP_CISCO))
77625944Sjoerg				lcp.Open(sp);
77726018Sjoerg		} else if (going_down) {
77826018Sjoerg			sppp_flush(ifp);
77925944Sjoerg			ifp->if_flags &= ~IFF_RUNNING;
78026018Sjoerg		}
7814910Swollman
7824910Swollman		break;
78311189Sjkh
78425944Sjoerg#ifdef SIOCSIFMTU
78525944Sjoerg#ifndef ifr_mtu
78625944Sjoerg#define ifr_mtu ifr_metric
78725944Sjoerg#endif
78825944Sjoerg	case SIOCSIFMTU:
78925944Sjoerg		if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru)
79025944Sjoerg			return (EINVAL);
79125944Sjoerg		ifp->if_mtu = ifr->ifr_mtu;
7924910Swollman		break;
79325944Sjoerg#endif
79425944Sjoerg#ifdef SLIOCSETMTU
79525944Sjoerg	case SLIOCSETMTU:
79625944Sjoerg		if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru)
79725944Sjoerg			return (EINVAL);
79825944Sjoerg		ifp->if_mtu = *(short*)data;
7994910Swollman		break;
80025944Sjoerg#endif
80125944Sjoerg#ifdef SIOCGIFMTU
80225944Sjoerg	case SIOCGIFMTU:
80325944Sjoerg		ifr->ifr_mtu = ifp->if_mtu;
80411189Sjkh		break;
80525944Sjoerg#endif
80625944Sjoerg#ifdef SLIOCGETMTU
80725944Sjoerg	case SLIOCGETMTU:
80825944Sjoerg		*(short*)data = ifp->if_mtu;
8094910Swollman		break;
81025944Sjoerg#endif
81125944Sjoerg	case SIOCADDMULTI:
81225944Sjoerg	case SIOCDELMULTI:
8134910Swollman		break;
81411189Sjkh
81525944Sjoerg	default:
81625944Sjoerg		splx(s);
81725944Sjoerg		return (ENOTTY);
8184910Swollman	}
81925944Sjoerg	splx(s);
82025944Sjoerg	return (0);
8214910Swollman}
8224910Swollman
82325944Sjoerg
82425944Sjoerg/*
82525944Sjoerg * Cisco framing implementation.
82625944Sjoerg */
82725944Sjoerg
8284910Swollman/*
8294910Swollman * Handle incoming Cisco keepalive protocol packets.
8304910Swollman */
83112820Sphkstatic void
83225706Sjoergsppp_cisco_input(struct sppp *sp, struct mbuf *m)
8334910Swollman{
83425944Sjoerg	STDDCL;
8354910Swollman	struct cisco_packet *h;
8364910Swollman	struct ifaddr *ifa;
8374910Swollman
83827929Sitojun	if (m->m_pkthdr.len < CISCO_PACKET_LEN) {
83925706Sjoerg		if (debug)
84025706Sjoerg			log(LOG_DEBUG,
84125706Sjoerg			    "%s%d: invalid cisco packet length: %d bytes\n",
84225706Sjoerg			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
8434910Swollman		return;
8444910Swollman	}
8454910Swollman	h = mtod (m, struct cisco_packet*);
84625706Sjoerg	if (debug)
84725706Sjoerg		log(LOG_DEBUG,
84825706Sjoerg		    "%s%d: cisco input: %d bytes "
84925706Sjoerg		    "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
85025706Sjoerg		    ifp->if_name, ifp->if_unit, m->m_pkthdr.len,
85125706Sjoerg		    ntohl (h->type), h->par1, h->par2, h->rel,
85225706Sjoerg		    h->time0, h->time1);
8534910Swollman	switch (ntohl (h->type)) {
8544910Swollman	default:
85525706Sjoerg		if (debug)
85625706Sjoerg			addlog("%s%d: unknown cisco packet type: 0x%lx\n",
85725706Sjoerg			       ifp->if_name, ifp->if_unit, ntohl (h->type));
8584910Swollman		break;
8594910Swollman	case CISCO_ADDR_REPLY:
8604910Swollman		/* Reply on address request, ignore */
8614910Swollman		break;
8624910Swollman	case CISCO_KEEPALIVE_REQ:
8634910Swollman		sp->pp_alivecnt = 0;
8644910Swollman		sp->pp_rseq = ntohl (h->par1);
8654910Swollman		if (sp->pp_seq == sp->pp_rseq) {
8664910Swollman			/* Local and remote sequence numbers are equal.
8674910Swollman			 * Probably, the line is in loopback mode. */
86811189Sjkh			if (sp->pp_loopcnt >= MAXALIVECNT) {
86911189Sjkh				printf ("%s%d: loopback\n",
87011189Sjkh					ifp->if_name, ifp->if_unit);
87111189Sjkh				sp->pp_loopcnt = 0;
87211189Sjkh				if (ifp->if_flags & IFF_UP) {
87311189Sjkh					if_down (ifp);
87426018Sjoerg					sppp_qflush (&sp->pp_cpq);
87511189Sjkh				}
87611189Sjkh			}
8774910Swollman			++sp->pp_loopcnt;
8784910Swollman
8794910Swollman			/* Generate new local sequence number */
8804910Swollman			sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
88111189Sjkh			break;
88211189Sjkh		}
8834910Swollman			sp->pp_loopcnt = 0;
88411189Sjkh		if (! (ifp->if_flags & IFF_UP) &&
88511189Sjkh		    (ifp->if_flags & IFF_RUNNING)) {
88611189Sjkh			ifp->if_flags |= IFF_UP;
88711189Sjkh			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
88811189Sjkh		}
8894910Swollman		break;
8904910Swollman	case CISCO_ADDR_REQ:
89120407Swollman		for (ifa=ifp->if_addrhead.tqh_first; ifa;
89220407Swollman		     ifa=ifa->ifa_link.tqe_next)
8934910Swollman			if (ifa->ifa_addr->sa_family == AF_INET)
8944910Swollman				break;
8954910Swollman		if (! ifa) {
89625706Sjoerg			if (debug)
89725706Sjoerg				addlog("%s%d: unknown address for cisco request\n",
89825706Sjoerg				       ifp->if_name, ifp->if_unit);
8994910Swollman			return;
9004910Swollman		}
9014910Swollman		sppp_cisco_send (sp, CISCO_ADDR_REPLY,
9024910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr),
9034910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr));
9044910Swollman		break;
9054910Swollman	}
9064910Swollman}
9074910Swollman
9084910Swollman/*
90925944Sjoerg * Send Cisco keepalive packet.
9104910Swollman */
91112820Sphkstatic void
91225944Sjoergsppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
91325944Sjoerg{
91425944Sjoerg	STDDCL;
91525944Sjoerg	struct ppp_header *h;
91625944Sjoerg	struct cisco_packet *ch;
91725944Sjoerg	struct mbuf *m;
91825944Sjoerg	u_long t = (time.tv_sec - boottime.tv_sec) * 1000;
91925944Sjoerg
92025944Sjoerg	MGETHDR (m, M_DONTWAIT, MT_DATA);
92125944Sjoerg	if (! m)
92225944Sjoerg		return;
92325944Sjoerg	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
92425944Sjoerg	m->m_pkthdr.rcvif = 0;
92525944Sjoerg
92625944Sjoerg	h = mtod (m, struct ppp_header*);
92725944Sjoerg	h->address = CISCO_MULTICAST;
92825944Sjoerg	h->control = 0;
92925944Sjoerg	h->protocol = htons (CISCO_KEEPALIVE);
93025944Sjoerg
93125944Sjoerg	ch = (struct cisco_packet*) (h + 1);
93225944Sjoerg	ch->type = htonl (type);
93325944Sjoerg	ch->par1 = htonl (par1);
93425944Sjoerg	ch->par2 = htonl (par2);
93525944Sjoerg	ch->rel = -1;
93625944Sjoerg	ch->time0 = htons ((u_short) (t >> 16));
93725944Sjoerg	ch->time1 = htons ((u_short) t);
93825944Sjoerg
93925944Sjoerg	if (debug)
94025944Sjoerg		log(LOG_DEBUG,
94125944Sjoerg		    "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
94225944Sjoerg			ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
94325944Sjoerg			ch->par2, ch->rel, ch->time0, ch->time1);
94425944Sjoerg
94526018Sjoerg	if (IF_QFULL (&sp->pp_cpq)) {
94626018Sjoerg		IF_DROP (&sp->pp_fastq);
94725944Sjoerg		IF_DROP (&ifp->if_snd);
94825944Sjoerg		m_freem (m);
94925944Sjoerg	} else
95026018Sjoerg		IF_ENQUEUE (&sp->pp_cpq, m);
95125944Sjoerg	if (! (ifp->if_flags & IFF_OACTIVE))
95225944Sjoerg		(*ifp->if_start) (ifp);
95325944Sjoerg	ifp->if_obytes += m->m_pkthdr.len + 3;
95425944Sjoerg}
95525944Sjoerg
95625944Sjoerg/*
95725944Sjoerg * PPP protocol implementation.
95825944Sjoerg */
95925944Sjoerg
96025944Sjoerg/*
96125944Sjoerg * Send PPP control protocol packet.
96225944Sjoerg */
96325944Sjoergstatic void
96425706Sjoergsppp_cp_send(struct sppp *sp, u_short proto, u_char type,
96525706Sjoerg	     u_char ident, u_short len, void *data)
9664910Swollman{
96725944Sjoerg	STDDCL;
9684910Swollman	struct ppp_header *h;
9694910Swollman	struct lcp_header *lh;
9704910Swollman	struct mbuf *m;
9714910Swollman
9724910Swollman	if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
9734910Swollman		len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
9744910Swollman	MGETHDR (m, M_DONTWAIT, MT_DATA);
9754910Swollman	if (! m)
9764910Swollman		return;
9774910Swollman	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
9784910Swollman	m->m_pkthdr.rcvif = 0;
9794910Swollman
9804910Swollman	h = mtod (m, struct ppp_header*);
9814910Swollman	h->address = PPP_ALLSTATIONS;        /* broadcast address */
9824910Swollman	h->control = PPP_UI;                 /* Unnumbered Info */
9834910Swollman	h->protocol = htons (proto);         /* Link Control Protocol */
9844910Swollman
9854910Swollman	lh = (struct lcp_header*) (h + 1);
9864910Swollman	lh->type = type;
9874910Swollman	lh->ident = ident;
9884910Swollman	lh->len = htons (LCP_HEADER_LEN + len);
9894910Swollman	if (len)
9904910Swollman		bcopy (data, lh+1, len);
9914910Swollman
99225706Sjoerg	if (debug) {
99325944Sjoerg		log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d",
99425944Sjoerg		    ifp->if_name, ifp->if_unit,
99525944Sjoerg		    sppp_proto_name(proto),
99625944Sjoerg		    sppp_cp_type_name (lh->type), lh->ident,
99725944Sjoerg		    ntohs (lh->len));
9984910Swollman		if (len)
99911189Sjkh			sppp_print_bytes ((u_char*) (lh+1), len);
100025706Sjoerg		addlog(">\n");
10014910Swollman	}
100226018Sjoerg	if (IF_QFULL (&sp->pp_cpq)) {
100326018Sjoerg		IF_DROP (&sp->pp_fastq);
10044910Swollman		IF_DROP (&ifp->if_snd);
10054910Swollman		m_freem (m);
100625944Sjoerg		++ifp->if_oerrors;
10074910Swollman	} else
100826018Sjoerg		IF_ENQUEUE (&sp->pp_cpq, m);
10094910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
10104910Swollman		(*ifp->if_start) (ifp);
10114910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
10124910Swollman}
10134910Swollman
10144910Swollman/*
101525944Sjoerg * Handle incoming PPP control protocol packets.
10164910Swollman */
101712820Sphkstatic void
101825944Sjoergsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
10194910Swollman{
102025944Sjoerg	STDDCL;
102125944Sjoerg	struct lcp_header *h;
102225944Sjoerg	int len = m->m_pkthdr.len;
102325944Sjoerg	int rv;
102425944Sjoerg	u_char *p;
10254910Swollman
102625944Sjoerg	if (len < 4) {
102725944Sjoerg		if (debug)
102825944Sjoerg			log(LOG_DEBUG,
102925944Sjoerg			    "%s%d: %s invalid packet length: %d bytes\n",
103025944Sjoerg			    ifp->if_name, ifp->if_unit, cp->name, len);
10314910Swollman		return;
103225944Sjoerg	}
103325944Sjoerg	h = mtod (m, struct lcp_header*);
103425944Sjoerg	if (debug) {
103525944Sjoerg		log(LOG_DEBUG,
103625944Sjoerg		    "%s%d: %s input(%s): <%s id=0x%x len=%d",
103725944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
103825944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
103925944Sjoerg		    sppp_cp_type_name (h->type), h->ident, ntohs (h->len));
104025944Sjoerg		if (len > 4)
104125944Sjoerg			sppp_print_bytes ((u_char*) (h+1), len-4);
104225944Sjoerg		addlog(">\n");
104325944Sjoerg	}
104425944Sjoerg	if (len > ntohs (h->len))
104525944Sjoerg		len = ntohs (h->len);
104625944Sjoerg	switch (h->type) {
104725944Sjoerg	case CONF_REQ:
104825944Sjoerg		if (len < 4) {
104925944Sjoerg			if (debug)
105025944Sjoerg				addlog("%s%d: %s invalid conf-req length %d\n",
105125944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
105225944Sjoerg				       len);
105325944Sjoerg			++ifp->if_ierrors;
105425944Sjoerg			break;
105525944Sjoerg		}
105625944Sjoerg		rv = (cp->RCR)(sp, h, len);
105725944Sjoerg		switch (sp->state[cp->protoidx]) {
105825944Sjoerg		case STATE_OPENED:
105925944Sjoerg			(cp->tld)(sp);
106025944Sjoerg			(cp->scr)(sp);
106125944Sjoerg			/* fall through... */
106225944Sjoerg		case STATE_ACK_SENT:
106325944Sjoerg		case STATE_REQ_SENT:
106425944Sjoerg			sppp_cp_change_state(cp, sp, rv?
106525944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
106625944Sjoerg			break;
106725944Sjoerg		case STATE_CLOSING:
106825944Sjoerg		case STATE_STOPPING:
106925944Sjoerg			break;
107025944Sjoerg		case STATE_STOPPED:
107125944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
107225944Sjoerg			(cp->scr)(sp);
107325944Sjoerg			sppp_cp_change_state(cp, sp, rv?
107425944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
107525944Sjoerg			break;
107625944Sjoerg		case STATE_CLOSED:
107725944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
107825944Sjoerg				     0, 0);
107925944Sjoerg			break;
108025944Sjoerg		case STATE_ACK_RCVD:
108125944Sjoerg			if (rv) {
108225944Sjoerg				sppp_cp_change_state(cp, sp, STATE_OPENED);
108325944Sjoerg				if (debug)
108426077Sjoerg					log(LOG_DEBUG, "%s%d: %s tlu\n",
108526077Sjoerg					    ifp->if_name, ifp->if_unit,
108626077Sjoerg					    cp->name);
108725944Sjoerg				(cp->tlu)(sp);
108825944Sjoerg			} else
108925944Sjoerg				sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
109025944Sjoerg			break;
109125944Sjoerg		default:
109225944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
109325944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
109425944Sjoerg			       sppp_cp_type_name(h->type),
109525944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
109625944Sjoerg			++ifp->if_ierrors;
109725944Sjoerg		}
109825944Sjoerg		break;
109925944Sjoerg	case CONF_ACK:
110025944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
110125944Sjoerg			if (debug)
110225944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
110325944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
110425944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
110525944Sjoerg			++ifp->if_ierrors;
110625944Sjoerg			break;
110725944Sjoerg		}
110825944Sjoerg		switch (sp->state[cp->protoidx]) {
110925944Sjoerg		case STATE_CLOSED:
111025944Sjoerg		case STATE_STOPPED:
111125944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
111225944Sjoerg			break;
111325944Sjoerg		case STATE_CLOSING:
111425944Sjoerg		case STATE_STOPPING:
111525944Sjoerg			break;
111625944Sjoerg		case STATE_REQ_SENT:
111725944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
111825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
111925944Sjoerg			break;
112025944Sjoerg		case STATE_OPENED:
112125944Sjoerg			(cp->tld)(sp);
112225944Sjoerg			/* fall through */
112325944Sjoerg		case STATE_ACK_RCVD:
112425944Sjoerg			(cp->scr)(sp);
112525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
112625944Sjoerg			break;
112725944Sjoerg		case STATE_ACK_SENT:
112825944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
112925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_OPENED);
113025944Sjoerg			if (debug)
113125944Sjoerg				addlog("%s%d: %s tlu\n",
113225944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name);
113325944Sjoerg			(cp->tlu)(sp);
113425944Sjoerg			break;
113525944Sjoerg		default:
113625944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
113725944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
113825944Sjoerg			       sppp_cp_type_name(h->type),
113925944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
114025944Sjoerg			++ifp->if_ierrors;
114125944Sjoerg		}
114225944Sjoerg		break;
114325944Sjoerg	case CONF_NAK:
114425944Sjoerg	case CONF_REJ:
114525944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
114625944Sjoerg			if (debug)
114725944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
114825944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
114925944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
115025944Sjoerg			++ifp->if_ierrors;
115125944Sjoerg			break;
115225944Sjoerg		}
115325944Sjoerg		if (h->type == CONF_NAK)
115425944Sjoerg			(cp->RCN_nak)(sp, h, len);
115525944Sjoerg		else /* CONF_REJ */
115625944Sjoerg			(cp->RCN_rej)(sp, h, len);
11574910Swollman
115825944Sjoerg		switch (sp->state[cp->protoidx]) {
115925944Sjoerg		case STATE_CLOSED:
116025944Sjoerg		case STATE_STOPPED:
116125944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
116225944Sjoerg			break;
116325944Sjoerg		case STATE_REQ_SENT:
116425944Sjoerg		case STATE_ACK_SENT:
116525944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
116625944Sjoerg			(cp->scr)(sp);
116725944Sjoerg			break;
116825944Sjoerg		case STATE_OPENED:
116925944Sjoerg			(cp->tld)(sp);
117025944Sjoerg			/* fall through */
117125944Sjoerg		case STATE_ACK_RCVD:
117225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_SENT);
117325944Sjoerg			(cp->scr)(sp);
117425944Sjoerg			break;
117525944Sjoerg		case STATE_CLOSING:
117625944Sjoerg		case STATE_STOPPING:
117725944Sjoerg			break;
117825944Sjoerg		default:
117925944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
118025944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
118125944Sjoerg			       sppp_cp_type_name(h->type),
118225944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
118325944Sjoerg			++ifp->if_ierrors;
118425944Sjoerg		}
118525944Sjoerg		break;
11864910Swollman
118725944Sjoerg	case TERM_REQ:
118825944Sjoerg		switch (sp->state[cp->protoidx]) {
118925944Sjoerg		case STATE_ACK_RCVD:
119025944Sjoerg		case STATE_ACK_SENT:
119125944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
119225944Sjoerg			/* fall through */
119325944Sjoerg		case STATE_CLOSED:
119425944Sjoerg		case STATE_STOPPED:
119525944Sjoerg		case STATE_CLOSING:
119625944Sjoerg		case STATE_STOPPING:
119725944Sjoerg		case STATE_REQ_SENT:
119825944Sjoerg		  sta:
119925944Sjoerg			/* Send Terminate-Ack packet. */
120025944Sjoerg			if (debug)
120125944Sjoerg				log(LOG_DEBUG, "%s%d: %s send terminate-ack\n",
120225944Sjoerg				    ifp->if_name, ifp->if_unit, cp->name);
120325944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
120425944Sjoerg			break;
120525944Sjoerg		case STATE_OPENED:
120625944Sjoerg			(cp->tld)(sp);
120725944Sjoerg			sp->rst_counter[cp->protoidx] = 0;
120825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPING);
120925944Sjoerg			goto sta;
121025944Sjoerg			break;
121125944Sjoerg		default:
121225944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
121325944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
121425944Sjoerg			       sppp_cp_type_name(h->type),
121525944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
121625944Sjoerg			++ifp->if_ierrors;
121725944Sjoerg		}
121825944Sjoerg		break;
121925944Sjoerg	case TERM_ACK:
122025944Sjoerg		switch (sp->state[cp->protoidx]) {
122125944Sjoerg		case STATE_CLOSED:
122225944Sjoerg		case STATE_STOPPED:
122325944Sjoerg		case STATE_REQ_SENT:
122425944Sjoerg		case STATE_ACK_SENT:
122525944Sjoerg			break;
122625944Sjoerg		case STATE_CLOSING:
122725944Sjoerg			(cp->tlf)(sp);
122825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
122925944Sjoerg			break;
123025944Sjoerg		case STATE_STOPPING:
123125944Sjoerg			(cp->tlf)(sp);
123225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
123325944Sjoerg			break;
123425944Sjoerg		case STATE_ACK_RCVD:
123525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
123625944Sjoerg			break;
123725944Sjoerg		case STATE_OPENED:
123825944Sjoerg			(cp->tld)(sp);
123925944Sjoerg			(cp->scr)(sp);
124025944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
124125944Sjoerg			break;
124225944Sjoerg		default:
124325944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
124425944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
124525944Sjoerg			       sppp_cp_type_name(h->type),
124625944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
124725944Sjoerg			++ifp->if_ierrors;
124825944Sjoerg		}
124925944Sjoerg		break;
125025944Sjoerg	case CODE_REJ:
125125944Sjoerg	case PROTO_REJ:
125225944Sjoerg		/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
125325944Sjoerg		switch (sp->state[cp->protoidx]) {
125425944Sjoerg		case STATE_CLOSED:
125525944Sjoerg		case STATE_STOPPED:
125625944Sjoerg		case STATE_REQ_SENT:
125725944Sjoerg		case STATE_ACK_SENT:
125825944Sjoerg		case STATE_CLOSING:
125925944Sjoerg		case STATE_STOPPING:
126025944Sjoerg		case STATE_OPENED:
126125944Sjoerg			break;
126225944Sjoerg		case STATE_ACK_RCVD:
126325944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
126425944Sjoerg			break;
126525944Sjoerg		default:
126625944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
126725944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
126825944Sjoerg			       sppp_cp_type_name(h->type),
126925944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
127025944Sjoerg			++ifp->if_ierrors;
127125944Sjoerg		}
127225944Sjoerg		break;
127325944Sjoerg	case DISC_REQ:
127425944Sjoerg		if (cp->proto != PPP_LCP)
127525944Sjoerg			goto illegal;
127625944Sjoerg		/* Discard the packet. */
127725944Sjoerg		break;
127825944Sjoerg	case ECHO_REQ:
127925944Sjoerg		if (cp->proto != PPP_LCP)
128025944Sjoerg			goto illegal;
128125944Sjoerg		if (sp->state[cp->protoidx] != STATE_OPENED) {
128225944Sjoerg			if (debug)
128325944Sjoerg				addlog("%s%d: lcp echo req but lcp closed\n",
128425944Sjoerg				       ifp->if_name, ifp->if_unit);
128525944Sjoerg			++ifp->if_ierrors;
128625944Sjoerg			break;
128725944Sjoerg		}
128825944Sjoerg		if (len < 8) {
128925944Sjoerg			if (debug)
129025944Sjoerg				addlog("%s%d: invalid lcp echo request "
129125944Sjoerg				       "packet length: %d bytes\n",
129225944Sjoerg				       ifp->if_name, ifp->if_unit, len);
129325944Sjoerg			break;
129425944Sjoerg		}
129525944Sjoerg		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
129625944Sjoerg			/* Line loopback mode detected. */
129725944Sjoerg			printf("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
129825944Sjoerg			if_down (ifp);
129926018Sjoerg			sppp_qflush (&sp->pp_cpq);
13004910Swollman
130125944Sjoerg			/* Shut down the PPP link. */
130225944Sjoerg			/* XXX */
130325944Sjoerg			lcp.Down(sp);
130425944Sjoerg			lcp.Up(sp);
130525944Sjoerg			break;
130625944Sjoerg		}
130725944Sjoerg		*(long*)(h+1) = htonl (sp->lcp.magic);
130825944Sjoerg		if (debug)
130925944Sjoerg			addlog("%s%d: got lcp echo req, sending echo rep\n",
131025944Sjoerg			       ifp->if_name, ifp->if_unit);
131125944Sjoerg		sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1);
131225944Sjoerg		break;
131325944Sjoerg	case ECHO_REPLY:
131425944Sjoerg		if (cp->proto != PPP_LCP)
131525944Sjoerg			goto illegal;
131625944Sjoerg		if (h->ident != sp->lcp.echoid) {
131725944Sjoerg			++ifp->if_ierrors;
131825944Sjoerg			break;
131925944Sjoerg		}
132025944Sjoerg		if (len < 8) {
132125944Sjoerg			if (debug)
132225944Sjoerg				addlog("%s%d: lcp invalid echo reply "
132325944Sjoerg				       "packet length: %d bytes\n",
132425944Sjoerg				       ifp->if_name, ifp->if_unit, len);
132525944Sjoerg			break;
132625944Sjoerg		}
132725944Sjoerg		if (debug)
132825944Sjoerg			addlog("%s%d: lcp got echo rep\n",
132925944Sjoerg			       ifp->if_name, ifp->if_unit);
133025944Sjoerg		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
133125944Sjoerg			sp->pp_alivecnt = 0;
133225944Sjoerg		break;
133325944Sjoerg	default:
133425944Sjoerg		/* Unknown packet type -- send Code-Reject packet. */
133525944Sjoerg	  illegal:
133625944Sjoerg		if (debug)
133725944Sjoerg			addlog("%s%d: %c send code-rej for 0x%x\n",
133825944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name, h->type);
133925944Sjoerg		sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq,
134025944Sjoerg			     m->m_pkthdr.len, h);
134125944Sjoerg		++ifp->if_ierrors;
134225944Sjoerg	}
13434910Swollman}
13444910Swollman
134525944Sjoerg
13464910Swollman/*
134725944Sjoerg * The generic part of all Up/Down/Open/Close/TO event handlers.
134825944Sjoerg * Basically, the state transition handling in the automaton.
13494910Swollman */
135025944Sjoergstatic void
135125944Sjoergsppp_up_event(const struct cp *cp, struct sppp *sp)
13524910Swollman{
135325944Sjoerg	STDDCL;
13544910Swollman
135525944Sjoerg	if (debug)
135625944Sjoerg		log(LOG_DEBUG, "%s%d: %s up(%s)\n",
135725944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
135825944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
135925944Sjoerg
136025944Sjoerg	switch (sp->state[cp->protoidx]) {
136125944Sjoerg	case STATE_INITIAL:
136225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
136325944Sjoerg		break;
136425944Sjoerg	case STATE_STARTING:
136525944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
136625944Sjoerg		(cp->scr)(sp);
136725944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
136825944Sjoerg		break;
13694910Swollman	default:
137025944Sjoerg		printf("%s%d: %s illegal up in state %s\n",
137125944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
137225944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
137325944Sjoerg	}
137425944Sjoerg}
13754910Swollman
137625944Sjoergstatic void
137725944Sjoergsppp_down_event(const struct cp *cp, struct sppp *sp)
137825944Sjoerg{
137925944Sjoerg	STDDCL;
138025944Sjoerg
138125944Sjoerg	if (debug)
138225944Sjoerg		log(LOG_DEBUG, "%s%d: %s down(%s)\n",
138325944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
138425944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
138525944Sjoerg
138625944Sjoerg	switch (sp->state[cp->protoidx]) {
138725944Sjoerg	case STATE_CLOSED:
138825944Sjoerg	case STATE_CLOSING:
138925944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
13904910Swollman		break;
139125944Sjoerg	case STATE_STOPPED:
139225944Sjoerg		(cp->tls)(sp);
139325944Sjoerg		/* fall through */
139425944Sjoerg	case STATE_STOPPING:
139525944Sjoerg	case STATE_REQ_SENT:
139625944Sjoerg	case STATE_ACK_RCVD:
139725944Sjoerg	case STATE_ACK_SENT:
139825944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
139925944Sjoerg		break;
140025944Sjoerg	case STATE_OPENED:
140125944Sjoerg		(cp->tld)(sp);
140225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
140325944Sjoerg		break;
140425944Sjoerg	default:
140525944Sjoerg		printf("%s%d: %s illegal down in state %s\n",
140625944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
140725944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
140825944Sjoerg	}
140925944Sjoerg}
14104910Swollman
141111189Sjkh
141225944Sjoergstatic void
141325944Sjoergsppp_open_event(const struct cp *cp, struct sppp *sp)
141425944Sjoerg{
141525944Sjoerg	STDDCL;
141625944Sjoerg
141725944Sjoerg	if (debug)
141825944Sjoerg		log(LOG_DEBUG, "%s%d: %s open(%s)\n",
141925944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
142025944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
142125944Sjoerg
142225944Sjoerg	switch (sp->state[cp->protoidx]) {
142325944Sjoerg	case STATE_INITIAL:
142425944Sjoerg		(cp->tls)(sp);
142525944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
14264910Swollman		break;
142725944Sjoerg	case STATE_STARTING:
142825944Sjoerg		break;
142925944Sjoerg	case STATE_CLOSED:
143025944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
143125944Sjoerg		(cp->scr)(sp);
143225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
143325944Sjoerg		break;
143425944Sjoerg	case STATE_STOPPED:
143525944Sjoerg	case STATE_STOPPING:
143625944Sjoerg	case STATE_REQ_SENT:
143725944Sjoerg	case STATE_ACK_RCVD:
143825944Sjoerg	case STATE_ACK_SENT:
143925944Sjoerg	case STATE_OPENED:
144025944Sjoerg		break;
144125944Sjoerg	case STATE_CLOSING:
144225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STOPPING);
144325944Sjoerg		break;
144425944Sjoerg	}
144525944Sjoerg}
14464910Swollman
144725944Sjoerg
144825944Sjoergstatic void
144925944Sjoergsppp_close_event(const struct cp *cp, struct sppp *sp)
145025944Sjoerg{
145125944Sjoerg	STDDCL;
145225944Sjoerg
145325944Sjoerg	if (debug)
145425944Sjoerg		log(LOG_DEBUG, "%s%d: %s close(%s)\n",
145525944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
145625944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
145725944Sjoerg
145825944Sjoerg	switch (sp->state[cp->protoidx]) {
145925944Sjoerg	case STATE_INITIAL:
146025944Sjoerg	case STATE_CLOSED:
146125944Sjoerg	case STATE_CLOSING:
14624910Swollman		break;
146325944Sjoerg	case STATE_STARTING:
146425944Sjoerg		(cp->tlf)(sp);
146525944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
14664910Swollman		break;
146725944Sjoerg	case STATE_STOPPED:
146825944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
14694910Swollman		break;
147025944Sjoerg	case STATE_STOPPING:
147125944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
14724910Swollman		break;
147325944Sjoerg	case STATE_OPENED:
147425944Sjoerg		(cp->tld)(sp);
147525944Sjoerg		/* fall through */
147625944Sjoerg	case STATE_REQ_SENT:
147725944Sjoerg	case STATE_ACK_RCVD:
147825944Sjoerg	case STATE_ACK_SENT:
147925944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
148025944Sjoerg		sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0);
148125944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
14824910Swollman		break;
14834910Swollman	}
14844910Swollman}
14854910Swollman
148625944Sjoergstatic void
148725944Sjoergsppp_to_event(const struct cp *cp, struct sppp *sp)
148825944Sjoerg{
148925944Sjoerg	STDDCL;
149025944Sjoerg	int s;
149125944Sjoerg
149225944Sjoerg	s = splimp();
149325944Sjoerg	if (debug)
149425944Sjoerg		log(LOG_DEBUG, "%s%d: %s TO(%s) rst_counter = %d\n",
149525944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
149625944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
149725944Sjoerg		    sp->rst_counter[cp->protoidx]);
149825944Sjoerg
149925944Sjoerg	if (--sp->rst_counter[cp->protoidx] < 0)
150025944Sjoerg		/* TO- event */
150125944Sjoerg		switch (sp->state[cp->protoidx]) {
150225944Sjoerg		case STATE_CLOSING:
150325944Sjoerg			(cp->tlf)(sp);
150425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
150525944Sjoerg			break;
150625944Sjoerg		case STATE_STOPPING:
150725944Sjoerg			(cp->tlf)(sp);
150825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
150925944Sjoerg			break;
151025944Sjoerg		case STATE_REQ_SENT:
151125944Sjoerg		case STATE_ACK_RCVD:
151225944Sjoerg		case STATE_ACK_SENT:
151325944Sjoerg			(cp->tlf)(sp);
151425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
151525944Sjoerg			break;
151625944Sjoerg		}
151725944Sjoerg	else
151825944Sjoerg		/* TO+ event */
151925944Sjoerg		switch (sp->state[cp->protoidx]) {
152025944Sjoerg		case STATE_CLOSING:
152125944Sjoerg		case STATE_STOPPING:
152225944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
152325944Sjoerg				     0, 0);
152425944Sjoerg			timeout(cp->TO, (void *)sp, sp->lcp.timeout);
152525944Sjoerg			break;
152625944Sjoerg		case STATE_REQ_SENT:
152725944Sjoerg		case STATE_ACK_RCVD:
152825944Sjoerg			(cp->scr)(sp);
152925944Sjoerg			/* sppp_cp_change_state() will restart the timer */
153025944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
153125944Sjoerg			break;
153225944Sjoerg		case STATE_ACK_SENT:
153325944Sjoerg			(cp->scr)(sp);
153425944Sjoerg			timeout(cp->TO, (void *)sp, sp->lcp.timeout);
153525944Sjoerg			break;
153625944Sjoerg		}
153725944Sjoerg
153825944Sjoerg	splx(s);
153925944Sjoerg}
154025944Sjoerg
154111189Sjkh/*
154225944Sjoerg * Change the state of a control protocol in the state automaton.
154325944Sjoerg * Takes care of starting/stopping the restart timer.
154411189Sjkh */
154525944Sjoergvoid
154625944Sjoergsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
154725944Sjoerg{
154825944Sjoerg	sp->state[cp->protoidx] = newstate;
154925944Sjoerg
155025944Sjoerg	untimeout(cp->TO, (void *)sp);
155125944Sjoerg	switch (newstate) {
155225944Sjoerg	case STATE_INITIAL:
155325944Sjoerg	case STATE_STARTING:
155425944Sjoerg	case STATE_CLOSED:
155525944Sjoerg	case STATE_STOPPED:
155625944Sjoerg	case STATE_OPENED:
155725944Sjoerg		break;
155825944Sjoerg	case STATE_CLOSING:
155925944Sjoerg	case STATE_STOPPING:
156025944Sjoerg	case STATE_REQ_SENT:
156125944Sjoerg	case STATE_ACK_RCVD:
156225944Sjoerg	case STATE_ACK_SENT:
156325944Sjoerg		timeout(cp->TO, (void *)sp, sp->lcp.timeout);
156425944Sjoerg		break;
156525944Sjoerg	}
156625944Sjoerg}
156725944Sjoerg/*
156825944Sjoerg *--------------------------------------------------------------------------*
156925944Sjoerg *                                                                          *
157025944Sjoerg *                         The LCP implementation.                          *
157125944Sjoerg *                                                                          *
157225944Sjoerg *--------------------------------------------------------------------------*
157325944Sjoerg */
157425944Sjoergstatic void
157525944Sjoergsppp_lcp_init(struct sppp *sp)
157625944Sjoerg{
157725944Sjoerg	sp->lcp.opts = (1 << LCP_OPT_MAGIC);
157825944Sjoerg	sp->lcp.magic = 0;
157925944Sjoerg	sp->state[IDX_LCP] = STATE_INITIAL;
158025944Sjoerg	sp->fail_counter[IDX_LCP] = 0;
158125944Sjoerg	sp->lcp.protos = 0;
158225944Sjoerg	sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
158325944Sjoerg
158425944Sjoerg	/*
158525944Sjoerg	 * Initialize counters and timeout values.  Note that we don't
158625944Sjoerg	 * use the 3 seconds suggested in RFC 1661 since we are likely
158725944Sjoerg	 * running on a fast link.  XXX We should probably implement
158825944Sjoerg	 * the exponential backoff option.  Note that these values are
158925944Sjoerg	 * relevant for all control protocols, not just LCP only.
159025944Sjoerg	 */
159125944Sjoerg	sp->lcp.timeout = 1 * hz;
159225944Sjoerg	sp->lcp.max_terminate = 2;
159325944Sjoerg	sp->lcp.max_configure = 10;
159425944Sjoerg	sp->lcp.max_failure = 10;
159525944Sjoerg}
159625944Sjoerg
159725944Sjoergstatic void
159825944Sjoergsppp_lcp_up(struct sppp *sp)
159925944Sjoerg{
160025944Sjoerg	STDDCL;
160125944Sjoerg
160225944Sjoerg	/*
160325944Sjoerg	 * If this interface is passive or dial-on-demand, it means
160425944Sjoerg	 * we've got in incoming call.  Activate the interface.
160525944Sjoerg	 */
160625944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) {
160725944Sjoerg		if (debug)
160825944Sjoerg			log(LOG_DEBUG,
160925944Sjoerg			    "%s%d: Up event (incoming call)\n",
161025944Sjoerg			    ifp->if_name, ifp->if_unit);
161125944Sjoerg		ifp->if_flags |= IFF_RUNNING;
161225944Sjoerg		lcp.Open(sp);
161325944Sjoerg	}
161425944Sjoerg
161525944Sjoerg	sppp_up_event(&lcp, sp);
161625944Sjoerg}
161725944Sjoerg
161825944Sjoergstatic void
161925944Sjoergsppp_lcp_down(struct sppp *sp)
162025944Sjoerg{
162125944Sjoerg	STDDCL;
162225944Sjoerg
162325944Sjoerg	sppp_down_event(&lcp, sp);
162425944Sjoerg
162525944Sjoerg	/*
162625944Sjoerg	 * If this is neither a dial-on-demand nor a passive
162725944Sjoerg	 * interface, simulate an ``ifconfig down'' action, so the
162825944Sjoerg	 * administrator can force a redial by another ``ifconfig
162925944Sjoerg	 * up''.  XXX For leased line operation, should we immediately
163025944Sjoerg	 * try to reopen the connection here?
163125944Sjoerg	 */
163225944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
163325944Sjoerg		log(LOG_INFO,
163425944Sjoerg		    "%s%d: Down event (carrier loss), taking interface down.\n",
163525944Sjoerg		    ifp->if_name, ifp->if_unit);
163625944Sjoerg		if_down(ifp);
163725944Sjoerg	} else {
163825944Sjoerg		if (debug)
163925944Sjoerg			log(LOG_DEBUG,
164025944Sjoerg			    "%s%d: Down event (carrier loss)\n",
164125944Sjoerg			    ifp->if_name, ifp->if_unit);
164225944Sjoerg	}
164325944Sjoerg	lcp.Close(sp);
164425944Sjoerg	ifp->if_flags &= ~IFF_RUNNING;
164525944Sjoerg}
164625944Sjoerg
164725944Sjoergstatic void
164825944Sjoergsppp_lcp_open(struct sppp *sp)
164925944Sjoerg{
165025944Sjoerg	sppp_open_event(&lcp, sp);
165125944Sjoerg}
165225944Sjoerg
165325944Sjoergstatic void
165425944Sjoergsppp_lcp_close(struct sppp *sp)
165525944Sjoerg{
165625944Sjoerg	sppp_close_event(&lcp, sp);
165725944Sjoerg}
165825944Sjoerg
165925944Sjoergstatic void
166025944Sjoergsppp_lcp_TO(void *cookie)
166125944Sjoerg{
166225944Sjoerg	sppp_to_event(&lcp, (struct sppp *)cookie);
166325944Sjoerg}
166425944Sjoerg
166525944Sjoerg/*
166625944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
166725944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
166825944Sjoerg * caused action scn.  (The return value is used to make the state
166925944Sjoerg * transition decision in the state automaton.)
167025944Sjoerg */
167112820Sphkstatic int
167225944Sjoergsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
16734910Swollman{
167425944Sjoerg	STDDCL;
167511189Sjkh	u_char *buf, *r, *p;
167625944Sjoerg	int origlen, rlen;
167725944Sjoerg	u_long nmagic;
16784910Swollman
167911189Sjkh	len -= 4;
168025944Sjoerg	origlen = len;
168111189Sjkh	buf = r = malloc (len, M_TEMP, M_NOWAIT);
168211189Sjkh	if (! buf)
168311189Sjkh		return (0);
16844910Swollman
168525706Sjoerg	if (debug)
168625944Sjoerg		log(LOG_DEBUG, "%s%d: lcp parse opts: ",
168725944Sjoerg		    ifp->if_name, ifp->if_unit);
168825706Sjoerg
168925944Sjoerg	/* pass 1: check for things that need to be rejected */
169011189Sjkh	p = (void*) (h+1);
169111189Sjkh	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
169225944Sjoerg		if (debug)
169325944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
169411189Sjkh		switch (*p) {
169511189Sjkh		case LCP_OPT_MAGIC:
169625944Sjoerg			/* Magic number. */
169725944Sjoerg			/* fall through, both are same length */
169825944Sjoerg		case LCP_OPT_ASYNC_MAP:
169925944Sjoerg			/* Async control character map. */
170025944Sjoerg			if (len >= 6 || p[1] == 6)
170125944Sjoerg				continue;
170225944Sjoerg			if (debug)
170325944Sjoerg				addlog("[invalid] ");
170425944Sjoerg			break;
170525944Sjoerg		case LCP_OPT_MRU:
170625944Sjoerg			/* Maximum receive unit. */
170725944Sjoerg			if (len >= 4 && p[1] == 4)
170825944Sjoerg				continue;
170925944Sjoerg			if (debug)
171025944Sjoerg				addlog("[invalid] ");
171125944Sjoerg			break;
171225944Sjoerg		default:
171325944Sjoerg			/* Others not supported. */
171425944Sjoerg			if (debug)
171525944Sjoerg				addlog("[rej] ");
171625944Sjoerg			break;
171725944Sjoerg		}
171825944Sjoerg		/* Add the option to rejected list. */
171925944Sjoerg		bcopy (p, r, p[1]);
172025944Sjoerg		r += p[1];
172125944Sjoerg		rlen += p[1];
172225944Sjoerg	}
172325944Sjoerg	if (rlen) {
172425944Sjoerg		if (debug)
172525944Sjoerg			addlog(" send conf-rej\n");
172625944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
172725944Sjoerg		return 0;
172825944Sjoerg	} else if (debug)
172925944Sjoerg		addlog("\n");
173025944Sjoerg
173125944Sjoerg	/*
173225944Sjoerg	 * pass 2: check for option values that are unacceptable and
173325944Sjoerg	 * thus require to be nak'ed.
173425944Sjoerg	 */
173525944Sjoerg	if (debug)
173626077Sjoerg		log(LOG_DEBUG, "%s%d: lcp parse opt values: ",
173726077Sjoerg		    ifp->if_name, ifp->if_unit);
173825944Sjoerg
173925944Sjoerg	p = (void*) (h+1);
174025944Sjoerg	len = origlen;
174125944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
174225944Sjoerg		if (debug)
174325944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
174425944Sjoerg		switch (*p) {
174525944Sjoerg		case LCP_OPT_MAGIC:
174611189Sjkh			/* Magic number -- extract. */
174725944Sjoerg			nmagic = (u_long)p[2] << 24 |
174825944Sjoerg				(u_long)p[3] << 16 | p[4] << 8 | p[5];
174925944Sjoerg			if (nmagic != sp->lcp.magic) {
175025706Sjoerg				if (debug)
175125944Sjoerg					addlog("0x%x ", nmagic);
175211189Sjkh				continue;
175311189Sjkh			}
175425944Sjoerg			/*
175525944Sjoerg			 * Local and remote magics equal -- loopback?
175625944Sjoerg			 */
175725944Sjoerg			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
175825944Sjoerg				printf ("\n%s%d: loopback\n",
175925944Sjoerg					ifp->if_name, ifp->if_unit);
176025944Sjoerg				sp->pp_loopcnt = 0;
176125944Sjoerg				if (ifp->if_flags & IFF_UP) {
176225944Sjoerg					if_down(ifp);
176326018Sjoerg					sppp_qflush(&sp->pp_cpq);
176425944Sjoerg					/* XXX ? */
176525944Sjoerg					lcp.Down(sp);
176625944Sjoerg					lcp.Up(sp);
176725944Sjoerg				}
176825944Sjoerg			} else if (debug)
176925944Sjoerg				addlog("[glitch] ");
177025944Sjoerg			++sp->pp_loopcnt;
177125944Sjoerg			/*
177225944Sjoerg			 * We negate our magic here, and NAK it.  If
177325944Sjoerg			 * we see it later in an NAK packet, we
177425944Sjoerg			 * suggest a new one.
177525944Sjoerg			 */
177625944Sjoerg			nmagic = ~sp->lcp.magic;
177725944Sjoerg			/* Gonna NAK it. */
177825944Sjoerg			p[2] = nmagic >> 24;
177925944Sjoerg			p[3] = nmagic >> 16;
178025944Sjoerg			p[4] = nmagic >> 8;
178125944Sjoerg			p[5] = nmagic;
178211189Sjkh			break;
178325944Sjoerg
178411189Sjkh		case LCP_OPT_ASYNC_MAP:
178511189Sjkh			/* Async control character map -- check to be zero. */
178625944Sjoerg			if (! p[2] && ! p[3] && ! p[4] && ! p[5]) {
178725706Sjoerg				if (debug)
178825944Sjoerg					addlog("[empty] ");
178911189Sjkh				continue;
179025706Sjoerg			}
179125706Sjoerg			if (debug)
179225944Sjoerg				addlog("[non-empty] ");
179325944Sjoerg			/* suggest a zero one */
179425944Sjoerg			p[2] = p[3] = p[4] = p[5] = 0;
179511189Sjkh			break;
179625944Sjoerg
179711189Sjkh		case LCP_OPT_MRU:
179825944Sjoerg			/*
179925944Sjoerg			 * Maximum receive unit.  Always agreeable,
180025944Sjoerg			 * but ignored by now.
180125944Sjoerg			 */
180225944Sjoerg			sp->lcp.their_mru = p[2] * 256 + p[3];
180325706Sjoerg			if (debug)
180425944Sjoerg				addlog("%d ", sp->lcp.their_mru);
180511189Sjkh			continue;
180611189Sjkh		}
180725944Sjoerg		/* Add the option to nak'ed list. */
180825706Sjoerg		bcopy (p, r, p[1]);
180925706Sjoerg		r += p[1];
181011189Sjkh		rlen += p[1];
181112436Speter	}
181225706Sjoerg	if (rlen) {
181325706Sjoerg		if (debug)
181425944Sjoerg			addlog(" send conf-nak\n");
181525944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
181625944Sjoerg		return 0;
181725944Sjoerg	} else {
181825944Sjoerg		if (debug)
181925944Sjoerg			addlog(" send conf-ack\n");
182025944Sjoerg		sp->pp_loopcnt = 0;
182125944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_ACK,
182225944Sjoerg			      h->ident, origlen, h+1);
182325944Sjoerg	}
182425944Sjoerg
182511189Sjkh	free (buf, M_TEMP);
182611189Sjkh	return (rlen == 0);
18274910Swollman}
18284910Swollman
182925944Sjoerg/*
183025944Sjoerg * Analyze the LCP Configure-Reject option list, and adjust our
183125944Sjoerg * negotiation.
183225944Sjoerg */
183312820Sphkstatic void
183425944Sjoergsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
18354910Swollman{
183625944Sjoerg	STDDCL;
183725944Sjoerg	u_char *buf, *p;
18384910Swollman
183925944Sjoerg	len -= 4;
184025944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
184125944Sjoerg	if (!buf)
18424910Swollman		return;
184325944Sjoerg
184425944Sjoerg	if (debug)
184525944Sjoerg		log(LOG_DEBUG, "%s%d: lcp rej opts: ",
184625944Sjoerg		    ifp->if_name, ifp->if_unit);
184725944Sjoerg
184825944Sjoerg	p = (void*) (h+1);
184925944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
185025944Sjoerg		if (debug)
185125944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
185225944Sjoerg		switch (*p) {
185325944Sjoerg		case LCP_OPT_MAGIC:
185425944Sjoerg			/* Magic number -- can't use it, use 0 */
185525944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC);
185625944Sjoerg			sp->lcp.magic = 0;
185725944Sjoerg			break;
185825944Sjoerg		case LCP_OPT_MRU:
185925944Sjoerg			/*
186025944Sjoerg			 * Should not be rejected anyway, since we only
186125944Sjoerg			 * negotiate a MRU if explicitly requested by
186225944Sjoerg			 * peer.
186325944Sjoerg			 */
186425944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
186525944Sjoerg			break;
186625944Sjoerg		}
18674910Swollman	}
186825944Sjoerg	if (debug)
186925944Sjoerg		addlog("\n");
187025944Sjoerg	free (buf, M_TEMP);
187125944Sjoerg	return;
187225944Sjoerg}
187325944Sjoerg
187425944Sjoerg/*
187525944Sjoerg * Analyze the LCP Configure-NAK option list, and adjust our
187625944Sjoerg * negotiation.
187725944Sjoerg */
187825944Sjoergstatic void
187925944Sjoergsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
188025944Sjoerg{
188125944Sjoerg	STDDCL;
188225944Sjoerg	u_char *buf, *p;
188325944Sjoerg	u_long magic;
188425944Sjoerg
188525944Sjoerg	len -= 4;
188625944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
188725944Sjoerg	if (!buf)
188825944Sjoerg		return;
188925944Sjoerg
189025944Sjoerg	if (debug)
189125944Sjoerg		log(LOG_DEBUG, "%s%d: lcp nak opts: ",
189225944Sjoerg		    ifp->if_name, ifp->if_unit);
189325944Sjoerg
189425944Sjoerg	p = (void*) (h+1);
189525944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
189625706Sjoerg		if (debug)
189725944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
189825944Sjoerg		switch (*p) {
189925944Sjoerg		case LCP_OPT_MAGIC:
190025944Sjoerg			/* Magic number -- renegotiate */
190125944Sjoerg			if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
190225944Sjoerg			    len >= 6 && p[1] == 6) {
190325944Sjoerg				magic = (u_long)p[2] << 24 |
190425944Sjoerg					(u_long)p[3] << 16 | p[4] << 8 | p[5];
190525944Sjoerg				/*
190625944Sjoerg				 * If the remote magic is our negated one,
190725944Sjoerg				 * this looks like a loopback problem.
190825944Sjoerg				 * Suggest a new magic to make sure.
190925944Sjoerg				 */
191025944Sjoerg				if (magic == ~sp->lcp.magic) {
191125944Sjoerg					if (debug)
191225944Sjoerg						addlog("magic glitch ");
191325944Sjoerg					sp->lcp.magic += time.tv_sec + time.tv_usec;
191425944Sjoerg				} else {
191525944Sjoerg					sp->lcp.magic = magic;
191625944Sjoerg					if (debug)
191725944Sjoerg						addlog("%d ");
191825944Sjoerg				}
191925944Sjoerg			}
192025944Sjoerg			break;
192125944Sjoerg		case LCP_OPT_MRU:
192225944Sjoerg			/*
192325944Sjoerg			 * Peer wants to advise us to negotiate an MRU.
192425944Sjoerg			 * Agree on it if it's reasonable, or use
192525944Sjoerg			 * default otherwise.
192625944Sjoerg			 */
192725944Sjoerg			if (len >= 4 && p[1] == 4) {
192825944Sjoerg				u_int mru = p[2] * 256 + p[3];
192925944Sjoerg				if (debug)
193025944Sjoerg					addlog("%d ", mru);
193125944Sjoerg				if (mru < PP_MTU || mru > PP_MAX_MRU)
193225944Sjoerg					mru = PP_MTU;
193325944Sjoerg				sp->lcp.mru = mru;
193425944Sjoerg				sp->lcp.opts |= (1 << LCP_OPT_MRU);
193525944Sjoerg			}
193625944Sjoerg			break;
19374910Swollman		}
193825944Sjoerg	}
193925944Sjoerg	if (debug)
194025944Sjoerg		addlog("\n");
194125944Sjoerg	free (buf, M_TEMP);
194225944Sjoerg	return;
194325944Sjoerg}
194411189Sjkh
194525944Sjoergstatic void
194625944Sjoergsppp_lcp_tlu(struct sppp *sp)
194725944Sjoerg{
194825944Sjoerg	STDDCL;
194925944Sjoerg	int i;
195025944Sjoerg	u_long mask;
195125944Sjoerg
195225944Sjoerg	/* XXX ? */
195325944Sjoerg	if (! (ifp->if_flags & IFF_UP) &&
195425944Sjoerg	    (ifp->if_flags & IFF_RUNNING)) {
195525944Sjoerg		/* Coming out of loopback mode. */
195625944Sjoerg		if_up(ifp);
195725944Sjoerg		printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
195825944Sjoerg	}
195925944Sjoerg
196025944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
196125944Sjoerg		if ((cps[i])->flags & CP_QUAL)
196225944Sjoerg			(cps[i])->Open(sp);
196325944Sjoerg
196425944Sjoerg	if (/* require authentication XXX */ 0)
196525944Sjoerg		sp->pp_phase = PHASE_AUTHENTICATE;
196625944Sjoerg	else
196725944Sjoerg		sp->pp_phase = PHASE_NETWORK;
196825944Sjoerg
196925944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
197025944Sjoerg	    sppp_phase_name(sp->pp_phase));
197125944Sjoerg
197225944Sjoerg	if (sp->pp_phase == PHASE_AUTHENTICATE) {
197325944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
197425944Sjoerg			if ((cps[i])->flags & CP_AUTH)
197525944Sjoerg				(cps[i])->Open(sp);
197625944Sjoerg	} else {
197725944Sjoerg		/* Notify all NCPs. */
197825944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
197925944Sjoerg			if ((cps[i])->flags & CP_NCP)
198025944Sjoerg				(cps[i])->Open(sp);
198125944Sjoerg	}
198225944Sjoerg
198325944Sjoerg	/* Send Up events to all started protos. */
198425944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
198525944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0)
198625944Sjoerg			(cps[i])->Up(sp);
198725944Sjoerg
198825944Sjoerg	if (sp->pp_phase == PHASE_NETWORK)
198925944Sjoerg		/* if no NCP is starting, close down */
199025944Sjoerg		sppp_lcp_check(sp);
199125944Sjoerg}
199225944Sjoerg
199325944Sjoergstatic void
199425944Sjoergsppp_lcp_tld(struct sppp *sp)
199525944Sjoerg{
199625944Sjoerg	STDDCL;
199725944Sjoerg	int i;
199825944Sjoerg	u_long mask;
199925944Sjoerg
200025944Sjoerg	sp->pp_phase = PHASE_TERMINATE;
200125944Sjoerg
200225944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
200325944Sjoerg	    sppp_phase_name(sp->pp_phase));
200425944Sjoerg
200525944Sjoerg	/*
200625944Sjoerg	 * Take upper layers down.  We send the Down event first and
200725944Sjoerg	 * the Close second to prevent the upper layers from sending
200825944Sjoerg	 * ``a flurry of terminate-request packets'', as the RFC
200925944Sjoerg	 * describes it.
201025944Sjoerg	 */
201125944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
201225944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) {
201325944Sjoerg			(cps[i])->Down(sp);
201425944Sjoerg			(cps[i])->Close(sp);
201525944Sjoerg		}
201625944Sjoerg}
201725944Sjoerg
201825944Sjoergstatic void
201925944Sjoergsppp_lcp_tls(struct sppp *sp)
202025944Sjoerg{
202125944Sjoerg	STDDCL;
202225944Sjoerg
202325944Sjoerg	sp->pp_phase = PHASE_ESTABLISH;
202425944Sjoerg
202525944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
202625944Sjoerg	    sppp_phase_name(sp->pp_phase));
202725944Sjoerg
202825944Sjoerg	/* Notify lower layer if desired. */
202925944Sjoerg	if (sp->pp_tls)
203025944Sjoerg		(sp->pp_tls)(sp);
203125944Sjoerg}
203225944Sjoerg
203325944Sjoergstatic void
203425944Sjoergsppp_lcp_tlf(struct sppp *sp)
203525944Sjoerg{
203625944Sjoerg	STDDCL;
203725944Sjoerg
203825944Sjoerg	sp->pp_phase = PHASE_DEAD;
203925944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
204025944Sjoerg	    sppp_phase_name(sp->pp_phase));
204125944Sjoerg
204225944Sjoerg	/* Notify lower layer if desired. */
204325944Sjoerg	if (sp->pp_tlf)
204425944Sjoerg		(sp->pp_tlf)(sp);
204525944Sjoerg}
204625944Sjoerg
204725944Sjoergstatic void
204825944Sjoergsppp_lcp_scr(struct sppp *sp)
204925944Sjoerg{
205025944Sjoerg	char opt[6 /* magicnum */ + 4 /* mru */];
205125944Sjoerg	int i = 0;
205225944Sjoerg
205325944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
205425944Sjoerg		if (! sp->lcp.magic)
205525944Sjoerg			sp->lcp.magic = time.tv_sec + time.tv_usec;
205625944Sjoerg		opt[i++] = LCP_OPT_MAGIC;
205725944Sjoerg		opt[i++] = 6;
205825944Sjoerg		opt[i++] = sp->lcp.magic >> 24;
205925944Sjoerg		opt[i++] = sp->lcp.magic >> 16;
206025944Sjoerg		opt[i++] = sp->lcp.magic >> 8;
206125944Sjoerg		opt[i++] = sp->lcp.magic;
206225944Sjoerg	}
206325944Sjoerg
206425944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MRU)) {
206525944Sjoerg		opt[i++] = LCP_OPT_MRU;
206625944Sjoerg		opt[i++] = 4;
206725944Sjoerg		opt[i++] = sp->lcp.mru >> 8;
206825944Sjoerg		opt[i++] = sp->lcp.mru;
206925944Sjoerg	}
207025944Sjoerg
207125944Sjoerg	sp->confid[IDX_LCP] = ++sp->pp_seq;
207225944Sjoerg	sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
207325944Sjoerg}
207425944Sjoerg
207525944Sjoerg/*
207625944Sjoerg * Re-check the open NCPs and see if we should terminate the link.
207725944Sjoerg * Called by the NCPs during their tlf action handling.
207825944Sjoerg */
207925944Sjoergstatic void
208025944Sjoergsppp_lcp_check(struct sppp *sp)
208125944Sjoerg{
208225944Sjoerg	int i, mask;
208325944Sjoerg
208425944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
208525944Sjoerg		if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP)
208625944Sjoerg			return;
208725944Sjoerg	lcp.Close(sp);
208825944Sjoerg}
208925944Sjoerg/*
209025944Sjoerg *--------------------------------------------------------------------------*
209125944Sjoerg *                                                                          *
209225944Sjoerg *                        The IPCP implementation.                          *
209325944Sjoerg *                                                                          *
209425944Sjoerg *--------------------------------------------------------------------------*
209525944Sjoerg */
209625944Sjoerg
209725944Sjoergstatic void
209825944Sjoergsppp_ipcp_init(struct sppp *sp)
209925944Sjoerg{
210025944Sjoerg	sp->ipcp.opts = 0;
210125944Sjoerg	sp->ipcp.flags = 0;
210225944Sjoerg	sp->state[IDX_IPCP] = STATE_INITIAL;
210325944Sjoerg	sp->fail_counter[IDX_IPCP] = 0;
210425944Sjoerg}
210525944Sjoerg
210625944Sjoergstatic void
210725944Sjoergsppp_ipcp_up(struct sppp *sp)
210825944Sjoerg{
210925944Sjoerg	sppp_up_event(&ipcp, sp);
211025944Sjoerg}
211125944Sjoerg
211225944Sjoergstatic void
211325944Sjoergsppp_ipcp_down(struct sppp *sp)
211425944Sjoerg{
211525944Sjoerg	sppp_down_event(&ipcp, sp);
211625944Sjoerg}
211725944Sjoerg
211825944Sjoergstatic void
211925944Sjoergsppp_ipcp_open(struct sppp *sp)
212025944Sjoerg{
212125944Sjoerg	STDDCL;
212225944Sjoerg	u_long myaddr, hisaddr;
212325944Sjoerg
212425944Sjoerg	sppp_get_ip_addrs(sp, &myaddr, &hisaddr);
212525944Sjoerg	/*
212625944Sjoerg	 * If we don't have his address, this probably means our
212725944Sjoerg	 * interface doesn't want to talk IP at all.  (This could
212825944Sjoerg	 * be the case if somebody wants to speak only IPX, for
212925944Sjoerg	 * example.)  Don't open IPCP in this case.
213025944Sjoerg	 */
213125944Sjoerg	if (hisaddr == 0L) {
213225944Sjoerg		/* XXX this message should go away */
213325944Sjoerg		if (debug)
213425944Sjoerg			log(LOG_DEBUG, "%s%d: ipcp_open(): no IP interface\n",
213525944Sjoerg			    ifp->if_name, ifp->if_unit);
213625944Sjoerg		return;
213725944Sjoerg	}
213825944Sjoerg
213925944Sjoerg	if (myaddr == 0L) {
214025944Sjoerg		/*
214125944Sjoerg		 * I don't have an assigned address, so i need to
214225944Sjoerg		 * negotiate my address.
214325944Sjoerg		 */
214425944Sjoerg		sp->ipcp.flags |= IPCP_MYADDR_DYN;
214525944Sjoerg		sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
214625944Sjoerg	}
214725944Sjoerg	sppp_open_event(&ipcp, sp);
214825944Sjoerg}
214925944Sjoerg
215025944Sjoergstatic void
215125944Sjoergsppp_ipcp_close(struct sppp *sp)
215225944Sjoerg{
215325944Sjoerg	sppp_close_event(&ipcp, sp);
215425944Sjoerg	if (sp->ipcp.flags & IPCP_MYADDR_DYN)
215525944Sjoerg		/*
215625944Sjoerg		 * My address was dynamic, clear it again.
215725944Sjoerg		 */
215825944Sjoerg		sppp_set_ip_addr(sp, 0L);
215925944Sjoerg}
216025944Sjoerg
216125944Sjoergstatic void
216225944Sjoergsppp_ipcp_TO(void *cookie)
216325944Sjoerg{
216425944Sjoerg	sppp_to_event(&ipcp, (struct sppp *)cookie);
216525944Sjoerg}
216625944Sjoerg
216725944Sjoerg/*
216825944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
216925944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
217025944Sjoerg * caused action scn.  (The return value is used to make the state
217125944Sjoerg * transition decision in the state automaton.)
217225944Sjoerg */
217325944Sjoergstatic int
217425944Sjoergsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
217525944Sjoerg{
217625944Sjoerg	u_char *buf, *r, *p;
217725944Sjoerg	struct ifnet *ifp = &sp->pp_if;
217825944Sjoerg	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
217925944Sjoerg	u_long hisaddr, desiredaddr;
218025944Sjoerg
218125944Sjoerg	len -= 4;
218225944Sjoerg	origlen = len;
218325944Sjoerg	/*
218425944Sjoerg	 * Make sure to allocate a buf that can at least hold a
218525944Sjoerg	 * conf-nak with an `address' option.  We might need it below.
218625944Sjoerg	 */
218725944Sjoerg	buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
218825944Sjoerg	if (! buf)
218925944Sjoerg		return (0);
219025944Sjoerg
219125944Sjoerg	/* pass 1: see if we can recognize them */
219225944Sjoerg	if (debug)
219325944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp parse opts: ",
219425944Sjoerg		    ifp->if_name, ifp->if_unit);
219525944Sjoerg	p = (void*) (h+1);
219625944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
219725944Sjoerg		if (debug)
219825944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
219925944Sjoerg		switch (*p) {
220025944Sjoerg#ifdef notyet
220125944Sjoerg		case IPCP_OPT_COMPRESSION:
220225944Sjoerg			if (len >= 6 && p[1] >= 6) {
220325944Sjoerg				/* correctly formed compress option */
220425944Sjoerg				continue;
220511189Sjkh			}
220625706Sjoerg			if (debug)
220725944Sjoerg				addlog("[invalid] ");
220825944Sjoerg			break;
220925944Sjoerg#endif
221025944Sjoerg		case IPCP_OPT_ADDRESS:
221125944Sjoerg			if (len >= 6 && p[1] == 6) {
221225944Sjoerg				/* correctly formed address option */
221325944Sjoerg				continue;
221425944Sjoerg			}
221525706Sjoerg			if (debug)
221625944Sjoerg				addlog("[invalid] ");
221711189Sjkh			break;
221825944Sjoerg		default:
221925944Sjoerg			/* Others not supported. */
222025944Sjoerg			if (debug)
222125944Sjoerg				addlog("[rej] ");
22224910Swollman			break;
22234910Swollman		}
222425944Sjoerg		/* Add the option to rejected list. */
222525944Sjoerg		bcopy (p, r, p[1]);
222625944Sjoerg		r += p[1];
222725944Sjoerg		rlen += p[1];
222825944Sjoerg	}
222925944Sjoerg	if (rlen) {
223025944Sjoerg		if (debug)
223125944Sjoerg			addlog(" send conf-rej\n");
223225944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf);
223325944Sjoerg		return 0;
223425944Sjoerg	} else if (debug)
223525944Sjoerg		addlog("\n");
223625944Sjoerg
223725944Sjoerg	/* pass 2: parse option values */
223825944Sjoerg	sppp_get_ip_addrs(sp, 0, &hisaddr);
223925944Sjoerg	if (debug)
224025944Sjoerg		addlog("%s%d: ipcp parse opt values: ", ifp->if_name, ifp->if_unit);
224125944Sjoerg	p = (void*) (h+1);
224225944Sjoerg	len = origlen;
224325944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
224425944Sjoerg		if (debug)
224525944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
224625944Sjoerg		switch (*p) {
224725944Sjoerg#ifdef notyet
224825944Sjoerg		case IPCP_OPT_COMPRESSION:
224925944Sjoerg			continue;
225025944Sjoerg#endif
225125944Sjoerg		case IPCP_OPT_ADDRESS:
225225944Sjoerg			desiredaddr = p[2] << 24 | p[3] << 16 |
225325944Sjoerg				p[4] << 8 | p[5];
225425944Sjoerg			if (desiredaddr == hisaddr) {
225525944Sjoerg				/*
225625944Sjoerg				 * Peer's address is same as our value,
225725944Sjoerg				 * this is agreeable.  Gonna conf-ack
225825944Sjoerg				 * it.
225925944Sjoerg				 */
226025944Sjoerg				if (debug)
226125944Sjoerg					addlog("0x%x [ack] ", hisaddr);
226225944Sjoerg				/* record that we've seen it already */
226325944Sjoerg				sp->ipcp.flags |= IPCP_HISADDR_SEEN;
226425944Sjoerg				continue;
226525944Sjoerg			}
226625944Sjoerg			/*
226725944Sjoerg			 * The address wasn't agreeable.  This is either
226825944Sjoerg			 * he sent us 0.0.0.0, asking to assign him an
226925944Sjoerg			 * address, or he send us another address not
227025944Sjoerg			 * matching our value.  Either case, we gonna
227125944Sjoerg			 * conf-nak it with our value.
227225944Sjoerg			 */
227325944Sjoerg			if (debug) {
227425944Sjoerg				if (desiredaddr == 0)
227525944Sjoerg					addlog("[addr requested] ");
227625944Sjoerg				else
227725944Sjoerg					addlog("0x%x [not agreed] ",
227825944Sjoerg					       desiredaddr);
227925944Sjoerg
228025944Sjoerg				p[2] = hisaddr >> 24;
228125944Sjoerg				p[3] = hisaddr >> 16;
228225944Sjoerg				p[4] = hisaddr >> 8;
228325944Sjoerg				p[5] = hisaddr;
228425944Sjoerg			}
228511189Sjkh			break;
228625706Sjoerg		}
228725944Sjoerg		/* Add the option to nak'ed list. */
228825944Sjoerg		bcopy (p, r, p[1]);
228925944Sjoerg		r += p[1];
229025944Sjoerg		rlen += p[1];
229125944Sjoerg	}
229225944Sjoerg
229325944Sjoerg	/*
229425944Sjoerg	 * If we are about to conf-ack the request, but haven't seen
229525944Sjoerg	 * his address so far, gonna conf-nak it instead, with the
229625944Sjoerg	 * `address' option present and our idea of his address being
229725944Sjoerg	 * filled in there, to request negotiation of both addresses.
229825944Sjoerg	 *
229925944Sjoerg	 * XXX This can result in an endless req - nak loop if peer
230025944Sjoerg	 * doesn't want to send us his address.  Q: What should we do
230125944Sjoerg	 * about it?  XXX  A: implement the max-failure counter.
230225944Sjoerg	 */
230325944Sjoerg	if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) {
230425944Sjoerg		buf[0] = IPCP_OPT_ADDRESS;
230525944Sjoerg		buf[1] = 6;
230625944Sjoerg		buf[2] = hisaddr >> 24;
230725944Sjoerg		buf[3] = hisaddr >> 16;
230825944Sjoerg		buf[4] = hisaddr >> 8;
230925944Sjoerg		buf[5] = hisaddr;
231025944Sjoerg		rlen = 6;
231125706Sjoerg		if (debug)
231225944Sjoerg			addlog("still need hisaddr ");
231325944Sjoerg	}
231425944Sjoerg
231525944Sjoerg	if (rlen) {
231625706Sjoerg		if (debug)
231725944Sjoerg			addlog(" send conf-nak\n");
231825944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf);
231925944Sjoerg	} else {
232025706Sjoerg		if (debug)
232125944Sjoerg			addlog(" send conf-ack\n");
232225944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_ACK,
232325944Sjoerg			      h->ident, origlen, h+1);
232425944Sjoerg	}
232525944Sjoerg
232625944Sjoerg	free (buf, M_TEMP);
232725944Sjoerg	return (rlen == 0);
232825944Sjoerg}
232925944Sjoerg
233025944Sjoerg/*
233125944Sjoerg * Analyze the IPCP Configure-Reject option list, and adjust our
233225944Sjoerg * negotiation.
233325944Sjoerg */
233425944Sjoergstatic void
233525944Sjoergsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
233625944Sjoerg{
233725944Sjoerg	u_char *buf, *p;
233825944Sjoerg	struct ifnet *ifp = &sp->pp_if;
233925944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
234025944Sjoerg
234125944Sjoerg	len -= 4;
234225944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
234325944Sjoerg	if (!buf)
234425944Sjoerg		return;
234525944Sjoerg
234625944Sjoerg	if (debug)
234725944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp rej opts: ",
234825944Sjoerg		    ifp->if_name, ifp->if_unit);
234925944Sjoerg
235025944Sjoerg	p = (void*) (h+1);
235125944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
235225706Sjoerg		if (debug)
235325944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
235425944Sjoerg		switch (*p) {
235525944Sjoerg		case IPCP_OPT_ADDRESS:
235625944Sjoerg			/*
235725944Sjoerg			 * Peer doesn't grok address option.  This is
235825944Sjoerg			 * bad.  XXX  Should we better give up here?
235925944Sjoerg			 */
236025944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS);
236125944Sjoerg			break;
236225944Sjoerg#ifdef notyet
236325944Sjoerg		case IPCP_OPT_COMPRESS:
236425944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS);
236525944Sjoerg			break;
236625944Sjoerg#endif
236725944Sjoerg		}
23684910Swollman	}
236925944Sjoerg	if (debug)
237025944Sjoerg		addlog("\n");
237125944Sjoerg	free (buf, M_TEMP);
237225944Sjoerg	return;
23734910Swollman}
23744910Swollman
237525944Sjoerg/*
237625944Sjoerg * Analyze the IPCP Configure-NAK option list, and adjust our
237725944Sjoerg * negotiation.
237825944Sjoerg */
237912820Sphkstatic void
238025944Sjoergsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
23814910Swollman{
238225944Sjoerg	u_char *buf, *p;
238325944Sjoerg	struct ifnet *ifp = &sp->pp_if;
238425944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
238525944Sjoerg	u_long wantaddr;
23864910Swollman
238725944Sjoerg	len -= 4;
238825944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
238925944Sjoerg	if (!buf)
239025944Sjoerg		return;
239125944Sjoerg
239225944Sjoerg	if (debug)
239325944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp nak opts: ",
239425944Sjoerg		    ifp->if_name, ifp->if_unit);
239525944Sjoerg
239625944Sjoerg	p = (void*) (h+1);
239725944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
239825944Sjoerg		if (debug)
239925944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
240025944Sjoerg		switch (*p) {
240125944Sjoerg		case IPCP_OPT_ADDRESS:
240225944Sjoerg			/*
240325944Sjoerg			 * Peer doesn't like our local IP address.  See
240425944Sjoerg			 * if we can do something for him.  We'll drop
240525944Sjoerg			 * him our address then.
240625944Sjoerg			 */
240725944Sjoerg			if (len >= 6 && p[1] == 6) {
240825944Sjoerg				wantaddr = p[2] << 24 | p[3] << 16 |
240925944Sjoerg					p[4] << 8 | p[5];
241025944Sjoerg				sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
241125944Sjoerg				if (debug)
241225944Sjoerg					addlog("[wantaddr 0x%x] ", wantaddr);
241325944Sjoerg				/*
241425944Sjoerg				 * When doing dynamic address assignment,
241525944Sjoerg				 * we accept his offer.  Otherwise, we
241625944Sjoerg				 * ignore it and thus continue to negotiate
241725944Sjoerg				 * our already existing value.
241825944Sjoerg				 */
241925944Sjoerg				if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
242025944Sjoerg					sppp_set_ip_addr(sp, wantaddr);
242125944Sjoerg					if (debug)
242225944Sjoerg						addlog("[agree] ");
242325944Sjoerg				}
242425944Sjoerg			}
242525944Sjoerg			break;
242625944Sjoerg#ifdef notyet
242725944Sjoerg		case IPCP_OPT_COMPRESS:
242825944Sjoerg			/*
242925944Sjoerg			 * Peer wants different compression parameters.
243025944Sjoerg			 */
243125944Sjoerg			break;
243225944Sjoerg#endif
243325944Sjoerg		}
243425944Sjoerg	}
243525944Sjoerg	if (debug)
243625944Sjoerg		addlog("\n");
243725944Sjoerg	free (buf, M_TEMP);
243825944Sjoerg	return;
24394910Swollman}
24404910Swollman
244112820Sphkstatic void
244225944Sjoergsppp_ipcp_tlu(struct sppp *sp)
24434910Swollman{
24444910Swollman}
24454910Swollman
244625944Sjoergstatic void
244725944Sjoergsppp_ipcp_tld(struct sppp *sp)
244825944Sjoerg{
244925944Sjoerg}
245025944Sjoerg
245125944Sjoergstatic void
245225944Sjoergsppp_ipcp_tls(struct sppp *sp)
245325944Sjoerg{
245425944Sjoerg	/* indicate to LCP that it must stay alive */
245525944Sjoerg	sp->lcp.protos |= (1 << IDX_IPCP);
245625944Sjoerg}
245725944Sjoerg
245825944Sjoergstatic void
245925944Sjoergsppp_ipcp_tlf(struct sppp *sp)
246025944Sjoerg{
246125944Sjoerg	/* we no longer need LCP */
246225944Sjoerg	sp->lcp.protos &= ~(1 << IDX_IPCP);
246325944Sjoerg	sppp_lcp_check(sp);
246425944Sjoerg}
246525944Sjoerg
246625944Sjoergstatic void
246725944Sjoergsppp_ipcp_scr(struct sppp *sp)
246825944Sjoerg{
246925944Sjoerg	char opt[6 /* compression */ + 6 /* address */];
247025944Sjoerg	u_long ouraddr;
247125944Sjoerg	int i = 0;
247225944Sjoerg
247325944Sjoerg#ifdef notyet
247425944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
247525944Sjoerg		opt[i++] = IPCP_OPT_COMPRESSION;
247625944Sjoerg		opt[i++] = 6;
247725944Sjoerg		opt[i++] = 0;	/* VJ header compression */
247825944Sjoerg		opt[i++] = 0x2d; /* VJ header compression */
247925944Sjoerg		opt[i++] = max_slot_id;
248025944Sjoerg		opt[i++] = comp_slot_id;
248125944Sjoerg	}
248225944Sjoerg#endif
248325944Sjoerg
248425944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
248525944Sjoerg		sppp_get_ip_addrs(sp, &ouraddr, 0);
248625944Sjoerg		opt[i++] = IPCP_OPT_ADDRESS;
248725944Sjoerg		opt[i++] = 6;
248825944Sjoerg		opt[i++] = ouraddr >> 24;
248925944Sjoerg		opt[i++] = ouraddr >> 16;
249025944Sjoerg		opt[i++] = ouraddr >> 8;
249125944Sjoerg		opt[i++] = ouraddr;
249225944Sjoerg	}
249325944Sjoerg
249425944Sjoerg	sp->confid[IDX_IPCP] = ++sp->pp_seq;
249525944Sjoerg	sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
249625944Sjoerg}
249725944Sjoerg
249825944Sjoerg
249925944Sjoerg/*
250025944Sjoerg * Random miscellaneous functions.
250125944Sjoerg */
250225944Sjoerg
25034910Swollman/*
250425944Sjoerg * Flush interface queue.
25054910Swollman */
250612820Sphkstatic void
250725944Sjoergsppp_qflush(struct ifqueue *ifq)
25084910Swollman{
250925944Sjoerg	struct mbuf *m, *n;
25104910Swollman
251125944Sjoerg	n = ifq->ifq_head;
251225944Sjoerg	while ((m = n)) {
251325944Sjoerg		n = m->m_act;
251425944Sjoerg		m_freem (m);
251511189Sjkh	}
251625944Sjoerg	ifq->ifq_head = 0;
251725944Sjoerg	ifq->ifq_tail = 0;
251825944Sjoerg	ifq->ifq_len = 0;
251925944Sjoerg}
252025944Sjoerg
252125944Sjoerg/*
252225944Sjoerg * Send keepalive packets, every 10 seconds.
252325944Sjoerg */
252425944Sjoergstatic void
252525944Sjoergsppp_keepalive(void *dummy)
252625944Sjoerg{
252725944Sjoerg	struct sppp *sp;
252825944Sjoerg	int s;
252925944Sjoerg
253025944Sjoerg	s = splimp();
253125944Sjoerg	for (sp=spppq; sp; sp=sp->pp_next) {
253225944Sjoerg		struct ifnet *ifp = &sp->pp_if;
253325944Sjoerg
253425944Sjoerg		/* Keepalive mode disabled or channel down? */
253525944Sjoerg		if (! (sp->pp_flags & PP_KEEPALIVE) ||
253625944Sjoerg		    ! (ifp->if_flags & IFF_RUNNING))
253725944Sjoerg			continue;
253825944Sjoerg
253925944Sjoerg		/* No keepalive in PPP mode if LCP not opened yet. */
254025944Sjoerg		if (! (sp->pp_flags & PP_CISCO) &&
254125944Sjoerg		    sp->pp_phase < PHASE_AUTHENTICATE)
254225944Sjoerg			continue;
254325944Sjoerg
254425944Sjoerg		if (sp->pp_alivecnt == MAXALIVECNT) {
254525944Sjoerg			/* No keepalive packets got.  Stop the interface. */
254625944Sjoerg			printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
254725944Sjoerg			if_down (ifp);
254826018Sjoerg			sppp_qflush (&sp->pp_cpq);
254925944Sjoerg			if (! (sp->pp_flags & PP_CISCO)) {
255025944Sjoerg				/* XXX */
255125944Sjoerg				/* Shut down the PPP link. */
255225944Sjoerg				lcp.Down(sp);
255325944Sjoerg				/* Initiate negotiation. XXX */
255425944Sjoerg				lcp.Up(sp);
255525944Sjoerg			}
25564910Swollman		}
255725944Sjoerg		if (sp->pp_alivecnt <= MAXALIVECNT)
255825944Sjoerg			++sp->pp_alivecnt;
255925944Sjoerg		if (sp->pp_flags & PP_CISCO)
256025944Sjoerg			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
256125944Sjoerg				sp->pp_rseq);
256225944Sjoerg		else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
256325944Sjoerg			long nmagic = htonl (sp->lcp.magic);
256425944Sjoerg			sp->lcp.echoid = ++sp->pp_seq;
256525944Sjoerg			sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
256625944Sjoerg				sp->lcp.echoid, 4, &nmagic);
256725944Sjoerg		}
25684910Swollman	}
256925944Sjoerg	splx(s);
257025944Sjoerg	timeout(sppp_keepalive, 0, hz * 10);
25714910Swollman}
25724910Swollman
257325944Sjoerg/*
257425944Sjoerg * Get both IP addresses.
257525944Sjoerg */
257625944Sjoergstatic void
257725944Sjoergsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst)
257825944Sjoerg{
257925944Sjoerg	struct ifnet *ifp = &sp->pp_if;
258025944Sjoerg	struct ifaddr *ifa;
258125944Sjoerg	struct sockaddr_in *si;
258225944Sjoerg	u_long ssrc, ddst;
258325944Sjoerg
258425944Sjoerg	ssrc = ddst = 0L;
258525944Sjoerg	/*
258625944Sjoerg	 * Pick the first AF_INET address from the list,
258725944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
258825944Sjoerg	 */
258925944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
259025944Sjoerg	     ifa;
259125944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
259225944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
259325944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
259425944Sjoerg			if (si)
259525944Sjoerg				break;
259625944Sjoerg		}
259725944Sjoerg	if (ifa) {
259825944Sjoerg		if (si && si->sin_addr.s_addr)
259925944Sjoerg			ssrc = si->sin_addr.s_addr;
260025944Sjoerg
260125944Sjoerg		si = (struct sockaddr_in *)ifa->ifa_dstaddr;
260225944Sjoerg		if (si && si->sin_addr.s_addr)
260325944Sjoerg			ddst = si->sin_addr.s_addr;
260425944Sjoerg	}
260525944Sjoerg
260625944Sjoerg	if (dst) *dst = ntohl(ddst);
260725944Sjoerg	if (src) *src = ntohl(ssrc);
260825944Sjoerg}
260925944Sjoerg
261025944Sjoerg/*
261125944Sjoerg * Set my IP address.  Must be called at splimp.
261225944Sjoerg */
261325944Sjoergstatic void
261425944Sjoergsppp_set_ip_addr(struct sppp *sp, u_long src)
261525944Sjoerg{
261625944Sjoerg	struct ifnet *ifp = &sp->pp_if;
261725944Sjoerg	struct ifaddr *ifa;
261825944Sjoerg	struct sockaddr_in *si;
261925944Sjoerg	u_long ssrc, ddst;
262025944Sjoerg
262125944Sjoerg	/*
262225944Sjoerg	 * Pick the first AF_INET address from the list,
262325944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
262425944Sjoerg	 */
262525944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
262625944Sjoerg	     ifa;
262725944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
262825944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
262925944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
263025944Sjoerg			if (si)
263125944Sjoerg				break;
263225944Sjoerg		}
263325944Sjoerg	if (ifa && si)
263425944Sjoerg		si->sin_addr.s_addr = htonl(src);
263525944Sjoerg}
263625944Sjoerg
263725706Sjoergstatic const char *
263825944Sjoergsppp_cp_type_name(u_char type)
26394910Swollman{
264025706Sjoerg	static char buf [12];
26414910Swollman	switch (type) {
264225944Sjoerg	case CONF_REQ:   return ("conf-req");
264325944Sjoerg	case CONF_ACK:   return ("conf-ack");
264425944Sjoerg	case CONF_NAK:   return ("conf-nak");
264525944Sjoerg	case CONF_REJ:   return ("conf-rej");
264625944Sjoerg	case TERM_REQ:   return ("term-req");
264725944Sjoerg	case TERM_ACK:   return ("term-ack");
264825944Sjoerg	case CODE_REJ:   return ("code-rej");
264925944Sjoerg	case PROTO_REJ:  return ("proto-rej");
265025944Sjoerg	case ECHO_REQ:   return ("echo-req");
265125944Sjoerg	case ECHO_REPLY: return ("echo-reply");
265225944Sjoerg	case DISC_REQ:   return ("discard-req");
26534910Swollman	}
265425706Sjoerg	sprintf (buf, "0x%x", type);
26554910Swollman	return (buf);
26564910Swollman}
26574910Swollman
265825706Sjoergstatic const char *
265925944Sjoergsppp_lcp_opt_name(u_char opt)
26604910Swollman{
266125706Sjoerg	static char buf [12];
266225944Sjoerg	switch (opt) {
266325944Sjoerg	case LCP_OPT_MRU:		return ("mru");
266425944Sjoerg	case LCP_OPT_ASYNC_MAP:		return ("async-map");
266525944Sjoerg	case LCP_OPT_AUTH_PROTO:	return ("auth-proto");
266625944Sjoerg	case LCP_OPT_QUAL_PROTO:	return ("qual-proto");
266725944Sjoerg	case LCP_OPT_MAGIC:		return ("magic");
266825944Sjoerg	case LCP_OPT_PROTO_COMP:	return ("proto-comp");
266925944Sjoerg	case LCP_OPT_ADDR_COMP:		return ("addr-comp");
26704910Swollman	}
267125944Sjoerg	sprintf (buf, "0x%x", opt);
26724910Swollman	return (buf);
26734910Swollman}
26744910Swollman
267525944Sjoergstatic const char *
267625944Sjoergsppp_ipcp_opt_name(u_char opt)
267725944Sjoerg{
267825944Sjoerg	static char buf [12];
267925944Sjoerg	switch (opt) {
268025944Sjoerg	case IPCP_OPT_ADDRESSES:	return ("addresses");
268125944Sjoerg	case IPCP_OPT_COMPRESSION:	return ("compression");
268225944Sjoerg	case IPCP_OPT_ADDRESS:		return ("address");
268325944Sjoerg	}
268425944Sjoerg	sprintf (buf, "0x%x", opt);
268525944Sjoerg	return (buf);
268625944Sjoerg}
268725944Sjoerg
268825944Sjoergstatic const char *
268925944Sjoergsppp_state_name(int state)
269025944Sjoerg{
269125944Sjoerg	switch (state) {
269225944Sjoerg	case STATE_INITIAL:	return "initial";
269325944Sjoerg	case STATE_STARTING:	return "starting";
269425944Sjoerg	case STATE_CLOSED:	return "closed";
269525944Sjoerg	case STATE_STOPPED:	return "stopped";
269625944Sjoerg	case STATE_CLOSING:	return "closing";
269725944Sjoerg	case STATE_STOPPING:	return "stopping";
269825944Sjoerg	case STATE_REQ_SENT:	return "req-sent";
269925944Sjoerg	case STATE_ACK_RCVD:	return "ack-rcvd";
270025944Sjoerg	case STATE_ACK_SENT:	return "ack-sent";
270125944Sjoerg	case STATE_OPENED:	return "opened";
270225944Sjoerg	}
270325944Sjoerg	return "illegal";
270425944Sjoerg}
270525944Sjoerg
270625944Sjoergstatic const char *
270725944Sjoergsppp_phase_name(enum ppp_phase phase)
270825944Sjoerg{
270925944Sjoerg	switch (phase) {
271025944Sjoerg	case PHASE_DEAD:	return "dead";
271125944Sjoerg	case PHASE_ESTABLISH:	return "establish";
271225944Sjoerg	case PHASE_TERMINATE:	return "terminate";
271325944Sjoerg	case PHASE_AUTHENTICATE: return "authenticate";
271425944Sjoerg	case PHASE_NETWORK:	return "network";
271525944Sjoerg	}
271625944Sjoerg	return "illegal";
271725944Sjoerg}
271825944Sjoerg
271925944Sjoergstatic const char *
272025944Sjoergsppp_proto_name(u_short proto)
272125944Sjoerg{
272225944Sjoerg	static char buf[12];
272325944Sjoerg	switch (proto) {
272425944Sjoerg	case PPP_LCP:	return "lcp";
272525944Sjoerg	case PPP_IPCP:	return "ipcp";
272625944Sjoerg	}
272725944Sjoerg	sprintf(buf, "0x%x", (unsigned)proto);
272825944Sjoerg	return buf;
272925944Sjoerg}
273025944Sjoerg
273112820Sphkstatic void
273225706Sjoergsppp_print_bytes(u_char *p, u_short len)
27334910Swollman{
273425706Sjoerg	addlog(" %x", *p++);
27354910Swollman	while (--len > 0)
273625706Sjoerg		addlog("-%x", *p++);
27374910Swollman}
273825944Sjoerg
273925944Sjoerg/*
274025944Sjoerg * This file is large.  Tell emacs to highlight it nevertheless.
274125944Sjoerg *
274225944Sjoerg * Local Variables:
274325944Sjoerg * hilit-auto-highlight-maxout: 100000
274425944Sjoerg * End:
274525944Sjoerg */
2746