if_spppsubr.c revision 29024
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 *
2029024Sbde * $Id: if_spppsubr.c,v 1.25 1997/08/12 05:22:54 kjc 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>
2929024Sbde#include <sys/malloc.h>
304910Swollman#include <sys/mbuf.h>
314910Swollman
324910Swollman#include <net/if.h>
334910Swollman#include <net/netisr.h>
344910Swollman#include <net/if_types.h>
354910Swollman
364910Swollman#ifdef INET
374910Swollman#include <netinet/in.h>
384910Swollman#include <netinet/in_systm.h>
394910Swollman#include <netinet/in_var.h>
404910Swollman#include <netinet/ip.h>
414910Swollman#include <netinet/tcp.h>
424910Swollman#include <netinet/if_ether.h>
434910Swollman#endif
444910Swollman
4511819Sjulian#ifdef IPX
4611819Sjulian#include <netipx/ipx.h>
4711819Sjulian#include <netipx/ipx_if.h>
4811819Sjulian#endif
4911819Sjulian
504910Swollman#ifdef NS
514910Swollman#include <netns/ns.h>
524910Swollman#include <netns/ns_if.h>
534910Swollman#endif
544910Swollman
554910Swollman#ifdef ISO
564910Swollman#include <netiso/argo_debug.h>
574910Swollman#include <netiso/iso.h>
584910Swollman#include <netiso/iso_var.h>
594910Swollman#include <netiso/iso_snpac.h>
604910Swollman#endif
614910Swollman
624910Swollman#include <net/if_sppp.h>
634910Swollman
644910Swollman#define MAXALIVECNT     3               /* max. alive packets */
654910Swollman
6625944Sjoerg/*
6725944Sjoerg * Interface flags that can be set in an ifconfig command.
6825944Sjoerg *
6925955Sjoerg * Setting link0 will make the link passive, i.e. it will be marked
7025944Sjoerg * as being administrative openable, but won't be opened to begin
7125944Sjoerg * with.  Incoming calls will be answered, or subsequent calls with
7225944Sjoerg * -link1 will cause the administrative open of the LCP layer.
7325955Sjoerg *
7425955Sjoerg * Setting link1 will cause the link to auto-dial only as packets
7525955Sjoerg * arrive to be sent.
7625944Sjoerg */
7725944Sjoerg
7825955Sjoerg#define IFF_PASSIVE	IFF_LINK0	/* wait passively for connection */
7925955Sjoerg#define IFF_AUTO	IFF_LINK1	/* auto-dial on output */
8025944Sjoerg
814910Swollman#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
824910Swollman#define PPP_UI          0x03            /* Unnumbered Information */
834910Swollman#define PPP_IP          0x0021          /* Internet Protocol */
844910Swollman#define PPP_ISO         0x0023          /* ISO OSI Protocol */
854910Swollman#define PPP_XNS         0x0025          /* Xerox NS Protocol */
8612495Speter#define PPP_IPX         0x002b          /* Novell IPX Protocol */
874910Swollman#define PPP_LCP         0xc021          /* Link Control Protocol */
884910Swollman#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
894910Swollman
9025944Sjoerg#define CONF_REQ	1		/* PPP configure request */
9125944Sjoerg#define CONF_ACK	2		/* PPP configure acknowledge */
9225944Sjoerg#define CONF_NAK	3		/* PPP configure negative ack */
9325944Sjoerg#define CONF_REJ	4		/* PPP configure reject */
9425944Sjoerg#define TERM_REQ	5		/* PPP terminate request */
9525944Sjoerg#define TERM_ACK	6		/* PPP terminate acknowledge */
9625944Sjoerg#define CODE_REJ	7		/* PPP code reject */
9725944Sjoerg#define PROTO_REJ	8		/* PPP protocol reject */
9825944Sjoerg#define ECHO_REQ	9		/* PPP echo request */
9925944Sjoerg#define ECHO_REPLY	10		/* PPP echo reply */
10025944Sjoerg#define DISC_REQ	11		/* PPP discard request */
1014910Swollman
1024910Swollman#define LCP_OPT_MRU             1       /* maximum receive unit */
1034910Swollman#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
1044910Swollman#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
1054910Swollman#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
1064910Swollman#define LCP_OPT_MAGIC           5       /* magic number */
1074910Swollman#define LCP_OPT_RESERVED        6       /* reserved */
1084910Swollman#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
1094910Swollman#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
1104910Swollman
11125944Sjoerg#define IPCP_OPT_ADDRESSES	1	/* both IP addresses; deprecated */
11225944Sjoerg#define IPCP_OPT_COMPRESSION	2	/* IP compression protocol (VJ) */
11325944Sjoerg#define IPCP_OPT_ADDRESS	3	/* local IP address */
1144910Swollman
1154910Swollman#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
1164910Swollman#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
1174910Swollman#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
1184910Swollman#define CISCO_ADDR_REQ          0       /* Cisco address request */
1194910Swollman#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
1204910Swollman#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
1214910Swollman
12225944Sjoerg/* states are named and numbered according to RFC 1661 */
12325944Sjoerg#define STATE_INITIAL	0
12425944Sjoerg#define STATE_STARTING	1
12525944Sjoerg#define STATE_CLOSED	2
12625944Sjoerg#define STATE_STOPPED	3
12725944Sjoerg#define STATE_CLOSING	4
12825944Sjoerg#define STATE_STOPPING	5
12925944Sjoerg#define STATE_REQ_SENT	6
13025944Sjoerg#define STATE_ACK_RCVD	7
13125944Sjoerg#define STATE_ACK_SENT	8
13225944Sjoerg#define STATE_OPENED	9
13325944Sjoerg
1344910Swollmanstruct ppp_header {
13511189Sjkh	u_char address;
13611189Sjkh	u_char control;
13711189Sjkh	u_short protocol;
1384910Swollman};
1394910Swollman#define PPP_HEADER_LEN          sizeof (struct ppp_header)
1404910Swollman
1414910Swollmanstruct lcp_header {
14211189Sjkh	u_char type;
14311189Sjkh	u_char ident;
14411189Sjkh	u_short len;
1454910Swollman};
1464910Swollman#define LCP_HEADER_LEN          sizeof (struct lcp_header)
1474910Swollman
1484910Swollmanstruct cisco_packet {
14911189Sjkh	u_long type;
15011189Sjkh	u_long par1;
15111189Sjkh	u_long par2;
15211189Sjkh	u_short rel;
15311189Sjkh	u_short time0;
15411189Sjkh	u_short time1;
1554910Swollman};
1564910Swollman#define CISCO_PACKET_LEN 18
1574910Swollman
15825944Sjoerg/*
15925944Sjoerg * We follow the spelling and capitalization of RFC 1661 here, to make
16025944Sjoerg * it easier comparing with the standard.  Please refer to this RFC in
16125944Sjoerg * case you can't make sense out of these abbreviation; it will also
16225944Sjoerg * explain the semantics related to the various events and actions.
16325944Sjoerg */
16425944Sjoergstruct cp {
16525944Sjoerg	u_short	proto;		/* PPP control protocol number */
16625944Sjoerg	u_char protoidx;	/* index into state table in struct sppp */
16725944Sjoerg	u_char flags;
16825944Sjoerg#define CP_LCP		0x01	/* this is the LCP */
16925944Sjoerg#define CP_AUTH		0x02	/* this is an authentication protocol */
17025944Sjoerg#define CP_NCP		0x04	/* this is a NCP */
17125944Sjoerg#define CP_QUAL		0x08	/* this is a quality reporting protocol */
17225944Sjoerg	const char *name;	/* name of this control protocol */
17325944Sjoerg	/* event handlers */
17425944Sjoerg	void	(*Up)(struct sppp *sp);
17525944Sjoerg	void	(*Down)(struct sppp *sp);
17625944Sjoerg	void	(*Open)(struct sppp *sp);
17725944Sjoerg	void	(*Close)(struct sppp *sp);
17825944Sjoerg	void	(*TO)(void *sp);
17925944Sjoerg	int	(*RCR)(struct sppp *sp, struct lcp_header *h, int len);
18025944Sjoerg	void	(*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len);
18125944Sjoerg	void	(*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len);
18225944Sjoerg	/* actions */
18325944Sjoerg	void	(*tlu)(struct sppp *sp);
18425944Sjoerg	void	(*tld)(struct sppp *sp);
18525944Sjoerg	void	(*tls)(struct sppp *sp);
18625944Sjoerg	void	(*tlf)(struct sppp *sp);
18725944Sjoerg	void	(*scr)(struct sppp *sp);
18825944Sjoerg};
18925944Sjoerg
19012820Sphkstatic struct sppp *spppq;
1914910Swollman
1924910Swollman/*
1934910Swollman * The following disgusting hack gets around the problem that IP TOS
1944910Swollman * can't be set yet.  We want to put "interactive" traffic on a high
1954910Swollman * priority queue.  To decide if traffic is interactive, we check that
1964910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
1974910Swollman */
19811189Sjkhstatic u_short interactive_ports[8] = {
1994910Swollman	0,	513,	0,	0,
2004910Swollman	0,	21,	0,	23,
2014910Swollman};
2024910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
2034910Swollman
20425944Sjoerg/* almost every function needs these */
20525944Sjoerg#define STDDCL							\
20625944Sjoerg	struct ifnet *ifp = &sp->pp_if;				\
20725944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG
20811189Sjkh
20925944Sjoergstatic int sppp_output(struct ifnet *ifp, struct mbuf *m,
21025944Sjoerg		       struct sockaddr *dst, struct rtentry *rt);
2114910Swollman
21225944Sjoergstatic void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2);
21325944Sjoergstatic void sppp_cisco_input(struct sppp *sp, struct mbuf *m);
21425944Sjoerg
21525944Sjoergstatic void sppp_cp_input(const struct cp *cp, struct sppp *sp,
21625944Sjoerg			  struct mbuf *m);
21725944Sjoergstatic void sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
21825944Sjoerg			 u_char ident, u_short len, void *data);
21925944Sjoergstatic void sppp_cp_timeout(void *arg);
22025944Sjoergstatic void sppp_cp_change_state(const struct cp *cp, struct sppp *sp,
22125944Sjoerg				 int newstate);
22225944Sjoerg
22325944Sjoergstatic void sppp_up_event(const struct cp *cp, struct sppp *sp);
22425944Sjoergstatic void sppp_down_event(const struct cp *cp, struct sppp *sp);
22525944Sjoergstatic void sppp_open_event(const struct cp *cp, struct sppp *sp);
22625944Sjoergstatic void sppp_close_event(const struct cp *cp, struct sppp *sp);
22725944Sjoergstatic void sppp_to_event(const struct cp *cp, struct sppp *sp);
22825944Sjoerg
22925944Sjoergstatic void sppp_lcp_init(struct sppp *sp);
23025944Sjoergstatic void sppp_lcp_up(struct sppp *sp);
23125944Sjoergstatic void sppp_lcp_down(struct sppp *sp);
23225944Sjoergstatic void sppp_lcp_open(struct sppp *sp);
23325944Sjoergstatic void sppp_lcp_close(struct sppp *sp);
23425944Sjoergstatic void sppp_lcp_TO(void *sp);
23525944Sjoergstatic int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
23625944Sjoergstatic void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
23725944Sjoergstatic void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
23825944Sjoergstatic void sppp_lcp_tlu(struct sppp *sp);
23925944Sjoergstatic void sppp_lcp_tld(struct sppp *sp);
24025944Sjoergstatic void sppp_lcp_tls(struct sppp *sp);
24125944Sjoergstatic void sppp_lcp_tlf(struct sppp *sp);
24225944Sjoergstatic void sppp_lcp_scr(struct sppp *sp);
24325944Sjoergstatic void sppp_lcp_check(struct sppp *sp);
24425944Sjoerg
24525944Sjoergstatic void sppp_ipcp_init(struct sppp *sp);
24625944Sjoergstatic void sppp_ipcp_up(struct sppp *sp);
24725944Sjoergstatic void sppp_ipcp_down(struct sppp *sp);
24825944Sjoergstatic void sppp_ipcp_open(struct sppp *sp);
24925944Sjoergstatic void sppp_ipcp_close(struct sppp *sp);
25025944Sjoergstatic void sppp_ipcp_TO(void *sp);
25125944Sjoergstatic int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
25225944Sjoergstatic void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
25325944Sjoergstatic void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
25425944Sjoergstatic void sppp_ipcp_tlu(struct sppp *sp);
25525944Sjoergstatic void sppp_ipcp_tld(struct sppp *sp);
25625944Sjoergstatic void sppp_ipcp_tls(struct sppp *sp);
25725944Sjoergstatic void sppp_ipcp_tlf(struct sppp *sp);
25825944Sjoergstatic void sppp_ipcp_scr(struct sppp *sp);
25925944Sjoerg
26025944Sjoergstatic const char *sppp_cp_type_name(u_char type);
26125944Sjoergstatic const char *sppp_lcp_opt_name(u_char opt);
26225944Sjoergstatic const char *sppp_ipcp_opt_name(u_char opt);
26325944Sjoergstatic const char *sppp_state_name(int state);
26425944Sjoergstatic const char *sppp_phase_name(enum ppp_phase phase);
26525944Sjoergstatic const char *sppp_proto_name(u_short proto);
26625944Sjoerg
26725944Sjoergstatic void sppp_keepalive(void *dummy);
26825944Sjoergstatic void sppp_qflush(struct ifqueue *ifq);
26925944Sjoerg
27025944Sjoergstatic void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst);
27125944Sjoergstatic void sppp_set_ip_addr(struct sppp *sp, u_long src);
27225944Sjoerg
27325944Sjoergstatic void sppp_print_bytes(u_char *p, u_short len);
27425944Sjoerg
27525944Sjoerg/* our control protocol descriptors */
27625944Sjoergconst struct cp lcp = {
27725944Sjoerg	PPP_LCP, IDX_LCP, CP_LCP, "lcp",
27825944Sjoerg	sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close,
27925944Sjoerg	sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak,
28025944Sjoerg	sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf,
28125944Sjoerg	sppp_lcp_scr
28225944Sjoerg};
28325944Sjoerg
28425944Sjoergconst struct cp ipcp = {
28525944Sjoerg	PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp",
28625944Sjoerg	sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close,
28725944Sjoerg	sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak,
28825944Sjoerg	sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf,
28925944Sjoerg	sppp_ipcp_scr
29025944Sjoerg};
29125944Sjoerg
29225944Sjoergconst struct cp *cps[IDX_COUNT] = {
29325944Sjoerg	&lcp,			/* IDX_LCP */
29425944Sjoerg	&ipcp,			/* IDX_IPCP */
29525944Sjoerg};
29625944Sjoerg
29725944Sjoerg
29825944Sjoerg/*
29925944Sjoerg * Exported functions, comprising our interface to the lower layer.
3004910Swollman */
3014910Swollman
3024910Swollman/*
3034910Swollman * Process the received packet.
3044910Swollman */
30525706Sjoergvoid
30625706Sjoergsppp_input(struct ifnet *ifp, struct mbuf *m)
3074910Swollman{
3084910Swollman	struct ppp_header *h;
3094910Swollman	struct ifqueue *inq = 0;
31011189Sjkh	int s;
31125944Sjoerg	struct sppp *sp = (struct sppp *)ifp;
31225944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
3134910Swollman
3144910Swollman	if (ifp->if_flags & IFF_UP)
3154910Swollman		/* Count received bytes, add FCS and one flag */
3164910Swollman		ifp->if_ibytes += m->m_pkthdr.len + 3;
3174910Swollman
3184910Swollman	if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
3194910Swollman		/* Too small packet, drop it. */
32025944Sjoerg		if (debug)
32125706Sjoerg			log(LOG_DEBUG,
32225706Sjoerg			    "%s%d: input packet is too small, %d bytes\n",
32325706Sjoerg			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
32425944Sjoerg	  drop:
32525944Sjoerg		++ifp->if_ierrors;
32625944Sjoerg		++ifp->if_iqdrops;
3274910Swollman		m_freem (m);
3284910Swollman		return;
3294910Swollman	}
3304910Swollman
3314910Swollman	/* Get PPP header. */
3324910Swollman	h = mtod (m, struct ppp_header*);
3334910Swollman	m_adj (m, PPP_HEADER_LEN);
3344910Swollman
3354910Swollman	switch (h->address) {
3364910Swollman	case PPP_ALLSTATIONS:
3374910Swollman		if (h->control != PPP_UI)
3384910Swollman			goto invalid;
33911189Sjkh		if (sp->pp_flags & PP_CISCO) {
34025944Sjoerg			if (debug)
34125706Sjoerg				log(LOG_DEBUG,
34225706Sjoerg				    "%s%d: PPP packet in Cisco mode "
34325706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
34425706Sjoerg				    ifp->if_name, ifp->if_unit,
34525706Sjoerg				    h->address, h->control, ntohs(h->protocol));
34611189Sjkh			goto drop;
34711189Sjkh		}
3484910Swollman		switch (ntohs (h->protocol)) {
3494910Swollman		default:
35025944Sjoerg			if (sp->state[IDX_LCP] == STATE_OPENED)
35125944Sjoerg				sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
35211189Sjkh					++sp->pp_seq, m->m_pkthdr.len + 2,
3534910Swollman					&h->protocol);
35425944Sjoerg			if (debug)
35525706Sjoerg				log(LOG_DEBUG,
35625706Sjoerg				    "%s%d: invalid input protocol "
35725706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
35825706Sjoerg				    ifp->if_name, ifp->if_unit,
35925706Sjoerg				    h->address, h->control, ntohs(h->protocol));
3604910Swollman			++ifp->if_noproto;
3614910Swollman			goto drop;
3624910Swollman		case PPP_LCP:
36325944Sjoerg			sppp_cp_input(&lcp, (struct sppp*)ifp, m);
3644910Swollman			m_freem (m);
3654910Swollman			return;
3664910Swollman#ifdef INET
3674910Swollman		case PPP_IPCP:
36825944Sjoerg			if (sp->pp_phase == PHASE_NETWORK)
36925944Sjoerg				sppp_cp_input(&ipcp, (struct sppp*) ifp, m);
3704910Swollman			m_freem (m);
3714910Swollman			return;
3724910Swollman		case PPP_IP:
37325944Sjoerg			if (sp->state[IDX_IPCP] == STATE_OPENED) {
3744910Swollman				schednetisr (NETISR_IP);
3754910Swollman				inq = &ipintrq;
3764910Swollman			}
3774910Swollman			break;
3784910Swollman#endif
37912495Speter#ifdef IPX
38012495Speter		case PPP_IPX:
38112495Speter			/* IPX IPXCP not implemented yet */
38225944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
38312495Speter				schednetisr (NETISR_IPX);
38412495Speter				inq = &ipxintrq;
38512495Speter			}
38612495Speter			break;
38712495Speter#endif
3884910Swollman#ifdef NS
3894910Swollman		case PPP_XNS:
3904910Swollman			/* XNS IDPCP not implemented yet */
39125944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
3924910Swollman				schednetisr (NETISR_NS);
3934910Swollman				inq = &nsintrq;
3944910Swollman			}
3954910Swollman			break;
3964910Swollman#endif
3974910Swollman#ifdef ISO
3984910Swollman		case PPP_ISO:
3994910Swollman			/* OSI NLCP not implemented yet */
40025944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
4014910Swollman				schednetisr (NETISR_ISO);
4024910Swollman				inq = &clnlintrq;
4034910Swollman			}
4044910Swollman			break;
4054910Swollman#endif
4064910Swollman		}
4074910Swollman		break;
4084910Swollman	case CISCO_MULTICAST:
4094910Swollman	case CISCO_UNICAST:
4104910Swollman		/* Don't check the control field here (RFC 1547). */
41111189Sjkh		if (! (sp->pp_flags & PP_CISCO)) {
41225944Sjoerg			if (debug)
41325706Sjoerg				log(LOG_DEBUG,
41425706Sjoerg				    "%s%d: Cisco packet in PPP mode "
41525706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
41625706Sjoerg				    ifp->if_name, ifp->if_unit,
41725706Sjoerg				    h->address, h->control, ntohs(h->protocol));
41811189Sjkh			goto drop;
41911189Sjkh		}
4204910Swollman		switch (ntohs (h->protocol)) {
4214910Swollman		default:
4224910Swollman			++ifp->if_noproto;
4234910Swollman			goto invalid;
4244910Swollman		case CISCO_KEEPALIVE:
4254910Swollman			sppp_cisco_input ((struct sppp*) ifp, m);
4264910Swollman			m_freem (m);
4274910Swollman			return;
4284910Swollman#ifdef INET
4294910Swollman		case ETHERTYPE_IP:
4304910Swollman			schednetisr (NETISR_IP);
4314910Swollman			inq = &ipintrq;
4324910Swollman			break;
4334910Swollman#endif
43412495Speter#ifdef IPX
43512495Speter		case ETHERTYPE_IPX:
43612495Speter			schednetisr (NETISR_IPX);
43712495Speter			inq = &ipxintrq;
43812495Speter			break;
43912495Speter#endif
4404910Swollman#ifdef NS
4414910Swollman		case ETHERTYPE_NS:
4424910Swollman			schednetisr (NETISR_NS);
4434910Swollman			inq = &nsintrq;
4444910Swollman			break;
4454910Swollman#endif
4464910Swollman		}
4474910Swollman		break;
44825944Sjoerg	default:        /* Invalid PPP packet. */
44925944Sjoerg	  invalid:
45025944Sjoerg		if (debug)
45125944Sjoerg			log(LOG_DEBUG,
45225944Sjoerg			    "%s%d: invalid input packet "
45325944Sjoerg			    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
45425944Sjoerg			    ifp->if_name, ifp->if_unit,
45525944Sjoerg			    h->address, h->control, ntohs(h->protocol));
45625944Sjoerg		goto drop;
4574910Swollman	}
4584910Swollman
4594910Swollman	if (! (ifp->if_flags & IFF_UP) || ! inq)
4604910Swollman		goto drop;
4614910Swollman
4624910Swollman	/* Check queue. */
46325944Sjoerg	s = splimp();
4644910Swollman	if (IF_QFULL (inq)) {
4654910Swollman		/* Queue overflow. */
46625944Sjoerg		IF_DROP(inq);
46725944Sjoerg		splx(s);
46825944Sjoerg		if (debug)
46925706Sjoerg			log(LOG_DEBUG, "%s%d: protocol queue overflow\n",
4704910Swollman				ifp->if_name, ifp->if_unit);
4714910Swollman		goto drop;
4724910Swollman	}
47325944Sjoerg	IF_ENQUEUE(inq, m);
47425944Sjoerg	splx(s);
4754910Swollman}
4764910Swollman
4774910Swollman/*
4784910Swollman * Enqueue transmit packet.
4794910Swollman */
48012820Sphkstatic int
48125706Sjoergsppp_output(struct ifnet *ifp, struct mbuf *m,
48225706Sjoerg	    struct sockaddr *dst, struct rtentry *rt)
4834910Swollman{
4844910Swollman	struct sppp *sp = (struct sppp*) ifp;
4854910Swollman	struct ppp_header *h;
4864910Swollman	struct ifqueue *ifq;
48725955Sjoerg	int s, rv = 0;
4884910Swollman
48925944Sjoerg	s = splimp();
49025944Sjoerg
49125944Sjoerg	if ((ifp->if_flags & IFF_UP) == 0 ||
49225944Sjoerg	    (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) {
4934910Swollman		m_freem (m);
4944910Swollman		splx (s);
4954910Swollman		return (ENETDOWN);
4964910Swollman	}
4974910Swollman
49825944Sjoerg	if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) {
49925944Sjoerg		/*
50025944Sjoerg		 * Interface is not yet running, but auto-dial.  Need
50125944Sjoerg		 * to start LCP for it.
50225944Sjoerg		 */
50325944Sjoerg		ifp->if_flags |= IFF_RUNNING;
50425944Sjoerg		splx(s);
50525944Sjoerg		lcp.Open(sp);
50625944Sjoerg		s = splimp();
50725944Sjoerg	}
50825944Sjoerg
5094910Swollman	ifq = &ifp->if_snd;
5104910Swollman#ifdef INET
5114910Swollman	/*
5124910Swollman	 * Put low delay, telnet, rlogin and ftp control packets
5134910Swollman	 * in front of the queue.
5144910Swollman	 */
51512436Speter	if (dst->sa_family == AF_INET) {
51612436Speter		struct ip *ip = mtod (m, struct ip*);
51712436Speter		struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
5184910Swollman
51912436Speter		if (! IF_QFULL (&sp->pp_fastq) &&
52012436Speter		    ((ip->ip_tos & IPTOS_LOWDELAY) ||
52112436Speter	    	    ip->ip_p == IPPROTO_TCP &&
52212436Speter	    	    m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) &&
52312436Speter	    	    (INTERACTIVE (ntohs (tcp->th_sport)) ||
52412436Speter	    	    INTERACTIVE (ntohs (tcp->th_dport)))))
52512436Speter			ifq = &sp->pp_fastq;
5264910Swollman	}
5274910Swollman#endif
5284910Swollman
5294910Swollman	/*
5304910Swollman	 * Prepend general data packet PPP header. For now, IP only.
5314910Swollman	 */
5324910Swollman	M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT);
5334910Swollman	if (! m) {
5344910Swollman		if (ifp->if_flags & IFF_DEBUG)
53525706Sjoerg			log(LOG_DEBUG, "%s%d: no memory for transmit header\n",
5364910Swollman				ifp->if_name, ifp->if_unit);
53725944Sjoerg		++ifp->if_oerrors;
5384910Swollman		splx (s);
5394910Swollman		return (ENOBUFS);
5404910Swollman	}
5414910Swollman	h = mtod (m, struct ppp_header*);
5424910Swollman	if (sp->pp_flags & PP_CISCO) {
54328088Skjc		h->address = CISCO_UNICAST;        /* unicast address */
5444910Swollman		h->control = 0;
5454910Swollman	} else {
5464910Swollman		h->address = PPP_ALLSTATIONS;        /* broadcast address */
5474910Swollman		h->control = PPP_UI;                 /* Unnumbered Info */
5484910Swollman	}
5494910Swollman
5504910Swollman	switch (dst->sa_family) {
5514910Swollman#ifdef INET
5524910Swollman	case AF_INET:   /* Internet Protocol */
55311189Sjkh		if (sp->pp_flags & PP_CISCO)
55411189Sjkh			h->protocol = htons (ETHERTYPE_IP);
55511189Sjkh		else {
55625955Sjoerg			/*
55725955Sjoerg			 * Don't choke with an ENETDOWN early.  It's
55825955Sjoerg			 * possible that we just started dialing out,
55925955Sjoerg			 * so don't drop the packet immediately.  If
56025955Sjoerg			 * we notice that we run out of buffer space
56125955Sjoerg			 * below, we will however remember that we are
56225955Sjoerg			 * not ready to carry IP packets, and return
56325955Sjoerg			 * ENETDOWN, as opposed to ENOBUFS.
56425955Sjoerg			 */
56525955Sjoerg			h->protocol = htons(PPP_IP);
56625955Sjoerg			if (sp->state[IDX_IPCP] != STATE_OPENED)
56725955Sjoerg				rv = ENETDOWN;
56811189Sjkh		}
5694910Swollman		break;
5704910Swollman#endif
5714910Swollman#ifdef NS
5724910Swollman	case AF_NS:     /* Xerox NS Protocol */
5734910Swollman		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
5744910Swollman			ETHERTYPE_NS : PPP_XNS);
5754910Swollman		break;
5764910Swollman#endif
57711819Sjulian#ifdef IPX
57812495Speter	case AF_IPX:     /* Novell IPX Protocol */
57911819Sjulian		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
58012495Speter			ETHERTYPE_IPX : PPP_IPX);
58111819Sjulian		break;
58211819Sjulian#endif
5834910Swollman#ifdef ISO
5844910Swollman	case AF_ISO:    /* ISO OSI Protocol */
5854910Swollman		if (sp->pp_flags & PP_CISCO)
5864910Swollman			goto nosupport;
5874910Swollman		h->protocol = htons (PPP_ISO);
5884910Swollman		break;
58912820Sphknosupport:
5904910Swollman#endif
5914910Swollman	default:
5924910Swollman		m_freem (m);
59325944Sjoerg		++ifp->if_oerrors;
5944910Swollman		splx (s);
5954910Swollman		return (EAFNOSUPPORT);
5964910Swollman	}
5974910Swollman
5984910Swollman	/*
5994910Swollman	 * Queue message on interface, and start output if interface
6004910Swollman	 * not yet active.
6014910Swollman	 */
6024910Swollman	if (IF_QFULL (ifq)) {
6034910Swollman		IF_DROP (&ifp->if_snd);
6044910Swollman		m_freem (m);
60525944Sjoerg		++ifp->if_oerrors;
6064910Swollman		splx (s);
60725955Sjoerg		return (rv? rv: ENOBUFS);
6084910Swollman	}
6094910Swollman	IF_ENQUEUE (ifq, m);
6104910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
6114910Swollman		(*ifp->if_start) (ifp);
6124910Swollman
6134910Swollman	/*
6144910Swollman	 * Count output packets and bytes.
6154910Swollman	 * The packet length includes header, FCS and 1 flag,
6164910Swollman	 * according to RFC 1333.
6174910Swollman	 */
6184910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
6194910Swollman	splx (s);
6204910Swollman	return (0);
6214910Swollman}
6224910Swollman
62325706Sjoergvoid
62425706Sjoergsppp_attach(struct ifnet *ifp)
6254910Swollman{
6264910Swollman	struct sppp *sp = (struct sppp*) ifp;
6274910Swollman
6284910Swollman	/* Initialize keepalive handler. */
6294910Swollman	if (! spppq)
63011189Sjkh		timeout (sppp_keepalive, 0, hz * 10);
6314910Swollman
6324910Swollman	/* Insert new entry into the keepalive list. */
6334910Swollman	sp->pp_next = spppq;
6344910Swollman	spppq = sp;
6354910Swollman
6364910Swollman	sp->pp_if.if_type = IFT_PPP;
6374910Swollman	sp->pp_if.if_output = sppp_output;
6384910Swollman	sp->pp_fastq.ifq_maxlen = 32;
63926018Sjoerg	sp->pp_cpq.ifq_maxlen = 20;
6404910Swollman	sp->pp_loopcnt = 0;
6414910Swollman	sp->pp_alivecnt = 0;
64211189Sjkh	sp->pp_seq = 0;
6434910Swollman	sp->pp_rseq = 0;
64425944Sjoerg	sp->pp_phase = PHASE_DEAD;
64525944Sjoerg	sp->pp_up = lcp.Up;
64625944Sjoerg	sp->pp_down = lcp.Down;
64725944Sjoerg
64825944Sjoerg	sppp_lcp_init(sp);
64925944Sjoerg	sppp_ipcp_init(sp);
6504910Swollman}
6514910Swollman
65212820Sphkvoid
65325706Sjoergsppp_detach(struct ifnet *ifp)
6544910Swollman{
6554910Swollman	struct sppp **q, *p, *sp = (struct sppp*) ifp;
65625944Sjoerg	int i;
6574910Swollman
6584910Swollman	/* Remove the entry from the keepalive list. */
6594910Swollman	for (q = &spppq; (p = *q); q = &p->pp_next)
6604910Swollman		if (p == sp) {
6614910Swollman			*q = p->pp_next;
6624910Swollman			break;
6634910Swollman		}
6644910Swollman
6654910Swollman	/* Stop keepalive handler. */
6664910Swollman	if (! spppq)
66711189Sjkh		untimeout (sppp_keepalive, 0);
66825944Sjoerg
66925944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
67025944Sjoerg		untimeout((cps[i])->TO, (void *)sp);
6714910Swollman}
6724910Swollman
6734910Swollman/*
6744910Swollman * Flush the interface output queue.
6754910Swollman */
67625706Sjoergvoid
67725706Sjoergsppp_flush(struct ifnet *ifp)
6784910Swollman{
6794910Swollman	struct sppp *sp = (struct sppp*) ifp;
6804910Swollman
68125944Sjoerg	sppp_qflush (&sp->pp_if.if_snd);
68225944Sjoerg	sppp_qflush (&sp->pp_fastq);
68326018Sjoerg	sppp_qflush (&sp->pp_cpq);
6844910Swollman}
6854910Swollman
6864910Swollman/*
68711189Sjkh * Check if the output queue is empty.
68811189Sjkh */
68912820Sphkint
69025706Sjoergsppp_isempty(struct ifnet *ifp)
69111189Sjkh{
69211189Sjkh	struct sppp *sp = (struct sppp*) ifp;
69325944Sjoerg	int empty, s;
69411189Sjkh
69525944Sjoerg	s = splimp();
69626018Sjoerg	empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head &&
69726018Sjoerg		!sp->pp_if.if_snd.ifq_head;
69825944Sjoerg	splx(s);
69911189Sjkh	return (empty);
70011189Sjkh}
70111189Sjkh
70211189Sjkh/*
7034910Swollman * Get next packet to send.
7044910Swollman */
70525706Sjoergstruct mbuf *
70625706Sjoergsppp_dequeue(struct ifnet *ifp)
7074910Swollman{
7084910Swollman	struct sppp *sp = (struct sppp*) ifp;
7094910Swollman	struct mbuf *m;
71025944Sjoerg	int s;
7114910Swollman
71225944Sjoerg	s = splimp();
71326018Sjoerg	/*
71426018Sjoerg	 * Process only the control protocol queue until we are in
71526018Sjoerg	 * network phase.
71626018Sjoerg	 *
71726018Sjoerg	 * XXX Network phase itself is still not a sufficient test, we
71826018Sjoerg	 * normally should keep a separate queue for each supported
71926018Sjoerg	 * protocol family, and only serve these queues as the
72026018Sjoerg	 * respective NCPs were opened.  The simplistic logic used
72126018Sjoerg	 * here might cause some loss of network traffic while the
72226018Sjoerg	 * NCPs are being negotiated, in particular if the NCPs take a
72326018Sjoerg	 * long time to negotiate.
72426018Sjoerg	 *
72526018Sjoerg	 * Do always serve all three queues in Cisco mode.
72626018Sjoerg	 */
72726018Sjoerg	IF_DEQUEUE(&sp->pp_cpq, m);
72826018Sjoerg	if (m == NULL &&
72926018Sjoerg	    (sp->pp_phase == PHASE_NETWORK ||
73026018Sjoerg	     (sp->pp_flags & PP_CISCO) != 0)) {
73126018Sjoerg		IF_DEQUEUE(&sp->pp_fastq, m);
73226018Sjoerg		if (m == NULL)
73326018Sjoerg			IF_DEQUEUE (&sp->pp_if.if_snd, m);
73426018Sjoerg	}
73526018Sjoerg	splx(s);
73626018Sjoerg	return m;
7374910Swollman}
7384910Swollman
7394910Swollman/*
74025944Sjoerg * Process an ioctl request.  Called on low priority level.
7414910Swollman */
74225944Sjoergint
74325944Sjoergsppp_ioctl(struct ifnet *ifp, int cmd, void *data)
7444910Swollman{
74525944Sjoerg	struct ifreq *ifr = (struct ifreq*) data;
74625944Sjoerg	struct sppp *sp = (struct sppp*) ifp;
74725944Sjoerg	int s, going_up, going_down, newmode;
7484910Swollman
74925944Sjoerg	s = splimp();
75025944Sjoerg	switch (cmd) {
75125944Sjoerg	case SIOCAIFADDR:
75225944Sjoerg	case SIOCSIFDSTADDR:
75325944Sjoerg		break;
7544910Swollman
75525944Sjoerg	case SIOCSIFADDR:
75625944Sjoerg		if_up(ifp);
75725944Sjoerg		/* fall through... */
75811189Sjkh
75925944Sjoerg	case SIOCSIFFLAGS:
76025944Sjoerg		going_up = ifp->if_flags & IFF_UP &&
76125944Sjoerg			(ifp->if_flags & IFF_RUNNING) == 0;
76225944Sjoerg		going_down = (ifp->if_flags & IFF_UP) == 0 &&
76325944Sjoerg			ifp->if_flags & IFF_RUNNING;
76425944Sjoerg		newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE);
76525944Sjoerg		if (newmode == (IFF_AUTO | IFF_PASSIVE)) {
76625944Sjoerg			/* sanity */
76725944Sjoerg			newmode = IFF_PASSIVE;
76825944Sjoerg			ifp->if_flags &= ~IFF_AUTO;
7694910Swollman		}
7704910Swollman
77125944Sjoerg		if (going_up || going_down)
77225944Sjoerg			lcp.Close(sp);
77325944Sjoerg		if (going_up && newmode == 0) {
77425944Sjoerg			/* neither auto-dial nor passive */
77525944Sjoerg			ifp->if_flags |= IFF_RUNNING;
77625944Sjoerg			if (!(sp->pp_flags & PP_CISCO))
77725944Sjoerg				lcp.Open(sp);
77826018Sjoerg		} else if (going_down) {
77926018Sjoerg			sppp_flush(ifp);
78025944Sjoerg			ifp->if_flags &= ~IFF_RUNNING;
78126018Sjoerg		}
7824910Swollman
7834910Swollman		break;
78411189Sjkh
78525944Sjoerg#ifdef SIOCSIFMTU
78625944Sjoerg#ifndef ifr_mtu
78725944Sjoerg#define ifr_mtu ifr_metric
78825944Sjoerg#endif
78925944Sjoerg	case SIOCSIFMTU:
79025944Sjoerg		if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru)
79125944Sjoerg			return (EINVAL);
79225944Sjoerg		ifp->if_mtu = ifr->ifr_mtu;
7934910Swollman		break;
79425944Sjoerg#endif
79525944Sjoerg#ifdef SLIOCSETMTU
79625944Sjoerg	case SLIOCSETMTU:
79725944Sjoerg		if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru)
79825944Sjoerg			return (EINVAL);
79925944Sjoerg		ifp->if_mtu = *(short*)data;
8004910Swollman		break;
80125944Sjoerg#endif
80225944Sjoerg#ifdef SIOCGIFMTU
80325944Sjoerg	case SIOCGIFMTU:
80425944Sjoerg		ifr->ifr_mtu = ifp->if_mtu;
80511189Sjkh		break;
80625944Sjoerg#endif
80725944Sjoerg#ifdef SLIOCGETMTU
80825944Sjoerg	case SLIOCGETMTU:
80925944Sjoerg		*(short*)data = ifp->if_mtu;
8104910Swollman		break;
81125944Sjoerg#endif
81225944Sjoerg	case SIOCADDMULTI:
81325944Sjoerg	case SIOCDELMULTI:
8144910Swollman		break;
81511189Sjkh
81625944Sjoerg	default:
81725944Sjoerg		splx(s);
81825944Sjoerg		return (ENOTTY);
8194910Swollman	}
82025944Sjoerg	splx(s);
82125944Sjoerg	return (0);
8224910Swollman}
8234910Swollman
82425944Sjoerg
82525944Sjoerg/*
82625944Sjoerg * Cisco framing implementation.
82725944Sjoerg */
82825944Sjoerg
8294910Swollman/*
8304910Swollman * Handle incoming Cisco keepalive protocol packets.
8314910Swollman */
83212820Sphkstatic void
83325706Sjoergsppp_cisco_input(struct sppp *sp, struct mbuf *m)
8344910Swollman{
83525944Sjoerg	STDDCL;
8364910Swollman	struct cisco_packet *h;
8374910Swollman	struct ifaddr *ifa;
8384910Swollman
83927929Sitojun	if (m->m_pkthdr.len < CISCO_PACKET_LEN) {
84025706Sjoerg		if (debug)
84125706Sjoerg			log(LOG_DEBUG,
84225706Sjoerg			    "%s%d: invalid cisco packet length: %d bytes\n",
84325706Sjoerg			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
8444910Swollman		return;
8454910Swollman	}
8464910Swollman	h = mtod (m, struct cisco_packet*);
84725706Sjoerg	if (debug)
84825706Sjoerg		log(LOG_DEBUG,
84925706Sjoerg		    "%s%d: cisco input: %d bytes "
85025706Sjoerg		    "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
85125706Sjoerg		    ifp->if_name, ifp->if_unit, m->m_pkthdr.len,
85225706Sjoerg		    ntohl (h->type), h->par1, h->par2, h->rel,
85325706Sjoerg		    h->time0, h->time1);
8544910Swollman	switch (ntohl (h->type)) {
8554910Swollman	default:
85625706Sjoerg		if (debug)
85725706Sjoerg			addlog("%s%d: unknown cisco packet type: 0x%lx\n",
85825706Sjoerg			       ifp->if_name, ifp->if_unit, ntohl (h->type));
8594910Swollman		break;
8604910Swollman	case CISCO_ADDR_REPLY:
8614910Swollman		/* Reply on address request, ignore */
8624910Swollman		break;
8634910Swollman	case CISCO_KEEPALIVE_REQ:
8644910Swollman		sp->pp_alivecnt = 0;
8654910Swollman		sp->pp_rseq = ntohl (h->par1);
8664910Swollman		if (sp->pp_seq == sp->pp_rseq) {
8674910Swollman			/* Local and remote sequence numbers are equal.
8684910Swollman			 * Probably, the line is in loopback mode. */
86911189Sjkh			if (sp->pp_loopcnt >= MAXALIVECNT) {
87011189Sjkh				printf ("%s%d: loopback\n",
87111189Sjkh					ifp->if_name, ifp->if_unit);
87211189Sjkh				sp->pp_loopcnt = 0;
87311189Sjkh				if (ifp->if_flags & IFF_UP) {
87411189Sjkh					if_down (ifp);
87526018Sjoerg					sppp_qflush (&sp->pp_cpq);
87611189Sjkh				}
87711189Sjkh			}
8784910Swollman			++sp->pp_loopcnt;
8794910Swollman
8804910Swollman			/* Generate new local sequence number */
8814910Swollman			sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
88211189Sjkh			break;
88311189Sjkh		}
8844910Swollman			sp->pp_loopcnt = 0;
88511189Sjkh		if (! (ifp->if_flags & IFF_UP) &&
88611189Sjkh		    (ifp->if_flags & IFF_RUNNING)) {
88711189Sjkh			ifp->if_flags |= IFF_UP;
88811189Sjkh			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
88911189Sjkh		}
8904910Swollman		break;
8914910Swollman	case CISCO_ADDR_REQ:
89220407Swollman		for (ifa=ifp->if_addrhead.tqh_first; ifa;
89320407Swollman		     ifa=ifa->ifa_link.tqe_next)
8944910Swollman			if (ifa->ifa_addr->sa_family == AF_INET)
8954910Swollman				break;
8964910Swollman		if (! ifa) {
89725706Sjoerg			if (debug)
89825706Sjoerg				addlog("%s%d: unknown address for cisco request\n",
89925706Sjoerg				       ifp->if_name, ifp->if_unit);
9004910Swollman			return;
9014910Swollman		}
9024910Swollman		sppp_cisco_send (sp, CISCO_ADDR_REPLY,
9034910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr),
9044910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr));
9054910Swollman		break;
9064910Swollman	}
9074910Swollman}
9084910Swollman
9094910Swollman/*
91025944Sjoerg * Send Cisco keepalive packet.
9114910Swollman */
91212820Sphkstatic void
91325944Sjoergsppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
91425944Sjoerg{
91525944Sjoerg	STDDCL;
91625944Sjoerg	struct ppp_header *h;
91725944Sjoerg	struct cisco_packet *ch;
91825944Sjoerg	struct mbuf *m;
91925944Sjoerg	u_long t = (time.tv_sec - boottime.tv_sec) * 1000;
92025944Sjoerg
92125944Sjoerg	MGETHDR (m, M_DONTWAIT, MT_DATA);
92225944Sjoerg	if (! m)
92325944Sjoerg		return;
92425944Sjoerg	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
92525944Sjoerg	m->m_pkthdr.rcvif = 0;
92625944Sjoerg
92725944Sjoerg	h = mtod (m, struct ppp_header*);
92825944Sjoerg	h->address = CISCO_MULTICAST;
92925944Sjoerg	h->control = 0;
93025944Sjoerg	h->protocol = htons (CISCO_KEEPALIVE);
93125944Sjoerg
93225944Sjoerg	ch = (struct cisco_packet*) (h + 1);
93325944Sjoerg	ch->type = htonl (type);
93425944Sjoerg	ch->par1 = htonl (par1);
93525944Sjoerg	ch->par2 = htonl (par2);
93625944Sjoerg	ch->rel = -1;
93725944Sjoerg	ch->time0 = htons ((u_short) (t >> 16));
93825944Sjoerg	ch->time1 = htons ((u_short) t);
93925944Sjoerg
94025944Sjoerg	if (debug)
94125944Sjoerg		log(LOG_DEBUG,
94225944Sjoerg		    "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
94325944Sjoerg			ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
94425944Sjoerg			ch->par2, ch->rel, ch->time0, ch->time1);
94525944Sjoerg
94626018Sjoerg	if (IF_QFULL (&sp->pp_cpq)) {
94726018Sjoerg		IF_DROP (&sp->pp_fastq);
94825944Sjoerg		IF_DROP (&ifp->if_snd);
94925944Sjoerg		m_freem (m);
95025944Sjoerg	} else
95126018Sjoerg		IF_ENQUEUE (&sp->pp_cpq, m);
95225944Sjoerg	if (! (ifp->if_flags & IFF_OACTIVE))
95325944Sjoerg		(*ifp->if_start) (ifp);
95425944Sjoerg	ifp->if_obytes += m->m_pkthdr.len + 3;
95525944Sjoerg}
95625944Sjoerg
95725944Sjoerg/*
95825944Sjoerg * PPP protocol implementation.
95925944Sjoerg */
96025944Sjoerg
96125944Sjoerg/*
96225944Sjoerg * Send PPP control protocol packet.
96325944Sjoerg */
96425944Sjoergstatic void
96525706Sjoergsppp_cp_send(struct sppp *sp, u_short proto, u_char type,
96625706Sjoerg	     u_char ident, u_short len, void *data)
9674910Swollman{
96825944Sjoerg	STDDCL;
9694910Swollman	struct ppp_header *h;
9704910Swollman	struct lcp_header *lh;
9714910Swollman	struct mbuf *m;
9724910Swollman
9734910Swollman	if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
9744910Swollman		len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
9754910Swollman	MGETHDR (m, M_DONTWAIT, MT_DATA);
9764910Swollman	if (! m)
9774910Swollman		return;
9784910Swollman	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
9794910Swollman	m->m_pkthdr.rcvif = 0;
9804910Swollman
9814910Swollman	h = mtod (m, struct ppp_header*);
9824910Swollman	h->address = PPP_ALLSTATIONS;        /* broadcast address */
9834910Swollman	h->control = PPP_UI;                 /* Unnumbered Info */
9844910Swollman	h->protocol = htons (proto);         /* Link Control Protocol */
9854910Swollman
9864910Swollman	lh = (struct lcp_header*) (h + 1);
9874910Swollman	lh->type = type;
9884910Swollman	lh->ident = ident;
9894910Swollman	lh->len = htons (LCP_HEADER_LEN + len);
9904910Swollman	if (len)
9914910Swollman		bcopy (data, lh+1, len);
9924910Swollman
99325706Sjoerg	if (debug) {
99425944Sjoerg		log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d",
99525944Sjoerg		    ifp->if_name, ifp->if_unit,
99625944Sjoerg		    sppp_proto_name(proto),
99725944Sjoerg		    sppp_cp_type_name (lh->type), lh->ident,
99825944Sjoerg		    ntohs (lh->len));
9994910Swollman		if (len)
100011189Sjkh			sppp_print_bytes ((u_char*) (lh+1), len);
100125706Sjoerg		addlog(">\n");
10024910Swollman	}
100326018Sjoerg	if (IF_QFULL (&sp->pp_cpq)) {
100426018Sjoerg		IF_DROP (&sp->pp_fastq);
10054910Swollman		IF_DROP (&ifp->if_snd);
10064910Swollman		m_freem (m);
100725944Sjoerg		++ifp->if_oerrors;
10084910Swollman	} else
100926018Sjoerg		IF_ENQUEUE (&sp->pp_cpq, m);
10104910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
10114910Swollman		(*ifp->if_start) (ifp);
10124910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
10134910Swollman}
10144910Swollman
10154910Swollman/*
101625944Sjoerg * Handle incoming PPP control protocol packets.
10174910Swollman */
101812820Sphkstatic void
101925944Sjoergsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
10204910Swollman{
102125944Sjoerg	STDDCL;
102225944Sjoerg	struct lcp_header *h;
102325944Sjoerg	int len = m->m_pkthdr.len;
102425944Sjoerg	int rv;
102525944Sjoerg	u_char *p;
10264910Swollman
102725944Sjoerg	if (len < 4) {
102825944Sjoerg		if (debug)
102925944Sjoerg			log(LOG_DEBUG,
103025944Sjoerg			    "%s%d: %s invalid packet length: %d bytes\n",
103125944Sjoerg			    ifp->if_name, ifp->if_unit, cp->name, len);
10324910Swollman		return;
103325944Sjoerg	}
103425944Sjoerg	h = mtod (m, struct lcp_header*);
103525944Sjoerg	if (debug) {
103625944Sjoerg		log(LOG_DEBUG,
103725944Sjoerg		    "%s%d: %s input(%s): <%s id=0x%x len=%d",
103825944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
103925944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
104025944Sjoerg		    sppp_cp_type_name (h->type), h->ident, ntohs (h->len));
104125944Sjoerg		if (len > 4)
104225944Sjoerg			sppp_print_bytes ((u_char*) (h+1), len-4);
104325944Sjoerg		addlog(">\n");
104425944Sjoerg	}
104525944Sjoerg	if (len > ntohs (h->len))
104625944Sjoerg		len = ntohs (h->len);
104725944Sjoerg	switch (h->type) {
104825944Sjoerg	case CONF_REQ:
104925944Sjoerg		if (len < 4) {
105025944Sjoerg			if (debug)
105125944Sjoerg				addlog("%s%d: %s invalid conf-req length %d\n",
105225944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
105325944Sjoerg				       len);
105425944Sjoerg			++ifp->if_ierrors;
105525944Sjoerg			break;
105625944Sjoerg		}
105725944Sjoerg		rv = (cp->RCR)(sp, h, len);
105825944Sjoerg		switch (sp->state[cp->protoidx]) {
105925944Sjoerg		case STATE_OPENED:
106025944Sjoerg			(cp->tld)(sp);
106125944Sjoerg			(cp->scr)(sp);
106225944Sjoerg			/* fall through... */
106325944Sjoerg		case STATE_ACK_SENT:
106425944Sjoerg		case STATE_REQ_SENT:
106525944Sjoerg			sppp_cp_change_state(cp, sp, rv?
106625944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
106725944Sjoerg			break;
106825944Sjoerg		case STATE_CLOSING:
106925944Sjoerg		case STATE_STOPPING:
107025944Sjoerg			break;
107125944Sjoerg		case STATE_STOPPED:
107225944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
107325944Sjoerg			(cp->scr)(sp);
107425944Sjoerg			sppp_cp_change_state(cp, sp, rv?
107525944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
107625944Sjoerg			break;
107725944Sjoerg		case STATE_CLOSED:
107825944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
107925944Sjoerg				     0, 0);
108025944Sjoerg			break;
108125944Sjoerg		case STATE_ACK_RCVD:
108225944Sjoerg			if (rv) {
108325944Sjoerg				sppp_cp_change_state(cp, sp, STATE_OPENED);
108425944Sjoerg				if (debug)
108526077Sjoerg					log(LOG_DEBUG, "%s%d: %s tlu\n",
108626077Sjoerg					    ifp->if_name, ifp->if_unit,
108726077Sjoerg					    cp->name);
108825944Sjoerg				(cp->tlu)(sp);
108925944Sjoerg			} else
109025944Sjoerg				sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
109125944Sjoerg			break;
109225944Sjoerg		default:
109325944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
109425944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
109525944Sjoerg			       sppp_cp_type_name(h->type),
109625944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
109725944Sjoerg			++ifp->if_ierrors;
109825944Sjoerg		}
109925944Sjoerg		break;
110025944Sjoerg	case CONF_ACK:
110125944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
110225944Sjoerg			if (debug)
110325944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
110425944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
110525944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
110625944Sjoerg			++ifp->if_ierrors;
110725944Sjoerg			break;
110825944Sjoerg		}
110925944Sjoerg		switch (sp->state[cp->protoidx]) {
111025944Sjoerg		case STATE_CLOSED:
111125944Sjoerg		case STATE_STOPPED:
111225944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
111325944Sjoerg			break;
111425944Sjoerg		case STATE_CLOSING:
111525944Sjoerg		case STATE_STOPPING:
111625944Sjoerg			break;
111725944Sjoerg		case STATE_REQ_SENT:
111825944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
111925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
112025944Sjoerg			break;
112125944Sjoerg		case STATE_OPENED:
112225944Sjoerg			(cp->tld)(sp);
112325944Sjoerg			/* fall through */
112425944Sjoerg		case STATE_ACK_RCVD:
112525944Sjoerg			(cp->scr)(sp);
112625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
112725944Sjoerg			break;
112825944Sjoerg		case STATE_ACK_SENT:
112925944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
113025944Sjoerg			sppp_cp_change_state(cp, sp, STATE_OPENED);
113125944Sjoerg			if (debug)
113225944Sjoerg				addlog("%s%d: %s tlu\n",
113325944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name);
113425944Sjoerg			(cp->tlu)(sp);
113525944Sjoerg			break;
113625944Sjoerg		default:
113725944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
113825944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
113925944Sjoerg			       sppp_cp_type_name(h->type),
114025944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
114125944Sjoerg			++ifp->if_ierrors;
114225944Sjoerg		}
114325944Sjoerg		break;
114425944Sjoerg	case CONF_NAK:
114525944Sjoerg	case CONF_REJ:
114625944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
114725944Sjoerg			if (debug)
114825944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
114925944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
115025944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
115125944Sjoerg			++ifp->if_ierrors;
115225944Sjoerg			break;
115325944Sjoerg		}
115425944Sjoerg		if (h->type == CONF_NAK)
115525944Sjoerg			(cp->RCN_nak)(sp, h, len);
115625944Sjoerg		else /* CONF_REJ */
115725944Sjoerg			(cp->RCN_rej)(sp, h, len);
11584910Swollman
115925944Sjoerg		switch (sp->state[cp->protoidx]) {
116025944Sjoerg		case STATE_CLOSED:
116125944Sjoerg		case STATE_STOPPED:
116225944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
116325944Sjoerg			break;
116425944Sjoerg		case STATE_REQ_SENT:
116525944Sjoerg		case STATE_ACK_SENT:
116625944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
116725944Sjoerg			(cp->scr)(sp);
116825944Sjoerg			break;
116925944Sjoerg		case STATE_OPENED:
117025944Sjoerg			(cp->tld)(sp);
117125944Sjoerg			/* fall through */
117225944Sjoerg		case STATE_ACK_RCVD:
117325944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_SENT);
117425944Sjoerg			(cp->scr)(sp);
117525944Sjoerg			break;
117625944Sjoerg		case STATE_CLOSING:
117725944Sjoerg		case STATE_STOPPING:
117825944Sjoerg			break;
117925944Sjoerg		default:
118025944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
118125944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
118225944Sjoerg			       sppp_cp_type_name(h->type),
118325944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
118425944Sjoerg			++ifp->if_ierrors;
118525944Sjoerg		}
118625944Sjoerg		break;
11874910Swollman
118825944Sjoerg	case TERM_REQ:
118925944Sjoerg		switch (sp->state[cp->protoidx]) {
119025944Sjoerg		case STATE_ACK_RCVD:
119125944Sjoerg		case STATE_ACK_SENT:
119225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
119325944Sjoerg			/* fall through */
119425944Sjoerg		case STATE_CLOSED:
119525944Sjoerg		case STATE_STOPPED:
119625944Sjoerg		case STATE_CLOSING:
119725944Sjoerg		case STATE_STOPPING:
119825944Sjoerg		case STATE_REQ_SENT:
119925944Sjoerg		  sta:
120025944Sjoerg			/* Send Terminate-Ack packet. */
120125944Sjoerg			if (debug)
120225944Sjoerg				log(LOG_DEBUG, "%s%d: %s send terminate-ack\n",
120325944Sjoerg				    ifp->if_name, ifp->if_unit, cp->name);
120425944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
120525944Sjoerg			break;
120625944Sjoerg		case STATE_OPENED:
120725944Sjoerg			(cp->tld)(sp);
120825944Sjoerg			sp->rst_counter[cp->protoidx] = 0;
120925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPING);
121025944Sjoerg			goto sta;
121125944Sjoerg			break;
121225944Sjoerg		default:
121325944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
121425944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
121525944Sjoerg			       sppp_cp_type_name(h->type),
121625944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
121725944Sjoerg			++ifp->if_ierrors;
121825944Sjoerg		}
121925944Sjoerg		break;
122025944Sjoerg	case TERM_ACK:
122125944Sjoerg		switch (sp->state[cp->protoidx]) {
122225944Sjoerg		case STATE_CLOSED:
122325944Sjoerg		case STATE_STOPPED:
122425944Sjoerg		case STATE_REQ_SENT:
122525944Sjoerg		case STATE_ACK_SENT:
122625944Sjoerg			break;
122725944Sjoerg		case STATE_CLOSING:
122825944Sjoerg			(cp->tlf)(sp);
122925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
123025944Sjoerg			break;
123125944Sjoerg		case STATE_STOPPING:
123225944Sjoerg			(cp->tlf)(sp);
123325944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
123425944Sjoerg			break;
123525944Sjoerg		case STATE_ACK_RCVD:
123625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
123725944Sjoerg			break;
123825944Sjoerg		case STATE_OPENED:
123925944Sjoerg			(cp->tld)(sp);
124025944Sjoerg			(cp->scr)(sp);
124125944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
124225944Sjoerg			break;
124325944Sjoerg		default:
124425944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
124525944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
124625944Sjoerg			       sppp_cp_type_name(h->type),
124725944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
124825944Sjoerg			++ifp->if_ierrors;
124925944Sjoerg		}
125025944Sjoerg		break;
125125944Sjoerg	case CODE_REJ:
125225944Sjoerg	case PROTO_REJ:
125325944Sjoerg		/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
125425944Sjoerg		switch (sp->state[cp->protoidx]) {
125525944Sjoerg		case STATE_CLOSED:
125625944Sjoerg		case STATE_STOPPED:
125725944Sjoerg		case STATE_REQ_SENT:
125825944Sjoerg		case STATE_ACK_SENT:
125925944Sjoerg		case STATE_CLOSING:
126025944Sjoerg		case STATE_STOPPING:
126125944Sjoerg		case STATE_OPENED:
126225944Sjoerg			break;
126325944Sjoerg		case STATE_ACK_RCVD:
126425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
126525944Sjoerg			break;
126625944Sjoerg		default:
126725944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
126825944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
126925944Sjoerg			       sppp_cp_type_name(h->type),
127025944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
127125944Sjoerg			++ifp->if_ierrors;
127225944Sjoerg		}
127325944Sjoerg		break;
127425944Sjoerg	case DISC_REQ:
127525944Sjoerg		if (cp->proto != PPP_LCP)
127625944Sjoerg			goto illegal;
127725944Sjoerg		/* Discard the packet. */
127825944Sjoerg		break;
127925944Sjoerg	case ECHO_REQ:
128025944Sjoerg		if (cp->proto != PPP_LCP)
128125944Sjoerg			goto illegal;
128225944Sjoerg		if (sp->state[cp->protoidx] != STATE_OPENED) {
128325944Sjoerg			if (debug)
128425944Sjoerg				addlog("%s%d: lcp echo req but lcp closed\n",
128525944Sjoerg				       ifp->if_name, ifp->if_unit);
128625944Sjoerg			++ifp->if_ierrors;
128725944Sjoerg			break;
128825944Sjoerg		}
128925944Sjoerg		if (len < 8) {
129025944Sjoerg			if (debug)
129125944Sjoerg				addlog("%s%d: invalid lcp echo request "
129225944Sjoerg				       "packet length: %d bytes\n",
129325944Sjoerg				       ifp->if_name, ifp->if_unit, len);
129425944Sjoerg			break;
129525944Sjoerg		}
129625944Sjoerg		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
129725944Sjoerg			/* Line loopback mode detected. */
129825944Sjoerg			printf("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
129925944Sjoerg			if_down (ifp);
130026018Sjoerg			sppp_qflush (&sp->pp_cpq);
13014910Swollman
130225944Sjoerg			/* Shut down the PPP link. */
130325944Sjoerg			/* XXX */
130425944Sjoerg			lcp.Down(sp);
130525944Sjoerg			lcp.Up(sp);
130625944Sjoerg			break;
130725944Sjoerg		}
130825944Sjoerg		*(long*)(h+1) = htonl (sp->lcp.magic);
130925944Sjoerg		if (debug)
131025944Sjoerg			addlog("%s%d: got lcp echo req, sending echo rep\n",
131125944Sjoerg			       ifp->if_name, ifp->if_unit);
131225944Sjoerg		sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1);
131325944Sjoerg		break;
131425944Sjoerg	case ECHO_REPLY:
131525944Sjoerg		if (cp->proto != PPP_LCP)
131625944Sjoerg			goto illegal;
131725944Sjoerg		if (h->ident != sp->lcp.echoid) {
131825944Sjoerg			++ifp->if_ierrors;
131925944Sjoerg			break;
132025944Sjoerg		}
132125944Sjoerg		if (len < 8) {
132225944Sjoerg			if (debug)
132325944Sjoerg				addlog("%s%d: lcp invalid echo reply "
132425944Sjoerg				       "packet length: %d bytes\n",
132525944Sjoerg				       ifp->if_name, ifp->if_unit, len);
132625944Sjoerg			break;
132725944Sjoerg		}
132825944Sjoerg		if (debug)
132925944Sjoerg			addlog("%s%d: lcp got echo rep\n",
133025944Sjoerg			       ifp->if_name, ifp->if_unit);
133125944Sjoerg		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
133225944Sjoerg			sp->pp_alivecnt = 0;
133325944Sjoerg		break;
133425944Sjoerg	default:
133525944Sjoerg		/* Unknown packet type -- send Code-Reject packet. */
133625944Sjoerg	  illegal:
133725944Sjoerg		if (debug)
133825944Sjoerg			addlog("%s%d: %c send code-rej for 0x%x\n",
133925944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name, h->type);
134025944Sjoerg		sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq,
134125944Sjoerg			     m->m_pkthdr.len, h);
134225944Sjoerg		++ifp->if_ierrors;
134325944Sjoerg	}
13444910Swollman}
13454910Swollman
134625944Sjoerg
13474910Swollman/*
134825944Sjoerg * The generic part of all Up/Down/Open/Close/TO event handlers.
134925944Sjoerg * Basically, the state transition handling in the automaton.
13504910Swollman */
135125944Sjoergstatic void
135225944Sjoergsppp_up_event(const struct cp *cp, struct sppp *sp)
13534910Swollman{
135425944Sjoerg	STDDCL;
13554910Swollman
135625944Sjoerg	if (debug)
135725944Sjoerg		log(LOG_DEBUG, "%s%d: %s up(%s)\n",
135825944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
135925944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
136025944Sjoerg
136125944Sjoerg	switch (sp->state[cp->protoidx]) {
136225944Sjoerg	case STATE_INITIAL:
136325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
136425944Sjoerg		break;
136525944Sjoerg	case STATE_STARTING:
136625944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
136725944Sjoerg		(cp->scr)(sp);
136825944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
136925944Sjoerg		break;
13704910Swollman	default:
137125944Sjoerg		printf("%s%d: %s illegal up in state %s\n",
137225944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
137325944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
137425944Sjoerg	}
137525944Sjoerg}
13764910Swollman
137725944Sjoergstatic void
137825944Sjoergsppp_down_event(const struct cp *cp, struct sppp *sp)
137925944Sjoerg{
138025944Sjoerg	STDDCL;
138125944Sjoerg
138225944Sjoerg	if (debug)
138325944Sjoerg		log(LOG_DEBUG, "%s%d: %s down(%s)\n",
138425944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
138525944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
138625944Sjoerg
138725944Sjoerg	switch (sp->state[cp->protoidx]) {
138825944Sjoerg	case STATE_CLOSED:
138925944Sjoerg	case STATE_CLOSING:
139025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
13914910Swollman		break;
139225944Sjoerg	case STATE_STOPPED:
139325944Sjoerg		(cp->tls)(sp);
139425944Sjoerg		/* fall through */
139525944Sjoerg	case STATE_STOPPING:
139625944Sjoerg	case STATE_REQ_SENT:
139725944Sjoerg	case STATE_ACK_RCVD:
139825944Sjoerg	case STATE_ACK_SENT:
139925944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
140025944Sjoerg		break;
140125944Sjoerg	case STATE_OPENED:
140225944Sjoerg		(cp->tld)(sp);
140325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
140425944Sjoerg		break;
140525944Sjoerg	default:
140625944Sjoerg		printf("%s%d: %s illegal down in state %s\n",
140725944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
140825944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
140925944Sjoerg	}
141025944Sjoerg}
14114910Swollman
141211189Sjkh
141325944Sjoergstatic void
141425944Sjoergsppp_open_event(const struct cp *cp, struct sppp *sp)
141525944Sjoerg{
141625944Sjoerg	STDDCL;
141725944Sjoerg
141825944Sjoerg	if (debug)
141925944Sjoerg		log(LOG_DEBUG, "%s%d: %s open(%s)\n",
142025944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
142125944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
142225944Sjoerg
142325944Sjoerg	switch (sp->state[cp->protoidx]) {
142425944Sjoerg	case STATE_INITIAL:
142525944Sjoerg		(cp->tls)(sp);
142625944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
14274910Swollman		break;
142825944Sjoerg	case STATE_STARTING:
142925944Sjoerg		break;
143025944Sjoerg	case STATE_CLOSED:
143125944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
143225944Sjoerg		(cp->scr)(sp);
143325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
143425944Sjoerg		break;
143525944Sjoerg	case STATE_STOPPED:
143625944Sjoerg	case STATE_STOPPING:
143725944Sjoerg	case STATE_REQ_SENT:
143825944Sjoerg	case STATE_ACK_RCVD:
143925944Sjoerg	case STATE_ACK_SENT:
144025944Sjoerg	case STATE_OPENED:
144125944Sjoerg		break;
144225944Sjoerg	case STATE_CLOSING:
144325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STOPPING);
144425944Sjoerg		break;
144525944Sjoerg	}
144625944Sjoerg}
14474910Swollman
144825944Sjoerg
144925944Sjoergstatic void
145025944Sjoergsppp_close_event(const struct cp *cp, struct sppp *sp)
145125944Sjoerg{
145225944Sjoerg	STDDCL;
145325944Sjoerg
145425944Sjoerg	if (debug)
145525944Sjoerg		log(LOG_DEBUG, "%s%d: %s close(%s)\n",
145625944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
145725944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
145825944Sjoerg
145925944Sjoerg	switch (sp->state[cp->protoidx]) {
146025944Sjoerg	case STATE_INITIAL:
146125944Sjoerg	case STATE_CLOSED:
146225944Sjoerg	case STATE_CLOSING:
14634910Swollman		break;
146425944Sjoerg	case STATE_STARTING:
146525944Sjoerg		(cp->tlf)(sp);
146625944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
14674910Swollman		break;
146825944Sjoerg	case STATE_STOPPED:
146925944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
14704910Swollman		break;
147125944Sjoerg	case STATE_STOPPING:
147225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
14734910Swollman		break;
147425944Sjoerg	case STATE_OPENED:
147525944Sjoerg		(cp->tld)(sp);
147625944Sjoerg		/* fall through */
147725944Sjoerg	case STATE_REQ_SENT:
147825944Sjoerg	case STATE_ACK_RCVD:
147925944Sjoerg	case STATE_ACK_SENT:
148025944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
148125944Sjoerg		sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0);
148225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
14834910Swollman		break;
14844910Swollman	}
14854910Swollman}
14864910Swollman
148725944Sjoergstatic void
148825944Sjoergsppp_to_event(const struct cp *cp, struct sppp *sp)
148925944Sjoerg{
149025944Sjoerg	STDDCL;
149125944Sjoerg	int s;
149225944Sjoerg
149325944Sjoerg	s = splimp();
149425944Sjoerg	if (debug)
149525944Sjoerg		log(LOG_DEBUG, "%s%d: %s TO(%s) rst_counter = %d\n",
149625944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
149725944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
149825944Sjoerg		    sp->rst_counter[cp->protoidx]);
149925944Sjoerg
150025944Sjoerg	if (--sp->rst_counter[cp->protoidx] < 0)
150125944Sjoerg		/* TO- event */
150225944Sjoerg		switch (sp->state[cp->protoidx]) {
150325944Sjoerg		case STATE_CLOSING:
150425944Sjoerg			(cp->tlf)(sp);
150525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
150625944Sjoerg			break;
150725944Sjoerg		case STATE_STOPPING:
150825944Sjoerg			(cp->tlf)(sp);
150925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
151025944Sjoerg			break;
151125944Sjoerg		case STATE_REQ_SENT:
151225944Sjoerg		case STATE_ACK_RCVD:
151325944Sjoerg		case STATE_ACK_SENT:
151425944Sjoerg			(cp->tlf)(sp);
151525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
151625944Sjoerg			break;
151725944Sjoerg		}
151825944Sjoerg	else
151925944Sjoerg		/* TO+ event */
152025944Sjoerg		switch (sp->state[cp->protoidx]) {
152125944Sjoerg		case STATE_CLOSING:
152225944Sjoerg		case STATE_STOPPING:
152325944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
152425944Sjoerg				     0, 0);
152525944Sjoerg			timeout(cp->TO, (void *)sp, sp->lcp.timeout);
152625944Sjoerg			break;
152725944Sjoerg		case STATE_REQ_SENT:
152825944Sjoerg		case STATE_ACK_RCVD:
152925944Sjoerg			(cp->scr)(sp);
153025944Sjoerg			/* sppp_cp_change_state() will restart the timer */
153125944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
153225944Sjoerg			break;
153325944Sjoerg		case STATE_ACK_SENT:
153425944Sjoerg			(cp->scr)(sp);
153525944Sjoerg			timeout(cp->TO, (void *)sp, sp->lcp.timeout);
153625944Sjoerg			break;
153725944Sjoerg		}
153825944Sjoerg
153925944Sjoerg	splx(s);
154025944Sjoerg}
154125944Sjoerg
154211189Sjkh/*
154325944Sjoerg * Change the state of a control protocol in the state automaton.
154425944Sjoerg * Takes care of starting/stopping the restart timer.
154511189Sjkh */
154625944Sjoergvoid
154725944Sjoergsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
154825944Sjoerg{
154925944Sjoerg	sp->state[cp->protoidx] = newstate;
155025944Sjoerg
155125944Sjoerg	untimeout(cp->TO, (void *)sp);
155225944Sjoerg	switch (newstate) {
155325944Sjoerg	case STATE_INITIAL:
155425944Sjoerg	case STATE_STARTING:
155525944Sjoerg	case STATE_CLOSED:
155625944Sjoerg	case STATE_STOPPED:
155725944Sjoerg	case STATE_OPENED:
155825944Sjoerg		break;
155925944Sjoerg	case STATE_CLOSING:
156025944Sjoerg	case STATE_STOPPING:
156125944Sjoerg	case STATE_REQ_SENT:
156225944Sjoerg	case STATE_ACK_RCVD:
156325944Sjoerg	case STATE_ACK_SENT:
156425944Sjoerg		timeout(cp->TO, (void *)sp, sp->lcp.timeout);
156525944Sjoerg		break;
156625944Sjoerg	}
156725944Sjoerg}
156825944Sjoerg/*
156925944Sjoerg *--------------------------------------------------------------------------*
157025944Sjoerg *                                                                          *
157125944Sjoerg *                         The LCP implementation.                          *
157225944Sjoerg *                                                                          *
157325944Sjoerg *--------------------------------------------------------------------------*
157425944Sjoerg */
157525944Sjoergstatic void
157625944Sjoergsppp_lcp_init(struct sppp *sp)
157725944Sjoerg{
157825944Sjoerg	sp->lcp.opts = (1 << LCP_OPT_MAGIC);
157925944Sjoerg	sp->lcp.magic = 0;
158025944Sjoerg	sp->state[IDX_LCP] = STATE_INITIAL;
158125944Sjoerg	sp->fail_counter[IDX_LCP] = 0;
158225944Sjoerg	sp->lcp.protos = 0;
158325944Sjoerg	sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
158425944Sjoerg
158525944Sjoerg	/*
158625944Sjoerg	 * Initialize counters and timeout values.  Note that we don't
158725944Sjoerg	 * use the 3 seconds suggested in RFC 1661 since we are likely
158825944Sjoerg	 * running on a fast link.  XXX We should probably implement
158925944Sjoerg	 * the exponential backoff option.  Note that these values are
159025944Sjoerg	 * relevant for all control protocols, not just LCP only.
159125944Sjoerg	 */
159225944Sjoerg	sp->lcp.timeout = 1 * hz;
159325944Sjoerg	sp->lcp.max_terminate = 2;
159425944Sjoerg	sp->lcp.max_configure = 10;
159525944Sjoerg	sp->lcp.max_failure = 10;
159625944Sjoerg}
159725944Sjoerg
159825944Sjoergstatic void
159925944Sjoergsppp_lcp_up(struct sppp *sp)
160025944Sjoerg{
160125944Sjoerg	STDDCL;
160225944Sjoerg
160325944Sjoerg	/*
160425944Sjoerg	 * If this interface is passive or dial-on-demand, it means
160525944Sjoerg	 * we've got in incoming call.  Activate the interface.
160625944Sjoerg	 */
160725944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) {
160825944Sjoerg		if (debug)
160925944Sjoerg			log(LOG_DEBUG,
161025944Sjoerg			    "%s%d: Up event (incoming call)\n",
161125944Sjoerg			    ifp->if_name, ifp->if_unit);
161225944Sjoerg		ifp->if_flags |= IFF_RUNNING;
161325944Sjoerg		lcp.Open(sp);
161425944Sjoerg	}
161525944Sjoerg
161625944Sjoerg	sppp_up_event(&lcp, sp);
161725944Sjoerg}
161825944Sjoerg
161925944Sjoergstatic void
162025944Sjoergsppp_lcp_down(struct sppp *sp)
162125944Sjoerg{
162225944Sjoerg	STDDCL;
162325944Sjoerg
162425944Sjoerg	sppp_down_event(&lcp, sp);
162525944Sjoerg
162625944Sjoerg	/*
162725944Sjoerg	 * If this is neither a dial-on-demand nor a passive
162825944Sjoerg	 * interface, simulate an ``ifconfig down'' action, so the
162925944Sjoerg	 * administrator can force a redial by another ``ifconfig
163025944Sjoerg	 * up''.  XXX For leased line operation, should we immediately
163125944Sjoerg	 * try to reopen the connection here?
163225944Sjoerg	 */
163325944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
163425944Sjoerg		log(LOG_INFO,
163525944Sjoerg		    "%s%d: Down event (carrier loss), taking interface down.\n",
163625944Sjoerg		    ifp->if_name, ifp->if_unit);
163725944Sjoerg		if_down(ifp);
163825944Sjoerg	} else {
163925944Sjoerg		if (debug)
164025944Sjoerg			log(LOG_DEBUG,
164125944Sjoerg			    "%s%d: Down event (carrier loss)\n",
164225944Sjoerg			    ifp->if_name, ifp->if_unit);
164325944Sjoerg	}
164425944Sjoerg	lcp.Close(sp);
164525944Sjoerg	ifp->if_flags &= ~IFF_RUNNING;
164625944Sjoerg}
164725944Sjoerg
164825944Sjoergstatic void
164925944Sjoergsppp_lcp_open(struct sppp *sp)
165025944Sjoerg{
165125944Sjoerg	sppp_open_event(&lcp, sp);
165225944Sjoerg}
165325944Sjoerg
165425944Sjoergstatic void
165525944Sjoergsppp_lcp_close(struct sppp *sp)
165625944Sjoerg{
165725944Sjoerg	sppp_close_event(&lcp, sp);
165825944Sjoerg}
165925944Sjoerg
166025944Sjoergstatic void
166125944Sjoergsppp_lcp_TO(void *cookie)
166225944Sjoerg{
166325944Sjoerg	sppp_to_event(&lcp, (struct sppp *)cookie);
166425944Sjoerg}
166525944Sjoerg
166625944Sjoerg/*
166725944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
166825944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
166925944Sjoerg * caused action scn.  (The return value is used to make the state
167025944Sjoerg * transition decision in the state automaton.)
167125944Sjoerg */
167212820Sphkstatic int
167325944Sjoergsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
16744910Swollman{
167525944Sjoerg	STDDCL;
167611189Sjkh	u_char *buf, *r, *p;
167725944Sjoerg	int origlen, rlen;
167825944Sjoerg	u_long nmagic;
16794910Swollman
168011189Sjkh	len -= 4;
168125944Sjoerg	origlen = len;
168211189Sjkh	buf = r = malloc (len, M_TEMP, M_NOWAIT);
168311189Sjkh	if (! buf)
168411189Sjkh		return (0);
16854910Swollman
168625706Sjoerg	if (debug)
168725944Sjoerg		log(LOG_DEBUG, "%s%d: lcp parse opts: ",
168825944Sjoerg		    ifp->if_name, ifp->if_unit);
168925706Sjoerg
169025944Sjoerg	/* pass 1: check for things that need to be rejected */
169111189Sjkh	p = (void*) (h+1);
169211189Sjkh	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
169325944Sjoerg		if (debug)
169425944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
169511189Sjkh		switch (*p) {
169611189Sjkh		case LCP_OPT_MAGIC:
169725944Sjoerg			/* Magic number. */
169825944Sjoerg			/* fall through, both are same length */
169925944Sjoerg		case LCP_OPT_ASYNC_MAP:
170025944Sjoerg			/* Async control character map. */
170125944Sjoerg			if (len >= 6 || p[1] == 6)
170225944Sjoerg				continue;
170325944Sjoerg			if (debug)
170425944Sjoerg				addlog("[invalid] ");
170525944Sjoerg			break;
170625944Sjoerg		case LCP_OPT_MRU:
170725944Sjoerg			/* Maximum receive unit. */
170825944Sjoerg			if (len >= 4 && p[1] == 4)
170925944Sjoerg				continue;
171025944Sjoerg			if (debug)
171125944Sjoerg				addlog("[invalid] ");
171225944Sjoerg			break;
171325944Sjoerg		default:
171425944Sjoerg			/* Others not supported. */
171525944Sjoerg			if (debug)
171625944Sjoerg				addlog("[rej] ");
171725944Sjoerg			break;
171825944Sjoerg		}
171925944Sjoerg		/* Add the option to rejected list. */
172025944Sjoerg		bcopy (p, r, p[1]);
172125944Sjoerg		r += p[1];
172225944Sjoerg		rlen += p[1];
172325944Sjoerg	}
172425944Sjoerg	if (rlen) {
172525944Sjoerg		if (debug)
172625944Sjoerg			addlog(" send conf-rej\n");
172725944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
172825944Sjoerg		return 0;
172925944Sjoerg	} else if (debug)
173025944Sjoerg		addlog("\n");
173125944Sjoerg
173225944Sjoerg	/*
173325944Sjoerg	 * pass 2: check for option values that are unacceptable and
173425944Sjoerg	 * thus require to be nak'ed.
173525944Sjoerg	 */
173625944Sjoerg	if (debug)
173726077Sjoerg		log(LOG_DEBUG, "%s%d: lcp parse opt values: ",
173826077Sjoerg		    ifp->if_name, ifp->if_unit);
173925944Sjoerg
174025944Sjoerg	p = (void*) (h+1);
174125944Sjoerg	len = origlen;
174225944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
174325944Sjoerg		if (debug)
174425944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
174525944Sjoerg		switch (*p) {
174625944Sjoerg		case LCP_OPT_MAGIC:
174711189Sjkh			/* Magic number -- extract. */
174825944Sjoerg			nmagic = (u_long)p[2] << 24 |
174925944Sjoerg				(u_long)p[3] << 16 | p[4] << 8 | p[5];
175025944Sjoerg			if (nmagic != sp->lcp.magic) {
175125706Sjoerg				if (debug)
175225944Sjoerg					addlog("0x%x ", nmagic);
175311189Sjkh				continue;
175411189Sjkh			}
175525944Sjoerg			/*
175625944Sjoerg			 * Local and remote magics equal -- loopback?
175725944Sjoerg			 */
175825944Sjoerg			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
175925944Sjoerg				printf ("\n%s%d: loopback\n",
176025944Sjoerg					ifp->if_name, ifp->if_unit);
176125944Sjoerg				sp->pp_loopcnt = 0;
176225944Sjoerg				if (ifp->if_flags & IFF_UP) {
176325944Sjoerg					if_down(ifp);
176426018Sjoerg					sppp_qflush(&sp->pp_cpq);
176525944Sjoerg					/* XXX ? */
176625944Sjoerg					lcp.Down(sp);
176725944Sjoerg					lcp.Up(sp);
176825944Sjoerg				}
176925944Sjoerg			} else if (debug)
177025944Sjoerg				addlog("[glitch] ");
177125944Sjoerg			++sp->pp_loopcnt;
177225944Sjoerg			/*
177325944Sjoerg			 * We negate our magic here, and NAK it.  If
177425944Sjoerg			 * we see it later in an NAK packet, we
177525944Sjoerg			 * suggest a new one.
177625944Sjoerg			 */
177725944Sjoerg			nmagic = ~sp->lcp.magic;
177825944Sjoerg			/* Gonna NAK it. */
177925944Sjoerg			p[2] = nmagic >> 24;
178025944Sjoerg			p[3] = nmagic >> 16;
178125944Sjoerg			p[4] = nmagic >> 8;
178225944Sjoerg			p[5] = nmagic;
178311189Sjkh			break;
178425944Sjoerg
178511189Sjkh		case LCP_OPT_ASYNC_MAP:
178611189Sjkh			/* Async control character map -- check to be zero. */
178725944Sjoerg			if (! p[2] && ! p[3] && ! p[4] && ! p[5]) {
178825706Sjoerg				if (debug)
178925944Sjoerg					addlog("[empty] ");
179011189Sjkh				continue;
179125706Sjoerg			}
179225706Sjoerg			if (debug)
179325944Sjoerg				addlog("[non-empty] ");
179425944Sjoerg			/* suggest a zero one */
179525944Sjoerg			p[2] = p[3] = p[4] = p[5] = 0;
179611189Sjkh			break;
179725944Sjoerg
179811189Sjkh		case LCP_OPT_MRU:
179925944Sjoerg			/*
180025944Sjoerg			 * Maximum receive unit.  Always agreeable,
180125944Sjoerg			 * but ignored by now.
180225944Sjoerg			 */
180325944Sjoerg			sp->lcp.their_mru = p[2] * 256 + p[3];
180425706Sjoerg			if (debug)
180525944Sjoerg				addlog("%d ", sp->lcp.their_mru);
180611189Sjkh			continue;
180711189Sjkh		}
180825944Sjoerg		/* Add the option to nak'ed list. */
180925706Sjoerg		bcopy (p, r, p[1]);
181025706Sjoerg		r += p[1];
181111189Sjkh		rlen += p[1];
181212436Speter	}
181325706Sjoerg	if (rlen) {
181428036Sjoerg		if (++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) {
181528036Sjoerg			if (debug)
181628036Sjoerg				addlog(" max_failure (%d) exceeded, "
181728036Sjoerg				       "send conf-rej\n",
181828036Sjoerg				       sp->lcp.max_failure);
181928036Sjoerg			sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
182028036Sjoerg		} else {
182128036Sjoerg			if (debug)
182228036Sjoerg				addlog(" send conf-nak\n");
182328036Sjoerg			sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
182428036Sjoerg		}
182525944Sjoerg		return 0;
182625944Sjoerg	} else {
182725944Sjoerg		if (debug)
182825944Sjoerg			addlog(" send conf-ack\n");
182928036Sjoerg		sp->fail_counter[IDX_LCP] = 0;
183025944Sjoerg		sp->pp_loopcnt = 0;
183125944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_ACK,
183225944Sjoerg			      h->ident, origlen, h+1);
183325944Sjoerg	}
183425944Sjoerg
183511189Sjkh	free (buf, M_TEMP);
183611189Sjkh	return (rlen == 0);
18374910Swollman}
18384910Swollman
183925944Sjoerg/*
184025944Sjoerg * Analyze the LCP Configure-Reject option list, and adjust our
184125944Sjoerg * negotiation.
184225944Sjoerg */
184312820Sphkstatic void
184425944Sjoergsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
18454910Swollman{
184625944Sjoerg	STDDCL;
184725944Sjoerg	u_char *buf, *p;
18484910Swollman
184925944Sjoerg	len -= 4;
185025944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
185125944Sjoerg	if (!buf)
18524910Swollman		return;
185325944Sjoerg
185425944Sjoerg	if (debug)
185525944Sjoerg		log(LOG_DEBUG, "%s%d: lcp rej opts: ",
185625944Sjoerg		    ifp->if_name, ifp->if_unit);
185725944Sjoerg
185825944Sjoerg	p = (void*) (h+1);
185925944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
186025944Sjoerg		if (debug)
186125944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
186225944Sjoerg		switch (*p) {
186325944Sjoerg		case LCP_OPT_MAGIC:
186425944Sjoerg			/* Magic number -- can't use it, use 0 */
186525944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC);
186625944Sjoerg			sp->lcp.magic = 0;
186725944Sjoerg			break;
186825944Sjoerg		case LCP_OPT_MRU:
186925944Sjoerg			/*
187025944Sjoerg			 * Should not be rejected anyway, since we only
187125944Sjoerg			 * negotiate a MRU if explicitly requested by
187225944Sjoerg			 * peer.
187325944Sjoerg			 */
187425944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
187525944Sjoerg			break;
187625944Sjoerg		}
18774910Swollman	}
187825944Sjoerg	if (debug)
187925944Sjoerg		addlog("\n");
188025944Sjoerg	free (buf, M_TEMP);
188125944Sjoerg	return;
188225944Sjoerg}
188325944Sjoerg
188425944Sjoerg/*
188525944Sjoerg * Analyze the LCP Configure-NAK option list, and adjust our
188625944Sjoerg * negotiation.
188725944Sjoerg */
188825944Sjoergstatic void
188925944Sjoergsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
189025944Sjoerg{
189125944Sjoerg	STDDCL;
189225944Sjoerg	u_char *buf, *p;
189325944Sjoerg	u_long magic;
189425944Sjoerg
189525944Sjoerg	len -= 4;
189625944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
189725944Sjoerg	if (!buf)
189825944Sjoerg		return;
189925944Sjoerg
190025944Sjoerg	if (debug)
190125944Sjoerg		log(LOG_DEBUG, "%s%d: lcp nak opts: ",
190225944Sjoerg		    ifp->if_name, ifp->if_unit);
190325944Sjoerg
190425944Sjoerg	p = (void*) (h+1);
190525944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
190625706Sjoerg		if (debug)
190725944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
190825944Sjoerg		switch (*p) {
190925944Sjoerg		case LCP_OPT_MAGIC:
191025944Sjoerg			/* Magic number -- renegotiate */
191125944Sjoerg			if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
191225944Sjoerg			    len >= 6 && p[1] == 6) {
191325944Sjoerg				magic = (u_long)p[2] << 24 |
191425944Sjoerg					(u_long)p[3] << 16 | p[4] << 8 | p[5];
191525944Sjoerg				/*
191625944Sjoerg				 * If the remote magic is our negated one,
191725944Sjoerg				 * this looks like a loopback problem.
191825944Sjoerg				 * Suggest a new magic to make sure.
191925944Sjoerg				 */
192025944Sjoerg				if (magic == ~sp->lcp.magic) {
192125944Sjoerg					if (debug)
192225944Sjoerg						addlog("magic glitch ");
192325944Sjoerg					sp->lcp.magic += time.tv_sec + time.tv_usec;
192425944Sjoerg				} else {
192525944Sjoerg					sp->lcp.magic = magic;
192625944Sjoerg					if (debug)
192725944Sjoerg						addlog("%d ");
192825944Sjoerg				}
192925944Sjoerg			}
193025944Sjoerg			break;
193125944Sjoerg		case LCP_OPT_MRU:
193225944Sjoerg			/*
193325944Sjoerg			 * Peer wants to advise us to negotiate an MRU.
193425944Sjoerg			 * Agree on it if it's reasonable, or use
193525944Sjoerg			 * default otherwise.
193625944Sjoerg			 */
193725944Sjoerg			if (len >= 4 && p[1] == 4) {
193825944Sjoerg				u_int mru = p[2] * 256 + p[3];
193925944Sjoerg				if (debug)
194025944Sjoerg					addlog("%d ", mru);
194125944Sjoerg				if (mru < PP_MTU || mru > PP_MAX_MRU)
194225944Sjoerg					mru = PP_MTU;
194325944Sjoerg				sp->lcp.mru = mru;
194425944Sjoerg				sp->lcp.opts |= (1 << LCP_OPT_MRU);
194525944Sjoerg			}
194625944Sjoerg			break;
19474910Swollman		}
194825944Sjoerg	}
194925944Sjoerg	if (debug)
195025944Sjoerg		addlog("\n");
195125944Sjoerg	free (buf, M_TEMP);
195225944Sjoerg	return;
195325944Sjoerg}
195411189Sjkh
195525944Sjoergstatic void
195625944Sjoergsppp_lcp_tlu(struct sppp *sp)
195725944Sjoerg{
195825944Sjoerg	STDDCL;
195925944Sjoerg	int i;
196025944Sjoerg	u_long mask;
196125944Sjoerg
196225944Sjoerg	/* XXX ? */
196325944Sjoerg	if (! (ifp->if_flags & IFF_UP) &&
196425944Sjoerg	    (ifp->if_flags & IFF_RUNNING)) {
196525944Sjoerg		/* Coming out of loopback mode. */
196625944Sjoerg		if_up(ifp);
196725944Sjoerg		printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
196825944Sjoerg	}
196925944Sjoerg
197025944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
197125944Sjoerg		if ((cps[i])->flags & CP_QUAL)
197225944Sjoerg			(cps[i])->Open(sp);
197325944Sjoerg
197425944Sjoerg	if (/* require authentication XXX */ 0)
197525944Sjoerg		sp->pp_phase = PHASE_AUTHENTICATE;
197625944Sjoerg	else
197725944Sjoerg		sp->pp_phase = PHASE_NETWORK;
197825944Sjoerg
197925944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
198025944Sjoerg	    sppp_phase_name(sp->pp_phase));
198125944Sjoerg
198225944Sjoerg	if (sp->pp_phase == PHASE_AUTHENTICATE) {
198325944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
198425944Sjoerg			if ((cps[i])->flags & CP_AUTH)
198525944Sjoerg				(cps[i])->Open(sp);
198625944Sjoerg	} else {
198725944Sjoerg		/* Notify all NCPs. */
198825944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
198925944Sjoerg			if ((cps[i])->flags & CP_NCP)
199025944Sjoerg				(cps[i])->Open(sp);
199125944Sjoerg	}
199225944Sjoerg
199325944Sjoerg	/* Send Up events to all started protos. */
199425944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
199525944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0)
199625944Sjoerg			(cps[i])->Up(sp);
199725944Sjoerg
199825944Sjoerg	if (sp->pp_phase == PHASE_NETWORK)
199925944Sjoerg		/* if no NCP is starting, close down */
200025944Sjoerg		sppp_lcp_check(sp);
200125944Sjoerg}
200225944Sjoerg
200325944Sjoergstatic void
200425944Sjoergsppp_lcp_tld(struct sppp *sp)
200525944Sjoerg{
200625944Sjoerg	STDDCL;
200725944Sjoerg	int i;
200825944Sjoerg	u_long mask;
200925944Sjoerg
201025944Sjoerg	sp->pp_phase = PHASE_TERMINATE;
201125944Sjoerg
201225944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
201325944Sjoerg	    sppp_phase_name(sp->pp_phase));
201425944Sjoerg
201525944Sjoerg	/*
201625944Sjoerg	 * Take upper layers down.  We send the Down event first and
201725944Sjoerg	 * the Close second to prevent the upper layers from sending
201825944Sjoerg	 * ``a flurry of terminate-request packets'', as the RFC
201925944Sjoerg	 * describes it.
202025944Sjoerg	 */
202125944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
202225944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) {
202325944Sjoerg			(cps[i])->Down(sp);
202425944Sjoerg			(cps[i])->Close(sp);
202525944Sjoerg		}
202625944Sjoerg}
202725944Sjoerg
202825944Sjoergstatic void
202925944Sjoergsppp_lcp_tls(struct sppp *sp)
203025944Sjoerg{
203125944Sjoerg	STDDCL;
203225944Sjoerg
203325944Sjoerg	sp->pp_phase = PHASE_ESTABLISH;
203425944Sjoerg
203525944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
203625944Sjoerg	    sppp_phase_name(sp->pp_phase));
203725944Sjoerg
203825944Sjoerg	/* Notify lower layer if desired. */
203925944Sjoerg	if (sp->pp_tls)
204025944Sjoerg		(sp->pp_tls)(sp);
204125944Sjoerg}
204225944Sjoerg
204325944Sjoergstatic void
204425944Sjoergsppp_lcp_tlf(struct sppp *sp)
204525944Sjoerg{
204625944Sjoerg	STDDCL;
204725944Sjoerg
204825944Sjoerg	sp->pp_phase = PHASE_DEAD;
204925944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
205025944Sjoerg	    sppp_phase_name(sp->pp_phase));
205125944Sjoerg
205225944Sjoerg	/* Notify lower layer if desired. */
205325944Sjoerg	if (sp->pp_tlf)
205425944Sjoerg		(sp->pp_tlf)(sp);
205525944Sjoerg}
205625944Sjoerg
205725944Sjoergstatic void
205825944Sjoergsppp_lcp_scr(struct sppp *sp)
205925944Sjoerg{
206025944Sjoerg	char opt[6 /* magicnum */ + 4 /* mru */];
206125944Sjoerg	int i = 0;
206225944Sjoerg
206325944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
206425944Sjoerg		if (! sp->lcp.magic)
206525944Sjoerg			sp->lcp.magic = time.tv_sec + time.tv_usec;
206625944Sjoerg		opt[i++] = LCP_OPT_MAGIC;
206725944Sjoerg		opt[i++] = 6;
206825944Sjoerg		opt[i++] = sp->lcp.magic >> 24;
206925944Sjoerg		opt[i++] = sp->lcp.magic >> 16;
207025944Sjoerg		opt[i++] = sp->lcp.magic >> 8;
207125944Sjoerg		opt[i++] = sp->lcp.magic;
207225944Sjoerg	}
207325944Sjoerg
207425944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MRU)) {
207525944Sjoerg		opt[i++] = LCP_OPT_MRU;
207625944Sjoerg		opt[i++] = 4;
207725944Sjoerg		opt[i++] = sp->lcp.mru >> 8;
207825944Sjoerg		opt[i++] = sp->lcp.mru;
207925944Sjoerg	}
208025944Sjoerg
208125944Sjoerg	sp->confid[IDX_LCP] = ++sp->pp_seq;
208225944Sjoerg	sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
208325944Sjoerg}
208425944Sjoerg
208525944Sjoerg/*
208625944Sjoerg * Re-check the open NCPs and see if we should terminate the link.
208725944Sjoerg * Called by the NCPs during their tlf action handling.
208825944Sjoerg */
208925944Sjoergstatic void
209025944Sjoergsppp_lcp_check(struct sppp *sp)
209125944Sjoerg{
209225944Sjoerg	int i, mask;
209325944Sjoerg
209425944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
209525944Sjoerg		if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP)
209625944Sjoerg			return;
209725944Sjoerg	lcp.Close(sp);
209825944Sjoerg}
209925944Sjoerg/*
210025944Sjoerg *--------------------------------------------------------------------------*
210125944Sjoerg *                                                                          *
210225944Sjoerg *                        The IPCP implementation.                          *
210325944Sjoerg *                                                                          *
210425944Sjoerg *--------------------------------------------------------------------------*
210525944Sjoerg */
210625944Sjoerg
210725944Sjoergstatic void
210825944Sjoergsppp_ipcp_init(struct sppp *sp)
210925944Sjoerg{
211025944Sjoerg	sp->ipcp.opts = 0;
211125944Sjoerg	sp->ipcp.flags = 0;
211225944Sjoerg	sp->state[IDX_IPCP] = STATE_INITIAL;
211325944Sjoerg	sp->fail_counter[IDX_IPCP] = 0;
211425944Sjoerg}
211525944Sjoerg
211625944Sjoergstatic void
211725944Sjoergsppp_ipcp_up(struct sppp *sp)
211825944Sjoerg{
211925944Sjoerg	sppp_up_event(&ipcp, sp);
212025944Sjoerg}
212125944Sjoerg
212225944Sjoergstatic void
212325944Sjoergsppp_ipcp_down(struct sppp *sp)
212425944Sjoerg{
212525944Sjoerg	sppp_down_event(&ipcp, sp);
212625944Sjoerg}
212725944Sjoerg
212825944Sjoergstatic void
212925944Sjoergsppp_ipcp_open(struct sppp *sp)
213025944Sjoerg{
213125944Sjoerg	STDDCL;
213225944Sjoerg	u_long myaddr, hisaddr;
213325944Sjoerg
213425944Sjoerg	sppp_get_ip_addrs(sp, &myaddr, &hisaddr);
213525944Sjoerg	/*
213625944Sjoerg	 * If we don't have his address, this probably means our
213725944Sjoerg	 * interface doesn't want to talk IP at all.  (This could
213825944Sjoerg	 * be the case if somebody wants to speak only IPX, for
213925944Sjoerg	 * example.)  Don't open IPCP in this case.
214025944Sjoerg	 */
214125944Sjoerg	if (hisaddr == 0L) {
214225944Sjoerg		/* XXX this message should go away */
214325944Sjoerg		if (debug)
214425944Sjoerg			log(LOG_DEBUG, "%s%d: ipcp_open(): no IP interface\n",
214525944Sjoerg			    ifp->if_name, ifp->if_unit);
214625944Sjoerg		return;
214725944Sjoerg	}
214825944Sjoerg
214925944Sjoerg	if (myaddr == 0L) {
215025944Sjoerg		/*
215125944Sjoerg		 * I don't have an assigned address, so i need to
215225944Sjoerg		 * negotiate my address.
215325944Sjoerg		 */
215425944Sjoerg		sp->ipcp.flags |= IPCP_MYADDR_DYN;
215525944Sjoerg		sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
215625944Sjoerg	}
215725944Sjoerg	sppp_open_event(&ipcp, sp);
215825944Sjoerg}
215925944Sjoerg
216025944Sjoergstatic void
216125944Sjoergsppp_ipcp_close(struct sppp *sp)
216225944Sjoerg{
216325944Sjoerg	sppp_close_event(&ipcp, sp);
216425944Sjoerg	if (sp->ipcp.flags & IPCP_MYADDR_DYN)
216525944Sjoerg		/*
216625944Sjoerg		 * My address was dynamic, clear it again.
216725944Sjoerg		 */
216825944Sjoerg		sppp_set_ip_addr(sp, 0L);
216925944Sjoerg}
217025944Sjoerg
217125944Sjoergstatic void
217225944Sjoergsppp_ipcp_TO(void *cookie)
217325944Sjoerg{
217425944Sjoerg	sppp_to_event(&ipcp, (struct sppp *)cookie);
217525944Sjoerg}
217625944Sjoerg
217725944Sjoerg/*
217825944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
217925944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
218025944Sjoerg * caused action scn.  (The return value is used to make the state
218125944Sjoerg * transition decision in the state automaton.)
218225944Sjoerg */
218325944Sjoergstatic int
218425944Sjoergsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
218525944Sjoerg{
218625944Sjoerg	u_char *buf, *r, *p;
218725944Sjoerg	struct ifnet *ifp = &sp->pp_if;
218825944Sjoerg	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
218925944Sjoerg	u_long hisaddr, desiredaddr;
219025944Sjoerg
219125944Sjoerg	len -= 4;
219225944Sjoerg	origlen = len;
219325944Sjoerg	/*
219425944Sjoerg	 * Make sure to allocate a buf that can at least hold a
219525944Sjoerg	 * conf-nak with an `address' option.  We might need it below.
219625944Sjoerg	 */
219725944Sjoerg	buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
219825944Sjoerg	if (! buf)
219925944Sjoerg		return (0);
220025944Sjoerg
220125944Sjoerg	/* pass 1: see if we can recognize them */
220225944Sjoerg	if (debug)
220325944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp parse opts: ",
220425944Sjoerg		    ifp->if_name, ifp->if_unit);
220525944Sjoerg	p = (void*) (h+1);
220625944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
220725944Sjoerg		if (debug)
220825944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
220925944Sjoerg		switch (*p) {
221025944Sjoerg#ifdef notyet
221125944Sjoerg		case IPCP_OPT_COMPRESSION:
221225944Sjoerg			if (len >= 6 && p[1] >= 6) {
221325944Sjoerg				/* correctly formed compress option */
221425944Sjoerg				continue;
221511189Sjkh			}
221625706Sjoerg			if (debug)
221725944Sjoerg				addlog("[invalid] ");
221825944Sjoerg			break;
221925944Sjoerg#endif
222025944Sjoerg		case IPCP_OPT_ADDRESS:
222125944Sjoerg			if (len >= 6 && p[1] == 6) {
222225944Sjoerg				/* correctly formed address option */
222325944Sjoerg				continue;
222425944Sjoerg			}
222525706Sjoerg			if (debug)
222625944Sjoerg				addlog("[invalid] ");
222711189Sjkh			break;
222825944Sjoerg		default:
222925944Sjoerg			/* Others not supported. */
223025944Sjoerg			if (debug)
223125944Sjoerg				addlog("[rej] ");
22324910Swollman			break;
22334910Swollman		}
223425944Sjoerg		/* Add the option to rejected list. */
223525944Sjoerg		bcopy (p, r, p[1]);
223625944Sjoerg		r += p[1];
223725944Sjoerg		rlen += p[1];
223825944Sjoerg	}
223925944Sjoerg	if (rlen) {
224025944Sjoerg		if (debug)
224125944Sjoerg			addlog(" send conf-rej\n");
224225944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf);
224325944Sjoerg		return 0;
224425944Sjoerg	} else if (debug)
224525944Sjoerg		addlog("\n");
224625944Sjoerg
224725944Sjoerg	/* pass 2: parse option values */
224825944Sjoerg	sppp_get_ip_addrs(sp, 0, &hisaddr);
224925944Sjoerg	if (debug)
225025944Sjoerg		addlog("%s%d: ipcp parse opt values: ", ifp->if_name, ifp->if_unit);
225125944Sjoerg	p = (void*) (h+1);
225225944Sjoerg	len = origlen;
225325944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
225425944Sjoerg		if (debug)
225525944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
225625944Sjoerg		switch (*p) {
225725944Sjoerg#ifdef notyet
225825944Sjoerg		case IPCP_OPT_COMPRESSION:
225925944Sjoerg			continue;
226025944Sjoerg#endif
226125944Sjoerg		case IPCP_OPT_ADDRESS:
226225944Sjoerg			desiredaddr = p[2] << 24 | p[3] << 16 |
226325944Sjoerg				p[4] << 8 | p[5];
226425944Sjoerg			if (desiredaddr == hisaddr) {
226525944Sjoerg				/*
226625944Sjoerg				 * Peer's address is same as our value,
226725944Sjoerg				 * this is agreeable.  Gonna conf-ack
226825944Sjoerg				 * it.
226925944Sjoerg				 */
227025944Sjoerg				if (debug)
227125944Sjoerg					addlog("0x%x [ack] ", hisaddr);
227225944Sjoerg				/* record that we've seen it already */
227325944Sjoerg				sp->ipcp.flags |= IPCP_HISADDR_SEEN;
227425944Sjoerg				continue;
227525944Sjoerg			}
227625944Sjoerg			/*
227725944Sjoerg			 * The address wasn't agreeable.  This is either
227825944Sjoerg			 * he sent us 0.0.0.0, asking to assign him an
227925944Sjoerg			 * address, or he send us another address not
228025944Sjoerg			 * matching our value.  Either case, we gonna
228125944Sjoerg			 * conf-nak it with our value.
228225944Sjoerg			 */
228325944Sjoerg			if (debug) {
228425944Sjoerg				if (desiredaddr == 0)
228525944Sjoerg					addlog("[addr requested] ");
228625944Sjoerg				else
228725944Sjoerg					addlog("0x%x [not agreed] ",
228825944Sjoerg					       desiredaddr);
228925944Sjoerg
229025944Sjoerg				p[2] = hisaddr >> 24;
229125944Sjoerg				p[3] = hisaddr >> 16;
229225944Sjoerg				p[4] = hisaddr >> 8;
229325944Sjoerg				p[5] = hisaddr;
229425944Sjoerg			}
229511189Sjkh			break;
229625706Sjoerg		}
229725944Sjoerg		/* Add the option to nak'ed list. */
229825944Sjoerg		bcopy (p, r, p[1]);
229925944Sjoerg		r += p[1];
230025944Sjoerg		rlen += p[1];
230125944Sjoerg	}
230225944Sjoerg
230325944Sjoerg	/*
230425944Sjoerg	 * If we are about to conf-ack the request, but haven't seen
230525944Sjoerg	 * his address so far, gonna conf-nak it instead, with the
230625944Sjoerg	 * `address' option present and our idea of his address being
230725944Sjoerg	 * filled in there, to request negotiation of both addresses.
230825944Sjoerg	 *
230925944Sjoerg	 * XXX This can result in an endless req - nak loop if peer
231025944Sjoerg	 * doesn't want to send us his address.  Q: What should we do
231125944Sjoerg	 * about it?  XXX  A: implement the max-failure counter.
231225944Sjoerg	 */
231325944Sjoerg	if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) {
231425944Sjoerg		buf[0] = IPCP_OPT_ADDRESS;
231525944Sjoerg		buf[1] = 6;
231625944Sjoerg		buf[2] = hisaddr >> 24;
231725944Sjoerg		buf[3] = hisaddr >> 16;
231825944Sjoerg		buf[4] = hisaddr >> 8;
231925944Sjoerg		buf[5] = hisaddr;
232025944Sjoerg		rlen = 6;
232125706Sjoerg		if (debug)
232225944Sjoerg			addlog("still need hisaddr ");
232325944Sjoerg	}
232425944Sjoerg
232525944Sjoerg	if (rlen) {
232625706Sjoerg		if (debug)
232725944Sjoerg			addlog(" send conf-nak\n");
232825944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf);
232925944Sjoerg	} else {
233025706Sjoerg		if (debug)
233125944Sjoerg			addlog(" send conf-ack\n");
233225944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_ACK,
233325944Sjoerg			      h->ident, origlen, h+1);
233425944Sjoerg	}
233525944Sjoerg
233625944Sjoerg	free (buf, M_TEMP);
233725944Sjoerg	return (rlen == 0);
233825944Sjoerg}
233925944Sjoerg
234025944Sjoerg/*
234125944Sjoerg * Analyze the IPCP Configure-Reject option list, and adjust our
234225944Sjoerg * negotiation.
234325944Sjoerg */
234425944Sjoergstatic void
234525944Sjoergsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
234625944Sjoerg{
234725944Sjoerg	u_char *buf, *p;
234825944Sjoerg	struct ifnet *ifp = &sp->pp_if;
234925944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
235025944Sjoerg
235125944Sjoerg	len -= 4;
235225944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
235325944Sjoerg	if (!buf)
235425944Sjoerg		return;
235525944Sjoerg
235625944Sjoerg	if (debug)
235725944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp rej opts: ",
235825944Sjoerg		    ifp->if_name, ifp->if_unit);
235925944Sjoerg
236025944Sjoerg	p = (void*) (h+1);
236125944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
236225706Sjoerg		if (debug)
236325944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
236425944Sjoerg		switch (*p) {
236525944Sjoerg		case IPCP_OPT_ADDRESS:
236625944Sjoerg			/*
236725944Sjoerg			 * Peer doesn't grok address option.  This is
236825944Sjoerg			 * bad.  XXX  Should we better give up here?
236925944Sjoerg			 */
237025944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS);
237125944Sjoerg			break;
237225944Sjoerg#ifdef notyet
237325944Sjoerg		case IPCP_OPT_COMPRESS:
237425944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS);
237525944Sjoerg			break;
237625944Sjoerg#endif
237725944Sjoerg		}
23784910Swollman	}
237925944Sjoerg	if (debug)
238025944Sjoerg		addlog("\n");
238125944Sjoerg	free (buf, M_TEMP);
238225944Sjoerg	return;
23834910Swollman}
23844910Swollman
238525944Sjoerg/*
238625944Sjoerg * Analyze the IPCP Configure-NAK option list, and adjust our
238725944Sjoerg * negotiation.
238825944Sjoerg */
238912820Sphkstatic void
239025944Sjoergsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
23914910Swollman{
239225944Sjoerg	u_char *buf, *p;
239325944Sjoerg	struct ifnet *ifp = &sp->pp_if;
239425944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
239525944Sjoerg	u_long wantaddr;
23964910Swollman
239725944Sjoerg	len -= 4;
239825944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
239925944Sjoerg	if (!buf)
240025944Sjoerg		return;
240125944Sjoerg
240225944Sjoerg	if (debug)
240325944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp nak opts: ",
240425944Sjoerg		    ifp->if_name, ifp->if_unit);
240525944Sjoerg
240625944Sjoerg	p = (void*) (h+1);
240725944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
240825944Sjoerg		if (debug)
240925944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
241025944Sjoerg		switch (*p) {
241125944Sjoerg		case IPCP_OPT_ADDRESS:
241225944Sjoerg			/*
241325944Sjoerg			 * Peer doesn't like our local IP address.  See
241425944Sjoerg			 * if we can do something for him.  We'll drop
241525944Sjoerg			 * him our address then.
241625944Sjoerg			 */
241725944Sjoerg			if (len >= 6 && p[1] == 6) {
241825944Sjoerg				wantaddr = p[2] << 24 | p[3] << 16 |
241925944Sjoerg					p[4] << 8 | p[5];
242025944Sjoerg				sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
242125944Sjoerg				if (debug)
242225944Sjoerg					addlog("[wantaddr 0x%x] ", wantaddr);
242325944Sjoerg				/*
242425944Sjoerg				 * When doing dynamic address assignment,
242525944Sjoerg				 * we accept his offer.  Otherwise, we
242625944Sjoerg				 * ignore it and thus continue to negotiate
242725944Sjoerg				 * our already existing value.
242825944Sjoerg				 */
242925944Sjoerg				if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
243025944Sjoerg					sppp_set_ip_addr(sp, wantaddr);
243125944Sjoerg					if (debug)
243225944Sjoerg						addlog("[agree] ");
243325944Sjoerg				}
243425944Sjoerg			}
243525944Sjoerg			break;
243625944Sjoerg#ifdef notyet
243725944Sjoerg		case IPCP_OPT_COMPRESS:
243825944Sjoerg			/*
243925944Sjoerg			 * Peer wants different compression parameters.
244025944Sjoerg			 */
244125944Sjoerg			break;
244225944Sjoerg#endif
244325944Sjoerg		}
244425944Sjoerg	}
244525944Sjoerg	if (debug)
244625944Sjoerg		addlog("\n");
244725944Sjoerg	free (buf, M_TEMP);
244825944Sjoerg	return;
24494910Swollman}
24504910Swollman
245112820Sphkstatic void
245225944Sjoergsppp_ipcp_tlu(struct sppp *sp)
24534910Swollman{
24544910Swollman}
24554910Swollman
245625944Sjoergstatic void
245725944Sjoergsppp_ipcp_tld(struct sppp *sp)
245825944Sjoerg{
245925944Sjoerg}
246025944Sjoerg
246125944Sjoergstatic void
246225944Sjoergsppp_ipcp_tls(struct sppp *sp)
246325944Sjoerg{
246425944Sjoerg	/* indicate to LCP that it must stay alive */
246525944Sjoerg	sp->lcp.protos |= (1 << IDX_IPCP);
246625944Sjoerg}
246725944Sjoerg
246825944Sjoergstatic void
246925944Sjoergsppp_ipcp_tlf(struct sppp *sp)
247025944Sjoerg{
247125944Sjoerg	/* we no longer need LCP */
247225944Sjoerg	sp->lcp.protos &= ~(1 << IDX_IPCP);
247325944Sjoerg	sppp_lcp_check(sp);
247425944Sjoerg}
247525944Sjoerg
247625944Sjoergstatic void
247725944Sjoergsppp_ipcp_scr(struct sppp *sp)
247825944Sjoerg{
247925944Sjoerg	char opt[6 /* compression */ + 6 /* address */];
248025944Sjoerg	u_long ouraddr;
248125944Sjoerg	int i = 0;
248225944Sjoerg
248325944Sjoerg#ifdef notyet
248425944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
248525944Sjoerg		opt[i++] = IPCP_OPT_COMPRESSION;
248625944Sjoerg		opt[i++] = 6;
248725944Sjoerg		opt[i++] = 0;	/* VJ header compression */
248825944Sjoerg		opt[i++] = 0x2d; /* VJ header compression */
248925944Sjoerg		opt[i++] = max_slot_id;
249025944Sjoerg		opt[i++] = comp_slot_id;
249125944Sjoerg	}
249225944Sjoerg#endif
249325944Sjoerg
249425944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
249525944Sjoerg		sppp_get_ip_addrs(sp, &ouraddr, 0);
249625944Sjoerg		opt[i++] = IPCP_OPT_ADDRESS;
249725944Sjoerg		opt[i++] = 6;
249825944Sjoerg		opt[i++] = ouraddr >> 24;
249925944Sjoerg		opt[i++] = ouraddr >> 16;
250025944Sjoerg		opt[i++] = ouraddr >> 8;
250125944Sjoerg		opt[i++] = ouraddr;
250225944Sjoerg	}
250325944Sjoerg
250425944Sjoerg	sp->confid[IDX_IPCP] = ++sp->pp_seq;
250525944Sjoerg	sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
250625944Sjoerg}
250725944Sjoerg
250825944Sjoerg
250925944Sjoerg/*
251025944Sjoerg * Random miscellaneous functions.
251125944Sjoerg */
251225944Sjoerg
25134910Swollman/*
251425944Sjoerg * Flush interface queue.
25154910Swollman */
251612820Sphkstatic void
251725944Sjoergsppp_qflush(struct ifqueue *ifq)
25184910Swollman{
251925944Sjoerg	struct mbuf *m, *n;
25204910Swollman
252125944Sjoerg	n = ifq->ifq_head;
252225944Sjoerg	while ((m = n)) {
252325944Sjoerg		n = m->m_act;
252425944Sjoerg		m_freem (m);
252511189Sjkh	}
252625944Sjoerg	ifq->ifq_head = 0;
252725944Sjoerg	ifq->ifq_tail = 0;
252825944Sjoerg	ifq->ifq_len = 0;
252925944Sjoerg}
253025944Sjoerg
253125944Sjoerg/*
253225944Sjoerg * Send keepalive packets, every 10 seconds.
253325944Sjoerg */
253425944Sjoergstatic void
253525944Sjoergsppp_keepalive(void *dummy)
253625944Sjoerg{
253725944Sjoerg	struct sppp *sp;
253825944Sjoerg	int s;
253925944Sjoerg
254025944Sjoerg	s = splimp();
254125944Sjoerg	for (sp=spppq; sp; sp=sp->pp_next) {
254225944Sjoerg		struct ifnet *ifp = &sp->pp_if;
254325944Sjoerg
254425944Sjoerg		/* Keepalive mode disabled or channel down? */
254525944Sjoerg		if (! (sp->pp_flags & PP_KEEPALIVE) ||
254625944Sjoerg		    ! (ifp->if_flags & IFF_RUNNING))
254725944Sjoerg			continue;
254825944Sjoerg
254925944Sjoerg		/* No keepalive in PPP mode if LCP not opened yet. */
255025944Sjoerg		if (! (sp->pp_flags & PP_CISCO) &&
255125944Sjoerg		    sp->pp_phase < PHASE_AUTHENTICATE)
255225944Sjoerg			continue;
255325944Sjoerg
255425944Sjoerg		if (sp->pp_alivecnt == MAXALIVECNT) {
255525944Sjoerg			/* No keepalive packets got.  Stop the interface. */
255625944Sjoerg			printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
255725944Sjoerg			if_down (ifp);
255826018Sjoerg			sppp_qflush (&sp->pp_cpq);
255925944Sjoerg			if (! (sp->pp_flags & PP_CISCO)) {
256025944Sjoerg				/* XXX */
256125944Sjoerg				/* Shut down the PPP link. */
256225944Sjoerg				lcp.Down(sp);
256325944Sjoerg				/* Initiate negotiation. XXX */
256425944Sjoerg				lcp.Up(sp);
256525944Sjoerg			}
25664910Swollman		}
256725944Sjoerg		if (sp->pp_alivecnt <= MAXALIVECNT)
256825944Sjoerg			++sp->pp_alivecnt;
256925944Sjoerg		if (sp->pp_flags & PP_CISCO)
257025944Sjoerg			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
257125944Sjoerg				sp->pp_rseq);
257225944Sjoerg		else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
257325944Sjoerg			long nmagic = htonl (sp->lcp.magic);
257425944Sjoerg			sp->lcp.echoid = ++sp->pp_seq;
257525944Sjoerg			sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
257625944Sjoerg				sp->lcp.echoid, 4, &nmagic);
257725944Sjoerg		}
25784910Swollman	}
257925944Sjoerg	splx(s);
258025944Sjoerg	timeout(sppp_keepalive, 0, hz * 10);
25814910Swollman}
25824910Swollman
258325944Sjoerg/*
258425944Sjoerg * Get both IP addresses.
258525944Sjoerg */
258625944Sjoergstatic void
258725944Sjoergsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst)
258825944Sjoerg{
258925944Sjoerg	struct ifnet *ifp = &sp->pp_if;
259025944Sjoerg	struct ifaddr *ifa;
259125944Sjoerg	struct sockaddr_in *si;
259225944Sjoerg	u_long ssrc, ddst;
259325944Sjoerg
259425944Sjoerg	ssrc = ddst = 0L;
259525944Sjoerg	/*
259625944Sjoerg	 * Pick the first AF_INET address from the list,
259725944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
259825944Sjoerg	 */
259925944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
260025944Sjoerg	     ifa;
260125944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
260225944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
260325944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
260425944Sjoerg			if (si)
260525944Sjoerg				break;
260625944Sjoerg		}
260725944Sjoerg	if (ifa) {
260825944Sjoerg		if (si && si->sin_addr.s_addr)
260925944Sjoerg			ssrc = si->sin_addr.s_addr;
261025944Sjoerg
261125944Sjoerg		si = (struct sockaddr_in *)ifa->ifa_dstaddr;
261225944Sjoerg		if (si && si->sin_addr.s_addr)
261325944Sjoerg			ddst = si->sin_addr.s_addr;
261425944Sjoerg	}
261525944Sjoerg
261625944Sjoerg	if (dst) *dst = ntohl(ddst);
261725944Sjoerg	if (src) *src = ntohl(ssrc);
261825944Sjoerg}
261925944Sjoerg
262025944Sjoerg/*
262125944Sjoerg * Set my IP address.  Must be called at splimp.
262225944Sjoerg */
262325944Sjoergstatic void
262425944Sjoergsppp_set_ip_addr(struct sppp *sp, u_long src)
262525944Sjoerg{
262625944Sjoerg	struct ifnet *ifp = &sp->pp_if;
262725944Sjoerg	struct ifaddr *ifa;
262825944Sjoerg	struct sockaddr_in *si;
262925944Sjoerg	u_long ssrc, ddst;
263025944Sjoerg
263125944Sjoerg	/*
263225944Sjoerg	 * Pick the first AF_INET address from the list,
263325944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
263425944Sjoerg	 */
263525944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
263625944Sjoerg	     ifa;
263725944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
263825944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
263925944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
264025944Sjoerg			if (si)
264125944Sjoerg				break;
264225944Sjoerg		}
264325944Sjoerg	if (ifa && si)
264425944Sjoerg		si->sin_addr.s_addr = htonl(src);
264525944Sjoerg}
264625944Sjoerg
264725706Sjoergstatic const char *
264825944Sjoergsppp_cp_type_name(u_char type)
26494910Swollman{
265025706Sjoerg	static char buf [12];
26514910Swollman	switch (type) {
265225944Sjoerg	case CONF_REQ:   return ("conf-req");
265325944Sjoerg	case CONF_ACK:   return ("conf-ack");
265425944Sjoerg	case CONF_NAK:   return ("conf-nak");
265525944Sjoerg	case CONF_REJ:   return ("conf-rej");
265625944Sjoerg	case TERM_REQ:   return ("term-req");
265725944Sjoerg	case TERM_ACK:   return ("term-ack");
265825944Sjoerg	case CODE_REJ:   return ("code-rej");
265925944Sjoerg	case PROTO_REJ:  return ("proto-rej");
266025944Sjoerg	case ECHO_REQ:   return ("echo-req");
266125944Sjoerg	case ECHO_REPLY: return ("echo-reply");
266225944Sjoerg	case DISC_REQ:   return ("discard-req");
26634910Swollman	}
266425706Sjoerg	sprintf (buf, "0x%x", type);
26654910Swollman	return (buf);
26664910Swollman}
26674910Swollman
266825706Sjoergstatic const char *
266925944Sjoergsppp_lcp_opt_name(u_char opt)
26704910Swollman{
267125706Sjoerg	static char buf [12];
267225944Sjoerg	switch (opt) {
267325944Sjoerg	case LCP_OPT_MRU:		return ("mru");
267425944Sjoerg	case LCP_OPT_ASYNC_MAP:		return ("async-map");
267525944Sjoerg	case LCP_OPT_AUTH_PROTO:	return ("auth-proto");
267625944Sjoerg	case LCP_OPT_QUAL_PROTO:	return ("qual-proto");
267725944Sjoerg	case LCP_OPT_MAGIC:		return ("magic");
267825944Sjoerg	case LCP_OPT_PROTO_COMP:	return ("proto-comp");
267925944Sjoerg	case LCP_OPT_ADDR_COMP:		return ("addr-comp");
26804910Swollman	}
268125944Sjoerg	sprintf (buf, "0x%x", opt);
26824910Swollman	return (buf);
26834910Swollman}
26844910Swollman
268525944Sjoergstatic const char *
268625944Sjoergsppp_ipcp_opt_name(u_char opt)
268725944Sjoerg{
268825944Sjoerg	static char buf [12];
268925944Sjoerg	switch (opt) {
269025944Sjoerg	case IPCP_OPT_ADDRESSES:	return ("addresses");
269125944Sjoerg	case IPCP_OPT_COMPRESSION:	return ("compression");
269225944Sjoerg	case IPCP_OPT_ADDRESS:		return ("address");
269325944Sjoerg	}
269425944Sjoerg	sprintf (buf, "0x%x", opt);
269525944Sjoerg	return (buf);
269625944Sjoerg}
269725944Sjoerg
269825944Sjoergstatic const char *
269925944Sjoergsppp_state_name(int state)
270025944Sjoerg{
270125944Sjoerg	switch (state) {
270225944Sjoerg	case STATE_INITIAL:	return "initial";
270325944Sjoerg	case STATE_STARTING:	return "starting";
270425944Sjoerg	case STATE_CLOSED:	return "closed";
270525944Sjoerg	case STATE_STOPPED:	return "stopped";
270625944Sjoerg	case STATE_CLOSING:	return "closing";
270725944Sjoerg	case STATE_STOPPING:	return "stopping";
270825944Sjoerg	case STATE_REQ_SENT:	return "req-sent";
270925944Sjoerg	case STATE_ACK_RCVD:	return "ack-rcvd";
271025944Sjoerg	case STATE_ACK_SENT:	return "ack-sent";
271125944Sjoerg	case STATE_OPENED:	return "opened";
271225944Sjoerg	}
271325944Sjoerg	return "illegal";
271425944Sjoerg}
271525944Sjoerg
271625944Sjoergstatic const char *
271725944Sjoergsppp_phase_name(enum ppp_phase phase)
271825944Sjoerg{
271925944Sjoerg	switch (phase) {
272025944Sjoerg	case PHASE_DEAD:	return "dead";
272125944Sjoerg	case PHASE_ESTABLISH:	return "establish";
272225944Sjoerg	case PHASE_TERMINATE:	return "terminate";
272325944Sjoerg	case PHASE_AUTHENTICATE: return "authenticate";
272425944Sjoerg	case PHASE_NETWORK:	return "network";
272525944Sjoerg	}
272625944Sjoerg	return "illegal";
272725944Sjoerg}
272825944Sjoerg
272925944Sjoergstatic const char *
273025944Sjoergsppp_proto_name(u_short proto)
273125944Sjoerg{
273225944Sjoerg	static char buf[12];
273325944Sjoerg	switch (proto) {
273425944Sjoerg	case PPP_LCP:	return "lcp";
273525944Sjoerg	case PPP_IPCP:	return "ipcp";
273625944Sjoerg	}
273725944Sjoerg	sprintf(buf, "0x%x", (unsigned)proto);
273825944Sjoerg	return buf;
273925944Sjoerg}
274025944Sjoerg
274112820Sphkstatic void
274225706Sjoergsppp_print_bytes(u_char *p, u_short len)
27434910Swollman{
274425706Sjoerg	addlog(" %x", *p++);
27454910Swollman	while (--len > 0)
274625706Sjoerg		addlog("-%x", *p++);
27474910Swollman}
274825944Sjoerg
274925944Sjoerg/*
275025944Sjoerg * This file is large.  Tell emacs to highlight it nevertheless.
275125944Sjoerg *
275225944Sjoerg * Local Variables:
275325944Sjoerg * hilit-auto-highlight-maxout: 100000
275425944Sjoerg * End:
275525944Sjoerg */
2756