if_spppsubr.c revision 33181
14910Swollman/*
24910Swollman * Synchronous PPP/Cisco link level subroutines.
34910Swollman * Keepalive protocol implemented in both Cisco and PPP modes.
44910Swollman *
530300Sjoerg * Copyright (C) 1994-1996 Cronyx Engineering 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 *
1830300Sjoerg * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997
1916288Sgpalmer *
2033181Seivind * $Id: if_spppsubr.c,v 1.31 1998/01/08 23:41:31 eivind Exp $
214910Swollman */
224910Swollman
2332350Seivind#include "opt_inet.h"
2431742Seivind#include "opt_ipx.h"
2531742Seivind
264910Swollman#include <sys/param.h>
274952Sbde#include <sys/systm.h>
284952Sbde#include <sys/kernel.h>
2924204Sbde#include <sys/sockio.h>
304910Swollman#include <sys/socket.h>
3125706Sjoerg#include <sys/syslog.h>
3229024Sbde#include <sys/malloc.h>
334910Swollman#include <sys/mbuf.h>
3430300Sjoerg#include <sys/md5.h>
354910Swollman
364910Swollman#include <net/if.h>
374910Swollman#include <net/netisr.h>
384910Swollman#include <net/if_types.h>
394910Swollman
4030300Sjoerg#include <machine/stdarg.h>
4130300Sjoerg
424910Swollman#ifdef INET
434910Swollman#include <netinet/in.h>
444910Swollman#include <netinet/in_systm.h>
454910Swollman#include <netinet/in_var.h>
464910Swollman#include <netinet/ip.h>
474910Swollman#include <netinet/tcp.h>
484910Swollman#include <netinet/if_ether.h>
4932350Seivind#else
5032350Seivind#error Huh? sppp without INET?
514910Swollman#endif
524910Swollman
5311819Sjulian#ifdef IPX
5411819Sjulian#include <netipx/ipx.h>
5511819Sjulian#include <netipx/ipx_if.h>
5611819Sjulian#endif
5711819Sjulian
584910Swollman#ifdef NS
594910Swollman#include <netns/ns.h>
604910Swollman#include <netns/ns_if.h>
614910Swollman#endif
624910Swollman
634910Swollman#ifdef ISO
644910Swollman#include <netiso/argo_debug.h>
654910Swollman#include <netiso/iso.h>
664910Swollman#include <netiso/iso_var.h>
674910Swollman#include <netiso/iso_snpac.h>
684910Swollman#endif
694910Swollman
704910Swollman#include <net/if_sppp.h>
714910Swollman
724910Swollman#define MAXALIVECNT     3               /* max. alive packets */
734910Swollman
7425944Sjoerg/*
7525944Sjoerg * Interface flags that can be set in an ifconfig command.
7625944Sjoerg *
7725955Sjoerg * Setting link0 will make the link passive, i.e. it will be marked
7825944Sjoerg * as being administrative openable, but won't be opened to begin
7925944Sjoerg * with.  Incoming calls will be answered, or subsequent calls with
8025944Sjoerg * -link1 will cause the administrative open of the LCP layer.
8125955Sjoerg *
8225955Sjoerg * Setting link1 will cause the link to auto-dial only as packets
8325955Sjoerg * arrive to be sent.
8430300Sjoerg *
8530300Sjoerg * Setting IFF_DEBUG will syslog the option negotiation and state
8630300Sjoerg * transitions at level kern.debug.  Note: all logs consistently look
8730300Sjoerg * like
8830300Sjoerg *
8930300Sjoerg *   <if-name><unit>: <proto-name> <additional info...>
9030300Sjoerg *
9130300Sjoerg * with <if-name><unit> being something like "bppp0", and <proto-name>
9230300Sjoerg * being one of "lcp", "ipcp", "cisco", "chap", "pap", etc.
9325944Sjoerg */
9425944Sjoerg
9525955Sjoerg#define IFF_PASSIVE	IFF_LINK0	/* wait passively for connection */
9625955Sjoerg#define IFF_AUTO	IFF_LINK1	/* auto-dial on output */
9725944Sjoerg
9830300Sjoerg#define PPP_ALLSTATIONS 0xff		/* All-Stations broadcast address */
9930300Sjoerg#define PPP_UI		0x03		/* Unnumbered Information */
10030300Sjoerg#define PPP_IP		0x0021		/* Internet Protocol */
10130300Sjoerg#define PPP_ISO		0x0023		/* ISO OSI Protocol */
10230300Sjoerg#define PPP_XNS		0x0025		/* Xerox NS Protocol */
10330300Sjoerg#define PPP_IPX		0x002b		/* Novell IPX Protocol */
10430300Sjoerg#define PPP_LCP		0xc021		/* Link Control Protocol */
10530300Sjoerg#define PPP_PAP		0xc023		/* Password Authentication Protocol */
10630300Sjoerg#define PPP_CHAP	0xc223		/* Challenge-Handshake Auth Protocol */
10730300Sjoerg#define PPP_IPCP	0x8021		/* Internet Protocol Control Protocol */
1084910Swollman
10925944Sjoerg#define CONF_REQ	1		/* PPP configure request */
11025944Sjoerg#define CONF_ACK	2		/* PPP configure acknowledge */
11125944Sjoerg#define CONF_NAK	3		/* PPP configure negative ack */
11225944Sjoerg#define CONF_REJ	4		/* PPP configure reject */
11325944Sjoerg#define TERM_REQ	5		/* PPP terminate request */
11425944Sjoerg#define TERM_ACK	6		/* PPP terminate acknowledge */
11525944Sjoerg#define CODE_REJ	7		/* PPP code reject */
11625944Sjoerg#define PROTO_REJ	8		/* PPP protocol reject */
11725944Sjoerg#define ECHO_REQ	9		/* PPP echo request */
11825944Sjoerg#define ECHO_REPLY	10		/* PPP echo reply */
11925944Sjoerg#define DISC_REQ	11		/* PPP discard request */
1204910Swollman
12130300Sjoerg#define LCP_OPT_MRU		1	/* maximum receive unit */
12230300Sjoerg#define LCP_OPT_ASYNC_MAP	2	/* async control character map */
12330300Sjoerg#define LCP_OPT_AUTH_PROTO	3	/* authentication protocol */
12430300Sjoerg#define LCP_OPT_QUAL_PROTO	4	/* quality protocol */
12530300Sjoerg#define LCP_OPT_MAGIC		5	/* magic number */
12630300Sjoerg#define LCP_OPT_RESERVED	6	/* reserved */
12730300Sjoerg#define LCP_OPT_PROTO_COMP	7	/* protocol field compression */
12830300Sjoerg#define LCP_OPT_ADDR_COMP	8	/* address/control field compression */
1294910Swollman
13025944Sjoerg#define IPCP_OPT_ADDRESSES	1	/* both IP addresses; deprecated */
13125944Sjoerg#define IPCP_OPT_COMPRESSION	2	/* IP compression protocol (VJ) */
13225944Sjoerg#define IPCP_OPT_ADDRESS	3	/* local IP address */
1334910Swollman
13430300Sjoerg#define PAP_REQ			1	/* PAP name/password request */
13530300Sjoerg#define PAP_ACK			2	/* PAP acknowledge */
13630300Sjoerg#define PAP_NAK			3	/* PAP fail */
1374910Swollman
13830300Sjoerg#define CHAP_CHALLENGE		1	/* CHAP challenge request */
13930300Sjoerg#define CHAP_RESPONSE		2	/* CHAP challenge response */
14030300Sjoerg#define CHAP_SUCCESS		3	/* CHAP response ok */
14130300Sjoerg#define CHAP_FAILURE		4	/* CHAP response failed */
14230300Sjoerg
14330300Sjoerg#define CHAP_MD5		5	/* hash algorithm - MD5 */
14430300Sjoerg
14530300Sjoerg#define CISCO_MULTICAST		0x8f	/* Cisco multicast address */
14630300Sjoerg#define CISCO_UNICAST		0x0f	/* Cisco unicast address */
14730300Sjoerg#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
14830300Sjoerg#define CISCO_ADDR_REQ		0	/* Cisco address request */
14930300Sjoerg#define CISCO_ADDR_REPLY	1	/* Cisco address reply */
15030300Sjoerg#define CISCO_KEEPALIVE_REQ	2	/* Cisco keepalive request */
15130300Sjoerg
15225944Sjoerg/* states are named and numbered according to RFC 1661 */
15325944Sjoerg#define STATE_INITIAL	0
15425944Sjoerg#define STATE_STARTING	1
15525944Sjoerg#define STATE_CLOSED	2
15625944Sjoerg#define STATE_STOPPED	3
15725944Sjoerg#define STATE_CLOSING	4
15825944Sjoerg#define STATE_STOPPING	5
15925944Sjoerg#define STATE_REQ_SENT	6
16025944Sjoerg#define STATE_ACK_RCVD	7
16125944Sjoerg#define STATE_ACK_SENT	8
16225944Sjoerg#define STATE_OPENED	9
16325944Sjoerg
1644910Swollmanstruct ppp_header {
16511189Sjkh	u_char address;
16611189Sjkh	u_char control;
16711189Sjkh	u_short protocol;
1684910Swollman};
1694910Swollman#define PPP_HEADER_LEN          sizeof (struct ppp_header)
1704910Swollman
1714910Swollmanstruct lcp_header {
17211189Sjkh	u_char type;
17311189Sjkh	u_char ident;
17411189Sjkh	u_short len;
1754910Swollman};
1764910Swollman#define LCP_HEADER_LEN          sizeof (struct lcp_header)
1774910Swollman
1784910Swollmanstruct cisco_packet {
17911189Sjkh	u_long type;
18011189Sjkh	u_long par1;
18111189Sjkh	u_long par2;
18211189Sjkh	u_short rel;
18311189Sjkh	u_short time0;
18411189Sjkh	u_short time1;
1854910Swollman};
1864910Swollman#define CISCO_PACKET_LEN 18
1874910Swollman
18825944Sjoerg/*
18925944Sjoerg * We follow the spelling and capitalization of RFC 1661 here, to make
19025944Sjoerg * it easier comparing with the standard.  Please refer to this RFC in
19125944Sjoerg * case you can't make sense out of these abbreviation; it will also
19225944Sjoerg * explain the semantics related to the various events and actions.
19325944Sjoerg */
19425944Sjoergstruct cp {
19525944Sjoerg	u_short	proto;		/* PPP control protocol number */
19625944Sjoerg	u_char protoidx;	/* index into state table in struct sppp */
19725944Sjoerg	u_char flags;
19825944Sjoerg#define CP_LCP		0x01	/* this is the LCP */
19925944Sjoerg#define CP_AUTH		0x02	/* this is an authentication protocol */
20025944Sjoerg#define CP_NCP		0x04	/* this is a NCP */
20125944Sjoerg#define CP_QUAL		0x08	/* this is a quality reporting protocol */
20225944Sjoerg	const char *name;	/* name of this control protocol */
20325944Sjoerg	/* event handlers */
20425944Sjoerg	void	(*Up)(struct sppp *sp);
20525944Sjoerg	void	(*Down)(struct sppp *sp);
20625944Sjoerg	void	(*Open)(struct sppp *sp);
20725944Sjoerg	void	(*Close)(struct sppp *sp);
20825944Sjoerg	void	(*TO)(void *sp);
20925944Sjoerg	int	(*RCR)(struct sppp *sp, struct lcp_header *h, int len);
21025944Sjoerg	void	(*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len);
21125944Sjoerg	void	(*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len);
21225944Sjoerg	/* actions */
21325944Sjoerg	void	(*tlu)(struct sppp *sp);
21425944Sjoerg	void	(*tld)(struct sppp *sp);
21525944Sjoerg	void	(*tls)(struct sppp *sp);
21625944Sjoerg	void	(*tlf)(struct sppp *sp);
21725944Sjoerg	void	(*scr)(struct sppp *sp);
21825944Sjoerg};
21925944Sjoerg
22012820Sphkstatic struct sppp *spppq;
22130300Sjoergstatic struct callout_handle keepalive_ch;
2224910Swollman
2234910Swollman/*
2244910Swollman * The following disgusting hack gets around the problem that IP TOS
2254910Swollman * can't be set yet.  We want to put "interactive" traffic on a high
2264910Swollman * priority queue.  To decide if traffic is interactive, we check that
2274910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
22830300Sjoerg *
22930300Sjoerg * XXX is this really still necessary?  - joerg -
2304910Swollman */
23111189Sjkhstatic u_short interactive_ports[8] = {
2324910Swollman	0,	513,	0,	0,
2334910Swollman	0,	21,	0,	23,
2344910Swollman};
2354910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
2364910Swollman
23725944Sjoerg/* almost every function needs these */
23825944Sjoerg#define STDDCL							\
23925944Sjoerg	struct ifnet *ifp = &sp->pp_if;				\
24025944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG
24111189Sjkh
24230300Sjoergstatic int sppp_output(struct ifnet *ifp, struct mbuf *m,
24325944Sjoerg		       struct sockaddr *dst, struct rtentry *rt);
2444910Swollman
24525944Sjoergstatic void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2);
24625944Sjoergstatic void sppp_cisco_input(struct sppp *sp, struct mbuf *m);
24725944Sjoerg
24825944Sjoergstatic void sppp_cp_input(const struct cp *cp, struct sppp *sp,
24925944Sjoerg			  struct mbuf *m);
25025944Sjoergstatic void sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
25125944Sjoerg			 u_char ident, u_short len, void *data);
25225944Sjoergstatic void sppp_cp_timeout(void *arg);
25325944Sjoergstatic void sppp_cp_change_state(const struct cp *cp, struct sppp *sp,
25425944Sjoerg				 int newstate);
25530300Sjoergstatic void sppp_auth_send(const struct cp *cp,
25630300Sjoerg			   struct sppp *sp, u_char type, u_char id,
25730300Sjoerg			   ...);
25825944Sjoerg
25925944Sjoergstatic void sppp_up_event(const struct cp *cp, struct sppp *sp);
26025944Sjoergstatic void sppp_down_event(const struct cp *cp, struct sppp *sp);
26125944Sjoergstatic void sppp_open_event(const struct cp *cp, struct sppp *sp);
26225944Sjoergstatic void sppp_close_event(const struct cp *cp, struct sppp *sp);
26325944Sjoergstatic void sppp_to_event(const struct cp *cp, struct sppp *sp);
26425944Sjoerg
26530300Sjoergstatic void sppp_null(struct sppp *sp);
26630300Sjoerg
26725944Sjoergstatic void sppp_lcp_init(struct sppp *sp);
26825944Sjoergstatic void sppp_lcp_up(struct sppp *sp);
26925944Sjoergstatic void sppp_lcp_down(struct sppp *sp);
27025944Sjoergstatic void sppp_lcp_open(struct sppp *sp);
27125944Sjoergstatic void sppp_lcp_close(struct sppp *sp);
27225944Sjoergstatic void sppp_lcp_TO(void *sp);
27325944Sjoergstatic int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
27425944Sjoergstatic void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
27525944Sjoergstatic void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
27625944Sjoergstatic void sppp_lcp_tlu(struct sppp *sp);
27725944Sjoergstatic void sppp_lcp_tld(struct sppp *sp);
27825944Sjoergstatic void sppp_lcp_tls(struct sppp *sp);
27925944Sjoergstatic void sppp_lcp_tlf(struct sppp *sp);
28025944Sjoergstatic void sppp_lcp_scr(struct sppp *sp);
28130300Sjoergstatic void sppp_lcp_check_and_close(struct sppp *sp);
28230300Sjoergstatic int sppp_ncp_check(struct sppp *sp);
28325944Sjoerg
28425944Sjoergstatic void sppp_ipcp_init(struct sppp *sp);
28525944Sjoergstatic void sppp_ipcp_up(struct sppp *sp);
28625944Sjoergstatic void sppp_ipcp_down(struct sppp *sp);
28725944Sjoergstatic void sppp_ipcp_open(struct sppp *sp);
28825944Sjoergstatic void sppp_ipcp_close(struct sppp *sp);
28925944Sjoergstatic void sppp_ipcp_TO(void *sp);
29025944Sjoergstatic int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
29125944Sjoergstatic void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
29225944Sjoergstatic void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
29325944Sjoergstatic void sppp_ipcp_tlu(struct sppp *sp);
29425944Sjoergstatic void sppp_ipcp_tld(struct sppp *sp);
29525944Sjoergstatic void sppp_ipcp_tls(struct sppp *sp);
29625944Sjoergstatic void sppp_ipcp_tlf(struct sppp *sp);
29725944Sjoergstatic void sppp_ipcp_scr(struct sppp *sp);
29825944Sjoerg
29930300Sjoergstatic void sppp_pap_input(struct sppp *sp, struct mbuf *m);
30030300Sjoergstatic void sppp_pap_init(struct sppp *sp);
30130300Sjoergstatic void sppp_pap_open(struct sppp *sp);
30230300Sjoergstatic void sppp_pap_close(struct sppp *sp);
30330300Sjoergstatic void sppp_pap_TO(void *sp);
30430300Sjoergstatic void sppp_pap_my_TO(void *sp);
30530300Sjoergstatic void sppp_pap_tlu(struct sppp *sp);
30630300Sjoergstatic void sppp_pap_tld(struct sppp *sp);
30730300Sjoergstatic void sppp_pap_scr(struct sppp *sp);
30830300Sjoerg
30930300Sjoergstatic void sppp_chap_input(struct sppp *sp, struct mbuf *m);
31030300Sjoergstatic void sppp_chap_init(struct sppp *sp);
31130300Sjoergstatic void sppp_chap_open(struct sppp *sp);
31230300Sjoergstatic void sppp_chap_close(struct sppp *sp);
31330300Sjoergstatic void sppp_chap_TO(void *sp);
31430300Sjoergstatic void sppp_chap_tlu(struct sppp *sp);
31530300Sjoergstatic void sppp_chap_tld(struct sppp *sp);
31630300Sjoergstatic void sppp_chap_scr(struct sppp *sp);
31730300Sjoerg
31830300Sjoergstatic const char *sppp_auth_type_name(u_short proto, u_char type);
31925944Sjoergstatic const char *sppp_cp_type_name(u_char type);
32030300Sjoergstatic const char *sppp_dotted_quad(u_long addr);
32130300Sjoergstatic const char *sppp_ipcp_opt_name(u_char opt);
32225944Sjoergstatic const char *sppp_lcp_opt_name(u_char opt);
32325944Sjoergstatic const char *sppp_phase_name(enum ppp_phase phase);
32425944Sjoergstatic const char *sppp_proto_name(u_short proto);
32530300Sjoergstatic const char *sppp_state_name(int state);
32630300Sjoergstatic int sppp_params(struct sppp *sp, int cmd, void *data);
32730300Sjoergstatic int sppp_strnlen(u_char *p, int max);
32830300Sjoergstatic void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst,
32930300Sjoerg			      u_long *srcmask);
33025944Sjoergstatic void sppp_keepalive(void *dummy);
33130300Sjoergstatic void sppp_phase_network(struct sppp *sp);
33230300Sjoergstatic void sppp_print_bytes(const u_char *p, u_short len);
33330300Sjoergstatic void sppp_print_string(const char *p, u_short len);
33425944Sjoergstatic void sppp_qflush(struct ifqueue *ifq);
33525944Sjoergstatic void sppp_set_ip_addr(struct sppp *sp, u_long src);
33625944Sjoerg
33725944Sjoerg/* our control protocol descriptors */
33833181Seivindstatic const struct cp lcp = {
33925944Sjoerg	PPP_LCP, IDX_LCP, CP_LCP, "lcp",
34025944Sjoerg	sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close,
34125944Sjoerg	sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak,
34225944Sjoerg	sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf,
34325944Sjoerg	sppp_lcp_scr
34425944Sjoerg};
34525944Sjoerg
34633181Seivindstatic const struct cp ipcp = {
34725944Sjoerg	PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp",
34825944Sjoerg	sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close,
34925944Sjoerg	sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak,
35025944Sjoerg	sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf,
35125944Sjoerg	sppp_ipcp_scr
35225944Sjoerg};
35325944Sjoerg
35433181Seivindstatic const struct cp pap = {
35530300Sjoerg	PPP_PAP, IDX_PAP, CP_AUTH, "pap",
35630300Sjoerg	sppp_null, sppp_null, sppp_pap_open, sppp_pap_close,
35730300Sjoerg	sppp_pap_TO, 0, 0, 0,
35830300Sjoerg	sppp_pap_tlu, sppp_pap_tld, sppp_null, sppp_null,
35930300Sjoerg	sppp_pap_scr
36030300Sjoerg};
36130300Sjoerg
36233181Seivindstatic const struct cp chap = {
36330300Sjoerg	PPP_CHAP, IDX_CHAP, CP_AUTH, "chap",
36430300Sjoerg	sppp_null, sppp_null, sppp_chap_open, sppp_chap_close,
36530300Sjoerg	sppp_chap_TO, 0, 0, 0,
36630300Sjoerg	sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null,
36730300Sjoerg	sppp_chap_scr
36830300Sjoerg};
36930300Sjoerg
37033181Seivindstatic const struct cp *cps[IDX_COUNT] = {
37125944Sjoerg	&lcp,			/* IDX_LCP */
37225944Sjoerg	&ipcp,			/* IDX_IPCP */
37330300Sjoerg	&pap,			/* IDX_PAP */
37430300Sjoerg	&chap,			/* IDX_CHAP */
37525944Sjoerg};
37625944Sjoerg
37725944Sjoerg
37825944Sjoerg/*
37925944Sjoerg * Exported functions, comprising our interface to the lower layer.
3804910Swollman */
3814910Swollman
3824910Swollman/*
3834910Swollman * Process the received packet.
3844910Swollman */
38525706Sjoergvoid
38625706Sjoergsppp_input(struct ifnet *ifp, struct mbuf *m)
3874910Swollman{
3884910Swollman	struct ppp_header *h;
3894910Swollman	struct ifqueue *inq = 0;
39011189Sjkh	int s;
39125944Sjoerg	struct sppp *sp = (struct sppp *)ifp;
39225944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
3934910Swollman
3944910Swollman	if (ifp->if_flags & IFF_UP)
3954910Swollman		/* Count received bytes, add FCS and one flag */
3964910Swollman		ifp->if_ibytes += m->m_pkthdr.len + 3;
3974910Swollman
3984910Swollman	if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
3994910Swollman		/* Too small packet, drop it. */
40025944Sjoerg		if (debug)
40125706Sjoerg			log(LOG_DEBUG,
40225706Sjoerg			    "%s%d: input packet is too small, %d bytes\n",
40325706Sjoerg			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
40425944Sjoerg	  drop:
40525944Sjoerg		++ifp->if_ierrors;
40625944Sjoerg		++ifp->if_iqdrops;
4074910Swollman		m_freem (m);
4084910Swollman		return;
4094910Swollman	}
4104910Swollman
4114910Swollman	/* Get PPP header. */
4124910Swollman	h = mtod (m, struct ppp_header*);
4134910Swollman	m_adj (m, PPP_HEADER_LEN);
4144910Swollman
4154910Swollman	switch (h->address) {
4164910Swollman	case PPP_ALLSTATIONS:
4174910Swollman		if (h->control != PPP_UI)
4184910Swollman			goto invalid;
41911189Sjkh		if (sp->pp_flags & PP_CISCO) {
42025944Sjoerg			if (debug)
42125706Sjoerg				log(LOG_DEBUG,
42225706Sjoerg				    "%s%d: PPP packet in Cisco mode "
42325706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
42425706Sjoerg				    ifp->if_name, ifp->if_unit,
42525706Sjoerg				    h->address, h->control, ntohs(h->protocol));
42611189Sjkh			goto drop;
42711189Sjkh		}
4284910Swollman		switch (ntohs (h->protocol)) {
4294910Swollman		default:
43025944Sjoerg			if (sp->state[IDX_LCP] == STATE_OPENED)
43125944Sjoerg				sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
43211189Sjkh					++sp->pp_seq, m->m_pkthdr.len + 2,
4334910Swollman					&h->protocol);
43425944Sjoerg			if (debug)
43525706Sjoerg				log(LOG_DEBUG,
43625706Sjoerg				    "%s%d: invalid input protocol "
43725706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
43825706Sjoerg				    ifp->if_name, ifp->if_unit,
43925706Sjoerg				    h->address, h->control, ntohs(h->protocol));
4404910Swollman			++ifp->if_noproto;
4414910Swollman			goto drop;
4424910Swollman		case PPP_LCP:
44330300Sjoerg			sppp_cp_input(&lcp, sp, m);
4444910Swollman			m_freem (m);
4454910Swollman			return;
44630300Sjoerg		case PPP_PAP:
44730300Sjoerg			if (sp->pp_phase >= PHASE_AUTHENTICATE)
44830300Sjoerg				sppp_pap_input(sp, m);
44930300Sjoerg			m_freem (m);
45030300Sjoerg			return;
45130300Sjoerg		case PPP_CHAP:
45230300Sjoerg			if (sp->pp_phase >= PHASE_AUTHENTICATE)
45330300Sjoerg				sppp_chap_input(sp, m);
45430300Sjoerg			m_freem (m);
45530300Sjoerg			return;
4564910Swollman#ifdef INET
4574910Swollman		case PPP_IPCP:
45825944Sjoerg			if (sp->pp_phase == PHASE_NETWORK)
45930300Sjoerg				sppp_cp_input(&ipcp, sp, m);
4604910Swollman			m_freem (m);
4614910Swollman			return;
4624910Swollman		case PPP_IP:
46325944Sjoerg			if (sp->state[IDX_IPCP] == STATE_OPENED) {
4644910Swollman				schednetisr (NETISR_IP);
4654910Swollman				inq = &ipintrq;
4664910Swollman			}
4674910Swollman			break;
4684910Swollman#endif
46912495Speter#ifdef IPX
47012495Speter		case PPP_IPX:
47112495Speter			/* IPX IPXCP not implemented yet */
47225944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
47312495Speter				schednetisr (NETISR_IPX);
47412495Speter				inq = &ipxintrq;
47512495Speter			}
47612495Speter			break;
47712495Speter#endif
4784910Swollman#ifdef NS
4794910Swollman		case PPP_XNS:
4804910Swollman			/* XNS IDPCP not implemented yet */
48125944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
4824910Swollman				schednetisr (NETISR_NS);
4834910Swollman				inq = &nsintrq;
4844910Swollman			}
4854910Swollman			break;
4864910Swollman#endif
4874910Swollman#ifdef ISO
4884910Swollman		case PPP_ISO:
4894910Swollman			/* OSI NLCP not implemented yet */
49025944Sjoerg			if (sp->pp_phase == PHASE_NETWORK) {
4914910Swollman				schednetisr (NETISR_ISO);
4924910Swollman				inq = &clnlintrq;
4934910Swollman			}
4944910Swollman			break;
4954910Swollman#endif
4964910Swollman		}
4974910Swollman		break;
4984910Swollman	case CISCO_MULTICAST:
4994910Swollman	case CISCO_UNICAST:
5004910Swollman		/* Don't check the control field here (RFC 1547). */
50111189Sjkh		if (! (sp->pp_flags & PP_CISCO)) {
50225944Sjoerg			if (debug)
50325706Sjoerg				log(LOG_DEBUG,
50425706Sjoerg				    "%s%d: Cisco packet in PPP mode "
50525706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
50625706Sjoerg				    ifp->if_name, ifp->if_unit,
50725706Sjoerg				    h->address, h->control, ntohs(h->protocol));
50811189Sjkh			goto drop;
50911189Sjkh		}
5104910Swollman		switch (ntohs (h->protocol)) {
5114910Swollman		default:
5124910Swollman			++ifp->if_noproto;
5134910Swollman			goto invalid;
5144910Swollman		case CISCO_KEEPALIVE:
5154910Swollman			sppp_cisco_input ((struct sppp*) ifp, m);
5164910Swollman			m_freem (m);
5174910Swollman			return;
5184910Swollman#ifdef INET
5194910Swollman		case ETHERTYPE_IP:
5204910Swollman			schednetisr (NETISR_IP);
5214910Swollman			inq = &ipintrq;
5224910Swollman			break;
5234910Swollman#endif
52412495Speter#ifdef IPX
52512495Speter		case ETHERTYPE_IPX:
52612495Speter			schednetisr (NETISR_IPX);
52712495Speter			inq = &ipxintrq;
52812495Speter			break;
52912495Speter#endif
5304910Swollman#ifdef NS
5314910Swollman		case ETHERTYPE_NS:
5324910Swollman			schednetisr (NETISR_NS);
5334910Swollman			inq = &nsintrq;
5344910Swollman			break;
5354910Swollman#endif
5364910Swollman		}
5374910Swollman		break;
53825944Sjoerg	default:        /* Invalid PPP packet. */
53925944Sjoerg	  invalid:
54025944Sjoerg		if (debug)
54125944Sjoerg			log(LOG_DEBUG,
54225944Sjoerg			    "%s%d: invalid input packet "
54325944Sjoerg			    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
54425944Sjoerg			    ifp->if_name, ifp->if_unit,
54525944Sjoerg			    h->address, h->control, ntohs(h->protocol));
54625944Sjoerg		goto drop;
5474910Swollman	}
5484910Swollman
5494910Swollman	if (! (ifp->if_flags & IFF_UP) || ! inq)
5504910Swollman		goto drop;
5514910Swollman
5524910Swollman	/* Check queue. */
55325944Sjoerg	s = splimp();
5544910Swollman	if (IF_QFULL (inq)) {
5554910Swollman		/* Queue overflow. */
55625944Sjoerg		IF_DROP(inq);
55725944Sjoerg		splx(s);
55825944Sjoerg		if (debug)
55925706Sjoerg			log(LOG_DEBUG, "%s%d: protocol queue overflow\n",
5604910Swollman				ifp->if_name, ifp->if_unit);
5614910Swollman		goto drop;
5624910Swollman	}
56325944Sjoerg	IF_ENQUEUE(inq, m);
56425944Sjoerg	splx(s);
5654910Swollman}
5664910Swollman
5674910Swollman/*
5684910Swollman * Enqueue transmit packet.
5694910Swollman */
57012820Sphkstatic int
57125706Sjoergsppp_output(struct ifnet *ifp, struct mbuf *m,
57225706Sjoerg	    struct sockaddr *dst, struct rtentry *rt)
5734910Swollman{
5744910Swollman	struct sppp *sp = (struct sppp*) ifp;
5754910Swollman	struct ppp_header *h;
5764910Swollman	struct ifqueue *ifq;
57725955Sjoerg	int s, rv = 0;
5784910Swollman
57925944Sjoerg	s = splimp();
58025944Sjoerg
58125944Sjoerg	if ((ifp->if_flags & IFF_UP) == 0 ||
58225944Sjoerg	    (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) {
5834910Swollman		m_freem (m);
5844910Swollman		splx (s);
5854910Swollman		return (ENETDOWN);
5864910Swollman	}
5874910Swollman
58825944Sjoerg	if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) {
58925944Sjoerg		/*
59025944Sjoerg		 * Interface is not yet running, but auto-dial.  Need
59125944Sjoerg		 * to start LCP for it.
59225944Sjoerg		 */
59325944Sjoerg		ifp->if_flags |= IFF_RUNNING;
59425944Sjoerg		splx(s);
59525944Sjoerg		lcp.Open(sp);
59625944Sjoerg		s = splimp();
59725944Sjoerg	}
59825944Sjoerg
5994910Swollman	ifq = &ifp->if_snd;
6004910Swollman#ifdef INET
6014910Swollman	/*
6024910Swollman	 * Put low delay, telnet, rlogin and ftp control packets
6034910Swollman	 * in front of the queue.
6044910Swollman	 */
60512436Speter	if (dst->sa_family == AF_INET) {
60612436Speter		struct ip *ip = mtod (m, struct ip*);
60712436Speter		struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
6084910Swollman
60912436Speter		if (! IF_QFULL (&sp->pp_fastq) &&
61012436Speter		    ((ip->ip_tos & IPTOS_LOWDELAY) ||
61112436Speter	    	    ip->ip_p == IPPROTO_TCP &&
61212436Speter	    	    m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) &&
61312436Speter	    	    (INTERACTIVE (ntohs (tcp->th_sport)) ||
61412436Speter	    	    INTERACTIVE (ntohs (tcp->th_dport)))))
61512436Speter			ifq = &sp->pp_fastq;
6164910Swollman	}
6174910Swollman#endif
6184910Swollman
6194910Swollman	/*
6204910Swollman	 * Prepend general data packet PPP header. For now, IP only.
6214910Swollman	 */
6224910Swollman	M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT);
6234910Swollman	if (! m) {
6244910Swollman		if (ifp->if_flags & IFF_DEBUG)
62525706Sjoerg			log(LOG_DEBUG, "%s%d: no memory for transmit header\n",
6264910Swollman				ifp->if_name, ifp->if_unit);
62725944Sjoerg		++ifp->if_oerrors;
6284910Swollman		splx (s);
6294910Swollman		return (ENOBUFS);
6304910Swollman	}
6314910Swollman	h = mtod (m, struct ppp_header*);
6324910Swollman	if (sp->pp_flags & PP_CISCO) {
63328088Skjc		h->address = CISCO_UNICAST;        /* unicast address */
6344910Swollman		h->control = 0;
6354910Swollman	} else {
6364910Swollman		h->address = PPP_ALLSTATIONS;        /* broadcast address */
6374910Swollman		h->control = PPP_UI;                 /* Unnumbered Info */
6384910Swollman	}
6394910Swollman
6404910Swollman	switch (dst->sa_family) {
6414910Swollman#ifdef INET
6424910Swollman	case AF_INET:   /* Internet Protocol */
64311189Sjkh		if (sp->pp_flags & PP_CISCO)
64411189Sjkh			h->protocol = htons (ETHERTYPE_IP);
64511189Sjkh		else {
64625955Sjoerg			/*
64725955Sjoerg			 * Don't choke with an ENETDOWN early.  It's
64825955Sjoerg			 * possible that we just started dialing out,
64925955Sjoerg			 * so don't drop the packet immediately.  If
65025955Sjoerg			 * we notice that we run out of buffer space
65125955Sjoerg			 * below, we will however remember that we are
65225955Sjoerg			 * not ready to carry IP packets, and return
65325955Sjoerg			 * ENETDOWN, as opposed to ENOBUFS.
65425955Sjoerg			 */
65525955Sjoerg			h->protocol = htons(PPP_IP);
65625955Sjoerg			if (sp->state[IDX_IPCP] != STATE_OPENED)
65725955Sjoerg				rv = ENETDOWN;
65811189Sjkh		}
6594910Swollman		break;
6604910Swollman#endif
6614910Swollman#ifdef NS
6624910Swollman	case AF_NS:     /* Xerox NS Protocol */
6634910Swollman		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
6644910Swollman			ETHERTYPE_NS : PPP_XNS);
6654910Swollman		break;
6664910Swollman#endif
66711819Sjulian#ifdef IPX
66812495Speter	case AF_IPX:     /* Novell IPX Protocol */
66911819Sjulian		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
67012495Speter			ETHERTYPE_IPX : PPP_IPX);
67111819Sjulian		break;
67211819Sjulian#endif
6734910Swollman#ifdef ISO
6744910Swollman	case AF_ISO:    /* ISO OSI Protocol */
6754910Swollman		if (sp->pp_flags & PP_CISCO)
6764910Swollman			goto nosupport;
6774910Swollman		h->protocol = htons (PPP_ISO);
6784910Swollman		break;
67912820Sphknosupport:
6804910Swollman#endif
6814910Swollman	default:
6824910Swollman		m_freem (m);
68325944Sjoerg		++ifp->if_oerrors;
6844910Swollman		splx (s);
6854910Swollman		return (EAFNOSUPPORT);
6864910Swollman	}
6874910Swollman
6884910Swollman	/*
6894910Swollman	 * Queue message on interface, and start output if interface
6904910Swollman	 * not yet active.
6914910Swollman	 */
6924910Swollman	if (IF_QFULL (ifq)) {
6934910Swollman		IF_DROP (&ifp->if_snd);
6944910Swollman		m_freem (m);
69525944Sjoerg		++ifp->if_oerrors;
6964910Swollman		splx (s);
69725955Sjoerg		return (rv? rv: ENOBUFS);
6984910Swollman	}
6994910Swollman	IF_ENQUEUE (ifq, m);
7004910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
7014910Swollman		(*ifp->if_start) (ifp);
7024910Swollman
7034910Swollman	/*
7044910Swollman	 * Count output packets and bytes.
7054910Swollman	 * The packet length includes header, FCS and 1 flag,
7064910Swollman	 * according to RFC 1333.
7074910Swollman	 */
7084910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
7094910Swollman	splx (s);
7104910Swollman	return (0);
7114910Swollman}
7124910Swollman
71325706Sjoergvoid
71425706Sjoergsppp_attach(struct ifnet *ifp)
7154910Swollman{
7164910Swollman	struct sppp *sp = (struct sppp*) ifp;
7174910Swollman
7184910Swollman	/* Initialize keepalive handler. */
7194910Swollman	if (! spppq)
72030300Sjoerg		keepalive_ch = timeout(sppp_keepalive, 0, hz * 10);
7214910Swollman
7224910Swollman	/* Insert new entry into the keepalive list. */
7234910Swollman	sp->pp_next = spppq;
7244910Swollman	spppq = sp;
7254910Swollman
7264910Swollman	sp->pp_if.if_type = IFT_PPP;
7274910Swollman	sp->pp_if.if_output = sppp_output;
7284910Swollman	sp->pp_fastq.ifq_maxlen = 32;
72926018Sjoerg	sp->pp_cpq.ifq_maxlen = 20;
7304910Swollman	sp->pp_loopcnt = 0;
7314910Swollman	sp->pp_alivecnt = 0;
73211189Sjkh	sp->pp_seq = 0;
7334910Swollman	sp->pp_rseq = 0;
73425944Sjoerg	sp->pp_phase = PHASE_DEAD;
73525944Sjoerg	sp->pp_up = lcp.Up;
73625944Sjoerg	sp->pp_down = lcp.Down;
73725944Sjoerg
73825944Sjoerg	sppp_lcp_init(sp);
73925944Sjoerg	sppp_ipcp_init(sp);
74030300Sjoerg	sppp_pap_init(sp);
74130300Sjoerg	sppp_chap_init(sp);
7424910Swollman}
7434910Swollman
74430300Sjoergvoid
74525706Sjoergsppp_detach(struct ifnet *ifp)
7464910Swollman{
7474910Swollman	struct sppp **q, *p, *sp = (struct sppp*) ifp;
74825944Sjoerg	int i;
7494910Swollman
7504910Swollman	/* Remove the entry from the keepalive list. */
7514910Swollman	for (q = &spppq; (p = *q); q = &p->pp_next)
7524910Swollman		if (p == sp) {
7534910Swollman			*q = p->pp_next;
7544910Swollman			break;
7554910Swollman		}
7564910Swollman
7574910Swollman	/* Stop keepalive handler. */
7584910Swollman	if (! spppq)
75930300Sjoerg		untimeout(sppp_keepalive, 0, keepalive_ch);
76025944Sjoerg
76125944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
76229681Sgibbs		untimeout((cps[i])->TO, (void *)sp, sp->ch[i]);
76330300Sjoerg	untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch);
7644910Swollman}
7654910Swollman
7664910Swollman/*
7674910Swollman * Flush the interface output queue.
7684910Swollman */
76925706Sjoergvoid
77025706Sjoergsppp_flush(struct ifnet *ifp)
7714910Swollman{
7724910Swollman	struct sppp *sp = (struct sppp*) ifp;
7734910Swollman
77425944Sjoerg	sppp_qflush (&sp->pp_if.if_snd);
77525944Sjoerg	sppp_qflush (&sp->pp_fastq);
77626018Sjoerg	sppp_qflush (&sp->pp_cpq);
7774910Swollman}
7784910Swollman
7794910Swollman/*
78011189Sjkh * Check if the output queue is empty.
78111189Sjkh */
78212820Sphkint
78325706Sjoergsppp_isempty(struct ifnet *ifp)
78411189Sjkh{
78511189Sjkh	struct sppp *sp = (struct sppp*) ifp;
78625944Sjoerg	int empty, s;
78711189Sjkh
78825944Sjoerg	s = splimp();
78926018Sjoerg	empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head &&
79026018Sjoerg		!sp->pp_if.if_snd.ifq_head;
79125944Sjoerg	splx(s);
79211189Sjkh	return (empty);
79311189Sjkh}
79411189Sjkh
79511189Sjkh/*
7964910Swollman * Get next packet to send.
7974910Swollman */
79825706Sjoergstruct mbuf *
79925706Sjoergsppp_dequeue(struct ifnet *ifp)
8004910Swollman{
8014910Swollman	struct sppp *sp = (struct sppp*) ifp;
8024910Swollman	struct mbuf *m;
80325944Sjoerg	int s;
8044910Swollman
80525944Sjoerg	s = splimp();
80626018Sjoerg	/*
80730300Sjoerg	 * Process only the control protocol queue until we have at
80830300Sjoerg	 * least one NCP open.
80926018Sjoerg	 *
81026018Sjoerg	 * Do always serve all three queues in Cisco mode.
81126018Sjoerg	 */
81226018Sjoerg	IF_DEQUEUE(&sp->pp_cpq, m);
81326018Sjoerg	if (m == NULL &&
81430300Sjoerg	    (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) {
81526018Sjoerg		IF_DEQUEUE(&sp->pp_fastq, m);
81626018Sjoerg		if (m == NULL)
81726018Sjoerg			IF_DEQUEUE (&sp->pp_if.if_snd, m);
81826018Sjoerg	}
81926018Sjoerg	splx(s);
82026018Sjoerg	return m;
8214910Swollman}
8224910Swollman
8234910Swollman/*
82430300Sjoerg * Pick the next packet, do not remove it from the queue.
82530300Sjoerg */
82630300Sjoergstruct mbuf *
82730300Sjoergsppp_pick(struct ifnet *ifp)
82830300Sjoerg{
82930300Sjoerg	struct sppp *sp = (struct sppp*)ifp;
83030300Sjoerg	struct mbuf *m;
83130300Sjoerg	int s;
83230300Sjoerg
83330300Sjoerg	s= splimp ();
83430300Sjoerg
83530300Sjoerg	m = sp->pp_cpq.ifq_head;
83630300Sjoerg	if (m == NULL &&
83730300Sjoerg	    (sp->pp_phase == PHASE_NETWORK ||
83830300Sjoerg	     (sp->pp_flags & PP_CISCO) != 0))
83930300Sjoerg		if ((m = sp->pp_fastq.ifq_head) == NULL)
84030300Sjoerg			m = sp->pp_if.if_snd.ifq_head;
84130300Sjoerg	splx (s);
84230300Sjoerg	return (m);
84330300Sjoerg}
84430300Sjoerg
84530300Sjoerg/*
84625944Sjoerg * Process an ioctl request.  Called on low priority level.
8474910Swollman */
84825944Sjoergint
84925944Sjoergsppp_ioctl(struct ifnet *ifp, int cmd, void *data)
8504910Swollman{
85125944Sjoerg	struct ifreq *ifr = (struct ifreq*) data;
85225944Sjoerg	struct sppp *sp = (struct sppp*) ifp;
85330300Sjoerg	int s, rv, going_up, going_down, newmode;
8544910Swollman
85525944Sjoerg	s = splimp();
85630300Sjoerg	rv = 0;
85725944Sjoerg	switch (cmd) {
85825944Sjoerg	case SIOCAIFADDR:
85925944Sjoerg	case SIOCSIFDSTADDR:
86025944Sjoerg		break;
8614910Swollman
86225944Sjoerg	case SIOCSIFADDR:
86325944Sjoerg		if_up(ifp);
86425944Sjoerg		/* fall through... */
86511189Sjkh
86625944Sjoerg	case SIOCSIFFLAGS:
86725944Sjoerg		going_up = ifp->if_flags & IFF_UP &&
86825944Sjoerg			(ifp->if_flags & IFF_RUNNING) == 0;
86925944Sjoerg		going_down = (ifp->if_flags & IFF_UP) == 0 &&
87025944Sjoerg			ifp->if_flags & IFF_RUNNING;
87125944Sjoerg		newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE);
87225944Sjoerg		if (newmode == (IFF_AUTO | IFF_PASSIVE)) {
87325944Sjoerg			/* sanity */
87425944Sjoerg			newmode = IFF_PASSIVE;
87525944Sjoerg			ifp->if_flags &= ~IFF_AUTO;
8764910Swollman		}
8774910Swollman
87825944Sjoerg		if (going_up || going_down)
87925944Sjoerg			lcp.Close(sp);
88025944Sjoerg		if (going_up && newmode == 0) {
88125944Sjoerg			/* neither auto-dial nor passive */
88225944Sjoerg			ifp->if_flags |= IFF_RUNNING;
88325944Sjoerg			if (!(sp->pp_flags & PP_CISCO))
88425944Sjoerg				lcp.Open(sp);
88526018Sjoerg		} else if (going_down) {
88626018Sjoerg			sppp_flush(ifp);
88725944Sjoerg			ifp->if_flags &= ~IFF_RUNNING;
88826018Sjoerg		}
8894910Swollman
8904910Swollman		break;
89111189Sjkh
89225944Sjoerg#ifdef SIOCSIFMTU
89325944Sjoerg#ifndef ifr_mtu
89425944Sjoerg#define ifr_mtu ifr_metric
89525944Sjoerg#endif
89625944Sjoerg	case SIOCSIFMTU:
89725944Sjoerg		if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru)
89825944Sjoerg			return (EINVAL);
89925944Sjoerg		ifp->if_mtu = ifr->ifr_mtu;
9004910Swollman		break;
90125944Sjoerg#endif
90225944Sjoerg#ifdef SLIOCSETMTU
90325944Sjoerg	case SLIOCSETMTU:
90425944Sjoerg		if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru)
90525944Sjoerg			return (EINVAL);
90625944Sjoerg		ifp->if_mtu = *(short*)data;
9074910Swollman		break;
90825944Sjoerg#endif
90925944Sjoerg#ifdef SIOCGIFMTU
91025944Sjoerg	case SIOCGIFMTU:
91125944Sjoerg		ifr->ifr_mtu = ifp->if_mtu;
91211189Sjkh		break;
91325944Sjoerg#endif
91425944Sjoerg#ifdef SLIOCGETMTU
91525944Sjoerg	case SLIOCGETMTU:
91625944Sjoerg		*(short*)data = ifp->if_mtu;
9174910Swollman		break;
91825944Sjoerg#endif
91925944Sjoerg	case SIOCADDMULTI:
92025944Sjoerg	case SIOCDELMULTI:
9214910Swollman		break;
92211189Sjkh
92330300Sjoerg	case SIOCGIFGENERIC:
92430300Sjoerg	case SIOCSIFGENERIC:
92530300Sjoerg		rv = sppp_params(sp, cmd, data);
92630300Sjoerg		break;
92730300Sjoerg
92825944Sjoerg	default:
92930300Sjoerg		rv = ENOTTY;
9304910Swollman	}
93125944Sjoerg	splx(s);
93230300Sjoerg	return rv;
9334910Swollman}
9344910Swollman
93525944Sjoerg
93625944Sjoerg/*
93725944Sjoerg * Cisco framing implementation.
93825944Sjoerg */
93925944Sjoerg
9404910Swollman/*
9414910Swollman * Handle incoming Cisco keepalive protocol packets.
9424910Swollman */
94330300Sjoergstatic void
94425706Sjoergsppp_cisco_input(struct sppp *sp, struct mbuf *m)
9454910Swollman{
94625944Sjoerg	STDDCL;
9474910Swollman	struct cisco_packet *h;
94830300Sjoerg	u_long me, mymask;
9494910Swollman
95027929Sitojun	if (m->m_pkthdr.len < CISCO_PACKET_LEN) {
95125706Sjoerg		if (debug)
95225706Sjoerg			log(LOG_DEBUG,
95330300Sjoerg			    "%s%d: cisco invalid packet length: %d bytes\n",
95425706Sjoerg			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
9554910Swollman		return;
9564910Swollman	}
9574910Swollman	h = mtod (m, struct cisco_packet*);
95825706Sjoerg	if (debug)
95925706Sjoerg		log(LOG_DEBUG,
96025706Sjoerg		    "%s%d: cisco input: %d bytes "
96125706Sjoerg		    "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
96225706Sjoerg		    ifp->if_name, ifp->if_unit, m->m_pkthdr.len,
96325706Sjoerg		    ntohl (h->type), h->par1, h->par2, h->rel,
96425706Sjoerg		    h->time0, h->time1);
9654910Swollman	switch (ntohl (h->type)) {
9664910Swollman	default:
96725706Sjoerg		if (debug)
96830300Sjoerg			addlog("%s%d: cisco unknown packet type: 0x%lx\n",
96925706Sjoerg			       ifp->if_name, ifp->if_unit, ntohl (h->type));
9704910Swollman		break;
9714910Swollman	case CISCO_ADDR_REPLY:
9724910Swollman		/* Reply on address request, ignore */
9734910Swollman		break;
9744910Swollman	case CISCO_KEEPALIVE_REQ:
9754910Swollman		sp->pp_alivecnt = 0;
9764910Swollman		sp->pp_rseq = ntohl (h->par1);
9774910Swollman		if (sp->pp_seq == sp->pp_rseq) {
9784910Swollman			/* Local and remote sequence numbers are equal.
9794910Swollman			 * Probably, the line is in loopback mode. */
98011189Sjkh			if (sp->pp_loopcnt >= MAXALIVECNT) {
98111189Sjkh				printf ("%s%d: loopback\n",
98211189Sjkh					ifp->if_name, ifp->if_unit);
98311189Sjkh				sp->pp_loopcnt = 0;
98411189Sjkh				if (ifp->if_flags & IFF_UP) {
98511189Sjkh					if_down (ifp);
98626018Sjoerg					sppp_qflush (&sp->pp_cpq);
98711189Sjkh				}
98811189Sjkh			}
9894910Swollman			++sp->pp_loopcnt;
9904910Swollman
9914910Swollman			/* Generate new local sequence number */
9924910Swollman			sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
99311189Sjkh			break;
99411189Sjkh		}
99530300Sjoerg		sp->pp_loopcnt = 0;
99611189Sjkh		if (! (ifp->if_flags & IFF_UP) &&
99711189Sjkh		    (ifp->if_flags & IFF_RUNNING)) {
99830300Sjoerg			if_up(ifp);
99911189Sjkh			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
100011189Sjkh		}
10014910Swollman		break;
10024910Swollman	case CISCO_ADDR_REQ:
100330300Sjoerg		sppp_get_ip_addrs(sp, &me, 0, &mymask);
100430300Sjoerg		if (me != 0L)
100530300Sjoerg			sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask);
10064910Swollman		break;
10074910Swollman	}
10084910Swollman}
10094910Swollman
10104910Swollman/*
101125944Sjoerg * Send Cisco keepalive packet.
10124910Swollman */
101312820Sphkstatic void
101425944Sjoergsppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
101525944Sjoerg{
101625944Sjoerg	STDDCL;
101725944Sjoerg	struct ppp_header *h;
101825944Sjoerg	struct cisco_packet *ch;
101925944Sjoerg	struct mbuf *m;
102025944Sjoerg	u_long t = (time.tv_sec - boottime.tv_sec) * 1000;
102125944Sjoerg
102225944Sjoerg	MGETHDR (m, M_DONTWAIT, MT_DATA);
102325944Sjoerg	if (! m)
102425944Sjoerg		return;
102525944Sjoerg	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
102625944Sjoerg	m->m_pkthdr.rcvif = 0;
102725944Sjoerg
102825944Sjoerg	h = mtod (m, struct ppp_header*);
102925944Sjoerg	h->address = CISCO_MULTICAST;
103025944Sjoerg	h->control = 0;
103125944Sjoerg	h->protocol = htons (CISCO_KEEPALIVE);
103225944Sjoerg
103325944Sjoerg	ch = (struct cisco_packet*) (h + 1);
103425944Sjoerg	ch->type = htonl (type);
103525944Sjoerg	ch->par1 = htonl (par1);
103625944Sjoerg	ch->par2 = htonl (par2);
103725944Sjoerg	ch->rel = -1;
103825944Sjoerg	ch->time0 = htons ((u_short) (t >> 16));
103925944Sjoerg	ch->time1 = htons ((u_short) t);
104025944Sjoerg
104125944Sjoerg	if (debug)
104225944Sjoerg		log(LOG_DEBUG,
104325944Sjoerg		    "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
104425944Sjoerg			ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
104525944Sjoerg			ch->par2, ch->rel, ch->time0, ch->time1);
104625944Sjoerg
104726018Sjoerg	if (IF_QFULL (&sp->pp_cpq)) {
104826018Sjoerg		IF_DROP (&sp->pp_fastq);
104925944Sjoerg		IF_DROP (&ifp->if_snd);
105025944Sjoerg		m_freem (m);
105125944Sjoerg	} else
105226018Sjoerg		IF_ENQUEUE (&sp->pp_cpq, m);
105325944Sjoerg	if (! (ifp->if_flags & IFF_OACTIVE))
105425944Sjoerg		(*ifp->if_start) (ifp);
105525944Sjoerg	ifp->if_obytes += m->m_pkthdr.len + 3;
105625944Sjoerg}
105725944Sjoerg
105825944Sjoerg/*
105925944Sjoerg * PPP protocol implementation.
106025944Sjoerg */
106125944Sjoerg
106225944Sjoerg/*
106325944Sjoerg * Send PPP control protocol packet.
106425944Sjoerg */
106525944Sjoergstatic void
106625706Sjoergsppp_cp_send(struct sppp *sp, u_short proto, u_char type,
106725706Sjoerg	     u_char ident, u_short len, void *data)
10684910Swollman{
106925944Sjoerg	STDDCL;
10704910Swollman	struct ppp_header *h;
10714910Swollman	struct lcp_header *lh;
10724910Swollman	struct mbuf *m;
10734910Swollman
10744910Swollman	if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
10754910Swollman		len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
10764910Swollman	MGETHDR (m, M_DONTWAIT, MT_DATA);
10774910Swollman	if (! m)
10784910Swollman		return;
10794910Swollman	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
10804910Swollman	m->m_pkthdr.rcvif = 0;
10814910Swollman
10824910Swollman	h = mtod (m, struct ppp_header*);
10834910Swollman	h->address = PPP_ALLSTATIONS;        /* broadcast address */
10844910Swollman	h->control = PPP_UI;                 /* Unnumbered Info */
10854910Swollman	h->protocol = htons (proto);         /* Link Control Protocol */
10864910Swollman
10874910Swollman	lh = (struct lcp_header*) (h + 1);
10884910Swollman	lh->type = type;
10894910Swollman	lh->ident = ident;
10904910Swollman	lh->len = htons (LCP_HEADER_LEN + len);
10914910Swollman	if (len)
10924910Swollman		bcopy (data, lh+1, len);
10934910Swollman
109425706Sjoerg	if (debug) {
109525944Sjoerg		log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d",
109625944Sjoerg		    ifp->if_name, ifp->if_unit,
109725944Sjoerg		    sppp_proto_name(proto),
109825944Sjoerg		    sppp_cp_type_name (lh->type), lh->ident,
109925944Sjoerg		    ntohs (lh->len));
11004910Swollman		if (len)
110111189Sjkh			sppp_print_bytes ((u_char*) (lh+1), len);
110225706Sjoerg		addlog(">\n");
11034910Swollman	}
110426018Sjoerg	if (IF_QFULL (&sp->pp_cpq)) {
110526018Sjoerg		IF_DROP (&sp->pp_fastq);
11064910Swollman		IF_DROP (&ifp->if_snd);
11074910Swollman		m_freem (m);
110825944Sjoerg		++ifp->if_oerrors;
11094910Swollman	} else
111026018Sjoerg		IF_ENQUEUE (&sp->pp_cpq, m);
11114910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
11124910Swollman		(*ifp->if_start) (ifp);
11134910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
11144910Swollman}
11154910Swollman
11164910Swollman/*
111725944Sjoerg * Handle incoming PPP control protocol packets.
11184910Swollman */
111912820Sphkstatic void
112025944Sjoergsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
11214910Swollman{
112225944Sjoerg	STDDCL;
112325944Sjoerg	struct lcp_header *h;
112425944Sjoerg	int len = m->m_pkthdr.len;
112525944Sjoerg	int rv;
112625944Sjoerg	u_char *p;
11274910Swollman
112825944Sjoerg	if (len < 4) {
112925944Sjoerg		if (debug)
113025944Sjoerg			log(LOG_DEBUG,
113125944Sjoerg			    "%s%d: %s invalid packet length: %d bytes\n",
113225944Sjoerg			    ifp->if_name, ifp->if_unit, cp->name, len);
11334910Swollman		return;
113425944Sjoerg	}
113525944Sjoerg	h = mtod (m, struct lcp_header*);
113625944Sjoerg	if (debug) {
113725944Sjoerg		log(LOG_DEBUG,
113825944Sjoerg		    "%s%d: %s input(%s): <%s id=0x%x len=%d",
113925944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
114025944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
114125944Sjoerg		    sppp_cp_type_name (h->type), h->ident, ntohs (h->len));
114225944Sjoerg		if (len > 4)
114325944Sjoerg			sppp_print_bytes ((u_char*) (h+1), len-4);
114425944Sjoerg		addlog(">\n");
114525944Sjoerg	}
114625944Sjoerg	if (len > ntohs (h->len))
114725944Sjoerg		len = ntohs (h->len);
114830300Sjoerg	p = (u_char *)(h + 1);
114925944Sjoerg	switch (h->type) {
115025944Sjoerg	case CONF_REQ:
115125944Sjoerg		if (len < 4) {
115225944Sjoerg			if (debug)
115325944Sjoerg				addlog("%s%d: %s invalid conf-req length %d\n",
115425944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
115525944Sjoerg				       len);
115625944Sjoerg			++ifp->if_ierrors;
115725944Sjoerg			break;
115825944Sjoerg		}
115930300Sjoerg		/* handle states where RCR doesn't get a SCA/SCN */
116030300Sjoerg		switch (sp->state[cp->protoidx]) {
116130300Sjoerg		case STATE_CLOSING:
116230300Sjoerg		case STATE_STOPPING:
116330300Sjoerg			return;
116430300Sjoerg		case STATE_CLOSED:
116530300Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
116630300Sjoerg				     0, 0);
116730300Sjoerg			return;
116830300Sjoerg		}
116925944Sjoerg		rv = (cp->RCR)(sp, h, len);
117025944Sjoerg		switch (sp->state[cp->protoidx]) {
117125944Sjoerg		case STATE_OPENED:
117225944Sjoerg			(cp->tld)(sp);
117325944Sjoerg			(cp->scr)(sp);
117425944Sjoerg			/* fall through... */
117525944Sjoerg		case STATE_ACK_SENT:
117625944Sjoerg		case STATE_REQ_SENT:
117725944Sjoerg			sppp_cp_change_state(cp, sp, rv?
117825944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
117925944Sjoerg			break;
118025944Sjoerg		case STATE_STOPPED:
118125944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
118225944Sjoerg			(cp->scr)(sp);
118325944Sjoerg			sppp_cp_change_state(cp, sp, rv?
118425944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
118525944Sjoerg			break;
118625944Sjoerg		case STATE_ACK_RCVD:
118725944Sjoerg			if (rv) {
118825944Sjoerg				sppp_cp_change_state(cp, sp, STATE_OPENED);
118925944Sjoerg				if (debug)
119026077Sjoerg					log(LOG_DEBUG, "%s%d: %s tlu\n",
119126077Sjoerg					    ifp->if_name, ifp->if_unit,
119226077Sjoerg					    cp->name);
119325944Sjoerg				(cp->tlu)(sp);
119425944Sjoerg			} else
119525944Sjoerg				sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
119625944Sjoerg			break;
119725944Sjoerg		default:
119825944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
119925944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
120025944Sjoerg			       sppp_cp_type_name(h->type),
120125944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
120225944Sjoerg			++ifp->if_ierrors;
120325944Sjoerg		}
120425944Sjoerg		break;
120525944Sjoerg	case CONF_ACK:
120625944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
120725944Sjoerg			if (debug)
120825944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
120925944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
121025944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
121125944Sjoerg			++ifp->if_ierrors;
121225944Sjoerg			break;
121325944Sjoerg		}
121425944Sjoerg		switch (sp->state[cp->protoidx]) {
121525944Sjoerg		case STATE_CLOSED:
121625944Sjoerg		case STATE_STOPPED:
121725944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
121825944Sjoerg			break;
121925944Sjoerg		case STATE_CLOSING:
122025944Sjoerg		case STATE_STOPPING:
122125944Sjoerg			break;
122225944Sjoerg		case STATE_REQ_SENT:
122325944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
122425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
122525944Sjoerg			break;
122625944Sjoerg		case STATE_OPENED:
122725944Sjoerg			(cp->tld)(sp);
122825944Sjoerg			/* fall through */
122925944Sjoerg		case STATE_ACK_RCVD:
123025944Sjoerg			(cp->scr)(sp);
123125944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
123225944Sjoerg			break;
123325944Sjoerg		case STATE_ACK_SENT:
123425944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
123525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_OPENED);
123625944Sjoerg			if (debug)
123730300Sjoerg				log(LOG_DEBUG, "%s%d: %s tlu\n",
123825944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name);
123925944Sjoerg			(cp->tlu)(sp);
124025944Sjoerg			break;
124125944Sjoerg		default:
124225944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
124325944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
124425944Sjoerg			       sppp_cp_type_name(h->type),
124525944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
124625944Sjoerg			++ifp->if_ierrors;
124725944Sjoerg		}
124825944Sjoerg		break;
124925944Sjoerg	case CONF_NAK:
125025944Sjoerg	case CONF_REJ:
125125944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
125225944Sjoerg			if (debug)
125325944Sjoerg				addlog("%s%d: %s id mismatch 0x%x != 0x%x\n",
125425944Sjoerg				       ifp->if_name, ifp->if_unit, cp->name,
125525944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
125625944Sjoerg			++ifp->if_ierrors;
125725944Sjoerg			break;
125825944Sjoerg		}
125925944Sjoerg		if (h->type == CONF_NAK)
126025944Sjoerg			(cp->RCN_nak)(sp, h, len);
126125944Sjoerg		else /* CONF_REJ */
126225944Sjoerg			(cp->RCN_rej)(sp, h, len);
12634910Swollman
126425944Sjoerg		switch (sp->state[cp->protoidx]) {
126525944Sjoerg		case STATE_CLOSED:
126625944Sjoerg		case STATE_STOPPED:
126725944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
126825944Sjoerg			break;
126925944Sjoerg		case STATE_REQ_SENT:
127025944Sjoerg		case STATE_ACK_SENT:
127125944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
127225944Sjoerg			(cp->scr)(sp);
127325944Sjoerg			break;
127425944Sjoerg		case STATE_OPENED:
127525944Sjoerg			(cp->tld)(sp);
127625944Sjoerg			/* fall through */
127725944Sjoerg		case STATE_ACK_RCVD:
127825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_SENT);
127925944Sjoerg			(cp->scr)(sp);
128025944Sjoerg			break;
128125944Sjoerg		case STATE_CLOSING:
128225944Sjoerg		case STATE_STOPPING:
128325944Sjoerg			break;
128425944Sjoerg		default:
128525944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
128625944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
128725944Sjoerg			       sppp_cp_type_name(h->type),
128825944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
128925944Sjoerg			++ifp->if_ierrors;
129025944Sjoerg		}
129125944Sjoerg		break;
12924910Swollman
129325944Sjoerg	case TERM_REQ:
129425944Sjoerg		switch (sp->state[cp->protoidx]) {
129525944Sjoerg		case STATE_ACK_RCVD:
129625944Sjoerg		case STATE_ACK_SENT:
129725944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
129825944Sjoerg			/* fall through */
129925944Sjoerg		case STATE_CLOSED:
130025944Sjoerg		case STATE_STOPPED:
130125944Sjoerg		case STATE_CLOSING:
130225944Sjoerg		case STATE_STOPPING:
130325944Sjoerg		case STATE_REQ_SENT:
130425944Sjoerg		  sta:
130525944Sjoerg			/* Send Terminate-Ack packet. */
130625944Sjoerg			if (debug)
130725944Sjoerg				log(LOG_DEBUG, "%s%d: %s send terminate-ack\n",
130825944Sjoerg				    ifp->if_name, ifp->if_unit, cp->name);
130925944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
131025944Sjoerg			break;
131125944Sjoerg		case STATE_OPENED:
131225944Sjoerg			(cp->tld)(sp);
131325944Sjoerg			sp->rst_counter[cp->protoidx] = 0;
131425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPING);
131525944Sjoerg			goto sta;
131625944Sjoerg			break;
131725944Sjoerg		default:
131825944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
131925944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
132025944Sjoerg			       sppp_cp_type_name(h->type),
132125944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
132225944Sjoerg			++ifp->if_ierrors;
132325944Sjoerg		}
132425944Sjoerg		break;
132525944Sjoerg	case TERM_ACK:
132625944Sjoerg		switch (sp->state[cp->protoidx]) {
132725944Sjoerg		case STATE_CLOSED:
132825944Sjoerg		case STATE_STOPPED:
132925944Sjoerg		case STATE_REQ_SENT:
133025944Sjoerg		case STATE_ACK_SENT:
133125944Sjoerg			break;
133225944Sjoerg		case STATE_CLOSING:
133325944Sjoerg			(cp->tlf)(sp);
133425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
133525944Sjoerg			break;
133625944Sjoerg		case STATE_STOPPING:
133725944Sjoerg			(cp->tlf)(sp);
133825944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
133925944Sjoerg			break;
134025944Sjoerg		case STATE_ACK_RCVD:
134125944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
134225944Sjoerg			break;
134325944Sjoerg		case STATE_OPENED:
134425944Sjoerg			(cp->tld)(sp);
134525944Sjoerg			(cp->scr)(sp);
134625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
134725944Sjoerg			break;
134825944Sjoerg		default:
134925944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
135025944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
135125944Sjoerg			       sppp_cp_type_name(h->type),
135225944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
135325944Sjoerg			++ifp->if_ierrors;
135425944Sjoerg		}
135525944Sjoerg		break;
135625944Sjoerg	case CODE_REJ:
135725944Sjoerg	case PROTO_REJ:
135825944Sjoerg		/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
135930300Sjoerg		log(LOG_INFO,
136030300Sjoerg		    "%s%d: %s: ignoring RXJ (%s) for proto 0x%x, "
136130300Sjoerg		    "danger will robinson\n",
136230300Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
136330300Sjoerg		    sppp_cp_type_name(h->type), ntohs(*((u_short *)p)));
136425944Sjoerg		switch (sp->state[cp->protoidx]) {
136525944Sjoerg		case STATE_CLOSED:
136625944Sjoerg		case STATE_STOPPED:
136725944Sjoerg		case STATE_REQ_SENT:
136825944Sjoerg		case STATE_ACK_SENT:
136925944Sjoerg		case STATE_CLOSING:
137025944Sjoerg		case STATE_STOPPING:
137125944Sjoerg		case STATE_OPENED:
137225944Sjoerg			break;
137325944Sjoerg		case STATE_ACK_RCVD:
137425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
137525944Sjoerg			break;
137625944Sjoerg		default:
137725944Sjoerg			printf("%s%d: %s illegal %s in state %s\n",
137825944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name,
137925944Sjoerg			       sppp_cp_type_name(h->type),
138025944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
138125944Sjoerg			++ifp->if_ierrors;
138225944Sjoerg		}
138325944Sjoerg		break;
138425944Sjoerg	case DISC_REQ:
138525944Sjoerg		if (cp->proto != PPP_LCP)
138625944Sjoerg			goto illegal;
138725944Sjoerg		/* Discard the packet. */
138825944Sjoerg		break;
138925944Sjoerg	case ECHO_REQ:
139025944Sjoerg		if (cp->proto != PPP_LCP)
139125944Sjoerg			goto illegal;
139225944Sjoerg		if (sp->state[cp->protoidx] != STATE_OPENED) {
139325944Sjoerg			if (debug)
139425944Sjoerg				addlog("%s%d: lcp echo req but lcp closed\n",
139525944Sjoerg				       ifp->if_name, ifp->if_unit);
139625944Sjoerg			++ifp->if_ierrors;
139725944Sjoerg			break;
139825944Sjoerg		}
139925944Sjoerg		if (len < 8) {
140025944Sjoerg			if (debug)
140125944Sjoerg				addlog("%s%d: invalid lcp echo request "
140225944Sjoerg				       "packet length: %d bytes\n",
140325944Sjoerg				       ifp->if_name, ifp->if_unit, len);
140425944Sjoerg			break;
140525944Sjoerg		}
140625944Sjoerg		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
140725944Sjoerg			/* Line loopback mode detected. */
140825944Sjoerg			printf("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
140925944Sjoerg			if_down (ifp);
141026018Sjoerg			sppp_qflush (&sp->pp_cpq);
14114910Swollman
141225944Sjoerg			/* Shut down the PPP link. */
141325944Sjoerg			/* XXX */
141425944Sjoerg			lcp.Down(sp);
141525944Sjoerg			lcp.Up(sp);
141625944Sjoerg			break;
141725944Sjoerg		}
141825944Sjoerg		*(long*)(h+1) = htonl (sp->lcp.magic);
141925944Sjoerg		if (debug)
142025944Sjoerg			addlog("%s%d: got lcp echo req, sending echo rep\n",
142125944Sjoerg			       ifp->if_name, ifp->if_unit);
142225944Sjoerg		sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1);
142325944Sjoerg		break;
142425944Sjoerg	case ECHO_REPLY:
142525944Sjoerg		if (cp->proto != PPP_LCP)
142625944Sjoerg			goto illegal;
142725944Sjoerg		if (h->ident != sp->lcp.echoid) {
142825944Sjoerg			++ifp->if_ierrors;
142925944Sjoerg			break;
143025944Sjoerg		}
143125944Sjoerg		if (len < 8) {
143225944Sjoerg			if (debug)
143325944Sjoerg				addlog("%s%d: lcp invalid echo reply "
143425944Sjoerg				       "packet length: %d bytes\n",
143525944Sjoerg				       ifp->if_name, ifp->if_unit, len);
143625944Sjoerg			break;
143725944Sjoerg		}
143825944Sjoerg		if (debug)
143925944Sjoerg			addlog("%s%d: lcp got echo rep\n",
144025944Sjoerg			       ifp->if_name, ifp->if_unit);
144125944Sjoerg		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
144225944Sjoerg			sp->pp_alivecnt = 0;
144325944Sjoerg		break;
144425944Sjoerg	default:
144525944Sjoerg		/* Unknown packet type -- send Code-Reject packet. */
144625944Sjoerg	  illegal:
144725944Sjoerg		if (debug)
144825944Sjoerg			addlog("%s%d: %c send code-rej for 0x%x\n",
144925944Sjoerg			       ifp->if_name, ifp->if_unit, cp->name, h->type);
145025944Sjoerg		sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq,
145125944Sjoerg			     m->m_pkthdr.len, h);
145225944Sjoerg		++ifp->if_ierrors;
145325944Sjoerg	}
14544910Swollman}
14554910Swollman
145625944Sjoerg
14574910Swollman/*
145825944Sjoerg * The generic part of all Up/Down/Open/Close/TO event handlers.
145925944Sjoerg * Basically, the state transition handling in the automaton.
14604910Swollman */
146125944Sjoergstatic void
146225944Sjoergsppp_up_event(const struct cp *cp, struct sppp *sp)
14634910Swollman{
146425944Sjoerg	STDDCL;
14654910Swollman
146625944Sjoerg	if (debug)
146725944Sjoerg		log(LOG_DEBUG, "%s%d: %s up(%s)\n",
146825944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
146925944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
147025944Sjoerg
147125944Sjoerg	switch (sp->state[cp->protoidx]) {
147225944Sjoerg	case STATE_INITIAL:
147325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
147425944Sjoerg		break;
147525944Sjoerg	case STATE_STARTING:
147625944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
147725944Sjoerg		(cp->scr)(sp);
147825944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
147925944Sjoerg		break;
14804910Swollman	default:
148125944Sjoerg		printf("%s%d: %s illegal up in state %s\n",
148225944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
148325944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
148425944Sjoerg	}
148525944Sjoerg}
14864910Swollman
148725944Sjoergstatic void
148825944Sjoergsppp_down_event(const struct cp *cp, struct sppp *sp)
148925944Sjoerg{
149025944Sjoerg	STDDCL;
149125944Sjoerg
149225944Sjoerg	if (debug)
149325944Sjoerg		log(LOG_DEBUG, "%s%d: %s down(%s)\n",
149425944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
149525944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
149625944Sjoerg
149725944Sjoerg	switch (sp->state[cp->protoidx]) {
149825944Sjoerg	case STATE_CLOSED:
149925944Sjoerg	case STATE_CLOSING:
150025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
15014910Swollman		break;
150225944Sjoerg	case STATE_STOPPED:
150325944Sjoerg		(cp->tls)(sp);
150425944Sjoerg		/* fall through */
150525944Sjoerg	case STATE_STOPPING:
150625944Sjoerg	case STATE_REQ_SENT:
150725944Sjoerg	case STATE_ACK_RCVD:
150825944Sjoerg	case STATE_ACK_SENT:
150925944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
151025944Sjoerg		break;
151125944Sjoerg	case STATE_OPENED:
151225944Sjoerg		(cp->tld)(sp);
151325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
151425944Sjoerg		break;
151525944Sjoerg	default:
151625944Sjoerg		printf("%s%d: %s illegal down in state %s\n",
151725944Sjoerg		       ifp->if_name, ifp->if_unit, cp->name,
151825944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
151925944Sjoerg	}
152025944Sjoerg}
15214910Swollman
152211189Sjkh
152325944Sjoergstatic void
152425944Sjoergsppp_open_event(const struct cp *cp, struct sppp *sp)
152525944Sjoerg{
152625944Sjoerg	STDDCL;
152725944Sjoerg
152825944Sjoerg	if (debug)
152925944Sjoerg		log(LOG_DEBUG, "%s%d: %s open(%s)\n",
153025944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
153125944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
153225944Sjoerg
153325944Sjoerg	switch (sp->state[cp->protoidx]) {
153425944Sjoerg	case STATE_INITIAL:
153525944Sjoerg		(cp->tls)(sp);
153625944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
15374910Swollman		break;
153825944Sjoerg	case STATE_STARTING:
153925944Sjoerg		break;
154025944Sjoerg	case STATE_CLOSED:
154125944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
154225944Sjoerg		(cp->scr)(sp);
154325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
154425944Sjoerg		break;
154525944Sjoerg	case STATE_STOPPED:
154625944Sjoerg	case STATE_STOPPING:
154725944Sjoerg	case STATE_REQ_SENT:
154825944Sjoerg	case STATE_ACK_RCVD:
154925944Sjoerg	case STATE_ACK_SENT:
155025944Sjoerg	case STATE_OPENED:
155125944Sjoerg		break;
155225944Sjoerg	case STATE_CLOSING:
155325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STOPPING);
155425944Sjoerg		break;
155525944Sjoerg	}
155625944Sjoerg}
15574910Swollman
155825944Sjoerg
155925944Sjoergstatic void
156025944Sjoergsppp_close_event(const struct cp *cp, struct sppp *sp)
156125944Sjoerg{
156225944Sjoerg	STDDCL;
156325944Sjoerg
156425944Sjoerg	if (debug)
156525944Sjoerg		log(LOG_DEBUG, "%s%d: %s close(%s)\n",
156625944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
156725944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
156825944Sjoerg
156925944Sjoerg	switch (sp->state[cp->protoidx]) {
157025944Sjoerg	case STATE_INITIAL:
157125944Sjoerg	case STATE_CLOSED:
157225944Sjoerg	case STATE_CLOSING:
15734910Swollman		break;
157425944Sjoerg	case STATE_STARTING:
157525944Sjoerg		(cp->tlf)(sp);
157625944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
15774910Swollman		break;
157825944Sjoerg	case STATE_STOPPED:
157925944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
15804910Swollman		break;
158125944Sjoerg	case STATE_STOPPING:
158225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
15834910Swollman		break;
158425944Sjoerg	case STATE_OPENED:
158525944Sjoerg		(cp->tld)(sp);
158625944Sjoerg		/* fall through */
158725944Sjoerg	case STATE_REQ_SENT:
158825944Sjoerg	case STATE_ACK_RCVD:
158925944Sjoerg	case STATE_ACK_SENT:
159025944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
159125944Sjoerg		sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0);
159225944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
15934910Swollman		break;
15944910Swollman	}
15954910Swollman}
15964910Swollman
159725944Sjoergstatic void
159825944Sjoergsppp_to_event(const struct cp *cp, struct sppp *sp)
159925944Sjoerg{
160025944Sjoerg	STDDCL;
160125944Sjoerg	int s;
160225944Sjoerg
160325944Sjoerg	s = splimp();
160425944Sjoerg	if (debug)
160525944Sjoerg		log(LOG_DEBUG, "%s%d: %s TO(%s) rst_counter = %d\n",
160625944Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
160725944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
160825944Sjoerg		    sp->rst_counter[cp->protoidx]);
160925944Sjoerg
161025944Sjoerg	if (--sp->rst_counter[cp->protoidx] < 0)
161125944Sjoerg		/* TO- event */
161225944Sjoerg		switch (sp->state[cp->protoidx]) {
161325944Sjoerg		case STATE_CLOSING:
161425944Sjoerg			(cp->tlf)(sp);
161525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_CLOSED);
161625944Sjoerg			break;
161725944Sjoerg		case STATE_STOPPING:
161825944Sjoerg			(cp->tlf)(sp);
161925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
162025944Sjoerg			break;
162125944Sjoerg		case STATE_REQ_SENT:
162225944Sjoerg		case STATE_ACK_RCVD:
162325944Sjoerg		case STATE_ACK_SENT:
162425944Sjoerg			(cp->tlf)(sp);
162525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPED);
162625944Sjoerg			break;
162725944Sjoerg		}
162825944Sjoerg	else
162925944Sjoerg		/* TO+ event */
163025944Sjoerg		switch (sp->state[cp->protoidx]) {
163125944Sjoerg		case STATE_CLOSING:
163225944Sjoerg		case STATE_STOPPING:
163325944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
163425944Sjoerg				     0, 0);
163529681Sgibbs			sp->ch[cp->protoidx] = timeout(cp->TO, (void *)sp,
163629681Sgibbs						       sp->lcp.timeout);
163725944Sjoerg			break;
163825944Sjoerg		case STATE_REQ_SENT:
163925944Sjoerg		case STATE_ACK_RCVD:
164025944Sjoerg			(cp->scr)(sp);
164125944Sjoerg			/* sppp_cp_change_state() will restart the timer */
164225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
164325944Sjoerg			break;
164425944Sjoerg		case STATE_ACK_SENT:
164525944Sjoerg			(cp->scr)(sp);
164629681Sgibbs			sp->ch[cp->protoidx] = timeout(cp->TO, (void *)sp,
164729681Sgibbs						       sp->lcp.timeout);
164825944Sjoerg			break;
164925944Sjoerg		}
165025944Sjoerg
165125944Sjoerg	splx(s);
165225944Sjoerg}
165325944Sjoerg
165411189Sjkh/*
165525944Sjoerg * Change the state of a control protocol in the state automaton.
165625944Sjoerg * Takes care of starting/stopping the restart timer.
165711189Sjkh */
165825944Sjoergvoid
165925944Sjoergsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
166025944Sjoerg{
166125944Sjoerg	sp->state[cp->protoidx] = newstate;
166225944Sjoerg
166329681Sgibbs	untimeout(cp->TO, (void *)sp, sp->ch[cp->protoidx]);
166425944Sjoerg	switch (newstate) {
166525944Sjoerg	case STATE_INITIAL:
166625944Sjoerg	case STATE_STARTING:
166725944Sjoerg	case STATE_CLOSED:
166825944Sjoerg	case STATE_STOPPED:
166925944Sjoerg	case STATE_OPENED:
167025944Sjoerg		break;
167125944Sjoerg	case STATE_CLOSING:
167225944Sjoerg	case STATE_STOPPING:
167325944Sjoerg	case STATE_REQ_SENT:
167425944Sjoerg	case STATE_ACK_RCVD:
167525944Sjoerg	case STATE_ACK_SENT:
167629681Sgibbs		sp->ch[cp->protoidx]  = timeout(cp->TO, (void *)sp,
167729681Sgibbs						sp->lcp.timeout);
167825944Sjoerg		break;
167925944Sjoerg	}
168025944Sjoerg}
168125944Sjoerg/*
168225944Sjoerg *--------------------------------------------------------------------------*
168325944Sjoerg *                                                                          *
168425944Sjoerg *                         The LCP implementation.                          *
168525944Sjoerg *                                                                          *
168625944Sjoerg *--------------------------------------------------------------------------*
168725944Sjoerg */
168825944Sjoergstatic void
168925944Sjoergsppp_lcp_init(struct sppp *sp)
169025944Sjoerg{
169125944Sjoerg	sp->lcp.opts = (1 << LCP_OPT_MAGIC);
169225944Sjoerg	sp->lcp.magic = 0;
169325944Sjoerg	sp->state[IDX_LCP] = STATE_INITIAL;
169425944Sjoerg	sp->fail_counter[IDX_LCP] = 0;
169525944Sjoerg	sp->lcp.protos = 0;
169625944Sjoerg	sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
169730300Sjoerg
169825944Sjoerg	/*
169925944Sjoerg	 * Initialize counters and timeout values.  Note that we don't
170025944Sjoerg	 * use the 3 seconds suggested in RFC 1661 since we are likely
170125944Sjoerg	 * running on a fast link.  XXX We should probably implement
170225944Sjoerg	 * the exponential backoff option.  Note that these values are
170325944Sjoerg	 * relevant for all control protocols, not just LCP only.
170425944Sjoerg	 */
170525944Sjoerg	sp->lcp.timeout = 1 * hz;
170625944Sjoerg	sp->lcp.max_terminate = 2;
170725944Sjoerg	sp->lcp.max_configure = 10;
170825944Sjoerg	sp->lcp.max_failure = 10;
170930300Sjoerg	callout_handle_init(&sp->ch[IDX_LCP]);
171025944Sjoerg}
171125944Sjoerg
171225944Sjoergstatic void
171325944Sjoergsppp_lcp_up(struct sppp *sp)
171425944Sjoerg{
171525944Sjoerg	STDDCL;
171625944Sjoerg
171725944Sjoerg	/*
171830300Sjoerg	 * If this interface is passive or dial-on-demand, and we are
171930300Sjoerg	 * still in Initial state, it means we've got an incoming
172030300Sjoerg	 * call.  Activate the interface.
172125944Sjoerg	 */
172225944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) {
172325944Sjoerg		if (debug)
172425944Sjoerg			log(LOG_DEBUG,
172530300Sjoerg			    "%s%d: Up event", ifp->if_name, ifp->if_unit);
172625944Sjoerg		ifp->if_flags |= IFF_RUNNING;
172730300Sjoerg		if (sp->state[IDX_LCP] == STATE_INITIAL) {
172830300Sjoerg			if (debug)
172930300Sjoerg				addlog("(incoming call)\n");
173030300Sjoerg			sp->pp_flags |= PP_CALLIN;
173130300Sjoerg			lcp.Open(sp);
173230300Sjoerg		} else if (debug)
173330300Sjoerg			addlog("\n");
173425944Sjoerg	}
173525944Sjoerg
173625944Sjoerg	sppp_up_event(&lcp, sp);
173725944Sjoerg}
173825944Sjoerg
173925944Sjoergstatic void
174025944Sjoergsppp_lcp_down(struct sppp *sp)
174125944Sjoerg{
174225944Sjoerg	STDDCL;
174325944Sjoerg
174425944Sjoerg	sppp_down_event(&lcp, sp);
174525944Sjoerg
174625944Sjoerg	/*
174725944Sjoerg	 * If this is neither a dial-on-demand nor a passive
174825944Sjoerg	 * interface, simulate an ``ifconfig down'' action, so the
174925944Sjoerg	 * administrator can force a redial by another ``ifconfig
175025944Sjoerg	 * up''.  XXX For leased line operation, should we immediately
175125944Sjoerg	 * try to reopen the connection here?
175225944Sjoerg	 */
175325944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
175425944Sjoerg		log(LOG_INFO,
175525944Sjoerg		    "%s%d: Down event (carrier loss), taking interface down.\n",
175625944Sjoerg		    ifp->if_name, ifp->if_unit);
175725944Sjoerg		if_down(ifp);
175825944Sjoerg	} else {
175925944Sjoerg		if (debug)
176025944Sjoerg			log(LOG_DEBUG,
176125944Sjoerg			    "%s%d: Down event (carrier loss)\n",
176225944Sjoerg			    ifp->if_name, ifp->if_unit);
176325944Sjoerg	}
176430300Sjoerg	sp->pp_flags &= ~PP_CALLIN;
176530300Sjoerg	if (sp->state[IDX_LCP] != STATE_INITIAL)
176630300Sjoerg		lcp.Close(sp);
176725944Sjoerg	ifp->if_flags &= ~IFF_RUNNING;
176825944Sjoerg}
176925944Sjoerg
177025944Sjoergstatic void
177125944Sjoergsppp_lcp_open(struct sppp *sp)
177225944Sjoerg{
177330300Sjoerg	/*
177430300Sjoerg	 * If we are authenticator, negotiate LCP_AUTH
177530300Sjoerg	 */
177630300Sjoerg	if (sp->hisauth.proto != 0)
177730300Sjoerg		sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO);
177830300Sjoerg	else
177930300Sjoerg		sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
178030300Sjoerg	sp->pp_flags &= ~PP_NEEDAUTH;
178125944Sjoerg	sppp_open_event(&lcp, sp);
178225944Sjoerg}
178325944Sjoerg
178425944Sjoergstatic void
178525944Sjoergsppp_lcp_close(struct sppp *sp)
178625944Sjoerg{
178725944Sjoerg	sppp_close_event(&lcp, sp);
178825944Sjoerg}
178925944Sjoerg
179025944Sjoergstatic void
179125944Sjoergsppp_lcp_TO(void *cookie)
179225944Sjoerg{
179325944Sjoerg	sppp_to_event(&lcp, (struct sppp *)cookie);
179425944Sjoerg}
179525944Sjoerg
179625944Sjoerg/*
179725944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
179825944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
179925944Sjoerg * caused action scn.  (The return value is used to make the state
180025944Sjoerg * transition decision in the state automaton.)
180125944Sjoerg */
180212820Sphkstatic int
180325944Sjoergsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
18044910Swollman{
180525944Sjoerg	STDDCL;
180611189Sjkh	u_char *buf, *r, *p;
180725944Sjoerg	int origlen, rlen;
180825944Sjoerg	u_long nmagic;
180930300Sjoerg	u_short authproto;
18104910Swollman
181111189Sjkh	len -= 4;
181225944Sjoerg	origlen = len;
181311189Sjkh	buf = r = malloc (len, M_TEMP, M_NOWAIT);
181411189Sjkh	if (! buf)
181511189Sjkh		return (0);
18164910Swollman
181725706Sjoerg	if (debug)
181825944Sjoerg		log(LOG_DEBUG, "%s%d: lcp parse opts: ",
181925944Sjoerg		    ifp->if_name, ifp->if_unit);
182025706Sjoerg
182125944Sjoerg	/* pass 1: check for things that need to be rejected */
182211189Sjkh	p = (void*) (h+1);
182311189Sjkh	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
182425944Sjoerg		if (debug)
182525944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
182611189Sjkh		switch (*p) {
182711189Sjkh		case LCP_OPT_MAGIC:
182825944Sjoerg			/* Magic number. */
182925944Sjoerg			/* fall through, both are same length */
183025944Sjoerg		case LCP_OPT_ASYNC_MAP:
183125944Sjoerg			/* Async control character map. */
183225944Sjoerg			if (len >= 6 || p[1] == 6)
183325944Sjoerg				continue;
183425944Sjoerg			if (debug)
183525944Sjoerg				addlog("[invalid] ");
183625944Sjoerg			break;
183725944Sjoerg		case LCP_OPT_MRU:
183825944Sjoerg			/* Maximum receive unit. */
183925944Sjoerg			if (len >= 4 && p[1] == 4)
184025944Sjoerg				continue;
184125944Sjoerg			if (debug)
184225944Sjoerg				addlog("[invalid] ");
184325944Sjoerg			break;
184430300Sjoerg		case LCP_OPT_AUTH_PROTO:
184530300Sjoerg			if (len < 4) {
184630300Sjoerg				if (debug)
184730300Sjoerg					addlog("[invalid] ");
184830300Sjoerg				break;
184930300Sjoerg			}
185030300Sjoerg			authproto = (p[2] << 8) + p[3];
185130300Sjoerg			if (authproto == PPP_CHAP && p[1] != 5) {
185230300Sjoerg				if (debug)
185330300Sjoerg					addlog("[invalid chap len] ");
185430300Sjoerg				break;
185530300Sjoerg			}
185630300Sjoerg			if (sp->myauth.proto == 0) {
185730300Sjoerg				/* we are not configured to do auth */
185830300Sjoerg				if (debug)
185930300Sjoerg					addlog("[not configured] ");
186030300Sjoerg				break;
186130300Sjoerg			}
186230300Sjoerg			/*
186330300Sjoerg			 * Remote want us to authenticate, remember this,
186430300Sjoerg			 * so we stay in PHASE_AUTHENTICATE after LCP got
186530300Sjoerg			 * up.
186630300Sjoerg			 */
186730300Sjoerg			sp->pp_flags |= PP_NEEDAUTH;
186830300Sjoerg			continue;
186925944Sjoerg		default:
187025944Sjoerg			/* Others not supported. */
187125944Sjoerg			if (debug)
187225944Sjoerg				addlog("[rej] ");
187325944Sjoerg			break;
187425944Sjoerg		}
187525944Sjoerg		/* Add the option to rejected list. */
187625944Sjoerg		bcopy (p, r, p[1]);
187725944Sjoerg		r += p[1];
187825944Sjoerg		rlen += p[1];
187925944Sjoerg	}
188025944Sjoerg	if (rlen) {
188125944Sjoerg		if (debug)
188225944Sjoerg			addlog(" send conf-rej\n");
188325944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
188425944Sjoerg		return 0;
188525944Sjoerg	} else if (debug)
188625944Sjoerg		addlog("\n");
188725944Sjoerg
188825944Sjoerg	/*
188925944Sjoerg	 * pass 2: check for option values that are unacceptable and
189025944Sjoerg	 * thus require to be nak'ed.
189125944Sjoerg	 */
189225944Sjoerg	if (debug)
189326077Sjoerg		log(LOG_DEBUG, "%s%d: lcp parse opt values: ",
189426077Sjoerg		    ifp->if_name, ifp->if_unit);
189525944Sjoerg
189625944Sjoerg	p = (void*) (h+1);
189725944Sjoerg	len = origlen;
189825944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
189925944Sjoerg		if (debug)
190025944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
190125944Sjoerg		switch (*p) {
190225944Sjoerg		case LCP_OPT_MAGIC:
190311189Sjkh			/* Magic number -- extract. */
190425944Sjoerg			nmagic = (u_long)p[2] << 24 |
190525944Sjoerg				(u_long)p[3] << 16 | p[4] << 8 | p[5];
190625944Sjoerg			if (nmagic != sp->lcp.magic) {
190725706Sjoerg				if (debug)
190825944Sjoerg					addlog("0x%x ", nmagic);
190911189Sjkh				continue;
191011189Sjkh			}
191125944Sjoerg			/*
191225944Sjoerg			 * Local and remote magics equal -- loopback?
191325944Sjoerg			 */
191425944Sjoerg			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
191530300Sjoerg				printf ("%s%d: loopback\n",
191625944Sjoerg					ifp->if_name, ifp->if_unit);
191725944Sjoerg				sp->pp_loopcnt = 0;
191825944Sjoerg				if (ifp->if_flags & IFF_UP) {
191925944Sjoerg					if_down(ifp);
192026018Sjoerg					sppp_qflush(&sp->pp_cpq);
192125944Sjoerg					/* XXX ? */
192225944Sjoerg					lcp.Down(sp);
192325944Sjoerg					lcp.Up(sp);
192425944Sjoerg				}
192525944Sjoerg			} else if (debug)
192625944Sjoerg				addlog("[glitch] ");
192725944Sjoerg			++sp->pp_loopcnt;
192825944Sjoerg			/*
192925944Sjoerg			 * We negate our magic here, and NAK it.  If
193025944Sjoerg			 * we see it later in an NAK packet, we
193125944Sjoerg			 * suggest a new one.
193225944Sjoerg			 */
193325944Sjoerg			nmagic = ~sp->lcp.magic;
193425944Sjoerg			/* Gonna NAK it. */
193525944Sjoerg			p[2] = nmagic >> 24;
193625944Sjoerg			p[3] = nmagic >> 16;
193725944Sjoerg			p[4] = nmagic >> 8;
193825944Sjoerg			p[5] = nmagic;
193911189Sjkh			break;
194025944Sjoerg
194111189Sjkh		case LCP_OPT_ASYNC_MAP:
194211189Sjkh			/* Async control character map -- check to be zero. */
194325944Sjoerg			if (! p[2] && ! p[3] && ! p[4] && ! p[5]) {
194425706Sjoerg				if (debug)
194525944Sjoerg					addlog("[empty] ");
194611189Sjkh				continue;
194725706Sjoerg			}
194825706Sjoerg			if (debug)
194925944Sjoerg				addlog("[non-empty] ");
195025944Sjoerg			/* suggest a zero one */
195125944Sjoerg			p[2] = p[3] = p[4] = p[5] = 0;
195211189Sjkh			break;
195325944Sjoerg
195411189Sjkh		case LCP_OPT_MRU:
195525944Sjoerg			/*
195625944Sjoerg			 * Maximum receive unit.  Always agreeable,
195725944Sjoerg			 * but ignored by now.
195825944Sjoerg			 */
195925944Sjoerg			sp->lcp.their_mru = p[2] * 256 + p[3];
196025706Sjoerg			if (debug)
196125944Sjoerg				addlog("%d ", sp->lcp.their_mru);
196211189Sjkh			continue;
196330300Sjoerg
196430300Sjoerg		case LCP_OPT_AUTH_PROTO:
196530300Sjoerg			authproto = (p[2] << 8) + p[3];
196630300Sjoerg			if (sp->myauth.proto != authproto) {
196730300Sjoerg				/* not agreed, nak */
196830300Sjoerg				if (debug)
196930300Sjoerg					addlog("[mine %s != his %s] ",
197030300Sjoerg					       sppp_proto_name(sp->hisauth.proto),
197130300Sjoerg					       sppp_proto_name(authproto));
197230300Sjoerg				p[2] = sp->myauth.proto >> 8;
197330300Sjoerg				p[3] = sp->myauth.proto;
197430300Sjoerg				break;
197530300Sjoerg			}
197630300Sjoerg			if (authproto == PPP_CHAP && p[4] != CHAP_MD5) {
197730300Sjoerg				if (debug)
197830300Sjoerg					addlog("[chap not MD5] ");
197930300Sjoerg				p[4] == CHAP_MD5;
198030300Sjoerg				break;
198130300Sjoerg			}
198230300Sjoerg			continue;
198311189Sjkh		}
198425944Sjoerg		/* Add the option to nak'ed list. */
198525706Sjoerg		bcopy (p, r, p[1]);
198625706Sjoerg		r += p[1];
198711189Sjkh		rlen += p[1];
198812436Speter	}
198925706Sjoerg	if (rlen) {
199028036Sjoerg		if (++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) {
199128036Sjoerg			if (debug)
199228036Sjoerg				addlog(" max_failure (%d) exceeded, "
199328036Sjoerg				       "send conf-rej\n",
199428036Sjoerg				       sp->lcp.max_failure);
199528036Sjoerg			sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
199628036Sjoerg		} else {
199728036Sjoerg			if (debug)
199828036Sjoerg				addlog(" send conf-nak\n");
199928036Sjoerg			sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
200028036Sjoerg		}
200125944Sjoerg		return 0;
200225944Sjoerg	} else {
200325944Sjoerg		if (debug)
200425944Sjoerg			addlog(" send conf-ack\n");
200528036Sjoerg		sp->fail_counter[IDX_LCP] = 0;
200625944Sjoerg		sp->pp_loopcnt = 0;
200725944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_ACK,
200825944Sjoerg			      h->ident, origlen, h+1);
200925944Sjoerg	}
201025944Sjoerg
201111189Sjkh	free (buf, M_TEMP);
201211189Sjkh	return (rlen == 0);
20134910Swollman}
20144910Swollman
201525944Sjoerg/*
201625944Sjoerg * Analyze the LCP Configure-Reject option list, and adjust our
201725944Sjoerg * negotiation.
201825944Sjoerg */
201912820Sphkstatic void
202025944Sjoergsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
20214910Swollman{
202225944Sjoerg	STDDCL;
202325944Sjoerg	u_char *buf, *p;
20244910Swollman
202525944Sjoerg	len -= 4;
202625944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
202725944Sjoerg	if (!buf)
20284910Swollman		return;
202925944Sjoerg
203025944Sjoerg	if (debug)
203125944Sjoerg		log(LOG_DEBUG, "%s%d: lcp rej opts: ",
203225944Sjoerg		    ifp->if_name, ifp->if_unit);
203325944Sjoerg
203425944Sjoerg	p = (void*) (h+1);
203525944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
203625944Sjoerg		if (debug)
203725944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
203825944Sjoerg		switch (*p) {
203925944Sjoerg		case LCP_OPT_MAGIC:
204025944Sjoerg			/* Magic number -- can't use it, use 0 */
204125944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC);
204225944Sjoerg			sp->lcp.magic = 0;
204325944Sjoerg			break;
204425944Sjoerg		case LCP_OPT_MRU:
204525944Sjoerg			/*
204625944Sjoerg			 * Should not be rejected anyway, since we only
204725944Sjoerg			 * negotiate a MRU if explicitly requested by
204825944Sjoerg			 * peer.
204925944Sjoerg			 */
205025944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
205125944Sjoerg			break;
205230300Sjoerg		case LCP_OPT_AUTH_PROTO:
205330300Sjoerg			/*
205430300Sjoerg			 * Peer doesn't want to authenticate himself,
205530300Sjoerg			 * deny unless this is a dialout call, and
205630300Sjoerg			 * AUTHFLAG_NOCALLOUT is set.
205730300Sjoerg			 */
205830300Sjoerg			if ((sp->pp_flags & PP_CALLIN) == 0 &&
205930300Sjoerg			    (sp->hisauth.flags & AUTHFLAG_NOCALLOUT) != 0) {
206030300Sjoerg				if (debug)
206130300Sjoerg					addlog("[don't insist on auth "
206230300Sjoerg					       "for callout]");
206330300Sjoerg				sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
206430300Sjoerg				break;
206530300Sjoerg			}
206630300Sjoerg			if (debug)
206730300Sjoerg				addlog("[access denied]\n");
206830300Sjoerg			lcp.Close(sp);
206930300Sjoerg			break;
207025944Sjoerg		}
20714910Swollman	}
207225944Sjoerg	if (debug)
207325944Sjoerg		addlog("\n");
207425944Sjoerg	free (buf, M_TEMP);
207525944Sjoerg	return;
207625944Sjoerg}
207725944Sjoerg
207825944Sjoerg/*
207925944Sjoerg * Analyze the LCP Configure-NAK option list, and adjust our
208025944Sjoerg * negotiation.
208125944Sjoerg */
208225944Sjoergstatic void
208325944Sjoergsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
208425944Sjoerg{
208525944Sjoerg	STDDCL;
208625944Sjoerg	u_char *buf, *p;
208725944Sjoerg	u_long magic;
208825944Sjoerg
208925944Sjoerg	len -= 4;
209025944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
209125944Sjoerg	if (!buf)
209225944Sjoerg		return;
209325944Sjoerg
209425944Sjoerg	if (debug)
209525944Sjoerg		log(LOG_DEBUG, "%s%d: lcp nak opts: ",
209625944Sjoerg		    ifp->if_name, ifp->if_unit);
209725944Sjoerg
209825944Sjoerg	p = (void*) (h+1);
209925944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
210025706Sjoerg		if (debug)
210125944Sjoerg			addlog(" %s ", sppp_lcp_opt_name(*p));
210225944Sjoerg		switch (*p) {
210325944Sjoerg		case LCP_OPT_MAGIC:
210425944Sjoerg			/* Magic number -- renegotiate */
210525944Sjoerg			if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
210625944Sjoerg			    len >= 6 && p[1] == 6) {
210725944Sjoerg				magic = (u_long)p[2] << 24 |
210825944Sjoerg					(u_long)p[3] << 16 | p[4] << 8 | p[5];
210925944Sjoerg				/*
211025944Sjoerg				 * If the remote magic is our negated one,
211125944Sjoerg				 * this looks like a loopback problem.
211225944Sjoerg				 * Suggest a new magic to make sure.
211325944Sjoerg				 */
211425944Sjoerg				if (magic == ~sp->lcp.magic) {
211525944Sjoerg					if (debug)
211625944Sjoerg						addlog("magic glitch ");
211725944Sjoerg					sp->lcp.magic += time.tv_sec + time.tv_usec;
211825944Sjoerg				} else {
211925944Sjoerg					sp->lcp.magic = magic;
212025944Sjoerg					if (debug)
212125944Sjoerg						addlog("%d ");
212225944Sjoerg				}
212325944Sjoerg			}
212425944Sjoerg			break;
212525944Sjoerg		case LCP_OPT_MRU:
212625944Sjoerg			/*
212725944Sjoerg			 * Peer wants to advise us to negotiate an MRU.
212825944Sjoerg			 * Agree on it if it's reasonable, or use
212925944Sjoerg			 * default otherwise.
213025944Sjoerg			 */
213125944Sjoerg			if (len >= 4 && p[1] == 4) {
213225944Sjoerg				u_int mru = p[2] * 256 + p[3];
213325944Sjoerg				if (debug)
213425944Sjoerg					addlog("%d ", mru);
213525944Sjoerg				if (mru < PP_MTU || mru > PP_MAX_MRU)
213625944Sjoerg					mru = PP_MTU;
213725944Sjoerg				sp->lcp.mru = mru;
213825944Sjoerg				sp->lcp.opts |= (1 << LCP_OPT_MRU);
213925944Sjoerg			}
214025944Sjoerg			break;
214130300Sjoerg		case LCP_OPT_AUTH_PROTO:
214230300Sjoerg			/*
214330300Sjoerg			 * Peer doesn't like our authentication method,
214430300Sjoerg			 * deny.
214530300Sjoerg			 */
214630300Sjoerg			if (debug)
214730300Sjoerg				addlog("[access denied]\n");
214830300Sjoerg			lcp.Close(sp);
214930300Sjoerg			break;
21504910Swollman		}
215125944Sjoerg	}
215225944Sjoerg	if (debug)
215325944Sjoerg		addlog("\n");
215425944Sjoerg	free (buf, M_TEMP);
215525944Sjoerg	return;
215625944Sjoerg}
215711189Sjkh
215825944Sjoergstatic void
215925944Sjoergsppp_lcp_tlu(struct sppp *sp)
216025944Sjoerg{
216125944Sjoerg	STDDCL;
216225944Sjoerg	int i;
216325944Sjoerg	u_long mask;
216425944Sjoerg
216525944Sjoerg	/* XXX ? */
216625944Sjoerg	if (! (ifp->if_flags & IFF_UP) &&
216725944Sjoerg	    (ifp->if_flags & IFF_RUNNING)) {
216825944Sjoerg		/* Coming out of loopback mode. */
216925944Sjoerg		if_up(ifp);
217025944Sjoerg		printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
217125944Sjoerg	}
217225944Sjoerg
217325944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
217425944Sjoerg		if ((cps[i])->flags & CP_QUAL)
217525944Sjoerg			(cps[i])->Open(sp);
217625944Sjoerg
217730300Sjoerg	if ((sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0 ||
217830300Sjoerg	    (sp->pp_flags & PP_NEEDAUTH) != 0)
217925944Sjoerg		sp->pp_phase = PHASE_AUTHENTICATE;
218025944Sjoerg	else
218125944Sjoerg		sp->pp_phase = PHASE_NETWORK;
218225944Sjoerg
218325944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
218425944Sjoerg	    sppp_phase_name(sp->pp_phase));
218525944Sjoerg
218630300Sjoerg	/*
218730300Sjoerg	 * Open all authentication protocols.  This is even required
218830300Sjoerg	 * if we already proceeded to network phase, since it might be
218930300Sjoerg	 * that remote wants us to authenticate, so we might have to
219030300Sjoerg	 * send a PAP request.  Undesired authentication protocols
219130300Sjoerg	 * don't do anything when they get an Open event.
219230300Sjoerg	 */
219330300Sjoerg	for (i = 0; i < IDX_COUNT; i++)
219430300Sjoerg		if ((cps[i])->flags & CP_AUTH)
219530300Sjoerg			(cps[i])->Open(sp);
219630300Sjoerg
219730300Sjoerg	if (sp->pp_phase == PHASE_NETWORK) {
219825944Sjoerg		/* Notify all NCPs. */
219925944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
220025944Sjoerg			if ((cps[i])->flags & CP_NCP)
220125944Sjoerg				(cps[i])->Open(sp);
220225944Sjoerg	}
220325944Sjoerg
220425944Sjoerg	/* Send Up events to all started protos. */
220525944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
220625944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0)
220725944Sjoerg			(cps[i])->Up(sp);
220825944Sjoerg
220925944Sjoerg	if (sp->pp_phase == PHASE_NETWORK)
221025944Sjoerg		/* if no NCP is starting, close down */
221130300Sjoerg		sppp_lcp_check_and_close(sp);
221225944Sjoerg}
221325944Sjoerg
221425944Sjoergstatic void
221525944Sjoergsppp_lcp_tld(struct sppp *sp)
221625944Sjoerg{
221725944Sjoerg	STDDCL;
221825944Sjoerg	int i;
221925944Sjoerg	u_long mask;
222025944Sjoerg
222125944Sjoerg	sp->pp_phase = PHASE_TERMINATE;
222225944Sjoerg
222325944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
222425944Sjoerg	    sppp_phase_name(sp->pp_phase));
222525944Sjoerg
222625944Sjoerg	/*
222725944Sjoerg	 * Take upper layers down.  We send the Down event first and
222825944Sjoerg	 * the Close second to prevent the upper layers from sending
222925944Sjoerg	 * ``a flurry of terminate-request packets'', as the RFC
223025944Sjoerg	 * describes it.
223125944Sjoerg	 */
223225944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
223325944Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) {
223425944Sjoerg			(cps[i])->Down(sp);
223525944Sjoerg			(cps[i])->Close(sp);
223625944Sjoerg		}
223725944Sjoerg}
223825944Sjoerg
223925944Sjoergstatic void
224025944Sjoergsppp_lcp_tls(struct sppp *sp)
224125944Sjoerg{
224225944Sjoerg	STDDCL;
224325944Sjoerg
224425944Sjoerg	sp->pp_phase = PHASE_ESTABLISH;
224525944Sjoerg
224625944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
224725944Sjoerg	    sppp_phase_name(sp->pp_phase));
224825944Sjoerg
224925944Sjoerg	/* Notify lower layer if desired. */
225025944Sjoerg	if (sp->pp_tls)
225125944Sjoerg		(sp->pp_tls)(sp);
225225944Sjoerg}
225325944Sjoerg
225425944Sjoergstatic void
225525944Sjoergsppp_lcp_tlf(struct sppp *sp)
225625944Sjoerg{
225725944Sjoerg	STDDCL;
225825944Sjoerg
225925944Sjoerg	sp->pp_phase = PHASE_DEAD;
226025944Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
226125944Sjoerg	    sppp_phase_name(sp->pp_phase));
226225944Sjoerg
226325944Sjoerg	/* Notify lower layer if desired. */
226425944Sjoerg	if (sp->pp_tlf)
226525944Sjoerg		(sp->pp_tlf)(sp);
226625944Sjoerg}
226725944Sjoerg
226825944Sjoergstatic void
226925944Sjoergsppp_lcp_scr(struct sppp *sp)
227025944Sjoerg{
227130300Sjoerg	char opt[6 /* magicnum */ + 4 /* mru */ + 5 /* chap */];
227225944Sjoerg	int i = 0;
227330300Sjoerg	u_short authproto;
227425944Sjoerg
227525944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
227625944Sjoerg		if (! sp->lcp.magic)
227725944Sjoerg			sp->lcp.magic = time.tv_sec + time.tv_usec;
227825944Sjoerg		opt[i++] = LCP_OPT_MAGIC;
227925944Sjoerg		opt[i++] = 6;
228025944Sjoerg		opt[i++] = sp->lcp.magic >> 24;
228125944Sjoerg		opt[i++] = sp->lcp.magic >> 16;
228225944Sjoerg		opt[i++] = sp->lcp.magic >> 8;
228325944Sjoerg		opt[i++] = sp->lcp.magic;
228425944Sjoerg	}
228525944Sjoerg
228625944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MRU)) {
228725944Sjoerg		opt[i++] = LCP_OPT_MRU;
228825944Sjoerg		opt[i++] = 4;
228925944Sjoerg		opt[i++] = sp->lcp.mru >> 8;
229025944Sjoerg		opt[i++] = sp->lcp.mru;
229125944Sjoerg	}
229225944Sjoerg
229330300Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) {
229430300Sjoerg		authproto = sp->hisauth.proto;
229530300Sjoerg		opt[i++] = LCP_OPT_AUTH_PROTO;
229630300Sjoerg		opt[i++] = authproto == PPP_CHAP? 5: 4;
229730300Sjoerg		opt[i++] = authproto >> 8;
229830300Sjoerg		opt[i++] = authproto;
229930300Sjoerg		if (authproto == PPP_CHAP)
230030300Sjoerg			opt[i++] = CHAP_MD5;
230130300Sjoerg	}
230230300Sjoerg
230325944Sjoerg	sp->confid[IDX_LCP] = ++sp->pp_seq;
230425944Sjoerg	sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
230525944Sjoerg}
230625944Sjoerg
230725944Sjoerg/*
230830300Sjoerg * Check the open NCPs, return true if at least one NCP is open.
230930300Sjoerg */
231030300Sjoergstatic int
231130300Sjoergsppp_ncp_check(struct sppp *sp)
231230300Sjoerg{
231330300Sjoerg	int i, mask;
231430300Sjoerg
231530300Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
231630300Sjoerg		if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP)
231730300Sjoerg			return 1;
231830300Sjoerg	return 0;
231930300Sjoerg}
232030300Sjoerg
232130300Sjoerg/*
232225944Sjoerg * Re-check the open NCPs and see if we should terminate the link.
232325944Sjoerg * Called by the NCPs during their tlf action handling.
232425944Sjoerg */
232525944Sjoergstatic void
232630300Sjoergsppp_lcp_check_and_close(struct sppp *sp)
232725944Sjoerg{
232825944Sjoerg
232930300Sjoerg	if (sp->pp_phase < PHASE_NETWORK)
233030300Sjoerg		/* don't bother, we are already going down */
233130300Sjoerg		return;
233230300Sjoerg
233330300Sjoerg	if (sppp_ncp_check(sp))
233430300Sjoerg		return;
233530300Sjoerg
233625944Sjoerg	lcp.Close(sp);
233725944Sjoerg}
233825944Sjoerg/*
233925944Sjoerg *--------------------------------------------------------------------------*
234025944Sjoerg *                                                                          *
234125944Sjoerg *                        The IPCP implementation.                          *
234225944Sjoerg *                                                                          *
234325944Sjoerg *--------------------------------------------------------------------------*
234425944Sjoerg */
234525944Sjoerg
234625944Sjoergstatic void
234725944Sjoergsppp_ipcp_init(struct sppp *sp)
234825944Sjoerg{
234925944Sjoerg	sp->ipcp.opts = 0;
235025944Sjoerg	sp->ipcp.flags = 0;
235125944Sjoerg	sp->state[IDX_IPCP] = STATE_INITIAL;
235225944Sjoerg	sp->fail_counter[IDX_IPCP] = 0;
235329681Sgibbs	callout_handle_init(&sp->ch[IDX_IPCP]);
235425944Sjoerg}
235525944Sjoerg
235625944Sjoergstatic void
235725944Sjoergsppp_ipcp_up(struct sppp *sp)
235825944Sjoerg{
235925944Sjoerg	sppp_up_event(&ipcp, sp);
236025944Sjoerg}
236125944Sjoerg
236225944Sjoergstatic void
236325944Sjoergsppp_ipcp_down(struct sppp *sp)
236425944Sjoerg{
236525944Sjoerg	sppp_down_event(&ipcp, sp);
236625944Sjoerg}
236725944Sjoerg
236825944Sjoergstatic void
236925944Sjoergsppp_ipcp_open(struct sppp *sp)
237025944Sjoerg{
237125944Sjoerg	STDDCL;
237225944Sjoerg	u_long myaddr, hisaddr;
237325944Sjoerg
237430300Sjoerg	sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
237525944Sjoerg	/*
237625944Sjoerg	 * If we don't have his address, this probably means our
237725944Sjoerg	 * interface doesn't want to talk IP at all.  (This could
237825944Sjoerg	 * be the case if somebody wants to speak only IPX, for
237925944Sjoerg	 * example.)  Don't open IPCP in this case.
238025944Sjoerg	 */
238125944Sjoerg	if (hisaddr == 0L) {
238225944Sjoerg		/* XXX this message should go away */
238325944Sjoerg		if (debug)
238425944Sjoerg			log(LOG_DEBUG, "%s%d: ipcp_open(): no IP interface\n",
238525944Sjoerg			    ifp->if_name, ifp->if_unit);
238625944Sjoerg		return;
238725944Sjoerg	}
238825944Sjoerg
238925944Sjoerg	if (myaddr == 0L) {
239025944Sjoerg		/*
239125944Sjoerg		 * I don't have an assigned address, so i need to
239225944Sjoerg		 * negotiate my address.
239325944Sjoerg		 */
239425944Sjoerg		sp->ipcp.flags |= IPCP_MYADDR_DYN;
239525944Sjoerg		sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
239625944Sjoerg	}
239725944Sjoerg	sppp_open_event(&ipcp, sp);
239825944Sjoerg}
239925944Sjoerg
240025944Sjoergstatic void
240125944Sjoergsppp_ipcp_close(struct sppp *sp)
240225944Sjoerg{
240325944Sjoerg	sppp_close_event(&ipcp, sp);
240425944Sjoerg	if (sp->ipcp.flags & IPCP_MYADDR_DYN)
240525944Sjoerg		/*
240625944Sjoerg		 * My address was dynamic, clear it again.
240725944Sjoerg		 */
240825944Sjoerg		sppp_set_ip_addr(sp, 0L);
240925944Sjoerg}
241025944Sjoerg
241125944Sjoergstatic void
241225944Sjoergsppp_ipcp_TO(void *cookie)
241325944Sjoerg{
241425944Sjoerg	sppp_to_event(&ipcp, (struct sppp *)cookie);
241525944Sjoerg}
241625944Sjoerg
241725944Sjoerg/*
241825944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
241925944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
242025944Sjoerg * caused action scn.  (The return value is used to make the state
242125944Sjoerg * transition decision in the state automaton.)
242225944Sjoerg */
242325944Sjoergstatic int
242425944Sjoergsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
242525944Sjoerg{
242625944Sjoerg	u_char *buf, *r, *p;
242725944Sjoerg	struct ifnet *ifp = &sp->pp_if;
242825944Sjoerg	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
242925944Sjoerg	u_long hisaddr, desiredaddr;
243025944Sjoerg
243125944Sjoerg	len -= 4;
243225944Sjoerg	origlen = len;
243325944Sjoerg	/*
243425944Sjoerg	 * Make sure to allocate a buf that can at least hold a
243525944Sjoerg	 * conf-nak with an `address' option.  We might need it below.
243625944Sjoerg	 */
243725944Sjoerg	buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
243825944Sjoerg	if (! buf)
243925944Sjoerg		return (0);
244025944Sjoerg
244125944Sjoerg	/* pass 1: see if we can recognize them */
244225944Sjoerg	if (debug)
244325944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp parse opts: ",
244425944Sjoerg		    ifp->if_name, ifp->if_unit);
244525944Sjoerg	p = (void*) (h+1);
244625944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
244725944Sjoerg		if (debug)
244825944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
244925944Sjoerg		switch (*p) {
245025944Sjoerg#ifdef notyet
245125944Sjoerg		case IPCP_OPT_COMPRESSION:
245225944Sjoerg			if (len >= 6 && p[1] >= 6) {
245325944Sjoerg				/* correctly formed compress option */
245425944Sjoerg				continue;
245511189Sjkh			}
245625706Sjoerg			if (debug)
245725944Sjoerg				addlog("[invalid] ");
245825944Sjoerg			break;
245925944Sjoerg#endif
246025944Sjoerg		case IPCP_OPT_ADDRESS:
246125944Sjoerg			if (len >= 6 && p[1] == 6) {
246225944Sjoerg				/* correctly formed address option */
246325944Sjoerg				continue;
246425944Sjoerg			}
246525706Sjoerg			if (debug)
246625944Sjoerg				addlog("[invalid] ");
246711189Sjkh			break;
246825944Sjoerg		default:
246925944Sjoerg			/* Others not supported. */
247025944Sjoerg			if (debug)
247125944Sjoerg				addlog("[rej] ");
24724910Swollman			break;
24734910Swollman		}
247425944Sjoerg		/* Add the option to rejected list. */
247525944Sjoerg		bcopy (p, r, p[1]);
247625944Sjoerg		r += p[1];
247725944Sjoerg		rlen += p[1];
247825944Sjoerg	}
247925944Sjoerg	if (rlen) {
248025944Sjoerg		if (debug)
248125944Sjoerg			addlog(" send conf-rej\n");
248225944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf);
248325944Sjoerg		return 0;
248425944Sjoerg	} else if (debug)
248525944Sjoerg		addlog("\n");
248625944Sjoerg
248725944Sjoerg	/* pass 2: parse option values */
248830300Sjoerg	sppp_get_ip_addrs(sp, 0, &hisaddr, 0);
248925944Sjoerg	if (debug)
249030300Sjoerg		log(LOG_DEBUG, "%s%d: ipcp parse opt values: ",
249130300Sjoerg		       ifp->if_name, ifp->if_unit);
249225944Sjoerg	p = (void*) (h+1);
249325944Sjoerg	len = origlen;
249425944Sjoerg	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
249525944Sjoerg		if (debug)
249625944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
249725944Sjoerg		switch (*p) {
249825944Sjoerg#ifdef notyet
249925944Sjoerg		case IPCP_OPT_COMPRESSION:
250025944Sjoerg			continue;
250125944Sjoerg#endif
250225944Sjoerg		case IPCP_OPT_ADDRESS:
250325944Sjoerg			desiredaddr = p[2] << 24 | p[3] << 16 |
250425944Sjoerg				p[4] << 8 | p[5];
250525944Sjoerg			if (desiredaddr == hisaddr) {
250625944Sjoerg				/*
250725944Sjoerg				 * Peer's address is same as our value,
250825944Sjoerg				 * this is agreeable.  Gonna conf-ack
250925944Sjoerg				 * it.
251025944Sjoerg				 */
251125944Sjoerg				if (debug)
251230300Sjoerg					addlog("%s [ack] ",
251330300Sjoerg					       sppp_dotted_quad(hisaddr));
251425944Sjoerg				/* record that we've seen it already */
251525944Sjoerg				sp->ipcp.flags |= IPCP_HISADDR_SEEN;
251625944Sjoerg				continue;
251725944Sjoerg			}
251825944Sjoerg			/*
251925944Sjoerg			 * The address wasn't agreeable.  This is either
252025944Sjoerg			 * he sent us 0.0.0.0, asking to assign him an
252125944Sjoerg			 * address, or he send us another address not
252225944Sjoerg			 * matching our value.  Either case, we gonna
252325944Sjoerg			 * conf-nak it with our value.
252425944Sjoerg			 */
252525944Sjoerg			if (debug) {
252625944Sjoerg				if (desiredaddr == 0)
252725944Sjoerg					addlog("[addr requested] ");
252825944Sjoerg				else
252930300Sjoerg					addlog("%s [not agreed] ",
253030300Sjoerg					       sppp_dotted_quad(desiredaddr));
253125944Sjoerg
253225944Sjoerg				p[2] = hisaddr >> 24;
253325944Sjoerg				p[3] = hisaddr >> 16;
253425944Sjoerg				p[4] = hisaddr >> 8;
253525944Sjoerg				p[5] = hisaddr;
253625944Sjoerg			}
253711189Sjkh			break;
253825706Sjoerg		}
253925944Sjoerg		/* Add the option to nak'ed list. */
254025944Sjoerg		bcopy (p, r, p[1]);
254125944Sjoerg		r += p[1];
254225944Sjoerg		rlen += p[1];
254325944Sjoerg	}
254425944Sjoerg
254525944Sjoerg	/*
254625944Sjoerg	 * If we are about to conf-ack the request, but haven't seen
254725944Sjoerg	 * his address so far, gonna conf-nak it instead, with the
254825944Sjoerg	 * `address' option present and our idea of his address being
254925944Sjoerg	 * filled in there, to request negotiation of both addresses.
255025944Sjoerg	 *
255125944Sjoerg	 * XXX This can result in an endless req - nak loop if peer
255225944Sjoerg	 * doesn't want to send us his address.  Q: What should we do
255325944Sjoerg	 * about it?  XXX  A: implement the max-failure counter.
255425944Sjoerg	 */
255525944Sjoerg	if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) {
255625944Sjoerg		buf[0] = IPCP_OPT_ADDRESS;
255725944Sjoerg		buf[1] = 6;
255825944Sjoerg		buf[2] = hisaddr >> 24;
255925944Sjoerg		buf[3] = hisaddr >> 16;
256025944Sjoerg		buf[4] = hisaddr >> 8;
256125944Sjoerg		buf[5] = hisaddr;
256225944Sjoerg		rlen = 6;
256325706Sjoerg		if (debug)
256425944Sjoerg			addlog("still need hisaddr ");
256525944Sjoerg	}
256625944Sjoerg
256725944Sjoerg	if (rlen) {
256825706Sjoerg		if (debug)
256925944Sjoerg			addlog(" send conf-nak\n");
257025944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf);
257125944Sjoerg	} else {
257225706Sjoerg		if (debug)
257325944Sjoerg			addlog(" send conf-ack\n");
257425944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_ACK,
257525944Sjoerg			      h->ident, origlen, h+1);
257625944Sjoerg	}
257725944Sjoerg
257825944Sjoerg	free (buf, M_TEMP);
257925944Sjoerg	return (rlen == 0);
258025944Sjoerg}
258125944Sjoerg
258225944Sjoerg/*
258325944Sjoerg * Analyze the IPCP Configure-Reject option list, and adjust our
258425944Sjoerg * negotiation.
258525944Sjoerg */
258625944Sjoergstatic void
258725944Sjoergsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
258825944Sjoerg{
258925944Sjoerg	u_char *buf, *p;
259025944Sjoerg	struct ifnet *ifp = &sp->pp_if;
259125944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
259225944Sjoerg
259325944Sjoerg	len -= 4;
259425944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
259525944Sjoerg	if (!buf)
259625944Sjoerg		return;
259725944Sjoerg
259825944Sjoerg	if (debug)
259925944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp rej opts: ",
260025944Sjoerg		    ifp->if_name, ifp->if_unit);
260125944Sjoerg
260225944Sjoerg	p = (void*) (h+1);
260325944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
260425706Sjoerg		if (debug)
260525944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
260625944Sjoerg		switch (*p) {
260725944Sjoerg		case IPCP_OPT_ADDRESS:
260825944Sjoerg			/*
260925944Sjoerg			 * Peer doesn't grok address option.  This is
261025944Sjoerg			 * bad.  XXX  Should we better give up here?
261125944Sjoerg			 */
261225944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS);
261325944Sjoerg			break;
261425944Sjoerg#ifdef notyet
261525944Sjoerg		case IPCP_OPT_COMPRESS:
261625944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS);
261725944Sjoerg			break;
261825944Sjoerg#endif
261925944Sjoerg		}
26204910Swollman	}
262125944Sjoerg	if (debug)
262225944Sjoerg		addlog("\n");
262325944Sjoerg	free (buf, M_TEMP);
262425944Sjoerg	return;
26254910Swollman}
26264910Swollman
262725944Sjoerg/*
262825944Sjoerg * Analyze the IPCP Configure-NAK option list, and adjust our
262925944Sjoerg * negotiation.
263025944Sjoerg */
263112820Sphkstatic void
263225944Sjoergsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
26334910Swollman{
263425944Sjoerg	u_char *buf, *p;
263525944Sjoerg	struct ifnet *ifp = &sp->pp_if;
263625944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
263725944Sjoerg	u_long wantaddr;
26384910Swollman
263925944Sjoerg	len -= 4;
264025944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
264125944Sjoerg	if (!buf)
264225944Sjoerg		return;
264325944Sjoerg
264425944Sjoerg	if (debug)
264525944Sjoerg		log(LOG_DEBUG, "%s%d: ipcp nak opts: ",
264625944Sjoerg		    ifp->if_name, ifp->if_unit);
264725944Sjoerg
264825944Sjoerg	p = (void*) (h+1);
264925944Sjoerg	for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
265025944Sjoerg		if (debug)
265125944Sjoerg			addlog(" %s ", sppp_ipcp_opt_name(*p));
265225944Sjoerg		switch (*p) {
265325944Sjoerg		case IPCP_OPT_ADDRESS:
265425944Sjoerg			/*
265525944Sjoerg			 * Peer doesn't like our local IP address.  See
265625944Sjoerg			 * if we can do something for him.  We'll drop
265725944Sjoerg			 * him our address then.
265825944Sjoerg			 */
265925944Sjoerg			if (len >= 6 && p[1] == 6) {
266025944Sjoerg				wantaddr = p[2] << 24 | p[3] << 16 |
266125944Sjoerg					p[4] << 8 | p[5];
266225944Sjoerg				sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
266325944Sjoerg				if (debug)
266430300Sjoerg					addlog("[wantaddr %s] ",
266530300Sjoerg					       sppp_dotted_quad(wantaddr));
266625944Sjoerg				/*
266725944Sjoerg				 * When doing dynamic address assignment,
266825944Sjoerg				 * we accept his offer.  Otherwise, we
266925944Sjoerg				 * ignore it and thus continue to negotiate
267025944Sjoerg				 * our already existing value.
267125944Sjoerg				 */
267225944Sjoerg				if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
267325944Sjoerg					sppp_set_ip_addr(sp, wantaddr);
267425944Sjoerg					if (debug)
267525944Sjoerg						addlog("[agree] ");
267625944Sjoerg				}
267725944Sjoerg			}
267825944Sjoerg			break;
267925944Sjoerg#ifdef notyet
268025944Sjoerg		case IPCP_OPT_COMPRESS:
268125944Sjoerg			/*
268225944Sjoerg			 * Peer wants different compression parameters.
268325944Sjoerg			 */
268425944Sjoerg			break;
268525944Sjoerg#endif
268625944Sjoerg		}
268725944Sjoerg	}
268825944Sjoerg	if (debug)
268925944Sjoerg		addlog("\n");
269025944Sjoerg	free (buf, M_TEMP);
269125944Sjoerg	return;
26924910Swollman}
26934910Swollman
269412820Sphkstatic void
269525944Sjoergsppp_ipcp_tlu(struct sppp *sp)
26964910Swollman{
26974910Swollman}
26984910Swollman
269925944Sjoergstatic void
270025944Sjoergsppp_ipcp_tld(struct sppp *sp)
270125944Sjoerg{
270225944Sjoerg}
270325944Sjoerg
270425944Sjoergstatic void
270525944Sjoergsppp_ipcp_tls(struct sppp *sp)
270625944Sjoerg{
270725944Sjoerg	/* indicate to LCP that it must stay alive */
270825944Sjoerg	sp->lcp.protos |= (1 << IDX_IPCP);
270925944Sjoerg}
271025944Sjoerg
271125944Sjoergstatic void
271225944Sjoergsppp_ipcp_tlf(struct sppp *sp)
271325944Sjoerg{
271425944Sjoerg	/* we no longer need LCP */
271525944Sjoerg	sp->lcp.protos &= ~(1 << IDX_IPCP);
271630300Sjoerg	sppp_lcp_check_and_close(sp);
271725944Sjoerg}
271825944Sjoerg
271925944Sjoergstatic void
272025944Sjoergsppp_ipcp_scr(struct sppp *sp)
272125944Sjoerg{
272225944Sjoerg	char opt[6 /* compression */ + 6 /* address */];
272325944Sjoerg	u_long ouraddr;
272425944Sjoerg	int i = 0;
272525944Sjoerg
272625944Sjoerg#ifdef notyet
272725944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
272825944Sjoerg		opt[i++] = IPCP_OPT_COMPRESSION;
272925944Sjoerg		opt[i++] = 6;
273025944Sjoerg		opt[i++] = 0;	/* VJ header compression */
273125944Sjoerg		opt[i++] = 0x2d; /* VJ header compression */
273225944Sjoerg		opt[i++] = max_slot_id;
273325944Sjoerg		opt[i++] = comp_slot_id;
273425944Sjoerg	}
273525944Sjoerg#endif
273625944Sjoerg
273725944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
273830300Sjoerg		sppp_get_ip_addrs(sp, &ouraddr, 0, 0);
273925944Sjoerg		opt[i++] = IPCP_OPT_ADDRESS;
274025944Sjoerg		opt[i++] = 6;
274125944Sjoerg		opt[i++] = ouraddr >> 24;
274225944Sjoerg		opt[i++] = ouraddr >> 16;
274325944Sjoerg		opt[i++] = ouraddr >> 8;
274425944Sjoerg		opt[i++] = ouraddr;
274525944Sjoerg	}
274625944Sjoerg
274725944Sjoerg	sp->confid[IDX_IPCP] = ++sp->pp_seq;
274825944Sjoerg	sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
274925944Sjoerg}
275025944Sjoerg
275125944Sjoerg
275225944Sjoerg/*
275330300Sjoerg *--------------------------------------------------------------------------*
275430300Sjoerg *                                                                          *
275530300Sjoerg *                        The CHAP implementation.                          *
275630300Sjoerg *                                                                          *
275730300Sjoerg *--------------------------------------------------------------------------*
275830300Sjoerg */
275930300Sjoerg
276030300Sjoerg/*
276130300Sjoerg * The authentication protocols don't employ a full-fledged state machine as
276230300Sjoerg * the control protocols do, since they do have Open and Close events, but
276330300Sjoerg * not Up and Down, nor are they explicitly terminated.  Also, use of the
276430300Sjoerg * authentication protocols may be different in both directions (this makes
276530300Sjoerg * sense, think of a machine that never accepts incoming calls but only
276630300Sjoerg * calls out, it doesn't require the called party to authenticate itself).
276730300Sjoerg *
276830300Sjoerg * Our state machine for the local authentication protocol (we are requesting
276930300Sjoerg * the peer to authenticate) looks like:
277030300Sjoerg *
277130300Sjoerg *						    RCA-
277230300Sjoerg *	      +--------------------------------------------+
277330300Sjoerg *	      V					    scn,tld|
277430300Sjoerg *	  +--------+			       Close   +---------+ RCA+
277530300Sjoerg *	  |	   |<----------------------------------|	 |------+
277630300Sjoerg *   +--->| Closed |				TO*    | Opened	 | sca	|
277730300Sjoerg *   |	  |	   |-----+		       +-------|	 |<-----+
277830300Sjoerg *   |	  +--------+ irc |		       |       +---------+
277930300Sjoerg *   |	    ^		 |		       |	   ^
278030300Sjoerg *   |	    |		 |		       |	   |
278130300Sjoerg *   |	    |		 |		       |	   |
278230300Sjoerg *   |	 TO-|		 |		       |	   |
278330300Sjoerg *   |	    |tld  TO+	 V		       |	   |
278430300Sjoerg *   |	    |	+------->+		       |	   |
278530300Sjoerg *   |	    |	|	 |		       |	   |
278630300Sjoerg *   |	  +--------+	 V		       |	   |
278730300Sjoerg *   |	  |	   |<----+<--------------------+	   |
278830300Sjoerg *   |	  | Req-   | scr				   |
278930300Sjoerg *   |	  | Sent   |					   |
279030300Sjoerg *   |	  |	   |					   |
279130300Sjoerg *   |	  +--------+					   |
279230300Sjoerg *   | RCA- |	| RCA+					   |
279330300Sjoerg *   +------+	+------------------------------------------+
279430300Sjoerg *   scn,tld	  sca,irc,ict,tlu
279530300Sjoerg *
279630300Sjoerg *
279730300Sjoerg *   with:
279830300Sjoerg *
279930300Sjoerg *	Open:	LCP reached authentication phase
280030300Sjoerg *	Close:	LCP reached terminate phase
280130300Sjoerg *
280230300Sjoerg *	RCA+:	received reply (pap-req, chap-response), acceptable
280330300Sjoerg *	RCN:	received reply (pap-req, chap-response), not acceptable
280430300Sjoerg *	TO+:	timeout with restart counter >= 0
280530300Sjoerg *	TO-:	timeout with restart counter < 0
280630300Sjoerg *	TO*:	reschedule timeout for CHAP
280730300Sjoerg *
280830300Sjoerg *	scr:	send request packet (none for PAP, chap-challenge)
280930300Sjoerg *	sca:	send ack packet (pap-ack, chap-success)
281030300Sjoerg *	scn:	send nak packet (pap-nak, chap-failure)
281130300Sjoerg *	ict:	initialize re-challenge timer (CHAP only)
281230300Sjoerg *
281330300Sjoerg *	tlu:	this-layer-up, LCP reaches network phase
281430300Sjoerg *	tld:	this-layer-down, LCP enters terminate phase
281530300Sjoerg *
281630300Sjoerg * Note that in CHAP mode, after sending a new challenge, while the state
281730300Sjoerg * automaton falls back into Req-Sent state, it doesn't signal a tld
281830300Sjoerg * event to LCP, so LCP remains in network phase.  Only after not getting
281930300Sjoerg * any response (or after getting an unacceptable response), CHAP closes,
282030300Sjoerg * causing LCP to enter terminate phase.
282130300Sjoerg *
282230300Sjoerg * With PAP, there is no initial request that can be sent.  The peer is
282330300Sjoerg * expected to send one based on the successful negotiation of PAP as
282430300Sjoerg * the authentication protocol during the LCP option negotiation.
282530300Sjoerg *
282630300Sjoerg * Incoming authentication protocol requests (remote requests
282730300Sjoerg * authentication, we are peer) don't employ a state machine at all,
282830300Sjoerg * they are simply answered.  Some peers [Ascend P50 firmware rev
282930300Sjoerg * 4.50] react allergically when sending IPCP requests while they are
283030300Sjoerg * still in authentication phase (thereby violating the standard that
283130300Sjoerg * demands that these NCP packets are to be discarded), so we keep
283230300Sjoerg * track of the peer demanding us to authenticate, and only proceed to
283330300Sjoerg * phase network once we've seen a positive acknowledge for the
283430300Sjoerg * authentication.
283530300Sjoerg */
283630300Sjoerg
283730300Sjoerg/*
283830300Sjoerg * Handle incoming CHAP packets.
283930300Sjoerg */
284030300Sjoergvoid
284130300Sjoergsppp_chap_input(struct sppp *sp, struct mbuf *m)
284230300Sjoerg{
284330300Sjoerg	STDDCL;
284430300Sjoerg	struct lcp_header *h;
284530300Sjoerg	int len, x;
284630300Sjoerg	u_char *value, *name, digest[AUTHKEYLEN], dsize;
284730300Sjoerg	int value_len, name_len;
284830300Sjoerg	MD5_CTX ctx;
284930300Sjoerg
285030300Sjoerg	len = m->m_pkthdr.len;
285130300Sjoerg	if (len < 4) {
285230300Sjoerg		if (debug)
285330300Sjoerg			log(LOG_DEBUG,
285430300Sjoerg			    "%s%d: chap invalid packet length: %d bytes\n",
285530300Sjoerg			    ifp->if_name, ifp->if_unit, len);
285630300Sjoerg		return;
285730300Sjoerg	}
285830300Sjoerg	h = mtod (m, struct lcp_header*);
285930300Sjoerg	if (len > ntohs (h->len))
286030300Sjoerg		len = ntohs (h->len);
286130300Sjoerg
286230300Sjoerg	switch (h->type) {
286330300Sjoerg	/* challenge, failure and success are his authproto */
286430300Sjoerg	case CHAP_CHALLENGE:
286530300Sjoerg		value = 1 + (u_char*)(h+1);
286630300Sjoerg		value_len = value[-1];
286730300Sjoerg		name = value + value_len;
286830300Sjoerg		name_len = len - value_len - 5;
286930300Sjoerg		if (name_len < 0) {
287030300Sjoerg			if (debug) {
287130300Sjoerg				log(LOG_DEBUG,
287230300Sjoerg				    "%s%d: chap corrupted challenge "
287330300Sjoerg				    "<%s id=0x%x len=%d",
287430300Sjoerg				    ifp->if_name, ifp->if_unit,
287530300Sjoerg				    sppp_auth_type_name(PPP_CHAP, h->type),
287630300Sjoerg				    h->ident, ntohs(h->len));
287730300Sjoerg				if (len > 4)
287830300Sjoerg					sppp_print_bytes((u_char*) (h+1), len-4);
287930300Sjoerg				addlog(">\n");
288030300Sjoerg			}
288130300Sjoerg			break;
288230300Sjoerg		}
288330300Sjoerg
288430300Sjoerg		if (debug) {
288530300Sjoerg			log(LOG_DEBUG,
288630300Sjoerg			    "%s%d: chap input <%s id=0x%x len=%d name=",
288730300Sjoerg			    ifp->if_name, ifp->if_unit,
288830300Sjoerg			    sppp_auth_type_name(PPP_CHAP, h->type), h->ident,
288930300Sjoerg			    ntohs(h->len));
289030300Sjoerg			sppp_print_string((char*) name, name_len);
289130300Sjoerg			addlog(" value-size=%d value=", value_len);
289230300Sjoerg			sppp_print_bytes(value, value_len);
289330300Sjoerg			addlog(">\n");
289430300Sjoerg		}
289530300Sjoerg
289630300Sjoerg		/* Compute reply value. */
289730300Sjoerg		MD5Init(&ctx);
289830300Sjoerg		MD5Update(&ctx, &h->ident, 1);
289930300Sjoerg		MD5Update(&ctx, sp->myauth.secret,
290030300Sjoerg			  sppp_strnlen(sp->myauth.secret, AUTHKEYLEN));
290130300Sjoerg		MD5Update(&ctx, value, value_len);
290230300Sjoerg		MD5Final(digest, &ctx);
290330300Sjoerg		dsize = sizeof digest;
290430300Sjoerg
290530300Sjoerg		sppp_auth_send(&chap, sp, CHAP_RESPONSE, h->ident,
290630300Sjoerg			       sizeof dsize, (const char *)&dsize,
290730300Sjoerg			       sizeof digest, digest,
290830300Sjoerg			       sppp_strnlen(sp->myauth.name, AUTHNAMELEN),
290930300Sjoerg			       sp->myauth.name,
291030300Sjoerg			       0);
291130300Sjoerg		break;
291230300Sjoerg
291330300Sjoerg	case CHAP_SUCCESS:
291430300Sjoerg		if (debug) {
291530300Sjoerg			log(LOG_DEBUG, "%s%d: chap success",
291630300Sjoerg			    ifp->if_name, ifp->if_unit);
291730300Sjoerg			if (len > 4) {
291830300Sjoerg				addlog(": ");
291930300Sjoerg				sppp_print_string((char*)(h + 1), len - 4);
292030300Sjoerg			}
292130300Sjoerg			addlog("\n");
292230300Sjoerg		}
292330300Sjoerg		x = splimp();
292430300Sjoerg		sp->pp_flags &= ~PP_NEEDAUTH;
292530300Sjoerg		if (sp->myauth.proto == PPP_CHAP &&
292632169Sgj		    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) &&
292730300Sjoerg		    (sp->lcp.protos & (1 << IDX_CHAP)) == 0) {
292830300Sjoerg			/*
292930300Sjoerg			 * We are authenticator for CHAP but didn't
293030300Sjoerg			 * complete yet.  Leave it to tlu to proceed
293130300Sjoerg			 * to network phase.
293230300Sjoerg			 */
293330300Sjoerg			splx(x);
293430300Sjoerg			break;
293530300Sjoerg		}
293630300Sjoerg		splx(x);
293730300Sjoerg		sppp_phase_network(sp);
293830300Sjoerg		break;
293930300Sjoerg
294030300Sjoerg	case CHAP_FAILURE:
294130300Sjoerg		if (debug) {
294230300Sjoerg			log(LOG_INFO, "%s%d: chap failure",
294330300Sjoerg			    ifp->if_name, ifp->if_unit);
294430300Sjoerg			if (len > 4) {
294530300Sjoerg				addlog(": ");
294630300Sjoerg				sppp_print_string((char*)(h + 1), len - 4);
294730300Sjoerg			}
294830300Sjoerg			addlog("\n");
294930300Sjoerg		} else
295030300Sjoerg			log(LOG_INFO, "%s%d: chap failure\n",
295130300Sjoerg			    ifp->if_name, ifp->if_unit);
295230300Sjoerg		/* await LCP shutdown by authenticator */
295330300Sjoerg		break;
295430300Sjoerg
295530300Sjoerg	/* response is my authproto */
295630300Sjoerg	case CHAP_RESPONSE:
295730300Sjoerg		value = 1 + (u_char*)(h+1);
295830300Sjoerg		value_len = value[-1];
295930300Sjoerg		name = value + value_len;
296030300Sjoerg		name_len = len - value_len - 5;
296130300Sjoerg		if (name_len < 0) {
296230300Sjoerg			if (debug) {
296330300Sjoerg				log(LOG_DEBUG,
296430300Sjoerg				    "%s%d: chap corrupted response "
296530300Sjoerg				    "<%s id=0x%x len=%d",
296630300Sjoerg				    ifp->if_name, ifp->if_unit,
296730300Sjoerg				    sppp_auth_type_name(PPP_CHAP, h->type),
296830300Sjoerg				    h->ident, ntohs(h->len));
296930300Sjoerg				if (len > 4)
297030300Sjoerg					sppp_print_bytes((u_char*)(h+1), len-4);
297130300Sjoerg				addlog(">\n");
297230300Sjoerg			}
297330300Sjoerg			break;
297430300Sjoerg		}
297530300Sjoerg		if (h->ident != sp->confid[IDX_CHAP]) {
297630300Sjoerg			if (debug)
297730300Sjoerg				log(LOG_DEBUG,
297830300Sjoerg				    "%s%d: chap dropping response for old ID "
297930300Sjoerg				    "(got %d, expected %d)\n",
298030300Sjoerg				    h->ident, sp->confid[IDX_CHAP]);
298130300Sjoerg			break;
298230300Sjoerg		}
298330300Sjoerg		if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)
298430300Sjoerg		    || bcmp(name, sp->hisauth.name, name_len) != 0) {
298530300Sjoerg			log(LOG_INFO, "%s%d: chap response, his name ",
298630300Sjoerg			    ifp->if_name, ifp->if_unit);
298730300Sjoerg			sppp_print_string(name, name_len);
298830300Sjoerg			addlog(" != expected ");
298930300Sjoerg			sppp_print_string(sp->hisauth.name,
299030300Sjoerg					  sppp_strnlen(sp->hisauth.name, AUTHNAMELEN));
299130300Sjoerg			addlog("\n");
299230300Sjoerg		}
299330300Sjoerg		if (debug) {
299430300Sjoerg			log(LOG_DEBUG, "%s%d: chap input(%s) "
299530300Sjoerg			    "<%s id=0x%x len=%d name=",
299630300Sjoerg			    ifp->if_name, ifp->if_unit,
299730300Sjoerg			    sppp_state_name(sp->state[IDX_CHAP]),
299830300Sjoerg			    sppp_auth_type_name(PPP_CHAP, h->type),
299930300Sjoerg			    h->ident, ntohs (h->len));
300030300Sjoerg			sppp_print_string((char*)name, name_len);
300130300Sjoerg			addlog(" value-size=%d value=", value_len);
300230300Sjoerg			sppp_print_bytes(value, value_len);
300330300Sjoerg			addlog(">\n");
300430300Sjoerg		}
300530300Sjoerg		if (value_len != AUTHKEYLEN) {
300630300Sjoerg			if (debug)
300730300Sjoerg				log(LOG_DEBUG,
300830300Sjoerg				    "%s%d: chap bad hash value length: "
300930300Sjoerg				    "%d bytes, should be %d\n",
301030300Sjoerg				    ifp->if_name, ifp->if_unit, value_len,
301130300Sjoerg				    AUTHKEYLEN);
301230300Sjoerg			break;
301330300Sjoerg		}
301430300Sjoerg
301530300Sjoerg		MD5Init(&ctx);
301630300Sjoerg		MD5Update(&ctx, &h->ident, 1);
301730300Sjoerg		MD5Update(&ctx, sp->hisauth.secret,
301830300Sjoerg			  sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN));
301930300Sjoerg		MD5Update(&ctx, sp->myauth.challenge, AUTHKEYLEN);
302030300Sjoerg		MD5Final(digest, &ctx);
302130300Sjoerg
302230300Sjoerg#define FAILMSG "Failed..."
302330300Sjoerg#define SUCCMSG "Welcome!"
302430300Sjoerg
302530300Sjoerg		if (value_len != sizeof digest ||
302630300Sjoerg		    bcmp(digest, value, value_len) != 0) {
302730300Sjoerg			/* action scn, tld */
302830300Sjoerg			sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident,
302930300Sjoerg				       sizeof(FAILMSG) - 1, (u_char *)FAILMSG,
303030300Sjoerg				       0);
303130300Sjoerg			chap.tld(sp);
303230300Sjoerg			break;
303330300Sjoerg		}
303430300Sjoerg		/* action sca, perhaps tlu */
303530300Sjoerg		if (sp->state[IDX_CHAP] == STATE_REQ_SENT ||
303630300Sjoerg		    sp->state[IDX_CHAP] == STATE_OPENED)
303730300Sjoerg			sppp_auth_send(&chap, sp, CHAP_SUCCESS, h->ident,
303830300Sjoerg				       sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG,
303930300Sjoerg				       0);
304030300Sjoerg		if (sp->state[IDX_CHAP] == STATE_REQ_SENT) {
304130300Sjoerg			sppp_cp_change_state(&chap, sp, STATE_OPENED);
304230300Sjoerg			chap.tlu(sp);
304330300Sjoerg		}
304430300Sjoerg		break;
304530300Sjoerg
304630300Sjoerg	default:
304730300Sjoerg		/* Unknown CHAP packet type -- ignore. */
304830300Sjoerg		if (debug) {
304930300Sjoerg			log(LOG_DEBUG, "%s%d: chap unknown input(%s) "
305030300Sjoerg			    "<0x%x id=0x%xh len=%d",
305130300Sjoerg			    ifp->if_name, ifp->if_unit,
305230300Sjoerg			    sppp_state_name(sp->state[IDX_CHAP]),
305330300Sjoerg			    h->type, h->ident, ntohs(h->len));
305430300Sjoerg			if (len > 4)
305530300Sjoerg				sppp_print_bytes((u_char*)(h+1), len-4);
305630300Sjoerg			addlog(">\n");
305730300Sjoerg		}
305830300Sjoerg		break;
305930300Sjoerg
306030300Sjoerg	}
306130300Sjoerg}
306230300Sjoerg
306330300Sjoergstatic void
306430300Sjoergsppp_chap_init(struct sppp *sp)
306530300Sjoerg{
306630300Sjoerg	/* Chap doesn't have STATE_INITIAL at all. */
306730300Sjoerg	sp->state[IDX_CHAP] = STATE_CLOSED;
306830300Sjoerg	sp->fail_counter[IDX_CHAP] = 0;
306930300Sjoerg	callout_handle_init(&sp->ch[IDX_CHAP]);
307030300Sjoerg}
307130300Sjoerg
307230300Sjoergstatic void
307330300Sjoergsppp_chap_open(struct sppp *sp)
307430300Sjoerg{
307530300Sjoerg	if (sp->myauth.proto == PPP_CHAP &&
307630300Sjoerg	    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
307730300Sjoerg		/* we are authenticator for CHAP, start it */
307830300Sjoerg		chap.scr(sp);
307930300Sjoerg		sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
308030300Sjoerg		sppp_cp_change_state(&chap, sp, STATE_REQ_SENT);
308130300Sjoerg	}
308230300Sjoerg	/* nothing to be done if we are peer, await a challenge */
308330300Sjoerg}
308430300Sjoerg
308530300Sjoergstatic void
308630300Sjoergsppp_chap_close(struct sppp *sp)
308730300Sjoerg{
308830300Sjoerg	if (sp->state[IDX_CHAP] != STATE_CLOSED)
308930300Sjoerg		sppp_cp_change_state(&chap, sp, STATE_CLOSED);
309030300Sjoerg}
309130300Sjoerg
309230300Sjoergstatic void
309330300Sjoergsppp_chap_TO(void *cookie)
309430300Sjoerg{
309530300Sjoerg	struct sppp *sp = (struct sppp *)cookie;
309630300Sjoerg	STDDCL;
309730300Sjoerg	int s;
309830300Sjoerg
309930300Sjoerg	s = splimp();
310030300Sjoerg	if (debug)
310130300Sjoerg		log(LOG_DEBUG, "%s%d: chap TO(%s) rst_counter = %d\n",
310230300Sjoerg		    ifp->if_name, ifp->if_unit,
310330300Sjoerg		    sppp_state_name(sp->state[IDX_CHAP]),
310430300Sjoerg		    sp->rst_counter[IDX_CHAP]);
310530300Sjoerg
310630300Sjoerg	if (--sp->rst_counter[IDX_CHAP] < 0)
310730300Sjoerg		/* TO- event */
310830300Sjoerg		switch (sp->state[IDX_CHAP]) {
310930300Sjoerg		case STATE_REQ_SENT:
311030300Sjoerg			chap.tld(sp);
311130300Sjoerg			sppp_cp_change_state(&chap, sp, STATE_CLOSED);
311230300Sjoerg			break;
311330300Sjoerg		}
311430300Sjoerg	else
311530300Sjoerg		/* TO+ (or TO*) event */
311630300Sjoerg		switch (sp->state[IDX_CHAP]) {
311730300Sjoerg		case STATE_OPENED:
311830300Sjoerg			/* TO* event */
311930300Sjoerg			sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
312030300Sjoerg			/* fall through */
312130300Sjoerg		case STATE_REQ_SENT:
312230300Sjoerg			chap.scr(sp);
312330300Sjoerg			/* sppp_cp_change_state() will restart the timer */
312430300Sjoerg			sppp_cp_change_state(&chap, sp, STATE_REQ_SENT);
312530300Sjoerg			break;
312630300Sjoerg		}
312730300Sjoerg
312830300Sjoerg	splx(s);
312930300Sjoerg}
313030300Sjoerg
313130300Sjoergstatic void
313230300Sjoergsppp_chap_tlu(struct sppp *sp)
313330300Sjoerg{
313430300Sjoerg	STDDCL;
313530300Sjoerg	int i, x;
313630300Sjoerg
313730300Sjoerg	sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
313830300Sjoerg
313930300Sjoerg	/*
314030300Sjoerg	 * Some broken CHAP implementations (Conware CoNet, firmware
314130300Sjoerg	 * 4.0.?) don't want to re-authenticate their CHAP once the
314230300Sjoerg	 * initial challenge-response exchange has taken place.
314330300Sjoerg	 * Provide for an option to avoid rechallenges.
314430300Sjoerg	 */
314530300Sjoerg	if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) {
314630300Sjoerg		/*
314730300Sjoerg		 * Compute the re-challenge timeout.  This will yield
314830300Sjoerg		 * a number between 300 and 810 seconds.
314930300Sjoerg		 */
315030300Sjoerg		i = 300 + ((unsigned)(random() & 0xff00) >> 7);
315130300Sjoerg
315230300Sjoerg		sp->ch[IDX_CHAP] = timeout(chap.TO, (void *)sp, i * hz);
315330300Sjoerg	}
315430300Sjoerg
315530300Sjoerg	if (debug) {
315630300Sjoerg		log(LOG_DEBUG,
315730300Sjoerg		    "%s%d: chap %s, ",
315830300Sjoerg		    ifp->if_name, ifp->if_unit,
315930300Sjoerg		    sp->pp_phase == PHASE_NETWORK? "reconfirmed": "tlu");
316030300Sjoerg		if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0)
316130300Sjoerg			addlog("next re-challenge in %d seconds\n", i);
316230300Sjoerg		else
316330300Sjoerg			addlog("re-challenging supressed\n");
316430300Sjoerg	}
316530300Sjoerg
316630300Sjoerg	x = splimp();
316730300Sjoerg	/* indicate to LCP that we need to be closed down */
316830300Sjoerg	sp->lcp.protos |= (1 << IDX_CHAP);
316930300Sjoerg
317030300Sjoerg	if (sp->pp_flags & PP_NEEDAUTH) {
317130300Sjoerg		/*
317230300Sjoerg		 * Remote is authenticator, but his auth proto didn't
317330300Sjoerg		 * complete yet.  Defer the transition to network
317430300Sjoerg		 * phase.
317530300Sjoerg		 */
317630300Sjoerg		splx(x);
317730300Sjoerg		return;
317830300Sjoerg	}
317930300Sjoerg	splx(x);
318030300Sjoerg
318130300Sjoerg	/*
318230300Sjoerg	 * If we are already in phase network, we are done here.  This
318330300Sjoerg	 * is the case if this is a dummy tlu event after a re-challenge.
318430300Sjoerg	 */
318530300Sjoerg	if (sp->pp_phase != PHASE_NETWORK)
318630300Sjoerg		sppp_phase_network(sp);
318730300Sjoerg}
318830300Sjoerg
318930300Sjoergstatic void
319030300Sjoergsppp_chap_tld(struct sppp *sp)
319130300Sjoerg{
319230300Sjoerg	STDDCL;
319330300Sjoerg
319430300Sjoerg	if (debug)
319530300Sjoerg		log(LOG_DEBUG, "%s%d: chap tld\n", ifp->if_name, ifp->if_unit);
319630300Sjoerg	untimeout(chap.TO, (void *)sp, sp->ch[IDX_CHAP]);
319730300Sjoerg	sp->lcp.protos &= ~(1 << IDX_CHAP);
319830300Sjoerg
319930300Sjoerg	lcp.Close(sp);
320030300Sjoerg}
320130300Sjoerg
320230300Sjoergstatic void
320330300Sjoergsppp_chap_scr(struct sppp *sp)
320430300Sjoerg{
320530300Sjoerg	struct timeval tv;
320630300Sjoerg	u_long *ch, seed;
320730300Sjoerg	u_char clen;
320830300Sjoerg
320930300Sjoerg	/* Compute random challenge. */
321030300Sjoerg	ch = (u_long *)sp->myauth.challenge;
321130300Sjoerg	microtime(&tv);
321230300Sjoerg	seed = tv.tv_sec ^ tv.tv_usec;
321330300Sjoerg	ch[0] = seed ^ random();
321430300Sjoerg	ch[1] = seed ^ random();
321530300Sjoerg	ch[2] = seed ^ random();
321630300Sjoerg	ch[3] = seed ^ random();
321730300Sjoerg	clen = AUTHKEYLEN;
321830300Sjoerg
321930300Sjoerg	sp->confid[IDX_CHAP] = ++sp->pp_seq;
322030300Sjoerg
322130300Sjoerg	sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP],
322230300Sjoerg		       sizeof clen, (const char *)&clen,
322330300Sjoerg		       AUTHKEYLEN, sp->myauth.challenge,
322430300Sjoerg		       sppp_strnlen(sp->myauth.name, AUTHNAMELEN),
322530300Sjoerg		       sp->myauth.name,
322630300Sjoerg		       0);
322730300Sjoerg}
322830300Sjoerg/*
322930300Sjoerg *--------------------------------------------------------------------------*
323030300Sjoerg *                                                                          *
323130300Sjoerg *                        The PAP implementation.                           *
323230300Sjoerg *                                                                          *
323330300Sjoerg *--------------------------------------------------------------------------*
323430300Sjoerg */
323530300Sjoerg/*
323630300Sjoerg * For PAP, we need to keep a little state also if we are the peer, not the
323730300Sjoerg * authenticator.  This is since we don't get a request to authenticate, but
323830300Sjoerg * have to repeatedly authenticate ourself until we got a response (or the
323930300Sjoerg * retry counter is expired).
324030300Sjoerg */
324130300Sjoerg
324230300Sjoerg/*
324330300Sjoerg * Handle incoming PAP packets.  */
324430300Sjoergstatic void
324530300Sjoergsppp_pap_input(struct sppp *sp, struct mbuf *m)
324630300Sjoerg{
324730300Sjoerg	STDDCL;
324830300Sjoerg	struct lcp_header *h;
324930300Sjoerg	int len, x;
325030300Sjoerg	u_char *name, *passwd, mlen;
325130300Sjoerg	int name_len, passwd_len;
325230300Sjoerg
325330300Sjoerg	len = m->m_pkthdr.len;
325430300Sjoerg	if (len < 5) {
325530300Sjoerg		if (debug)
325630300Sjoerg			log(LOG_DEBUG,
325730300Sjoerg			    "%s%d: pap invalid packet length: %d bytes\n",
325830300Sjoerg			    ifp->if_name, ifp->if_unit, len);
325930300Sjoerg		return;
326030300Sjoerg	}
326130300Sjoerg	h = mtod (m, struct lcp_header*);
326230300Sjoerg	if (len > ntohs (h->len))
326330300Sjoerg		len = ntohs (h->len);
326430300Sjoerg	switch (h->type) {
326530300Sjoerg	/* PAP request is my authproto */
326630300Sjoerg	case PAP_REQ:
326730300Sjoerg		name = 1 + (u_char*)(h+1);
326830300Sjoerg		name_len = name[-1];
326930300Sjoerg		passwd = name + name_len + 1;
327030300Sjoerg		if (name_len > len - 6 ||
327130300Sjoerg		    (passwd_len = passwd[-1]) > len - 6 - name_len) {
327230300Sjoerg			if (debug) {
327330300Sjoerg				log(LOG_DEBUG, "%s%d: pap corrupted input "
327430300Sjoerg				    "<%s id=0x%x len=%d",
327530300Sjoerg				    ifp->if_name, ifp->if_unit,
327630300Sjoerg				    sppp_auth_type_name(PPP_PAP, h->type),
327730300Sjoerg				    h->ident, ntohs(h->len));
327830300Sjoerg				if (len > 4)
327930300Sjoerg					sppp_print_bytes((u_char*)(h+1), len-4);
328030300Sjoerg				addlog(">\n");
328130300Sjoerg			}
328230300Sjoerg			break;
328330300Sjoerg		}
328430300Sjoerg		if (debug) {
328530300Sjoerg			log(LOG_DEBUG, "%s%d: pap input(%s) "
328630300Sjoerg			    "<%s id=0x%x len=%d name=",
328730300Sjoerg			    ifp->if_name, ifp->if_unit,
328830300Sjoerg			    sppp_state_name(sp->state[IDX_PAP]),
328930300Sjoerg			    sppp_auth_type_name(PPP_PAP, h->type),
329030300Sjoerg			    h->ident, ntohs(h->len));
329130300Sjoerg			sppp_print_string((char*)name, name_len);
329230300Sjoerg			addlog(" passwd=");
329330300Sjoerg			sppp_print_string((char*)passwd, passwd_len);
329430300Sjoerg			addlog(">\n");
329530300Sjoerg		}
329630300Sjoerg		if (name_len > AUTHNAMELEN ||
329730300Sjoerg		    passwd_len > AUTHKEYLEN ||
329830300Sjoerg		    bcmp(name, sp->hisauth.name, name_len) != 0 ||
329930300Sjoerg		    bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) {
330030300Sjoerg			/* action scn, tld */
330130300Sjoerg			mlen = sizeof(FAILMSG) - 1;
330230300Sjoerg			sppp_auth_send(&pap, sp, PAP_NAK, h->ident,
330330300Sjoerg				       sizeof mlen, (const char *)&mlen,
330430300Sjoerg				       sizeof(FAILMSG) - 1, (u_char *)FAILMSG,
330530300Sjoerg				       0);
330630300Sjoerg			pap.tld(sp);
330730300Sjoerg			break;
330830300Sjoerg		}
330930300Sjoerg		/* action sca, perhaps tlu */
331030300Sjoerg		if (sp->state[IDX_PAP] == STATE_REQ_SENT ||
331130300Sjoerg		    sp->state[IDX_PAP] == STATE_OPENED) {
331230300Sjoerg			mlen = sizeof(SUCCMSG) - 1;
331330300Sjoerg			sppp_auth_send(&pap, sp, PAP_ACK, h->ident,
331430300Sjoerg				       sizeof mlen, (const char *)&mlen,
331530300Sjoerg				       sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG,
331630300Sjoerg				       0);
331730300Sjoerg		}
331830300Sjoerg		if (sp->state[IDX_PAP] == STATE_REQ_SENT) {
331930300Sjoerg			sppp_cp_change_state(&pap, sp, STATE_OPENED);
332030300Sjoerg			pap.tlu(sp);
332130300Sjoerg		}
332230300Sjoerg		break;
332330300Sjoerg
332430300Sjoerg	/* ack and nak are his authproto */
332530300Sjoerg	case PAP_ACK:
332630300Sjoerg		untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch);
332730300Sjoerg		if (debug) {
332830300Sjoerg			log(LOG_DEBUG, "%s%d: pap success",
332930300Sjoerg			    ifp->if_name, ifp->if_unit);
333030300Sjoerg			name_len = *((char *)h);
333130300Sjoerg			if (len > 5 && name_len) {
333230300Sjoerg				addlog(": ");
333330300Sjoerg				sppp_print_string((char*)(h+1), name_len);
333430300Sjoerg			}
333530300Sjoerg			addlog("\n");
333630300Sjoerg		}
333730300Sjoerg		x = splimp();
333830300Sjoerg		sp->pp_flags &= ~PP_NEEDAUTH;
333930300Sjoerg		if (sp->myauth.proto == PPP_PAP &&
334032169Sgj		    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) &&
334130300Sjoerg		    (sp->lcp.protos & (1 << IDX_PAP)) == 0) {
334230300Sjoerg			/*
334330300Sjoerg			 * We are authenticator for PAP but didn't
334430300Sjoerg			 * complete yet.  Leave it to tlu to proceed
334530300Sjoerg			 * to network phase.
334630300Sjoerg			 */
334730300Sjoerg			splx(x);
334830300Sjoerg			break;
334930300Sjoerg		}
335030300Sjoerg		splx(x);
335130300Sjoerg		sppp_phase_network(sp);
335230300Sjoerg		break;
335330300Sjoerg
335430300Sjoerg	case PAP_NAK:
335530300Sjoerg		untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch);
335630300Sjoerg		if (debug) {
335730300Sjoerg			log(LOG_INFO, "%s%d: pap failure",
335830300Sjoerg			    ifp->if_name, ifp->if_unit);
335930300Sjoerg			name_len = *((char *)h);
336030300Sjoerg			if (len > 5 && name_len) {
336130300Sjoerg				addlog(": ");
336230300Sjoerg				sppp_print_string((char*)(h+1), name_len);
336330300Sjoerg			}
336430300Sjoerg			addlog("\n");
336530300Sjoerg		} else
336630300Sjoerg			log(LOG_INFO, "%s%d: pap failure\n",
336730300Sjoerg			    ifp->if_name, ifp->if_unit);
336830300Sjoerg		/* await LCP shutdown by authenticator */
336930300Sjoerg		break;
337030300Sjoerg
337130300Sjoerg	default:
337230300Sjoerg		/* Unknown PAP packet type -- ignore. */
337330300Sjoerg		if (debug) {
337430300Sjoerg			log(LOG_DEBUG, "%s%d: pap corrupted input "
337530300Sjoerg			    "<0x%x id=0x%x len=%d",
337630300Sjoerg			    ifp->if_name, ifp->if_unit,
337730300Sjoerg			    h->type, h->ident, ntohs(h->len));
337830300Sjoerg			if (len > 4)
337930300Sjoerg				sppp_print_bytes((u_char*)(h+1), len-4);
338030300Sjoerg			addlog(">\n");
338130300Sjoerg		}
338230300Sjoerg		break;
338330300Sjoerg
338430300Sjoerg	}
338530300Sjoerg}
338630300Sjoerg
338730300Sjoergstatic void
338830300Sjoergsppp_pap_init(struct sppp *sp)
338930300Sjoerg{
339030300Sjoerg	/* PAP doesn't have STATE_INITIAL at all. */
339130300Sjoerg	sp->state[IDX_PAP] = STATE_CLOSED;
339230300Sjoerg	sp->fail_counter[IDX_PAP] = 0;
339330300Sjoerg	callout_handle_init(&sp->ch[IDX_PAP]);
339430300Sjoerg	callout_handle_init(&sp->pap_my_to_ch);
339530300Sjoerg}
339630300Sjoerg
339730300Sjoergstatic void
339830300Sjoergsppp_pap_open(struct sppp *sp)
339930300Sjoerg{
340030300Sjoerg	if (sp->hisauth.proto == PPP_PAP &&
340130300Sjoerg	    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
340230300Sjoerg		/* we are authenticator for PAP, start our timer */
340330300Sjoerg		sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
340430300Sjoerg		sppp_cp_change_state(&pap, sp, STATE_REQ_SENT);
340530300Sjoerg	}
340630300Sjoerg	if (sp->myauth.proto == PPP_PAP) {
340730300Sjoerg		/* we are peer, send a request, and start a timer */
340830300Sjoerg		pap.scr(sp);
340930300Sjoerg		sp->pap_my_to_ch = timeout(sppp_pap_my_TO, (void *)sp,
341030300Sjoerg					   sp->lcp.timeout);
341130300Sjoerg	}
341230300Sjoerg}
341330300Sjoerg
341430300Sjoergstatic void
341530300Sjoergsppp_pap_close(struct sppp *sp)
341630300Sjoerg{
341730300Sjoerg	if (sp->state[IDX_PAP] != STATE_CLOSED)
341830300Sjoerg		sppp_cp_change_state(&pap, sp, STATE_CLOSED);
341930300Sjoerg}
342030300Sjoerg
342130300Sjoerg/*
342230300Sjoerg * That's the timeout routine if we are authenticator.  Since the
342330300Sjoerg * authenticator is basically passive in PAP, we can't do much here.
342430300Sjoerg */
342530300Sjoergstatic void
342630300Sjoergsppp_pap_TO(void *cookie)
342730300Sjoerg{
342830300Sjoerg	struct sppp *sp = (struct sppp *)cookie;
342930300Sjoerg	STDDCL;
343030300Sjoerg	int s;
343130300Sjoerg
343230300Sjoerg	s = splimp();
343330300Sjoerg	if (debug)
343430300Sjoerg		log(LOG_DEBUG, "%s%d: pap TO(%s) rst_counter = %d\n",
343530300Sjoerg		    ifp->if_name, ifp->if_unit,
343630300Sjoerg		    sppp_state_name(sp->state[IDX_PAP]),
343730300Sjoerg		    sp->rst_counter[IDX_PAP]);
343830300Sjoerg
343930300Sjoerg	if (--sp->rst_counter[IDX_PAP] < 0)
344030300Sjoerg		/* TO- event */
344130300Sjoerg		switch (sp->state[IDX_PAP]) {
344230300Sjoerg		case STATE_REQ_SENT:
344330300Sjoerg			pap.tld(sp);
344430300Sjoerg			sppp_cp_change_state(&pap, sp, STATE_CLOSED);
344530300Sjoerg			break;
344630300Sjoerg		}
344730300Sjoerg	else
344830300Sjoerg		/* TO+ event, not very much we could do */
344930300Sjoerg		switch (sp->state[IDX_PAP]) {
345030300Sjoerg		case STATE_REQ_SENT:
345130300Sjoerg			/* sppp_cp_change_state() will restart the timer */
345230300Sjoerg			sppp_cp_change_state(&pap, sp, STATE_REQ_SENT);
345330300Sjoerg			break;
345430300Sjoerg		}
345530300Sjoerg
345630300Sjoerg	splx(s);
345730300Sjoerg}
345830300Sjoerg
345930300Sjoerg/*
346030300Sjoerg * That's the timeout handler if we are peer.  Since the peer is active,
346130300Sjoerg * we need to retransmit our PAP request since it is apparently lost.
346230300Sjoerg * XXX We should impose a max counter.
346330300Sjoerg */
346430300Sjoergstatic void
346530300Sjoergsppp_pap_my_TO(void *cookie)
346630300Sjoerg{
346730300Sjoerg	struct sppp *sp = (struct sppp *)cookie;
346830300Sjoerg	STDDCL;
346930300Sjoerg
347030300Sjoerg	if (debug)
347130300Sjoerg		log(LOG_DEBUG, "%s%d: pap peer TO\n",
347230300Sjoerg		    ifp->if_name, ifp->if_unit);
347330300Sjoerg
347430300Sjoerg	pap.scr(sp);
347530300Sjoerg}
347630300Sjoerg
347730300Sjoergstatic void
347830300Sjoergsppp_pap_tlu(struct sppp *sp)
347930300Sjoerg{
348030300Sjoerg	STDDCL;
348130300Sjoerg	int x;
348230300Sjoerg
348330300Sjoerg	sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
348430300Sjoerg
348530300Sjoerg	if (debug)
348630300Sjoerg		log(LOG_DEBUG, "%s%d: %s tlu\n",
348730300Sjoerg		    ifp->if_name, ifp->if_unit, pap.name);
348830300Sjoerg
348930300Sjoerg	x = splimp();
349030300Sjoerg	/* indicate to LCP that we need to be closed down */
349130300Sjoerg	sp->lcp.protos |= (1 << IDX_PAP);
349230300Sjoerg
349330300Sjoerg	if (sp->pp_flags & PP_NEEDAUTH) {
349430300Sjoerg		/*
349530300Sjoerg		 * Remote is authenticator, but his auth proto didn't
349630300Sjoerg		 * complete yet.  Defer the transition to network
349730300Sjoerg		 * phase.
349830300Sjoerg		 */
349930300Sjoerg		splx(x);
350030300Sjoerg		return;
350130300Sjoerg	}
350230300Sjoerg	splx(x);
350330300Sjoerg	sppp_phase_network(sp);
350430300Sjoerg}
350530300Sjoerg
350630300Sjoergstatic void
350730300Sjoergsppp_pap_tld(struct sppp *sp)
350830300Sjoerg{
350930300Sjoerg	STDDCL;
351030300Sjoerg
351130300Sjoerg	if (debug)
351230300Sjoerg		log(LOG_DEBUG, "%s%d: pap tld\n", ifp->if_name, ifp->if_unit);
351330300Sjoerg	untimeout(pap.TO, (void *)sp, sp->ch[IDX_PAP]);
351430300Sjoerg	untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch);
351530300Sjoerg	sp->lcp.protos &= ~(1 << IDX_PAP);
351630300Sjoerg
351730300Sjoerg	lcp.Close(sp);
351830300Sjoerg}
351930300Sjoerg
352030300Sjoergstatic void
352130300Sjoergsppp_pap_scr(struct sppp *sp)
352230300Sjoerg{
352330300Sjoerg	STDDCL;
352430300Sjoerg	u_char idlen, pwdlen;
352530300Sjoerg
352630300Sjoerg	sp->confid[IDX_PAP] = ++sp->pp_seq;
352730300Sjoerg	pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN);
352830300Sjoerg	idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN);
352930300Sjoerg
353030300Sjoerg	sppp_auth_send(&pap, sp, PAP_REQ, sp->confid[IDX_PAP],
353130300Sjoerg		       sizeof idlen, (const char *)&idlen,
353230300Sjoerg		       (unsigned)idlen, sp->myauth.name,
353330300Sjoerg		       sizeof pwdlen, (const char *)&pwdlen,
353430300Sjoerg		       (unsigned)pwdlen, sp->myauth.secret,
353530300Sjoerg		       0);
353630300Sjoerg}
353730300Sjoerg/*
353825944Sjoerg * Random miscellaneous functions.
353925944Sjoerg */
354025944Sjoerg
35414910Swollman/*
354230300Sjoerg * Send a PAP or CHAP proto packet.
354330300Sjoerg *
354430300Sjoerg * Varadic function, each of the elements for the ellipsis is of type
354530300Sjoerg * ``unsigned mlen, const u_char *msg''.  Processing will stop iff
354630300Sjoerg * mlen == 0.
354730300Sjoerg */
354830300Sjoerg
354930300Sjoergstatic void
355030300Sjoergsppp_auth_send(const struct cp *cp, struct sppp *sp, u_char type, u_char id,
355130300Sjoerg	       ...)
355230300Sjoerg{
355330300Sjoerg	STDDCL;
355430300Sjoerg	struct ppp_header *h;
355530300Sjoerg	struct lcp_header *lh;
355630300Sjoerg	struct mbuf *m;
355730300Sjoerg	u_char *p;
355830300Sjoerg	int len;
355930300Sjoerg	unsigned mlen;
356030300Sjoerg	const char *msg;
356130300Sjoerg	va_list ap;
356230300Sjoerg
356330300Sjoerg	MGETHDR (m, M_DONTWAIT, MT_DATA);
356430300Sjoerg	if (! m)
356530300Sjoerg		return;
356630300Sjoerg	m->m_pkthdr.rcvif = 0;
356730300Sjoerg
356830300Sjoerg	h = mtod (m, struct ppp_header*);
356930300Sjoerg	h->address = PPP_ALLSTATIONS;		/* broadcast address */
357030300Sjoerg	h->control = PPP_UI;			/* Unnumbered Info */
357130300Sjoerg	h->protocol = htons(cp->proto);
357230300Sjoerg
357330300Sjoerg	lh = (struct lcp_header*)(h + 1);
357430300Sjoerg	lh->type = type;
357530300Sjoerg	lh->ident = id;
357630300Sjoerg	p = (u_char*) (lh+1);
357730300Sjoerg
357830300Sjoerg	va_start(ap, id);
357930300Sjoerg	len = 0;
358030300Sjoerg
358130300Sjoerg	while ((mlen = va_arg(ap, unsigned)) != 0) {
358230300Sjoerg		msg = va_arg(ap, const char *);
358330300Sjoerg		len += mlen;
358430300Sjoerg		if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) {
358530300Sjoerg			va_end(ap);
358630300Sjoerg			m_freem(m);
358730300Sjoerg			return;
358830300Sjoerg		}
358930300Sjoerg
359030300Sjoerg		bcopy(msg, p, mlen);
359130300Sjoerg		p += mlen;
359230300Sjoerg	}
359330300Sjoerg	va_end(ap);
359430300Sjoerg
359530300Sjoerg	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
359630300Sjoerg	lh->len = htons (LCP_HEADER_LEN + len);
359730300Sjoerg
359830300Sjoerg	if (debug) {
359930300Sjoerg		log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d",
360030300Sjoerg		    ifp->if_name, ifp->if_unit, cp->name,
360130300Sjoerg		    sppp_auth_type_name(cp->proto, lh->type),
360230300Sjoerg		    lh->ident, ntohs(lh->len));
360330300Sjoerg		if (len)
360430300Sjoerg			sppp_print_bytes((u_char*) (lh+1), len);
360530300Sjoerg		addlog(">\n");
360630300Sjoerg	}
360730300Sjoerg	if (IF_QFULL (&sp->pp_cpq)) {
360830300Sjoerg		IF_DROP (&sp->pp_fastq);
360930300Sjoerg		IF_DROP (&ifp->if_snd);
361030300Sjoerg		m_freem (m);
361130300Sjoerg		++ifp->if_oerrors;
361230300Sjoerg	} else
361330300Sjoerg		IF_ENQUEUE (&sp->pp_cpq, m);
361430300Sjoerg	if (! (ifp->if_flags & IFF_OACTIVE))
361530300Sjoerg		(*ifp->if_start) (ifp);
361630300Sjoerg	ifp->if_obytes += m->m_pkthdr.len + 3;
361730300Sjoerg}
361830300Sjoerg
361930300Sjoerg/*
362025944Sjoerg * Flush interface queue.
36214910Swollman */
362212820Sphkstatic void
362325944Sjoergsppp_qflush(struct ifqueue *ifq)
36244910Swollman{
362525944Sjoerg	struct mbuf *m, *n;
36264910Swollman
362725944Sjoerg	n = ifq->ifq_head;
362825944Sjoerg	while ((m = n)) {
362925944Sjoerg		n = m->m_act;
363025944Sjoerg		m_freem (m);
363111189Sjkh	}
363225944Sjoerg	ifq->ifq_head = 0;
363325944Sjoerg	ifq->ifq_tail = 0;
363425944Sjoerg	ifq->ifq_len = 0;
363525944Sjoerg}
363625944Sjoerg
363725944Sjoerg/*
363825944Sjoerg * Send keepalive packets, every 10 seconds.
363925944Sjoerg */
364025944Sjoergstatic void
364125944Sjoergsppp_keepalive(void *dummy)
364225944Sjoerg{
364325944Sjoerg	struct sppp *sp;
364425944Sjoerg	int s;
364525944Sjoerg
364625944Sjoerg	s = splimp();
364725944Sjoerg	for (sp=spppq; sp; sp=sp->pp_next) {
364825944Sjoerg		struct ifnet *ifp = &sp->pp_if;
364925944Sjoerg
365025944Sjoerg		/* Keepalive mode disabled or channel down? */
365125944Sjoerg		if (! (sp->pp_flags & PP_KEEPALIVE) ||
365225944Sjoerg		    ! (ifp->if_flags & IFF_RUNNING))
365325944Sjoerg			continue;
365425944Sjoerg
365525944Sjoerg		/* No keepalive in PPP mode if LCP not opened yet. */
365625944Sjoerg		if (! (sp->pp_flags & PP_CISCO) &&
365725944Sjoerg		    sp->pp_phase < PHASE_AUTHENTICATE)
365825944Sjoerg			continue;
365925944Sjoerg
366025944Sjoerg		if (sp->pp_alivecnt == MAXALIVECNT) {
366125944Sjoerg			/* No keepalive packets got.  Stop the interface. */
366225944Sjoerg			printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
366325944Sjoerg			if_down (ifp);
366426018Sjoerg			sppp_qflush (&sp->pp_cpq);
366525944Sjoerg			if (! (sp->pp_flags & PP_CISCO)) {
366625944Sjoerg				/* XXX */
366725944Sjoerg				/* Shut down the PPP link. */
366825944Sjoerg				lcp.Down(sp);
366925944Sjoerg				/* Initiate negotiation. XXX */
367025944Sjoerg				lcp.Up(sp);
367125944Sjoerg			}
36724910Swollman		}
367325944Sjoerg		if (sp->pp_alivecnt <= MAXALIVECNT)
367425944Sjoerg			++sp->pp_alivecnt;
367525944Sjoerg		if (sp->pp_flags & PP_CISCO)
367625944Sjoerg			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
367725944Sjoerg				sp->pp_rseq);
367825944Sjoerg		else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
367925944Sjoerg			long nmagic = htonl (sp->lcp.magic);
368025944Sjoerg			sp->lcp.echoid = ++sp->pp_seq;
368125944Sjoerg			sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
368225944Sjoerg				sp->lcp.echoid, 4, &nmagic);
368325944Sjoerg		}
36844910Swollman	}
368525944Sjoerg	splx(s);
368629681Sgibbs	keepalive_ch = timeout(sppp_keepalive, 0, hz * 10);
36874910Swollman}
36884910Swollman
368925944Sjoerg/*
369025944Sjoerg * Get both IP addresses.
369125944Sjoerg */
369225944Sjoergstatic void
369330300Sjoergsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask)
369425944Sjoerg{
369525944Sjoerg	struct ifnet *ifp = &sp->pp_if;
369625944Sjoerg	struct ifaddr *ifa;
369730300Sjoerg	struct sockaddr_in *si, *sm;
369825944Sjoerg	u_long ssrc, ddst;
369925944Sjoerg
370025944Sjoerg	ssrc = ddst = 0L;
370125944Sjoerg	/*
370225944Sjoerg	 * Pick the first AF_INET address from the list,
370325944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
370425944Sjoerg	 */
370525944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
370630300Sjoerg	     ifa;
370725944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
370825944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
370925944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
371030300Sjoerg			sm = (struct sockaddr_in *)ifa->ifa_netmask;
371125944Sjoerg			if (si)
371225944Sjoerg				break;
371325944Sjoerg		}
371425944Sjoerg	if (ifa) {
371530300Sjoerg		if (si && si->sin_addr.s_addr) {
371625944Sjoerg			ssrc = si->sin_addr.s_addr;
371730300Sjoerg			if (srcmask)
371830300Sjoerg				*srcmask = ntohl(sm->sin_addr.s_addr);
371930300Sjoerg		}
372025944Sjoerg
372125944Sjoerg		si = (struct sockaddr_in *)ifa->ifa_dstaddr;
372225944Sjoerg		if (si && si->sin_addr.s_addr)
372325944Sjoerg			ddst = si->sin_addr.s_addr;
372425944Sjoerg	}
372525944Sjoerg
372625944Sjoerg	if (dst) *dst = ntohl(ddst);
372725944Sjoerg	if (src) *src = ntohl(ssrc);
372825944Sjoerg}
372925944Sjoerg
373025944Sjoerg/*
373125944Sjoerg * Set my IP address.  Must be called at splimp.
373225944Sjoerg */
373325944Sjoergstatic void
373425944Sjoergsppp_set_ip_addr(struct sppp *sp, u_long src)
373525944Sjoerg{
373625944Sjoerg	struct ifnet *ifp = &sp->pp_if;
373725944Sjoerg	struct ifaddr *ifa;
373825944Sjoerg	struct sockaddr_in *si;
373925944Sjoerg	u_long ssrc, ddst;
374025944Sjoerg
374125944Sjoerg	/*
374225944Sjoerg	 * Pick the first AF_INET address from the list,
374325944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
374425944Sjoerg	 */
374525944Sjoerg	for (ifa = ifp->if_addrhead.tqh_first, si = 0;
374630300Sjoerg	     ifa;
374725944Sjoerg	     ifa = ifa->ifa_link.tqe_next)
374825944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
374925944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
375025944Sjoerg			if (si)
375125944Sjoerg				break;
375225944Sjoerg		}
375325944Sjoerg	if (ifa && si)
375425944Sjoerg		si->sin_addr.s_addr = htonl(src);
375525944Sjoerg}
375625944Sjoerg
375730300Sjoergstatic int
375830300Sjoergsppp_params(struct sppp *sp, int cmd, void *data)
375930300Sjoerg{
376030300Sjoerg	int subcmd;
376130300Sjoerg	struct ifreq *ifr = (struct ifreq *)data;
376230300Sjoerg	struct spppreq spr;
376330300Sjoerg
376430300Sjoerg	/*
376530300Sjoerg	 * ifr->ifr_data is supposed to point to a struct spppreq.
376630300Sjoerg	 * Check the cmd word first before attempting to fetch all the
376730300Sjoerg	 * data.
376830300Sjoerg	 */
376930300Sjoerg	if ((subcmd = fuword(ifr->ifr_data)) == -1)
377030300Sjoerg		return EFAULT;
377130300Sjoerg
377230300Sjoerg	if (copyin((caddr_t)ifr->ifr_data, &spr, sizeof spr) != 0)
377330300Sjoerg		return EFAULT;
377430300Sjoerg
377530300Sjoerg	switch (subcmd) {
377630300Sjoerg	case SPPPIOGDEFS:
377730300Sjoerg		if (cmd != SIOCGIFGENERIC)
377830300Sjoerg			return EINVAL;
377930300Sjoerg		/*
378030300Sjoerg		 * We copy over the entire current state, but clean
378130300Sjoerg		 * out some of the stuff we don't wanna pass up.
378230300Sjoerg		 * Remember, SIOCGIFGENERIC is unprotected, and can be
378330300Sjoerg		 * called by any user.  No need to ever get PAP or
378430300Sjoerg		 * CHAP secrets back to userland anyway.
378530300Sjoerg		 */
378630300Sjoerg		bcopy(sp, &spr.defs, sizeof(struct sppp));
378730300Sjoerg		bzero(spr.defs.myauth.secret, AUTHKEYLEN);
378830300Sjoerg		bzero(spr.defs.myauth.challenge, AUTHKEYLEN);
378930300Sjoerg		bzero(spr.defs.hisauth.secret, AUTHKEYLEN);
379030300Sjoerg		bzero(spr.defs.hisauth.challenge, AUTHKEYLEN);
379130300Sjoerg		return copyout(&spr, (caddr_t)ifr->ifr_data, sizeof spr);
379230300Sjoerg
379330300Sjoerg	case SPPPIOSDEFS:
379430300Sjoerg		if (cmd != SIOCSIFGENERIC)
379530300Sjoerg			return EINVAL;
379630300Sjoerg		/*
379730300Sjoerg		 * We have a very specific idea of which fields we allow
379830300Sjoerg		 * being passed back from userland, so to not clobber our
379930300Sjoerg		 * current state.  For one, we only allow setting
380030300Sjoerg		 * anything if LCP is in dead phase.  Once the LCP
380130300Sjoerg		 * negotiations started, the authentication settings must
380230300Sjoerg		 * not be changed again.  (The administrator can force an
380330300Sjoerg		 * ifconfig down in order to get LCP back into dead
380430300Sjoerg		 * phase.)
380530300Sjoerg		 *
380630300Sjoerg		 * Also, we only allow for authentication parameters to be
380730300Sjoerg		 * specified.
380830300Sjoerg		 *
380930300Sjoerg		 * XXX Should allow to set or clear pp_flags.
381030300Sjoerg		 *
381130300Sjoerg		 * Finally, if the respective authentication protocol to
381230300Sjoerg		 * be used is set differently than 0, but the secret is
381330300Sjoerg		 * passed as all zeros, we don't trash the existing secret.
381430300Sjoerg		 * This allows an administrator to change the system name
381530300Sjoerg		 * only without clobbering the secret (which he didn't get
381630300Sjoerg		 * back in a previous SPPPIOGDEFS call).  However, the
381730300Sjoerg		 * secrets are cleared if the authentication protocol is
381830300Sjoerg		 * reset to 0.
381930300Sjoerg		 */
382030300Sjoerg		if (sp->pp_phase != PHASE_DEAD)
382130300Sjoerg			return EBUSY;
382230300Sjoerg
382330300Sjoerg		if ((spr.defs.myauth.proto != 0 && spr.defs.myauth.proto != PPP_PAP &&
382430300Sjoerg		     spr.defs.myauth.proto != PPP_CHAP) ||
382530300Sjoerg		    (spr.defs.hisauth.proto != 0 && spr.defs.hisauth.proto != PPP_PAP &&
382630300Sjoerg		     spr.defs.hisauth.proto != PPP_CHAP))
382730300Sjoerg			return EINVAL;
382830300Sjoerg
382930300Sjoerg		if (spr.defs.myauth.proto == 0)
383030300Sjoerg			/* resetting myauth */
383130300Sjoerg			bzero(&sp->myauth, sizeof sp->myauth);
383230300Sjoerg		else {
383330300Sjoerg			/* setting/changing myauth */
383430300Sjoerg			sp->myauth.proto = spr.defs.myauth.proto;
383530300Sjoerg			bcopy(spr.defs.myauth.name, sp->myauth.name, AUTHNAMELEN);
383630300Sjoerg			if (spr.defs.myauth.secret[0] != '\0')
383730300Sjoerg				bcopy(spr.defs.myauth.secret, sp->myauth.secret,
383830300Sjoerg				      AUTHKEYLEN);
383930300Sjoerg		}
384030300Sjoerg		if (spr.defs.hisauth.proto == 0)
384130300Sjoerg			/* resetting hisauth */
384230300Sjoerg			bzero(&sp->hisauth, sizeof sp->hisauth);
384330300Sjoerg		else {
384430300Sjoerg			/* setting/changing hisauth */
384530300Sjoerg			sp->hisauth.proto = spr.defs.hisauth.proto;
384630300Sjoerg			sp->hisauth.flags = spr.defs.hisauth.flags;
384730300Sjoerg			bcopy(spr.defs.hisauth.name, sp->hisauth.name, AUTHNAMELEN);
384830300Sjoerg			if (spr.defs.hisauth.secret[0] != '\0')
384930300Sjoerg				bcopy(spr.defs.hisauth.secret, sp->hisauth.secret,
385030300Sjoerg				      AUTHKEYLEN);
385130300Sjoerg		}
385230300Sjoerg		break;
385330300Sjoerg
385430300Sjoerg	default:
385530300Sjoerg		return EINVAL;
385630300Sjoerg	}
385730300Sjoerg
385830300Sjoerg	return 0;
385930300Sjoerg}
386030300Sjoerg
386130300Sjoergstatic void
386230300Sjoergsppp_phase_network(struct sppp *sp)
386330300Sjoerg{
386430300Sjoerg	struct ifnet *ifp = &sp->pp_if;
386530300Sjoerg	int i;
386630300Sjoerg	u_long mask;
386730300Sjoerg
386830300Sjoerg	sp->pp_phase = PHASE_NETWORK;
386930300Sjoerg
387030300Sjoerg	log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit,
387130300Sjoerg	    sppp_phase_name(sp->pp_phase));
387230300Sjoerg
387330300Sjoerg	/* Notify NCPs now. */
387430300Sjoerg	for (i = 0; i < IDX_COUNT; i++)
387530300Sjoerg		if ((cps[i])->flags & CP_NCP)
387630300Sjoerg			(cps[i])->Open(sp);
387730300Sjoerg
387830300Sjoerg	/* Send Up events to all NCPs. */
387930300Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
388030300Sjoerg		if (sp->lcp.protos & mask && ((cps[i])->flags & CP_NCP))
388130300Sjoerg			(cps[i])->Up(sp);
388230300Sjoerg
388330300Sjoerg	/* if no NCP is starting, all this was in vain, close down */
388430300Sjoerg	sppp_lcp_check_and_close(sp);
388530300Sjoerg}
388630300Sjoerg
388730300Sjoerg
388825706Sjoergstatic const char *
388925944Sjoergsppp_cp_type_name(u_char type)
38904910Swollman{
389130300Sjoerg	static char buf[12];
38924910Swollman	switch (type) {
389330300Sjoerg	case CONF_REQ:   return "conf-req";
389430300Sjoerg	case CONF_ACK:   return "conf-ack";
389530300Sjoerg	case CONF_NAK:   return "conf-nak";
389630300Sjoerg	case CONF_REJ:   return "conf-rej";
389730300Sjoerg	case TERM_REQ:   return "term-req";
389830300Sjoerg	case TERM_ACK:   return "term-ack";
389930300Sjoerg	case CODE_REJ:   return "code-rej";
390030300Sjoerg	case PROTO_REJ:  return "proto-rej";
390130300Sjoerg	case ECHO_REQ:   return "echo-req";
390230300Sjoerg	case ECHO_REPLY: return "echo-reply";
390330300Sjoerg	case DISC_REQ:   return "discard-req";
39044910Swollman	}
390525706Sjoerg	sprintf (buf, "0x%x", type);
390630300Sjoerg	return buf;
39074910Swollman}
39084910Swollman
390925706Sjoergstatic const char *
391030300Sjoergsppp_auth_type_name(u_short proto, u_char type)
391130300Sjoerg{
391230300Sjoerg	static char buf[12];
391330300Sjoerg	switch (proto) {
391430300Sjoerg	case PPP_CHAP:
391530300Sjoerg		switch (type) {
391630300Sjoerg		case CHAP_CHALLENGE:	return "challenge";
391730300Sjoerg		case CHAP_RESPONSE:	return "response";
391830300Sjoerg		case CHAP_SUCCESS:	return "success";
391930300Sjoerg		case CHAP_FAILURE:	return "failure";
392030300Sjoerg		}
392130300Sjoerg	case PPP_PAP:
392230300Sjoerg		switch (type) {
392330300Sjoerg		case PAP_REQ:		return "req";
392430300Sjoerg		case PAP_ACK:		return "ack";
392530300Sjoerg		case PAP_NAK:		return "nak";
392630300Sjoerg		}
392730300Sjoerg	}
392830300Sjoerg	sprintf (buf, "0x%x", type);
392930300Sjoerg	return buf;
393030300Sjoerg}
393130300Sjoerg
393230300Sjoergstatic const char *
393325944Sjoergsppp_lcp_opt_name(u_char opt)
39344910Swollman{
393530300Sjoerg	static char buf[12];
393625944Sjoerg	switch (opt) {
393730300Sjoerg	case LCP_OPT_MRU:		return "mru";
393830300Sjoerg	case LCP_OPT_ASYNC_MAP:		return "async-map";
393930300Sjoerg	case LCP_OPT_AUTH_PROTO:	return "auth-proto";
394030300Sjoerg	case LCP_OPT_QUAL_PROTO:	return "qual-proto";
394130300Sjoerg	case LCP_OPT_MAGIC:		return "magic";
394230300Sjoerg	case LCP_OPT_PROTO_COMP:	return "proto-comp";
394330300Sjoerg	case LCP_OPT_ADDR_COMP:		return "addr-comp";
39444910Swollman	}
394525944Sjoerg	sprintf (buf, "0x%x", opt);
394630300Sjoerg	return buf;
39474910Swollman}
39484910Swollman
394925944Sjoergstatic const char *
395025944Sjoergsppp_ipcp_opt_name(u_char opt)
395125944Sjoerg{
395230300Sjoerg	static char buf[12];
395325944Sjoerg	switch (opt) {
395430300Sjoerg	case IPCP_OPT_ADDRESSES:	return "addresses";
395530300Sjoerg	case IPCP_OPT_COMPRESSION:	return "compression";
395630300Sjoerg	case IPCP_OPT_ADDRESS:		return "address";
395725944Sjoerg	}
395825944Sjoerg	sprintf (buf, "0x%x", opt);
395930300Sjoerg	return buf;
396025944Sjoerg}
396125944Sjoerg
396225944Sjoergstatic const char *
396325944Sjoergsppp_state_name(int state)
396425944Sjoerg{
396525944Sjoerg	switch (state) {
396625944Sjoerg	case STATE_INITIAL:	return "initial";
396725944Sjoerg	case STATE_STARTING:	return "starting";
396825944Sjoerg	case STATE_CLOSED:	return "closed";
396925944Sjoerg	case STATE_STOPPED:	return "stopped";
397025944Sjoerg	case STATE_CLOSING:	return "closing";
397125944Sjoerg	case STATE_STOPPING:	return "stopping";
397225944Sjoerg	case STATE_REQ_SENT:	return "req-sent";
397325944Sjoerg	case STATE_ACK_RCVD:	return "ack-rcvd";
397425944Sjoerg	case STATE_ACK_SENT:	return "ack-sent";
397525944Sjoerg	case STATE_OPENED:	return "opened";
397625944Sjoerg	}
397725944Sjoerg	return "illegal";
397825944Sjoerg}
397925944Sjoerg
398025944Sjoergstatic const char *
398125944Sjoergsppp_phase_name(enum ppp_phase phase)
398225944Sjoerg{
398325944Sjoerg	switch (phase) {
398425944Sjoerg	case PHASE_DEAD:	return "dead";
398525944Sjoerg	case PHASE_ESTABLISH:	return "establish";
398625944Sjoerg	case PHASE_TERMINATE:	return "terminate";
398725944Sjoerg	case PHASE_AUTHENTICATE: return "authenticate";
398825944Sjoerg	case PHASE_NETWORK:	return "network";
398925944Sjoerg	}
399025944Sjoerg	return "illegal";
399125944Sjoerg}
399225944Sjoerg
399325944Sjoergstatic const char *
399425944Sjoergsppp_proto_name(u_short proto)
399525944Sjoerg{
399625944Sjoerg	static char buf[12];
399725944Sjoerg	switch (proto) {
399825944Sjoerg	case PPP_LCP:	return "lcp";
399925944Sjoerg	case PPP_IPCP:	return "ipcp";
400030300Sjoerg	case PPP_PAP:	return "pap";
400130300Sjoerg	case PPP_CHAP:	return "chap";
400225944Sjoerg	}
400325944Sjoerg	sprintf(buf, "0x%x", (unsigned)proto);
400425944Sjoerg	return buf;
400525944Sjoerg}
400625944Sjoerg
400712820Sphkstatic void
400830300Sjoergsppp_print_bytes(const u_char *p, u_short len)
40094910Swollman{
401025706Sjoerg	addlog(" %x", *p++);
40114910Swollman	while (--len > 0)
401225706Sjoerg		addlog("-%x", *p++);
40134910Swollman}
401425944Sjoerg
401530300Sjoergstatic void
401630300Sjoergsppp_print_string(const char *p, u_short len)
401730300Sjoerg{
401830300Sjoerg	u_char c;
401930300Sjoerg
402030300Sjoerg	while (len-- > 0) {
402130300Sjoerg		c = *p++;
402230300Sjoerg		/*
402330300Sjoerg		 * Print only ASCII chars directly.  RFC 1994 recommends
402430300Sjoerg		 * using only them, but we don't rely on it.  */
402530300Sjoerg		if (c < ' ' || c > '~')
402630300Sjoerg			addlog("\\x%x", c);
402730300Sjoerg		else
402830300Sjoerg			addlog("%c", c);
402930300Sjoerg	}
403030300Sjoerg}
403130300Sjoerg
403230300Sjoergstatic const char *
403330300Sjoergsppp_dotted_quad(u_long addr)
403430300Sjoerg{
403530300Sjoerg	static char s[16];
403630300Sjoerg	sprintf(s, "%d.%d.%d.%d",
403730300Sjoerg		(addr >> 24) & 0xff,
403830300Sjoerg		(addr >> 16) & 0xff,
403930300Sjoerg		(addr >> 8) & 0xff,
404030300Sjoerg		addr & 0xff);
404130300Sjoerg	return s;
404230300Sjoerg}
404330300Sjoerg
404430300Sjoergstatic int
404530300Sjoergsppp_strnlen(u_char *p, int max)
404630300Sjoerg{
404730300Sjoerg	int len;
404830300Sjoerg
404930300Sjoerg	for (len = 0; len < max && *p; ++p)
405030300Sjoerg		++len;
405130300Sjoerg	return len;
405230300Sjoerg}
405330300Sjoerg
405430300Sjoerg/* a dummy, used to drop uninteresting events */
405530300Sjoergstatic void
405630300Sjoergsppp_null(struct sppp *unused)
405730300Sjoerg{
405830300Sjoerg	/* do just nothing */
405930300Sjoerg}
406025944Sjoerg/*
406125944Sjoerg * This file is large.  Tell emacs to highlight it nevertheless.
406225944Sjoerg *
406325944Sjoerg * Local Variables:
406430300Sjoerg * hilit-auto-highlight-maxout: 120000
406525944Sjoerg * End:
406625944Sjoerg */
4067