14910Swollman/*
2139365Srik * Synchronous PPP/Cisco/Frame Relay link level subroutines.
34910Swollman * Keepalive protocol implemented in both Cisco and PPP modes.
4139823Simp */
5139823Simp/*-
6139365Srik * Copyright (C) 1994-2000 Cronyx Engineering.
725944Sjoerg * Author: Serge Vakulenko, <vak@cronyx.ru>
84910Swollman *
925944Sjoerg * Heavily revamped to conform to RFC 1661.
1088534Sjoerg * Copyright (C) 1997, 2001 Joerg Wunsch.
1125944Sjoerg *
124910Swollman * This software is distributed with NO WARRANTIES, not even the implied
134910Swollman * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
144910Swollman *
154910Swollman * Authors grant any other persons or organisations permission to use
164910Swollman * or modify this software as long as this message is kept with the software,
174910Swollman * all derivative works or modified versions.
184910Swollman *
1930300Sjoerg * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997
2016288Sgpalmer *
2150477Speter * $FreeBSD: stable/11/sys/net/if_spppsubr.c 352481 2019-09-18 07:32:15Z hselasky $
224910Swollman */
234910Swollman
2440008Sjoerg#include <sys/param.h>
2540008Sjoerg
2632350Seivind#include "opt_inet.h"
2754263Sshin#include "opt_inet6.h"
2831742Seivind
294952Sbde#include <sys/systm.h>
304952Sbde#include <sys/kernel.h>
31286001Sae#include <sys/lock.h>
3270199Sjhay#include <sys/module.h>
33286001Sae#include <sys/rmlock.h>
3424204Sbde#include <sys/sockio.h>
354910Swollman#include <sys/socket.h>
3625706Sjoerg#include <sys/syslog.h>
3759604Sobrien#include <sys/random.h>
3829024Sbde#include <sys/malloc.h>
394910Swollman#include <sys/mbuf.h>
4040008Sjoerg
4130300Sjoerg#include <sys/md5.h>
424910Swollman
434910Swollman#include <net/if.h>
44257176Sglebius#include <net/if_var.h>
454910Swollman#include <net/netisr.h>
464910Swollman#include <net/if_types.h>
4742104Sphk#include <net/route.h>
48196019Srwatson#include <net/vnet.h>
4988534Sjoerg#include <netinet/in.h>
5088534Sjoerg#include <netinet/in_systm.h>
5188534Sjoerg#include <netinet/ip.h>
5288534Sjoerg#include <net/slcompress.h>
534910Swollman
5430300Sjoerg#include <machine/stdarg.h>
5530300Sjoerg
564910Swollman#include <netinet/in_var.h>
5788705Sjoerg
5888705Sjoerg#ifdef INET
594910Swollman#include <netinet/ip.h>
604910Swollman#include <netinet/tcp.h>
614910Swollman#endif
624910Swollman
63148385Sume#ifdef INET6
64148385Sume#include <netinet6/scope6_var.h>
65148385Sume#endif
66148385Sume
67182121Simp#include <netinet/if_ether.h>
6888705Sjoerg
694910Swollman#include <net/if_sppp.h>
704910Swollman
71182121Simp#define IOCTL_CMD_T	u_long
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 */
9745152Sphk#define IFF_CISCO	IFF_LINK2	/* auto-dial on output */
9825944Sjoerg
9930300Sjoerg#define PPP_ALLSTATIONS 0xff		/* All-Stations broadcast address */
10030300Sjoerg#define PPP_UI		0x03		/* Unnumbered Information */
10130300Sjoerg#define PPP_IP		0x0021		/* Internet Protocol */
10230300Sjoerg#define PPP_ISO		0x0023		/* ISO OSI Protocol */
10330300Sjoerg#define PPP_XNS		0x0025		/* Xerox NS Protocol */
10430300Sjoerg#define PPP_IPX		0x002b		/* Novell IPX Protocol */
10588534Sjoerg#define PPP_VJ_COMP	0x002d		/* VJ compressed TCP/IP */
10688534Sjoerg#define PPP_VJ_UCOMP	0x002f		/* VJ uncompressed TCP/IP */
10778064Sume#define PPP_IPV6	0x0057		/* Internet Protocol Version 6 */
10830300Sjoerg#define PPP_LCP		0xc021		/* Link Control Protocol */
10930300Sjoerg#define PPP_PAP		0xc023		/* Password Authentication Protocol */
11030300Sjoerg#define PPP_CHAP	0xc223		/* Challenge-Handshake Auth Protocol */
11130300Sjoerg#define PPP_IPCP	0x8021		/* Internet Protocol Control Protocol */
11278064Sume#define PPP_IPV6CP	0x8057		/* IPv6 Control Protocol */
1134910Swollman
11425944Sjoerg#define CONF_REQ	1		/* PPP configure request */
11525944Sjoerg#define CONF_ACK	2		/* PPP configure acknowledge */
11625944Sjoerg#define CONF_NAK	3		/* PPP configure negative ack */
11725944Sjoerg#define CONF_REJ	4		/* PPP configure reject */
11825944Sjoerg#define TERM_REQ	5		/* PPP terminate request */
11925944Sjoerg#define TERM_ACK	6		/* PPP terminate acknowledge */
12025944Sjoerg#define CODE_REJ	7		/* PPP code reject */
12125944Sjoerg#define PROTO_REJ	8		/* PPP protocol reject */
12225944Sjoerg#define ECHO_REQ	9		/* PPP echo request */
12325944Sjoerg#define ECHO_REPLY	10		/* PPP echo reply */
12425944Sjoerg#define DISC_REQ	11		/* PPP discard request */
1254910Swollman
12630300Sjoerg#define LCP_OPT_MRU		1	/* maximum receive unit */
12730300Sjoerg#define LCP_OPT_ASYNC_MAP	2	/* async control character map */
12830300Sjoerg#define LCP_OPT_AUTH_PROTO	3	/* authentication protocol */
12930300Sjoerg#define LCP_OPT_QUAL_PROTO	4	/* quality protocol */
13030300Sjoerg#define LCP_OPT_MAGIC		5	/* magic number */
13130300Sjoerg#define LCP_OPT_RESERVED	6	/* reserved */
13230300Sjoerg#define LCP_OPT_PROTO_COMP	7	/* protocol field compression */
13330300Sjoerg#define LCP_OPT_ADDR_COMP	8	/* address/control field compression */
1344910Swollman
13525944Sjoerg#define IPCP_OPT_ADDRESSES	1	/* both IP addresses; deprecated */
13625944Sjoerg#define IPCP_OPT_COMPRESSION	2	/* IP compression protocol (VJ) */
13725944Sjoerg#define IPCP_OPT_ADDRESS	3	/* local IP address */
1384910Swollman
13978064Sume#define IPV6CP_OPT_IFID	1	/* interface identifier */
14078064Sume#define IPV6CP_OPT_COMPRESSION	2	/* IPv6 compression protocol */
14178064Sume
14288534Sjoerg#define IPCP_COMP_VJ		0x2d	/* Code for VJ compression */
14388534Sjoerg
14430300Sjoerg#define PAP_REQ			1	/* PAP name/password request */
14530300Sjoerg#define PAP_ACK			2	/* PAP acknowledge */
14630300Sjoerg#define PAP_NAK			3	/* PAP fail */
1474910Swollman
14830300Sjoerg#define CHAP_CHALLENGE		1	/* CHAP challenge request */
14930300Sjoerg#define CHAP_RESPONSE		2	/* CHAP challenge response */
15030300Sjoerg#define CHAP_SUCCESS		3	/* CHAP response ok */
15130300Sjoerg#define CHAP_FAILURE		4	/* CHAP response failed */
15230300Sjoerg
15330300Sjoerg#define CHAP_MD5		5	/* hash algorithm - MD5 */
15430300Sjoerg
15530300Sjoerg#define CISCO_MULTICAST		0x8f	/* Cisco multicast address */
15630300Sjoerg#define CISCO_UNICAST		0x0f	/* Cisco unicast address */
15730300Sjoerg#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
15830300Sjoerg#define CISCO_ADDR_REQ		0	/* Cisco address request */
15930300Sjoerg#define CISCO_ADDR_REPLY	1	/* Cisco address reply */
16030300Sjoerg#define CISCO_KEEPALIVE_REQ	2	/* Cisco keepalive request */
16130300Sjoerg
16225944Sjoerg/* states are named and numbered according to RFC 1661 */
16325944Sjoerg#define STATE_INITIAL	0
16425944Sjoerg#define STATE_STARTING	1
16525944Sjoerg#define STATE_CLOSED	2
16625944Sjoerg#define STATE_STOPPED	3
16725944Sjoerg#define STATE_CLOSING	4
16825944Sjoerg#define STATE_STOPPING	5
16925944Sjoerg#define STATE_REQ_SENT	6
17025944Sjoerg#define STATE_ACK_RCVD	7
17125944Sjoerg#define STATE_ACK_SENT	8
17225944Sjoerg#define STATE_OPENED	9
17325944Sjoerg
174227293Sedstatic MALLOC_DEFINE(M_SPPP, "sppp", "synchronous PPP interface internals");
175147256Sbrooks
1764910Swollmanstruct ppp_header {
17711189Sjkh	u_char address;
17811189Sjkh	u_char control;
17911189Sjkh	u_short protocol;
180103842Salfred} __packed;
1814910Swollman#define PPP_HEADER_LEN          sizeof (struct ppp_header)
1824910Swollman
1834910Swollmanstruct lcp_header {
18411189Sjkh	u_char type;
18511189Sjkh	u_char ident;
18611189Sjkh	u_short len;
187103842Salfred} __packed;
1884910Swollman#define LCP_HEADER_LEN          sizeof (struct lcp_header)
1894910Swollman
1904910Swollmanstruct cisco_packet {
19111189Sjkh	u_long type;
19211189Sjkh	u_long par1;
19311189Sjkh	u_long par2;
19411189Sjkh	u_short rel;
19511189Sjkh	u_short time0;
19611189Sjkh	u_short time1;
197103842Salfred} __packed;
19888704Sjoerg#define CISCO_PACKET_LEN	sizeof (struct cisco_packet)
1994910Swollman
20025944Sjoerg/*
20125944Sjoerg * We follow the spelling and capitalization of RFC 1661 here, to make
20225944Sjoerg * it easier comparing with the standard.  Please refer to this RFC in
20325944Sjoerg * case you can't make sense out of these abbreviation; it will also
20425944Sjoerg * explain the semantics related to the various events and actions.
20525944Sjoerg */
20625944Sjoergstruct cp {
20725944Sjoerg	u_short	proto;		/* PPP control protocol number */
20825944Sjoerg	u_char protoidx;	/* index into state table in struct sppp */
20925944Sjoerg	u_char flags;
21025944Sjoerg#define CP_LCP		0x01	/* this is the LCP */
21125944Sjoerg#define CP_AUTH		0x02	/* this is an authentication protocol */
21225944Sjoerg#define CP_NCP		0x04	/* this is a NCP */
21325944Sjoerg#define CP_QUAL		0x08	/* this is a quality reporting protocol */
21425944Sjoerg	const char *name;	/* name of this control protocol */
21525944Sjoerg	/* event handlers */
21625944Sjoerg	void	(*Up)(struct sppp *sp);
21725944Sjoerg	void	(*Down)(struct sppp *sp);
21825944Sjoerg	void	(*Open)(struct sppp *sp);
21925944Sjoerg	void	(*Close)(struct sppp *sp);
22025944Sjoerg	void	(*TO)(void *sp);
22125944Sjoerg	int	(*RCR)(struct sppp *sp, struct lcp_header *h, int len);
22225944Sjoerg	void	(*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len);
22325944Sjoerg	void	(*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len);
22425944Sjoerg	/* actions */
22525944Sjoerg	void	(*tlu)(struct sppp *sp);
22625944Sjoerg	void	(*tld)(struct sppp *sp);
22725944Sjoerg	void	(*tls)(struct sppp *sp);
22825944Sjoerg	void	(*tlf)(struct sppp *sp);
22925944Sjoerg	void	(*scr)(struct sppp *sp);
23025944Sjoerg};
23125944Sjoerg
23240008Sjoerg#define	SPP_FMT		"%s: "
23340008Sjoerg#define	SPP_ARGS(ifp)	(ifp)->if_xname
23440008Sjoerg
235188668Srwatson#define SPPP_LOCK(sp)	mtx_lock (&(sp)->mtx)
236188668Srwatson#define SPPP_UNLOCK(sp)	mtx_unlock (&(sp)->mtx)
237188668Srwatson#define SPPP_LOCK_ASSERT(sp)	mtx_assert (&(sp)->mtx, MA_OWNED)
238190818Sed#define SPPP_LOCK_OWNED(sp)	mtx_owned (&(sp)->mtx)
239138745Srik
24088705Sjoerg#ifdef INET
2414910Swollman/*
2424910Swollman * The following disgusting hack gets around the problem that IP TOS
2434910Swollman * can't be set yet.  We want to put "interactive" traffic on a high
2444910Swollman * priority queue.  To decide if traffic is interactive, we check that
2454910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
24630300Sjoerg *
24730300Sjoerg * XXX is this really still necessary?  - joerg -
2484910Swollman */
249126910Srwatsonstatic const u_short interactive_ports[8] = {
2504910Swollman	0,	513,	0,	0,
2514910Swollman	0,	21,	0,	23,
2524910Swollman};
2534910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
25488705Sjoerg#endif
2554910Swollman
25625944Sjoerg/* almost every function needs these */
25725944Sjoerg#define STDDCL							\
258147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);				\
25925944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG
26011189Sjkh
26130300Sjoergstatic int sppp_output(struct ifnet *ifp, struct mbuf *m,
262249925Sglebius	const struct sockaddr *dst, struct route *ro);
2634910Swollman
26425944Sjoergstatic void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2);
26525944Sjoergstatic void sppp_cisco_input(struct sppp *sp, struct mbuf *m);
26625944Sjoerg
26725944Sjoergstatic void sppp_cp_input(const struct cp *cp, struct sppp *sp,
26825944Sjoerg			  struct mbuf *m);
26925944Sjoergstatic void sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
27025944Sjoerg			 u_char ident, u_short len, void *data);
27142104Sphk/* static void sppp_cp_timeout(void *arg); */
27225944Sjoergstatic void sppp_cp_change_state(const struct cp *cp, struct sppp *sp,
27325944Sjoerg				 int newstate);
27430300Sjoergstatic void sppp_auth_send(const struct cp *cp,
27542104Sphk			   struct sppp *sp, unsigned int type, unsigned int id,
27630300Sjoerg			   ...);
27725944Sjoerg
27825944Sjoergstatic void sppp_up_event(const struct cp *cp, struct sppp *sp);
27925944Sjoergstatic void sppp_down_event(const struct cp *cp, struct sppp *sp);
28025944Sjoergstatic void sppp_open_event(const struct cp *cp, struct sppp *sp);
28125944Sjoergstatic void sppp_close_event(const struct cp *cp, struct sppp *sp);
28225944Sjoergstatic void sppp_to_event(const struct cp *cp, struct sppp *sp);
28325944Sjoerg
28430300Sjoergstatic void sppp_null(struct sppp *sp);
28530300Sjoerg
286138745Srikstatic void sppp_pp_up(struct sppp *sp);
287138745Srikstatic void sppp_pp_down(struct sppp *sp);
288138745Srik
28925944Sjoergstatic void sppp_lcp_init(struct sppp *sp);
29025944Sjoergstatic void sppp_lcp_up(struct sppp *sp);
29125944Sjoergstatic void sppp_lcp_down(struct sppp *sp);
29225944Sjoergstatic void sppp_lcp_open(struct sppp *sp);
29325944Sjoergstatic void sppp_lcp_close(struct sppp *sp);
29425944Sjoergstatic void sppp_lcp_TO(void *sp);
29525944Sjoergstatic int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
29625944Sjoergstatic void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
29725944Sjoergstatic void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
29825944Sjoergstatic void sppp_lcp_tlu(struct sppp *sp);
29925944Sjoergstatic void sppp_lcp_tld(struct sppp *sp);
30025944Sjoergstatic void sppp_lcp_tls(struct sppp *sp);
30125944Sjoergstatic void sppp_lcp_tlf(struct sppp *sp);
30225944Sjoergstatic void sppp_lcp_scr(struct sppp *sp);
30330300Sjoergstatic void sppp_lcp_check_and_close(struct sppp *sp);
30430300Sjoergstatic int sppp_ncp_check(struct sppp *sp);
30525944Sjoerg
30625944Sjoergstatic void sppp_ipcp_init(struct sppp *sp);
30725944Sjoergstatic void sppp_ipcp_up(struct sppp *sp);
30825944Sjoergstatic void sppp_ipcp_down(struct sppp *sp);
30925944Sjoergstatic void sppp_ipcp_open(struct sppp *sp);
31025944Sjoergstatic void sppp_ipcp_close(struct sppp *sp);
31125944Sjoergstatic void sppp_ipcp_TO(void *sp);
31225944Sjoergstatic int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
31325944Sjoergstatic void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
31425944Sjoergstatic void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
31525944Sjoergstatic void sppp_ipcp_tlu(struct sppp *sp);
31625944Sjoergstatic void sppp_ipcp_tld(struct sppp *sp);
31725944Sjoergstatic void sppp_ipcp_tls(struct sppp *sp);
31825944Sjoergstatic void sppp_ipcp_tlf(struct sppp *sp);
31925944Sjoergstatic void sppp_ipcp_scr(struct sppp *sp);
32025944Sjoerg
32178064Sumestatic void sppp_ipv6cp_init(struct sppp *sp);
32278064Sumestatic void sppp_ipv6cp_up(struct sppp *sp);
32378064Sumestatic void sppp_ipv6cp_down(struct sppp *sp);
32478064Sumestatic void sppp_ipv6cp_open(struct sppp *sp);
32578064Sumestatic void sppp_ipv6cp_close(struct sppp *sp);
32678064Sumestatic void sppp_ipv6cp_TO(void *sp);
32778064Sumestatic int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len);
32878064Sumestatic void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
32978064Sumestatic void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
33078064Sumestatic void sppp_ipv6cp_tlu(struct sppp *sp);
33178064Sumestatic void sppp_ipv6cp_tld(struct sppp *sp);
33278064Sumestatic void sppp_ipv6cp_tls(struct sppp *sp);
33378064Sumestatic void sppp_ipv6cp_tlf(struct sppp *sp);
33478064Sumestatic void sppp_ipv6cp_scr(struct sppp *sp);
33578064Sume
33630300Sjoergstatic void sppp_pap_input(struct sppp *sp, struct mbuf *m);
33730300Sjoergstatic void sppp_pap_init(struct sppp *sp);
33830300Sjoergstatic void sppp_pap_open(struct sppp *sp);
33930300Sjoergstatic void sppp_pap_close(struct sppp *sp);
34030300Sjoergstatic void sppp_pap_TO(void *sp);
34130300Sjoergstatic void sppp_pap_my_TO(void *sp);
34230300Sjoergstatic void sppp_pap_tlu(struct sppp *sp);
34330300Sjoergstatic void sppp_pap_tld(struct sppp *sp);
34430300Sjoergstatic void sppp_pap_scr(struct sppp *sp);
34530300Sjoerg
34630300Sjoergstatic void sppp_chap_input(struct sppp *sp, struct mbuf *m);
34730300Sjoergstatic void sppp_chap_init(struct sppp *sp);
34830300Sjoergstatic void sppp_chap_open(struct sppp *sp);
34930300Sjoergstatic void sppp_chap_close(struct sppp *sp);
35030300Sjoergstatic void sppp_chap_TO(void *sp);
35130300Sjoergstatic void sppp_chap_tlu(struct sppp *sp);
35230300Sjoergstatic void sppp_chap_tld(struct sppp *sp);
35330300Sjoergstatic void sppp_chap_scr(struct sppp *sp);
35430300Sjoerg
35530300Sjoergstatic const char *sppp_auth_type_name(u_short proto, u_char type);
35625944Sjoergstatic const char *sppp_cp_type_name(u_char type);
357184682Sbz#ifdef INET
35830300Sjoergstatic const char *sppp_dotted_quad(u_long addr);
35930300Sjoergstatic const char *sppp_ipcp_opt_name(u_char opt);
360184682Sbz#endif
36178064Sume#ifdef INET6
36278064Sumestatic const char *sppp_ipv6cp_opt_name(u_char opt);
36378064Sume#endif
36425944Sjoergstatic const char *sppp_lcp_opt_name(u_char opt);
36525944Sjoergstatic const char *sppp_phase_name(enum ppp_phase phase);
36625944Sjoergstatic const char *sppp_proto_name(u_short proto);
36730300Sjoergstatic const char *sppp_state_name(int state);
36838343Sbdestatic int sppp_params(struct sppp *sp, u_long cmd, void *data);
36930300Sjoergstatic int sppp_strnlen(u_char *p, int max);
37025944Sjoergstatic void sppp_keepalive(void *dummy);
37130300Sjoergstatic void sppp_phase_network(struct sppp *sp);
37230300Sjoergstatic void sppp_print_bytes(const u_char *p, u_short len);
37330300Sjoergstatic void sppp_print_string(const char *p, u_short len);
37425944Sjoergstatic void sppp_qflush(struct ifqueue *ifq);
375184682Sbz#ifdef INET
37625944Sjoergstatic void sppp_set_ip_addr(struct sppp *sp, u_long src);
377184682Sbz#endif
37878064Sume#ifdef INET6
37978064Sumestatic void sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src,
38078064Sume			       struct in6_addr *dst, struct in6_addr *srcmask);
38178064Sume#ifdef IPV6CP_MYIFID_DYN
38278064Sumestatic void sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src);
38378064Sumestatic void sppp_gen_ip6_addr(struct sppp *sp, const struct in6_addr *src);
38478064Sume#endif
38578064Sumestatic void sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *src);
38678064Sume#endif
38725944Sjoerg
388138745Srik/* if_start () wrapper */
389138745Srikstatic void sppp_ifstart (struct ifnet *ifp);
390138745Srik
39125944Sjoerg/* our control protocol descriptors */
39233181Seivindstatic const struct cp lcp = {
39325944Sjoerg	PPP_LCP, IDX_LCP, CP_LCP, "lcp",
39425944Sjoerg	sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close,
39525944Sjoerg	sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak,
39625944Sjoerg	sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf,
39725944Sjoerg	sppp_lcp_scr
39825944Sjoerg};
39925944Sjoerg
40033181Seivindstatic const struct cp ipcp = {
40188709Sjoerg	PPP_IPCP, IDX_IPCP,
40288709Sjoerg#ifdef INET	/* don't run IPCP if there's no IPv4 support */
40388709Sjoerg	CP_NCP,
40488709Sjoerg#else
40588709Sjoerg	0,
40688709Sjoerg#endif
40788709Sjoerg	"ipcp",
40825944Sjoerg	sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close,
40925944Sjoerg	sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak,
41025944Sjoerg	sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf,
41125944Sjoerg	sppp_ipcp_scr
41225944Sjoerg};
41325944Sjoerg
41478064Sumestatic const struct cp ipv6cp = {
41578064Sume	PPP_IPV6CP, IDX_IPV6CP,
41678064Sume#ifdef INET6	/*don't run IPv6CP if there's no IPv6 support*/
41778064Sume	CP_NCP,
41878064Sume#else
41978064Sume	0,
42078064Sume#endif
42178064Sume	"ipv6cp",
42278064Sume	sppp_ipv6cp_up, sppp_ipv6cp_down, sppp_ipv6cp_open, sppp_ipv6cp_close,
42378064Sume	sppp_ipv6cp_TO, sppp_ipv6cp_RCR, sppp_ipv6cp_RCN_rej, sppp_ipv6cp_RCN_nak,
42478064Sume	sppp_ipv6cp_tlu, sppp_ipv6cp_tld, sppp_ipv6cp_tls, sppp_ipv6cp_tlf,
42578064Sume	sppp_ipv6cp_scr
42678064Sume};
42778064Sume
42833181Seivindstatic const struct cp pap = {
42930300Sjoerg	PPP_PAP, IDX_PAP, CP_AUTH, "pap",
43030300Sjoerg	sppp_null, sppp_null, sppp_pap_open, sppp_pap_close,
43130300Sjoerg	sppp_pap_TO, 0, 0, 0,
43230300Sjoerg	sppp_pap_tlu, sppp_pap_tld, sppp_null, sppp_null,
43330300Sjoerg	sppp_pap_scr
43430300Sjoerg};
43530300Sjoerg
43633181Seivindstatic const struct cp chap = {
43730300Sjoerg	PPP_CHAP, IDX_CHAP, CP_AUTH, "chap",
43830300Sjoerg	sppp_null, sppp_null, sppp_chap_open, sppp_chap_close,
43930300Sjoerg	sppp_chap_TO, 0, 0, 0,
44030300Sjoerg	sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null,
44130300Sjoerg	sppp_chap_scr
44230300Sjoerg};
44330300Sjoerg
44433181Seivindstatic const struct cp *cps[IDX_COUNT] = {
44525944Sjoerg	&lcp,			/* IDX_LCP */
44625944Sjoerg	&ipcp,			/* IDX_IPCP */
44778064Sume	&ipv6cp,		/* IDX_IPV6CP */
44830300Sjoerg	&pap,			/* IDX_PAP */
44930300Sjoerg	&chap,			/* IDX_CHAP */
45025944Sjoerg};
45125944Sjoerg
452147256Sbrooksstatic void*
453147256Sbrookssppp_alloc(u_char type, struct ifnet *ifp)
454147256Sbrooks{
455147256Sbrooks	struct sppp	*sp;
456147256Sbrooks
457147256Sbrooks        sp = malloc(sizeof(struct sppp), M_SPPP, M_WAITOK | M_ZERO);
458147256Sbrooks	sp->pp_ifp = ifp;
459147256Sbrooks
460147256Sbrooks	return (sp);
461147256Sbrooks}
462147256Sbrooks
463147256Sbrooksstatic void
464147256Sbrookssppp_free(void *com, u_char type)
465147256Sbrooks{
466147256Sbrooks
467147256Sbrooks	free(com, M_SPPP);
468147256Sbrooks}
469147256Sbrooks
47070199Sjhaystatic int
47170199Sjhaysppp_modevent(module_t mod, int type, void *unused)
47270199Sjhay{
47370199Sjhay	switch (type) {
47470199Sjhay	case MOD_LOAD:
475147256Sbrooks		/*
476147256Sbrooks		 * XXX: should probably be IFT_SPPP, but it's fairly
477147256Sbrooks		 * harmless to allocate struct sppp's for non-sppp
478147256Sbrooks		 * interfaces.
479147256Sbrooks		 */
480147256Sbrooks
481147256Sbrooks		if_register_com_alloc(IFT_PPP, sppp_alloc, sppp_free);
48270199Sjhay		break;
48370199Sjhay	case MOD_UNLOAD:
484147256Sbrooks		/* if_deregister_com_alloc(IFT_PPP); */
48570199Sjhay		return EACCES;
48670199Sjhay	default:
487132199Sphk		return EOPNOTSUPP;
48870199Sjhay	}
48970199Sjhay	return 0;
49070199Sjhay}
49170199Sjhaystatic moduledata_t spppmod = {
49270199Sjhay	"sppp",
49370199Sjhay	sppp_modevent,
494241394Skevlo	0
49570199Sjhay};
49670199SjhayMODULE_VERSION(sppp, 1);
49770199SjhayDECLARE_MODULE(sppp, spppmod, SI_SUB_DRIVERS, SI_ORDER_ANY);
49825944Sjoerg
49970199Sjhay/*
50025944Sjoerg * Exported functions, comprising our interface to the lower layer.
5014910Swollman */
5024910Swollman
5034910Swollman/*
5044910Swollman * Process the received packet.
5054910Swollman */
50625706Sjoergvoid
50725706Sjoergsppp_input(struct ifnet *ifp, struct mbuf *m)
5084910Swollman{
5094910Swollman	struct ppp_header *h;
510111888Sjlemon	int isr = -1;
511147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
512184682Sbz	int debug, do_account = 0;
513184682Sbz#ifdef INET
514184682Sbz	int hlen, vjlen;
51588700Sjoerg	u_char *iphdr;
516184682Sbz#endif
5174910Swollman
518138745Srik	SPPP_LOCK(sp);
519138745Srik	debug = ifp->if_flags & IFF_DEBUG;
520138745Srik
5214910Swollman	if (ifp->if_flags & IFF_UP)
5224910Swollman		/* Count received bytes, add FCS and one flag */
523271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len + 3);
5244910Swollman
5254910Swollman	if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
5264910Swollman		/* Too small packet, drop it. */
52725944Sjoerg		if (debug)
52825706Sjoerg			log(LOG_DEBUG,
52940008Sjoerg			    SPP_FMT "input packet is too small, %d bytes\n",
53040008Sjoerg			    SPP_ARGS(ifp), m->m_pkthdr.len);
53125944Sjoerg	  drop:
53288700Sjoerg		m_freem (m);
533138745Srik		SPPP_UNLOCK(sp);
53488700Sjoerg	  drop2:
535271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
536271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
5374910Swollman		return;
5384910Swollman	}
5394910Swollman
540139365Srik	if (sp->pp_mode == PP_FR) {
541139365Srik		sppp_fr_input (sp, m);
542139365Srik		SPPP_UNLOCK(sp);
543139365Srik		return;
544139365Srik	}
545139365Srik
5464910Swollman	/* Get PPP header. */
5474910Swollman	h = mtod (m, struct ppp_header*);
5484910Swollman	m_adj (m, PPP_HEADER_LEN);
5494910Swollman
5504910Swollman	switch (h->address) {
5514910Swollman	case PPP_ALLSTATIONS:
5524910Swollman		if (h->control != PPP_UI)
5534910Swollman			goto invalid;
55445152Sphk		if (sp->pp_mode == IFF_CISCO) {
55525944Sjoerg			if (debug)
55625706Sjoerg				log(LOG_DEBUG,
55740008Sjoerg				    SPP_FMT "PPP packet in Cisco mode "
55825706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
55940008Sjoerg				    SPP_ARGS(ifp),
56025706Sjoerg				    h->address, h->control, ntohs(h->protocol));
56111189Sjkh			goto drop;
56211189Sjkh		}
5634910Swollman		switch (ntohs (h->protocol)) {
5644910Swollman		default:
56525944Sjoerg			if (debug)
56625706Sjoerg				log(LOG_DEBUG,
56744145Sphk				    SPP_FMT "rejecting protocol "
56825706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
56940008Sjoerg				    SPP_ARGS(ifp),
57025706Sjoerg				    h->address, h->control, ntohs(h->protocol));
57144145Sphk			if (sp->state[IDX_LCP] == STATE_OPENED)
57244145Sphk				sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
57378064Sume					++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2,
57444145Sphk					&h->protocol);
575271867Sglebius			if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1);
5764910Swollman			goto drop;
5774910Swollman		case PPP_LCP:
57830300Sjoerg			sppp_cp_input(&lcp, sp, m);
5794910Swollman			m_freem (m);
580138745Srik			SPPP_UNLOCK(sp);
5814910Swollman			return;
58230300Sjoerg		case PPP_PAP:
58330300Sjoerg			if (sp->pp_phase >= PHASE_AUTHENTICATE)
58430300Sjoerg				sppp_pap_input(sp, m);
58530300Sjoerg			m_freem (m);
586138745Srik			SPPP_UNLOCK(sp);
58730300Sjoerg			return;
58830300Sjoerg		case PPP_CHAP:
58930300Sjoerg			if (sp->pp_phase >= PHASE_AUTHENTICATE)
59030300Sjoerg				sppp_chap_input(sp, m);
59130300Sjoerg			m_freem (m);
592138745Srik			SPPP_UNLOCK(sp);
59330300Sjoerg			return;
5944910Swollman#ifdef INET
5954910Swollman		case PPP_IPCP:
59625944Sjoerg			if (sp->pp_phase == PHASE_NETWORK)
59730300Sjoerg				sppp_cp_input(&ipcp, sp, m);
5984910Swollman			m_freem (m);
599138745Srik			SPPP_UNLOCK(sp);
6004910Swollman			return;
6014910Swollman		case PPP_IP:
60225944Sjoerg			if (sp->state[IDX_IPCP] == STATE_OPENED) {
603111888Sjlemon				isr = NETISR_IP;
6044910Swollman			}
60588577Sjoerg			do_account++;
6064910Swollman			break;
60788534Sjoerg		case PPP_VJ_COMP:
60888534Sjoerg			if (sp->state[IDX_IPCP] == STATE_OPENED) {
60988700Sjoerg				if ((vjlen =
61088700Sjoerg				     sl_uncompress_tcp_core(mtod(m, u_char *),
61188700Sjoerg							    m->m_len, m->m_len,
61288700Sjoerg							    TYPE_COMPRESSED_TCP,
61388700Sjoerg							    sp->pp_comp,
61488700Sjoerg							    &iphdr, &hlen)) <= 0) {
61588700Sjoerg					if (debug)
61688700Sjoerg						log(LOG_INFO,
61788700Sjoerg			    SPP_FMT "VJ uncompress failed on compressed packet\n",
61888700Sjoerg						    SPP_ARGS(ifp));
61988534Sjoerg					goto drop;
62088700Sjoerg				}
62188700Sjoerg
62288700Sjoerg				/*
62388700Sjoerg				 * Trim the VJ header off the packet, and prepend
62488700Sjoerg				 * the uncompressed IP header (which will usually
62588700Sjoerg				 * end up in two chained mbufs since there's not
62688700Sjoerg				 * enough leading space in the existing mbuf).
62788700Sjoerg				 */
62888700Sjoerg				m_adj(m, vjlen);
629243882Sglebius				M_PREPEND(m, hlen, M_NOWAIT);
630138745Srik				if (m == NULL) {
631138745Srik					SPPP_UNLOCK(sp);
63288700Sjoerg					goto drop2;
633138745Srik				}
63488700Sjoerg				bcopy(iphdr, mtod(m, u_char *), hlen);
635111888Sjlemon				isr = NETISR_IP;
63688534Sjoerg			}
63788599Sjoerg			do_account++;
63888534Sjoerg			break;
63988534Sjoerg		case PPP_VJ_UCOMP:
64088534Sjoerg			if (sp->state[IDX_IPCP] == STATE_OPENED) {
64188700Sjoerg				if (sl_uncompress_tcp_core(mtod(m, u_char *),
64288700Sjoerg							   m->m_len, m->m_len,
64388700Sjoerg							   TYPE_UNCOMPRESSED_TCP,
64488700Sjoerg							   sp->pp_comp,
64588700Sjoerg							   &iphdr, &hlen) != 0) {
64688700Sjoerg					if (debug)
64788700Sjoerg						log(LOG_INFO,
64888700Sjoerg			    SPP_FMT "VJ uncompress failed on uncompressed packet\n",
64988700Sjoerg						    SPP_ARGS(ifp));
65088534Sjoerg					goto drop;
65188700Sjoerg				}
652111888Sjlemon				isr = NETISR_IP;
65388534Sjoerg			}
65488599Sjoerg			do_account++;
65588534Sjoerg			break;
65678064Sume#endif
65788599Sjoerg#ifdef INET6
65888599Sjoerg		case PPP_IPV6CP:
65988599Sjoerg			if (sp->pp_phase == PHASE_NETWORK)
66088599Sjoerg			    sppp_cp_input(&ipv6cp, sp, m);
66188599Sjoerg			m_freem (m);
662138745Srik			SPPP_UNLOCK(sp);
66388599Sjoerg			return;
66488599Sjoerg
66588599Sjoerg		case PPP_IPV6:
666111888Sjlemon			if (sp->state[IDX_IPV6CP] == STATE_OPENED)
667111888Sjlemon				isr = NETISR_IPV6;
66888599Sjoerg			do_account++;
66988599Sjoerg			break;
67088599Sjoerg#endif
6714910Swollman		}
6724910Swollman		break;
6734910Swollman	case CISCO_MULTICAST:
6744910Swollman	case CISCO_UNICAST:
6754910Swollman		/* Don't check the control field here (RFC 1547). */
67645152Sphk		if (sp->pp_mode != IFF_CISCO) {
67725944Sjoerg			if (debug)
67825706Sjoerg				log(LOG_DEBUG,
67940008Sjoerg				    SPP_FMT "Cisco packet in PPP mode "
68025706Sjoerg				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
68140008Sjoerg				    SPP_ARGS(ifp),
68225706Sjoerg				    h->address, h->control, ntohs(h->protocol));
68311189Sjkh			goto drop;
68411189Sjkh		}
6854910Swollman		switch (ntohs (h->protocol)) {
6864910Swollman		default:
687271867Sglebius			if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1);
6884910Swollman			goto invalid;
6894910Swollman		case CISCO_KEEPALIVE:
690147256Sbrooks			sppp_cisco_input (sp, m);
6914910Swollman			m_freem (m);
692138745Srik			SPPP_UNLOCK(sp);
6934910Swollman			return;
6944910Swollman#ifdef INET
6954910Swollman		case ETHERTYPE_IP:
696111888Sjlemon			isr = NETISR_IP;
69788577Sjoerg			do_account++;
6984910Swollman			break;
6994910Swollman#endif
70054263Sshin#ifdef INET6
70154263Sshin		case ETHERTYPE_IPV6:
702111888Sjlemon			isr = NETISR_IPV6;
70388577Sjoerg			do_account++;
70454263Sshin			break;
70554263Sshin#endif
7064910Swollman		}
7074910Swollman		break;
70825944Sjoerg	default:        /* Invalid PPP packet. */
70925944Sjoerg	  invalid:
71025944Sjoerg		if (debug)
71125944Sjoerg			log(LOG_DEBUG,
71240008Sjoerg			    SPP_FMT "invalid input packet "
71325944Sjoerg			    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
71440008Sjoerg			    SPP_ARGS(ifp),
71525944Sjoerg			    h->address, h->control, ntohs(h->protocol));
71625944Sjoerg		goto drop;
7174910Swollman	}
7184910Swollman
719111888Sjlemon	if (! (ifp->if_flags & IFF_UP) || isr == -1)
7204910Swollman		goto drop;
7214910Swollman
722138745Srik	SPPP_UNLOCK(sp);
723223741Sbz	M_SETFIB(m, ifp->if_fib);
7244910Swollman	/* Check queue. */
725134391Sandre	if (netisr_queue(isr, m)) {	/* (0) on success. */
72625944Sjoerg		if (debug)
72740008Sjoerg			log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n",
72840008Sjoerg				SPP_ARGS(ifp));
729131241Srik		goto drop2;
7304910Swollman	}
731138745Srik
73288577Sjoerg	if (do_account)
73388577Sjoerg		/*
73488577Sjoerg		 * Do only account for network packets, not for control
73588577Sjoerg		 * packets.  This is used by some subsystems to detect
73688577Sjoerg		 * idle lines.
73788577Sjoerg		 */
738150349Sandre		sp->pp_last_recv = time_uptime;
7394910Swollman}
7404910Swollman
741138745Srikstatic void
742138745Sriksppp_ifstart_sched(void *dummy)
743138745Srik{
744138745Srik	struct sppp *sp = dummy;
745138745Srik
746147256Sbrooks	sp->if_start(SP2IFP(sp));
747138745Srik}
748138745Srik
749138745Srik/* if_start () wrapper function. We use it to schedule real if_start () for
750138745Srik * execution. We can't call it directly
751138745Srik */
752138745Srikstatic void
753138745Sriksppp_ifstart(struct ifnet *ifp)
754138745Srik{
755147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
756138745Srik
757138745Srik	if (SPPP_LOCK_OWNED(sp)) {
758138745Srik		if (callout_pending(&sp->ifstart_callout))
759138745Srik			return;
760138745Srik		callout_reset(&sp->ifstart_callout, 1, sppp_ifstart_sched,
761138745Srik		    (void *)sp);
762138745Srik	} else {
763138745Srik		sp->if_start(ifp);
764138745Srik	}
765138745Srik}
766138745Srik
7674910Swollman/*
7684910Swollman * Enqueue transmit packet.
7694910Swollman */
77012820Sphkstatic int
771249925Sglebiussppp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
772249925Sglebius	struct route *ro)
7734910Swollman{
774147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
7754910Swollman	struct ppp_header *h;
77678064Sume	struct ifqueue *ifq = NULL;
777241686Sandre	int error, rv = 0;
778184682Sbz#ifdef INET
77988534Sjoerg	int ipproto = PPP_IP;
780184682Sbz#endif
78142066Sphk	int debug = ifp->if_flags & IFF_DEBUG;
7824910Swollman
783138745Srik	SPPP_LOCK(sp);
78425944Sjoerg
785148887Srwatson	if (!(ifp->if_flags & IFF_UP) ||
786148887Srwatson	    (!(ifp->if_flags & IFF_AUTO) &&
787148887Srwatson	    !(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
78888723Sjoerg#ifdef INET6
78988723Sjoerg	  drop:
79088723Sjoerg#endif
7914910Swollman		m_freem (m);
792138745Srik		SPPP_UNLOCK(sp);
7934910Swollman		return (ENETDOWN);
7944910Swollman	}
7954910Swollman
796148887Srwatson	if ((ifp->if_flags & IFF_AUTO) &&
797148887Srwatson	    !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
79888723Sjoerg#ifdef INET6
79925944Sjoerg		/*
80088723Sjoerg		 * XXX
80188723Sjoerg		 *
80288723Sjoerg		 * Hack to prevent the initialization-time generated
80388723Sjoerg		 * IPv6 multicast packet to erroneously cause a
80488723Sjoerg		 * dialout event in case IPv6 has been
80588723Sjoerg		 * administratively disabled on that interface.
80688723Sjoerg		 */
80788723Sjoerg		if (dst->sa_family == AF_INET6 &&
80888723Sjoerg		    !(sp->confflags & CONF_ENABLE_IPV6))
80988723Sjoerg			goto drop;
81088723Sjoerg#endif
81188723Sjoerg		/*
81225944Sjoerg		 * Interface is not yet running, but auto-dial.  Need
81325944Sjoerg		 * to start LCP for it.
81425944Sjoerg		 */
815148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
81625944Sjoerg		lcp.Open(sp);
81725944Sjoerg	}
81825944Sjoerg
8194910Swollman#ifdef INET
82012436Speter	if (dst->sa_family == AF_INET) {
82140008Sjoerg		/* XXX Check mbuf length here? */
82212436Speter		struct ip *ip = mtod (m, struct ip*);
82312436Speter		struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
8244910Swollman
82542104Sphk		/*
82642104Sphk		 * When using dynamic local IP address assignment by using
82742104Sphk		 * 0.0.0.0 as a local address, the first TCP session will
82842104Sphk		 * not connect because the local TCP checksum is computed
82942104Sphk		 * using 0.0.0.0 which will later become our real IP address
83042104Sphk		 * so the TCP checksum computed at the remote end will
83142104Sphk		 * become invalid. So we
83242104Sphk		 * - don't let packets with src ip addr 0 thru
83342104Sphk		 * - we flag TCP packets with src ip 0 as an error
83470199Sjhay		 */
83542104Sphk
83642104Sphk		if(ip->ip_src.s_addr == INADDR_ANY)	/* -hm */
83742104Sphk		{
83842104Sphk			m_freem(m);
839138745Srik			SPPP_UNLOCK(sp);
84042104Sphk			if(ip->ip_p == IPPROTO_TCP)
84142104Sphk				return(EADDRNOTAVAIL);
84242104Sphk			else
84342104Sphk				return(0);
84442104Sphk		}
84570199Sjhay
84642104Sphk		/*
84742104Sphk		 * Put low delay, telnet, rlogin and ftp control packets
848130549Smlaier		 * in front of the queue or let ALTQ take care.
84942104Sphk		 */
850130549Smlaier		if (ALTQ_IS_ENABLED(&ifp->if_snd))
85141686Sphk			;
852130549Smlaier		else if (_IF_QFULL(&sp->pp_fastq))
853130549Smlaier			;
85441686Sphk		else if (ip->ip_tos & IPTOS_LOWDELAY)
85512436Speter			ifq = &sp->pp_fastq;
85641686Sphk		else if (m->m_len < sizeof *ip + sizeof *tcp)
85741686Sphk			;
85841686Sphk		else if (ip->ip_p != IPPROTO_TCP)
85941686Sphk			;
86041686Sphk		else if (INTERACTIVE (ntohs (tcp->th_sport)))
86141686Sphk			ifq = &sp->pp_fastq;
86241686Sphk		else if (INTERACTIVE (ntohs (tcp->th_dport)))
86341686Sphk			ifq = &sp->pp_fastq;
86488534Sjoerg
86588534Sjoerg		/*
86688534Sjoerg		 * Do IP Header compression
86788534Sjoerg		 */
868139365Srik		if (sp->pp_mode != IFF_CISCO && sp->pp_mode != PP_FR &&
869138745Srik		    (sp->ipcp.flags & IPCP_VJ) && ip->ip_p == IPPROTO_TCP)
87088599Sjoerg			switch (sl_compress_tcp(m, ip, sp->pp_comp,
87188534Sjoerg						sp->ipcp.compress_cid)) {
87288534Sjoerg			case TYPE_COMPRESSED_TCP:
87388534Sjoerg				ipproto = PPP_VJ_COMP;
87488534Sjoerg				break;
87588534Sjoerg			case TYPE_UNCOMPRESSED_TCP:
87688534Sjoerg				ipproto = PPP_VJ_UCOMP;
87788534Sjoerg				break;
87888534Sjoerg			case TYPE_IP:
87988534Sjoerg				ipproto = PPP_IP;
88088534Sjoerg				break;
88188534Sjoerg			default:
88288534Sjoerg				m_freem(m);
883138745Srik				SPPP_UNLOCK(sp);
88488534Sjoerg				return (EINVAL);
88588534Sjoerg			}
8864910Swollman	}
8874910Swollman#endif
8884910Swollman
88978064Sume#ifdef INET6
89078064Sume	if (dst->sa_family == AF_INET6) {
89178064Sume		/* XXX do something tricky here? */
89278064Sume	}
89378064Sume#endif
89478064Sume
895139365Srik	if (sp->pp_mode == PP_FR) {
896139365Srik		/* Add frame relay header. */
897139365Srik		m = sppp_fr_header (sp, m, dst->sa_family);
898139365Srik		if (! m)
899139365Srik			goto nobufs;
900139365Srik		goto out;
901139365Srik	}
902139365Srik
9034910Swollman	/*
9044910Swollman	 * Prepend general data packet PPP header. For now, IP only.
9054910Swollman	 */
906243882Sglebius	M_PREPEND (m, PPP_HEADER_LEN, M_NOWAIT);
9074910Swollman	if (! m) {
908139365Sriknobufs:		if (debug)
90940008Sjoerg			log(LOG_DEBUG, SPP_FMT "no memory for transmit header\n",
91040008Sjoerg				SPP_ARGS(ifp));
911271867Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
912138745Srik		SPPP_UNLOCK(sp);
9134910Swollman		return (ENOBUFS);
9144910Swollman	}
91540008Sjoerg	/*
91640008Sjoerg	 * May want to check size of packet
91740008Sjoerg	 * (albeit due to the implementation it's always enough)
91840008Sjoerg	 */
9194910Swollman	h = mtod (m, struct ppp_header*);
92045152Sphk	if (sp->pp_mode == IFF_CISCO) {
92128088Skjc		h->address = CISCO_UNICAST;        /* unicast address */
9224910Swollman		h->control = 0;
9234910Swollman	} else {
9244910Swollman		h->address = PPP_ALLSTATIONS;        /* broadcast address */
9254910Swollman		h->control = PPP_UI;                 /* Unnumbered Info */
9264910Swollman	}
9274910Swollman
9284910Swollman	switch (dst->sa_family) {
9294910Swollman#ifdef INET
9304910Swollman	case AF_INET:   /* Internet Protocol */
93145152Sphk		if (sp->pp_mode == IFF_CISCO)
93211189Sjkh			h->protocol = htons (ETHERTYPE_IP);
93311189Sjkh		else {
93425955Sjoerg			/*
93525955Sjoerg			 * Don't choke with an ENETDOWN early.  It's
93625955Sjoerg			 * possible that we just started dialing out,
93725955Sjoerg			 * so don't drop the packet immediately.  If
93825955Sjoerg			 * we notice that we run out of buffer space
93925955Sjoerg			 * below, we will however remember that we are
94025955Sjoerg			 * not ready to carry IP packets, and return
94125955Sjoerg			 * ENETDOWN, as opposed to ENOBUFS.
94225955Sjoerg			 */
94388534Sjoerg			h->protocol = htons(ipproto);
94425955Sjoerg			if (sp->state[IDX_IPCP] != STATE_OPENED)
94525955Sjoerg				rv = ENETDOWN;
94611189Sjkh		}
9474910Swollman		break;
9484910Swollman#endif
94954263Sshin#ifdef INET6
95054263Sshin	case AF_INET6:   /* Internet Protocol */
95154263Sshin		if (sp->pp_mode == IFF_CISCO)
95254263Sshin			h->protocol = htons (ETHERTYPE_IPV6);
95354263Sshin		else {
95478064Sume			/*
95578064Sume			 * Don't choke with an ENETDOWN early.  It's
95678064Sume			 * possible that we just started dialing out,
95778064Sume			 * so don't drop the packet immediately.  If
95878064Sume			 * we notice that we run out of buffer space
95978064Sume			 * below, we will however remember that we are
96078064Sume			 * not ready to carry IP packets, and return
96178064Sume			 * ENETDOWN, as opposed to ENOBUFS.
96278064Sume			 */
96378064Sume			h->protocol = htons(PPP_IPV6);
96478064Sume			if (sp->state[IDX_IPV6CP] != STATE_OPENED)
96578064Sume				rv = ENETDOWN;
96654263Sshin		}
96754263Sshin		break;
96854263Sshin#endif
9694910Swollman	default:
9704910Swollman		m_freem (m);
971271867Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
972138745Srik		SPPP_UNLOCK(sp);
9734910Swollman		return (EAFNOSUPPORT);
9744910Swollman	}
9754910Swollman
9764910Swollman	/*
9774910Swollman	 * Queue message on interface, and start output if interface
97888577Sjoerg	 * not yet active.
9794910Swollman	 */
980139365Srikout:
981130549Smlaier	if (ifq != NULL)
982130549Smlaier		error = !(IF_HANDOFF_ADJ(ifq, m, ifp, 3));
983130549Smlaier	else
984130549Smlaier		IFQ_HANDOFF_ADJ(ifp, m, 3, error);
985130549Smlaier	if (error) {
986271867Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
987138745Srik		SPPP_UNLOCK(sp);
98825955Sjoerg		return (rv? rv: ENOBUFS);
9894910Swollman	}
990138745Srik	SPPP_UNLOCK(sp);
99188577Sjoerg	/*
99288577Sjoerg	 * Unlike in sppp_input(), we can always bump the timestamp
99388577Sjoerg	 * here since sppp_output() is only called on behalf of
99488577Sjoerg	 * network-layer traffic; control-layer traffic is handled
99588577Sjoerg	 * by sppp_cp_send().
99688577Sjoerg	 */
997150349Sandre	sp->pp_last_sent = time_uptime;
9984910Swollman	return (0);
9994910Swollman}
10004910Swollman
100125706Sjoergvoid
100225706Sjoergsppp_attach(struct ifnet *ifp)
10034910Swollman{
1004147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
10054910Swollman
1006138745Srik	/* Initialize mtx lock */
1007138745Srik	mtx_init(&sp->mtx, "sppp", MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE);
1008138745Srik
10094910Swollman	/* Initialize keepalive handler. */
1010283291Sjkim 	callout_init(&sp->keepalive_callout, 1);
1011138745Srik	callout_reset(&sp->keepalive_callout, hz * 10, sppp_keepalive,
1012138745Srik 		    (void *)sp);
10134910Swollman
1014147256Sbrooks	ifp->if_mtu = PP_MTU;
1015147256Sbrooks	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
1016147256Sbrooks	ifp->if_output = sppp_output;
101742104Sphk#if 0
101842064Sphk	sp->pp_flags = PP_KEEPALIVE;
101942104Sphk#endif
1020147256Sbrooks 	ifp->if_snd.ifq_maxlen = 32;
102170199Sjhay 	sp->pp_fastq.ifq_maxlen = 32;
102270199Sjhay 	sp->pp_cpq.ifq_maxlen = 20;
10234910Swollman	sp->pp_loopcnt = 0;
10244910Swollman	sp->pp_alivecnt = 0;
102578064Sume	bzero(&sp->pp_seq[0], sizeof(sp->pp_seq));
102678064Sume	bzero(&sp->pp_rseq[0], sizeof(sp->pp_rseq));
102725944Sjoerg	sp->pp_phase = PHASE_DEAD;
1028138745Srik	sp->pp_up = sppp_pp_up;
1029138745Srik	sp->pp_down = sppp_pp_down;
103088716Sjoerg	if(!mtx_initialized(&sp->pp_cpq.ifq_mtx))
103193818Sjhb		mtx_init(&sp->pp_cpq.ifq_mtx, "sppp_cpq", NULL, MTX_DEF);
103288716Sjoerg	if(!mtx_initialized(&sp->pp_fastq.ifq_mtx))
103393818Sjhb		mtx_init(&sp->pp_fastq.ifq_mtx, "sppp_fastq", NULL, MTX_DEF);
1034150349Sandre	sp->pp_last_recv = sp->pp_last_sent = time_uptime;
103588723Sjoerg	sp->confflags = 0;
103688723Sjoerg#ifdef INET
103788723Sjoerg	sp->confflags |= CONF_ENABLE_VJ;
103888723Sjoerg#endif
103988723Sjoerg#ifdef INET6
104088723Sjoerg	sp->confflags |= CONF_ENABLE_IPV6;
104188723Sjoerg#endif
1042283291Sjkim 	callout_init(&sp->ifstart_callout, 1);
1043138745Srik	sp->if_start = ifp->if_start;
1044138745Srik	ifp->if_start = sppp_ifstart;
1045118072Sgj	sp->pp_comp = malloc(sizeof(struct slcompress), M_TEMP, M_WAITOK);
104688599Sjoerg	sl_compress_init(sp->pp_comp, -1);
104725944Sjoerg	sppp_lcp_init(sp);
104825944Sjoerg	sppp_ipcp_init(sp);
104978064Sume	sppp_ipv6cp_init(sp);
105030300Sjoerg	sppp_pap_init(sp);
105130300Sjoerg	sppp_chap_init(sp);
10524910Swollman}
10534910Swollman
105430300Sjoergvoid
105525706Sjoergsppp_detach(struct ifnet *ifp)
10564910Swollman{
1057147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
105825944Sjoerg	int i;
10594910Swollman
1060138745Srik	KASSERT(mtx_initialized(&sp->mtx), ("sppp mutex is not initialized"));
10614910Swollman
10624910Swollman	/* Stop keepalive handler. */
1063352481Shselasky 	callout_drain(&sp->keepalive_callout);
106425944Sjoerg
1065138745Srik	for (i = 0; i < IDX_COUNT; i++) {
1066352481Shselasky		callout_drain(&sp->ch[i]);
1067138745Srik	}
1068352481Shselasky	callout_drain(&sp->pap_my_to_ch);
1069352481Shselasky
107069152Sjlemon	mtx_destroy(&sp->pp_cpq.ifq_mtx);
107169152Sjlemon	mtx_destroy(&sp->pp_fastq.ifq_mtx);
1072138745Srik	mtx_destroy(&sp->mtx);
10734910Swollman}
10744910Swollman
10754910Swollman/*
10764910Swollman * Flush the interface output queue.
10774910Swollman */
1078138745Srikstatic void
1079138745Sriksppp_flush_unlocked(struct ifnet *ifp)
10804910Swollman{
1081147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
10824910Swollman
1083147256Sbrooks	sppp_qflush ((struct ifqueue *)&SP2IFP(sp)->if_snd);
108425944Sjoerg	sppp_qflush (&sp->pp_fastq);
108526018Sjoerg	sppp_qflush (&sp->pp_cpq);
10864910Swollman}
10874910Swollman
1088138745Srikvoid
1089138745Sriksppp_flush(struct ifnet *ifp)
1090138745Srik{
1091147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
1092138745Srik
1093138745Srik	SPPP_LOCK(sp);
1094138745Srik	sppp_flush_unlocked (ifp);
1095138745Srik	SPPP_UNLOCK(sp);
1096138745Srik}
1097138745Srik
10984910Swollman/*
109911189Sjkh * Check if the output queue is empty.
110011189Sjkh */
110112820Sphkint
110225706Sjoergsppp_isempty(struct ifnet *ifp)
110311189Sjkh{
1104147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
1105241686Sandre	int empty;
110611189Sjkh
1107138745Srik	SPPP_LOCK(sp);
110826018Sjoerg	empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head &&
1109147256Sbrooks		!SP2IFP(sp)->if_snd.ifq_head;
1110138745Srik	SPPP_UNLOCK(sp);
111111189Sjkh	return (empty);
111211189Sjkh}
111311189Sjkh
111411189Sjkh/*
11154910Swollman * Get next packet to send.
11164910Swollman */
111725706Sjoergstruct mbuf *
111825706Sjoergsppp_dequeue(struct ifnet *ifp)
11194910Swollman{
1120147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
11214910Swollman	struct mbuf *m;
11224910Swollman
1123138745Srik	SPPP_LOCK(sp);
112426018Sjoerg	/*
112530300Sjoerg	 * Process only the control protocol queue until we have at
112630300Sjoerg	 * least one NCP open.
112726018Sjoerg	 *
112826018Sjoerg	 * Do always serve all three queues in Cisco mode.
112926018Sjoerg	 */
113026018Sjoerg	IF_DEQUEUE(&sp->pp_cpq, m);
113126018Sjoerg	if (m == NULL &&
1132139365Srik	    (sppp_ncp_check(sp) || sp->pp_mode == IFF_CISCO ||
1133139365Srik	     sp->pp_mode == PP_FR)) {
113426018Sjoerg		IF_DEQUEUE(&sp->pp_fastq, m);
113526018Sjoerg		if (m == NULL)
1136147256Sbrooks			IF_DEQUEUE (&SP2IFP(sp)->if_snd, m);
113726018Sjoerg	}
1138138745Srik	SPPP_UNLOCK(sp);
113926018Sjoerg	return m;
11404910Swollman}
11414910Swollman
11424910Swollman/*
114330300Sjoerg * Pick the next packet, do not remove it from the queue.
114430300Sjoerg */
114530300Sjoergstruct mbuf *
114630300Sjoergsppp_pick(struct ifnet *ifp)
114730300Sjoerg{
1148147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
114930300Sjoerg	struct mbuf *m;
115030300Sjoerg
1151138745Srik	SPPP_LOCK(sp);
115230300Sjoerg
115330300Sjoerg	m = sp->pp_cpq.ifq_head;
115430300Sjoerg	if (m == NULL &&
1155138745Srik	    (sp->pp_phase == PHASE_NETWORK ||
1156139365Srik	     sp->pp_mode == IFF_CISCO ||
1157139365Srik	     sp->pp_mode == PP_FR))
115830300Sjoerg		if ((m = sp->pp_fastq.ifq_head) == NULL)
1159147256Sbrooks			m = SP2IFP(sp)->if_snd.ifq_head;
1160138745Srik	SPPP_UNLOCK(sp);
116130300Sjoerg	return (m);
116230300Sjoerg}
116330300Sjoerg
116430300Sjoerg/*
116525944Sjoerg * Process an ioctl request.  Called on low priority level.
11664910Swollman */
116725944Sjoergint
116842104Sphksppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data)
11694910Swollman{
117025944Sjoerg	struct ifreq *ifr = (struct ifreq*) data;
1171147256Sbrooks	struct sppp *sp = IFP2SP(ifp);
1172241686Sandre	int rv, going_up, going_down, newmode;
11734910Swollman
1174138745Srik	SPPP_LOCK(sp);
117530300Sjoerg	rv = 0;
117625944Sjoerg	switch (cmd) {
117725944Sjoerg	case SIOCAIFADDR:
117825944Sjoerg		break;
11794910Swollman
118025944Sjoerg	case SIOCSIFADDR:
118188503Sjoerg		/* set the interface "up" when assigning an IP address */
118288503Sjoerg		ifp->if_flags |= IFF_UP;
1183102412Scharnier		/* FALLTHROUGH */
118411189Sjkh
118525944Sjoerg	case SIOCSIFFLAGS:
118625944Sjoerg		going_up = ifp->if_flags & IFF_UP &&
1187148887Srwatson			(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0;
118825944Sjoerg		going_down = (ifp->if_flags & IFF_UP) == 0 &&
1189148887Srwatson			ifp->if_drv_flags & IFF_DRV_RUNNING;
119045152Sphk
119145152Sphk		newmode = ifp->if_flags & IFF_PASSIVE;
119245152Sphk		if (!newmode)
119345152Sphk			newmode = ifp->if_flags & IFF_AUTO;
119445152Sphk		if (!newmode)
119545152Sphk			newmode = ifp->if_flags & IFF_CISCO;
119645152Sphk		ifp->if_flags &= ~(IFF_PASSIVE | IFF_AUTO | IFF_CISCO);
119745152Sphk		ifp->if_flags |= newmode;
119845152Sphk
1199139365Srik		if (!newmode)
1200139365Srik			newmode = sp->pp_flags & PP_FR;
1201139365Srik
120245152Sphk		if (newmode != sp->pp_mode) {
120345152Sphk			going_down = 1;
120445152Sphk			if (!going_up)
1205148887Srwatson				going_up = ifp->if_drv_flags & IFF_DRV_RUNNING;
12064910Swollman		}
12074910Swollman
120845152Sphk		if (going_down) {
1209139365Srik			if (sp->pp_mode != IFF_CISCO &&
1210139365Srik			    sp->pp_mode != PP_FR)
121145152Sphk				lcp.Close(sp);
121245152Sphk			else if (sp->pp_tlf)
121345152Sphk				(sp->pp_tlf)(sp);
1214138745Srik			sppp_flush_unlocked(ifp);
1215148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
121645152Sphk			sp->pp_mode = newmode;
121726018Sjoerg		}
12184910Swollman
121945152Sphk		if (going_up) {
1220139365Srik			if (sp->pp_mode != IFF_CISCO &&
1221139365Srik			    sp->pp_mode != PP_FR)
122245152Sphk				lcp.Close(sp);
122345152Sphk			sp->pp_mode = newmode;
122445152Sphk			if (sp->pp_mode == 0) {
1225148887Srwatson				ifp->if_drv_flags |= IFF_DRV_RUNNING;
122645152Sphk				lcp.Open(sp);
122745152Sphk			}
1228139365Srik			if ((sp->pp_mode == IFF_CISCO) ||
1229139365Srik			    (sp->pp_mode == PP_FR)) {
123045152Sphk				if (sp->pp_tls)
123145152Sphk					(sp->pp_tls)(sp);
1232148887Srwatson				ifp->if_drv_flags |= IFF_DRV_RUNNING;
123345152Sphk			}
123445152Sphk		}
123545152Sphk
12364910Swollman		break;
123711189Sjkh
123825944Sjoerg#ifdef SIOCSIFMTU
123925944Sjoerg#ifndef ifr_mtu
124025944Sjoerg#define ifr_mtu ifr_metric
124125944Sjoerg#endif
124225944Sjoerg	case SIOCSIFMTU:
124325944Sjoerg		if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru)
124425944Sjoerg			return (EINVAL);
124525944Sjoerg		ifp->if_mtu = ifr->ifr_mtu;
12464910Swollman		break;
124725944Sjoerg#endif
124825944Sjoerg#ifdef SLIOCSETMTU
124925944Sjoerg	case SLIOCSETMTU:
125025944Sjoerg		if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru)
125125944Sjoerg			return (EINVAL);
125225944Sjoerg		ifp->if_mtu = *(short*)data;
12534910Swollman		break;
125425944Sjoerg#endif
125525944Sjoerg#ifdef SIOCGIFMTU
125625944Sjoerg	case SIOCGIFMTU:
125725944Sjoerg		ifr->ifr_mtu = ifp->if_mtu;
125811189Sjkh		break;
125925944Sjoerg#endif
126025944Sjoerg#ifdef SLIOCGETMTU
126125944Sjoerg	case SLIOCGETMTU:
126225944Sjoerg		*(short*)data = ifp->if_mtu;
12634910Swollman		break;
126425944Sjoerg#endif
126525944Sjoerg	case SIOCADDMULTI:
126625944Sjoerg	case SIOCDELMULTI:
12674910Swollman		break;
126811189Sjkh
126930300Sjoerg	case SIOCGIFGENERIC:
127030300Sjoerg	case SIOCSIFGENERIC:
127130300Sjoerg		rv = sppp_params(sp, cmd, data);
127230300Sjoerg		break;
127330300Sjoerg
127425944Sjoerg	default:
127530300Sjoerg		rv = ENOTTY;
12764910Swollman	}
1277138745Srik	SPPP_UNLOCK(sp);
127830300Sjoerg	return rv;
12794910Swollman}
12804910Swollman
128170199Sjhay/*
128225944Sjoerg * Cisco framing implementation.
128325944Sjoerg */
128425944Sjoerg
12854910Swollman/*
12864910Swollman * Handle incoming Cisco keepalive protocol packets.
12874910Swollman */
128830300Sjoergstatic void
128925706Sjoergsppp_cisco_input(struct sppp *sp, struct mbuf *m)
12904910Swollman{
129125944Sjoerg	STDDCL;
12924910Swollman	struct cisco_packet *h;
129330300Sjoerg	u_long me, mymask;
12944910Swollman
129527929Sitojun	if (m->m_pkthdr.len < CISCO_PACKET_LEN) {
129625706Sjoerg		if (debug)
129725706Sjoerg			log(LOG_DEBUG,
129840008Sjoerg			    SPP_FMT "cisco invalid packet length: %d bytes\n",
129940008Sjoerg			    SPP_ARGS(ifp), m->m_pkthdr.len);
13004910Swollman		return;
13014910Swollman	}
13024910Swollman	h = mtod (m, struct cisco_packet*);
130325706Sjoerg	if (debug)
130425706Sjoerg		log(LOG_DEBUG,
130540008Sjoerg		    SPP_FMT "cisco input: %d bytes "
130625706Sjoerg		    "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
130740008Sjoerg		    SPP_ARGS(ifp), m->m_pkthdr.len,
130840008Sjoerg		    (u_long)ntohl (h->type), (u_long)h->par1, (u_long)h->par2, (u_int)h->rel,
130940008Sjoerg		    (u_int)h->time0, (u_int)h->time1);
13104910Swollman	switch (ntohl (h->type)) {
13114910Swollman	default:
131225706Sjoerg		if (debug)
131369211Sphk			log(-1, SPP_FMT "cisco unknown packet type: 0x%lx\n",
131440008Sjoerg			       SPP_ARGS(ifp), (u_long)ntohl (h->type));
13154910Swollman		break;
13164910Swollman	case CISCO_ADDR_REPLY:
13174910Swollman		/* Reply on address request, ignore */
13184910Swollman		break;
13194910Swollman	case CISCO_KEEPALIVE_REQ:
13204910Swollman		sp->pp_alivecnt = 0;
132178064Sume		sp->pp_rseq[IDX_LCP] = ntohl (h->par1);
132278064Sume		if (sp->pp_seq[IDX_LCP] == sp->pp_rseq[IDX_LCP]) {
13234910Swollman			/* Local and remote sequence numbers are equal.
13244910Swollman			 * Probably, the line is in loopback mode. */
132511189Sjkh			if (sp->pp_loopcnt >= MAXALIVECNT) {
132640008Sjoerg				printf (SPP_FMT "loopback\n",
132740008Sjoerg					SPP_ARGS(ifp));
132811189Sjkh				sp->pp_loopcnt = 0;
132911189Sjkh				if (ifp->if_flags & IFF_UP) {
133011189Sjkh					if_down (ifp);
133126018Sjoerg					sppp_qflush (&sp->pp_cpq);
133211189Sjkh				}
133311189Sjkh			}
13344910Swollman			++sp->pp_loopcnt;
13354910Swollman
13364910Swollman			/* Generate new local sequence number */
133778064Sume			sp->pp_seq[IDX_LCP] = random();
133811189Sjkh			break;
133911189Sjkh		}
134030300Sjoerg		sp->pp_loopcnt = 0;
134111189Sjkh		if (! (ifp->if_flags & IFF_UP) &&
1342148887Srwatson		    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
134330300Sjoerg			if_up(ifp);
134440008Sjoerg			printf (SPP_FMT "up\n", SPP_ARGS(ifp));
134511189Sjkh		}
13464910Swollman		break;
13474910Swollman	case CISCO_ADDR_REQ:
134830300Sjoerg		sppp_get_ip_addrs(sp, &me, 0, &mymask);
134930300Sjoerg		if (me != 0L)
135030300Sjoerg			sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask);
13514910Swollman		break;
13524910Swollman	}
13534910Swollman}
13544910Swollman
13554910Swollman/*
135625944Sjoerg * Send Cisco keepalive packet.
13574910Swollman */
135812820Sphkstatic void
135925944Sjoergsppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
136025944Sjoerg{
136125944Sjoerg	STDDCL;
136225944Sjoerg	struct ppp_header *h;
136325944Sjoerg	struct cisco_packet *ch;
136425944Sjoerg	struct mbuf *m;
136535029Sphk	struct timeval tv;
136625944Sjoerg
136736119Sphk	getmicrouptime(&tv);
136870199Sjhay
1369243882Sglebius	MGETHDR (m, M_NOWAIT, MT_DATA);
137025944Sjoerg	if (! m)
137125944Sjoerg		return;
137225944Sjoerg	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
137325944Sjoerg	m->m_pkthdr.rcvif = 0;
137425944Sjoerg
137525944Sjoerg	h = mtod (m, struct ppp_header*);
137625944Sjoerg	h->address = CISCO_MULTICAST;
137725944Sjoerg	h->control = 0;
137825944Sjoerg	h->protocol = htons (CISCO_KEEPALIVE);
137925944Sjoerg
138025944Sjoerg	ch = (struct cisco_packet*) (h + 1);
138125944Sjoerg	ch->type = htonl (type);
138225944Sjoerg	ch->par1 = htonl (par1);
138325944Sjoerg	ch->par2 = htonl (par2);
138425944Sjoerg	ch->rel = -1;
138540008Sjoerg
138635029Sphk	ch->time0 = htons ((u_short) (tv.tv_sec >> 16));
138735029Sphk	ch->time1 = htons ((u_short) tv.tv_sec);
138825944Sjoerg
138925944Sjoerg	if (debug)
139025944Sjoerg		log(LOG_DEBUG,
139140008Sjoerg		    SPP_FMT "cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
139240008Sjoerg			SPP_ARGS(ifp), (u_long)ntohl (ch->type), (u_long)ch->par1,
139340008Sjoerg			(u_long)ch->par2, (u_int)ch->rel, (u_int)ch->time0, (u_int)ch->time1);
139425944Sjoerg
139569152Sjlemon	if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
1396271867Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
139725944Sjoerg}
139825944Sjoerg
139970199Sjhay/*
140025944Sjoerg * PPP protocol implementation.
140125944Sjoerg */
140225944Sjoerg
140325944Sjoerg/*
140425944Sjoerg * Send PPP control protocol packet.
140525944Sjoerg */
140625944Sjoergstatic void
140725706Sjoergsppp_cp_send(struct sppp *sp, u_short proto, u_char type,
140825706Sjoerg	     u_char ident, u_short len, void *data)
14094910Swollman{
141025944Sjoerg	STDDCL;
14114910Swollman	struct ppp_header *h;
14124910Swollman	struct lcp_header *lh;
14134910Swollman	struct mbuf *m;
14144910Swollman
14154910Swollman	if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
14164910Swollman		len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
1417243882Sglebius	MGETHDR (m, M_NOWAIT, MT_DATA);
14184910Swollman	if (! m)
14194910Swollman		return;
14204910Swollman	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
14214910Swollman	m->m_pkthdr.rcvif = 0;
14224910Swollman
14234910Swollman	h = mtod (m, struct ppp_header*);
14244910Swollman	h->address = PPP_ALLSTATIONS;        /* broadcast address */
14254910Swollman	h->control = PPP_UI;                 /* Unnumbered Info */
14264910Swollman	h->protocol = htons (proto);         /* Link Control Protocol */
14274910Swollman
14284910Swollman	lh = (struct lcp_header*) (h + 1);
14294910Swollman	lh->type = type;
14304910Swollman	lh->ident = ident;
14314910Swollman	lh->len = htons (LCP_HEADER_LEN + len);
14324910Swollman	if (len)
14334910Swollman		bcopy (data, lh+1, len);
14344910Swollman
143525706Sjoerg	if (debug) {
143640008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d",
143740008Sjoerg		    SPP_ARGS(ifp),
143825944Sjoerg		    sppp_proto_name(proto),
143925944Sjoerg		    sppp_cp_type_name (lh->type), lh->ident,
144025944Sjoerg		    ntohs (lh->len));
144144145Sphk		sppp_print_bytes ((u_char*) (lh+1), len);
144269211Sphk		log(-1, ">\n");
14434910Swollman	}
144469152Sjlemon	if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
1445271867Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
14464910Swollman}
14474910Swollman
14484910Swollman/*
144925944Sjoerg * Handle incoming PPP control protocol packets.
14504910Swollman */
145112820Sphkstatic void
145225944Sjoergsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
14534910Swollman{
145425944Sjoerg	STDDCL;
145525944Sjoerg	struct lcp_header *h;
145625944Sjoerg	int len = m->m_pkthdr.len;
145725944Sjoerg	int rv;
145825944Sjoerg	u_char *p;
14594910Swollman
146025944Sjoerg	if (len < 4) {
146125944Sjoerg		if (debug)
146225944Sjoerg			log(LOG_DEBUG,
146340008Sjoerg			    SPP_FMT "%s invalid packet length: %d bytes\n",
146440008Sjoerg			    SPP_ARGS(ifp), cp->name, len);
14654910Swollman		return;
146625944Sjoerg	}
146725944Sjoerg	h = mtod (m, struct lcp_header*);
146825944Sjoerg	if (debug) {
146925944Sjoerg		log(LOG_DEBUG,
147040008Sjoerg		    SPP_FMT "%s input(%s): <%s id=0x%x len=%d",
147140008Sjoerg		    SPP_ARGS(ifp), cp->name,
147225944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
147325944Sjoerg		    sppp_cp_type_name (h->type), h->ident, ntohs (h->len));
147444145Sphk		sppp_print_bytes ((u_char*) (h+1), len-4);
147569211Sphk		log(-1, ">\n");
147625944Sjoerg	}
147725944Sjoerg	if (len > ntohs (h->len))
147825944Sjoerg		len = ntohs (h->len);
147930300Sjoerg	p = (u_char *)(h + 1);
148025944Sjoerg	switch (h->type) {
148125944Sjoerg	case CONF_REQ:
148225944Sjoerg		if (len < 4) {
148325944Sjoerg			if (debug)
148469211Sphk				log(-1, SPP_FMT "%s invalid conf-req length %d\n",
148540008Sjoerg				       SPP_ARGS(ifp), cp->name,
148625944Sjoerg				       len);
1487271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
148825944Sjoerg			break;
148925944Sjoerg		}
149030300Sjoerg		/* handle states where RCR doesn't get a SCA/SCN */
149130300Sjoerg		switch (sp->state[cp->protoidx]) {
149230300Sjoerg		case STATE_CLOSING:
149330300Sjoerg		case STATE_STOPPING:
149430300Sjoerg			return;
149530300Sjoerg		case STATE_CLOSED:
149630300Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
149730300Sjoerg				     0, 0);
149830300Sjoerg			return;
149930300Sjoerg		}
150025944Sjoerg		rv = (cp->RCR)(sp, h, len);
150125944Sjoerg		switch (sp->state[cp->protoidx]) {
150225944Sjoerg		case STATE_OPENED:
150325944Sjoerg			(cp->tld)(sp);
150425944Sjoerg			(cp->scr)(sp);
1505102412Scharnier			/* FALLTHROUGH */
150625944Sjoerg		case STATE_ACK_SENT:
150725944Sjoerg		case STATE_REQ_SENT:
150870199Sjhay			/*
150970199Sjhay			 * sppp_cp_change_state() have the side effect of
151070199Sjhay			 * restarting the timeouts. We want to avoid that
151170199Sjhay			 * if the state don't change, otherwise we won't
151270199Sjhay			 * ever timeout and resend a configuration request
151370199Sjhay			 * that got lost.
151470199Sjhay			 */
151570199Sjhay			if (sp->state[cp->protoidx] == (rv ? STATE_ACK_SENT:
151670199Sjhay			    STATE_REQ_SENT))
151770199Sjhay				break;
151825944Sjoerg			sppp_cp_change_state(cp, sp, rv?
151925944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
152025944Sjoerg			break;
152125944Sjoerg		case STATE_STOPPED:
152225944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
152325944Sjoerg			(cp->scr)(sp);
152425944Sjoerg			sppp_cp_change_state(cp, sp, rv?
152525944Sjoerg					     STATE_ACK_SENT: STATE_REQ_SENT);
152625944Sjoerg			break;
152725944Sjoerg		case STATE_ACK_RCVD:
152825944Sjoerg			if (rv) {
152925944Sjoerg				sppp_cp_change_state(cp, sp, STATE_OPENED);
153025944Sjoerg				if (debug)
153140008Sjoerg					log(LOG_DEBUG, SPP_FMT "%s tlu\n",
153240008Sjoerg					    SPP_ARGS(ifp),
153326077Sjoerg					    cp->name);
153425944Sjoerg				(cp->tlu)(sp);
153525944Sjoerg			} else
153625944Sjoerg				sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
153725944Sjoerg			break;
153825944Sjoerg		default:
153940008Sjoerg			printf(SPP_FMT "%s illegal %s in state %s\n",
154040008Sjoerg			       SPP_ARGS(ifp), cp->name,
154125944Sjoerg			       sppp_cp_type_name(h->type),
154225944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
1543271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
154425944Sjoerg		}
154525944Sjoerg		break;
154625944Sjoerg	case CONF_ACK:
154725944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
154825944Sjoerg			if (debug)
154969211Sphk				log(-1, SPP_FMT "%s id mismatch 0x%x != 0x%x\n",
155040008Sjoerg				       SPP_ARGS(ifp), cp->name,
155125944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
1552271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
155325944Sjoerg			break;
155425944Sjoerg		}
155525944Sjoerg		switch (sp->state[cp->protoidx]) {
155625944Sjoerg		case STATE_CLOSED:
155725944Sjoerg		case STATE_STOPPED:
155825944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
155925944Sjoerg			break;
156025944Sjoerg		case STATE_CLOSING:
156125944Sjoerg		case STATE_STOPPING:
156225944Sjoerg			break;
156325944Sjoerg		case STATE_REQ_SENT:
156425944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
156525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
156625944Sjoerg			break;
156725944Sjoerg		case STATE_OPENED:
156825944Sjoerg			(cp->tld)(sp);
1569102412Scharnier			/* FALLTHROUGH */
157025944Sjoerg		case STATE_ACK_RCVD:
157125944Sjoerg			(cp->scr)(sp);
157225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
157325944Sjoerg			break;
157425944Sjoerg		case STATE_ACK_SENT:
157525944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
157625944Sjoerg			sppp_cp_change_state(cp, sp, STATE_OPENED);
157725944Sjoerg			if (debug)
157840008Sjoerg				log(LOG_DEBUG, SPP_FMT "%s tlu\n",
157940008Sjoerg				       SPP_ARGS(ifp), cp->name);
158025944Sjoerg			(cp->tlu)(sp);
158125944Sjoerg			break;
158225944Sjoerg		default:
158340008Sjoerg			printf(SPP_FMT "%s illegal %s in state %s\n",
158440008Sjoerg			       SPP_ARGS(ifp), cp->name,
158525944Sjoerg			       sppp_cp_type_name(h->type),
158625944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
1587271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
158825944Sjoerg		}
158925944Sjoerg		break;
159025944Sjoerg	case CONF_NAK:
159125944Sjoerg	case CONF_REJ:
159225944Sjoerg		if (h->ident != sp->confid[cp->protoidx]) {
159325944Sjoerg			if (debug)
159469211Sphk				log(-1, SPP_FMT "%s id mismatch 0x%x != 0x%x\n",
159540008Sjoerg				       SPP_ARGS(ifp), cp->name,
159625944Sjoerg				       h->ident, sp->confid[cp->protoidx]);
1597271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
159825944Sjoerg			break;
159925944Sjoerg		}
160025944Sjoerg		if (h->type == CONF_NAK)
160125944Sjoerg			(cp->RCN_nak)(sp, h, len);
160225944Sjoerg		else /* CONF_REJ */
160325944Sjoerg			(cp->RCN_rej)(sp, h, len);
16044910Swollman
160525944Sjoerg		switch (sp->state[cp->protoidx]) {
160625944Sjoerg		case STATE_CLOSED:
160725944Sjoerg		case STATE_STOPPED:
160825944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
160925944Sjoerg			break;
161025944Sjoerg		case STATE_REQ_SENT:
161125944Sjoerg		case STATE_ACK_SENT:
161225944Sjoerg			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
161370199Sjhay			/*
161470199Sjhay			 * Slow things down a bit if we think we might be
161570199Sjhay			 * in loopback. Depend on the timeout to send the
161670199Sjhay			 * next configuration request.
161770199Sjhay			 */
161870199Sjhay			if (sp->pp_loopcnt)
161970199Sjhay				break;
162025944Sjoerg			(cp->scr)(sp);
162125944Sjoerg			break;
162225944Sjoerg		case STATE_OPENED:
162325944Sjoerg			(cp->tld)(sp);
1624102412Scharnier			/* FALLTHROUGH */
162525944Sjoerg		case STATE_ACK_RCVD:
162652633Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
162725944Sjoerg			(cp->scr)(sp);
162825944Sjoerg			break;
162925944Sjoerg		case STATE_CLOSING:
163025944Sjoerg		case STATE_STOPPING:
163125944Sjoerg			break;
163225944Sjoerg		default:
163340008Sjoerg			printf(SPP_FMT "%s illegal %s in state %s\n",
163440008Sjoerg			       SPP_ARGS(ifp), cp->name,
163525944Sjoerg			       sppp_cp_type_name(h->type),
163625944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
1637271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
163825944Sjoerg		}
163925944Sjoerg		break;
16404910Swollman
164125944Sjoerg	case TERM_REQ:
164225944Sjoerg		switch (sp->state[cp->protoidx]) {
164325944Sjoerg		case STATE_ACK_RCVD:
164425944Sjoerg		case STATE_ACK_SENT:
164525944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
1646102412Scharnier			/* FALLTHROUGH */
164725944Sjoerg		case STATE_CLOSED:
164825944Sjoerg		case STATE_STOPPED:
164925944Sjoerg		case STATE_CLOSING:
165025944Sjoerg		case STATE_STOPPING:
165125944Sjoerg		case STATE_REQ_SENT:
165225944Sjoerg		  sta:
165325944Sjoerg			/* Send Terminate-Ack packet. */
165425944Sjoerg			if (debug)
165540008Sjoerg				log(LOG_DEBUG, SPP_FMT "%s send terminate-ack\n",
165640008Sjoerg				    SPP_ARGS(ifp), cp->name);
165725944Sjoerg			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
165825944Sjoerg			break;
165925944Sjoerg		case STATE_OPENED:
166025944Sjoerg			(cp->tld)(sp);
166125944Sjoerg			sp->rst_counter[cp->protoidx] = 0;
166225944Sjoerg			sppp_cp_change_state(cp, sp, STATE_STOPPING);
166325944Sjoerg			goto sta;
166425944Sjoerg			break;
166525944Sjoerg		default:
166640008Sjoerg			printf(SPP_FMT "%s illegal %s in state %s\n",
166740008Sjoerg			       SPP_ARGS(ifp), cp->name,
166825944Sjoerg			       sppp_cp_type_name(h->type),
166925944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
1670271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
167125944Sjoerg		}
167225944Sjoerg		break;
167325944Sjoerg	case TERM_ACK:
167425944Sjoerg		switch (sp->state[cp->protoidx]) {
167525944Sjoerg		case STATE_CLOSED:
167625944Sjoerg		case STATE_STOPPED:
167725944Sjoerg		case STATE_REQ_SENT:
167825944Sjoerg		case STATE_ACK_SENT:
167925944Sjoerg			break;
168025944Sjoerg		case STATE_CLOSING:
168141881Sphk			sppp_cp_change_state(cp, sp, STATE_CLOSED);
168225944Sjoerg			(cp->tlf)(sp);
168325944Sjoerg			break;
168425944Sjoerg		case STATE_STOPPING:
168541881Sphk			sppp_cp_change_state(cp, sp, STATE_STOPPED);
168625944Sjoerg			(cp->tlf)(sp);
168725944Sjoerg			break;
168825944Sjoerg		case STATE_ACK_RCVD:
168925944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
169025944Sjoerg			break;
169125944Sjoerg		case STATE_OPENED:
169225944Sjoerg			(cp->tld)(sp);
169325944Sjoerg			(cp->scr)(sp);
169425944Sjoerg			sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
169525944Sjoerg			break;
169625944Sjoerg		default:
169740008Sjoerg			printf(SPP_FMT "%s illegal %s in state %s\n",
169840008Sjoerg			       SPP_ARGS(ifp), cp->name,
169925944Sjoerg			       sppp_cp_type_name(h->type),
170025944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
1701271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
170225944Sjoerg		}
170325944Sjoerg		break;
170425944Sjoerg	case CODE_REJ:
170525944Sjoerg		/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
170630300Sjoerg		log(LOG_INFO,
170740008Sjoerg		    SPP_FMT "%s: ignoring RXJ (%s) for proto 0x%x, "
170830300Sjoerg		    "danger will robinson\n",
170940008Sjoerg		    SPP_ARGS(ifp), cp->name,
171030300Sjoerg		    sppp_cp_type_name(h->type), ntohs(*((u_short *)p)));
171125944Sjoerg		switch (sp->state[cp->protoidx]) {
171225944Sjoerg		case STATE_CLOSED:
171325944Sjoerg		case STATE_STOPPED:
171425944Sjoerg		case STATE_REQ_SENT:
171525944Sjoerg		case STATE_ACK_SENT:
171625944Sjoerg		case STATE_CLOSING:
171725944Sjoerg		case STATE_STOPPING:
171825944Sjoerg		case STATE_OPENED:
171925944Sjoerg			break;
172025944Sjoerg		case STATE_ACK_RCVD:
172125944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
172225944Sjoerg			break;
172325944Sjoerg		default:
172440008Sjoerg			printf(SPP_FMT "%s illegal %s in state %s\n",
172540008Sjoerg			       SPP_ARGS(ifp), cp->name,
172625944Sjoerg			       sppp_cp_type_name(h->type),
172725944Sjoerg			       sppp_state_name(sp->state[cp->protoidx]));
1728271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
172925944Sjoerg		}
173025944Sjoerg		break;
173180715Sume	case PROTO_REJ:
173280715Sume	    {
173380715Sume		int catastrophic;
173480715Sume		const struct cp *upper;
173580715Sume		int i;
173680715Sume		u_int16_t proto;
173780715Sume
173880715Sume		catastrophic = 0;
173980715Sume		upper = NULL;
174080715Sume		proto = ntohs(*((u_int16_t *)p));
174180715Sume		for (i = 0; i < IDX_COUNT; i++) {
174280715Sume			if (cps[i]->proto == proto) {
174380715Sume				upper = cps[i];
174480715Sume				break;
174580715Sume			}
174680715Sume		}
174780715Sume		if (upper == NULL)
174880715Sume			catastrophic++;
174980715Sume
175088508Sjoerg		if (catastrophic || debug)
175188508Sjoerg			log(catastrophic? LOG_INFO: LOG_DEBUG,
175288508Sjoerg			    SPP_FMT "%s: RXJ%c (%s) for proto 0x%x (%s/%s)\n",
175388508Sjoerg			    SPP_ARGS(ifp), cp->name, catastrophic ? '-' : '+',
175488508Sjoerg			    sppp_cp_type_name(h->type), proto,
175588508Sjoerg			    upper ? upper->name : "unknown",
175688508Sjoerg			    upper ? sppp_state_name(sp->state[upper->protoidx]) : "?");
175780715Sume
175880715Sume		/*
175980715Sume		 * if we got RXJ+ against conf-req, the peer does not implement
176080715Sume		 * this particular protocol type.  terminate the protocol.
176180715Sume		 */
176280715Sume		if (upper && !catastrophic) {
176380715Sume			if (sp->state[upper->protoidx] == STATE_REQ_SENT) {
176480715Sume				upper->Close(sp);
176580715Sume				break;
176680715Sume			}
176780715Sume		}
176880715Sume
176980715Sume		/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
177080715Sume		switch (sp->state[cp->protoidx]) {
177180715Sume		case STATE_CLOSED:
177280715Sume		case STATE_STOPPED:
177380715Sume		case STATE_REQ_SENT:
177480715Sume		case STATE_ACK_SENT:
177580715Sume		case STATE_CLOSING:
177680715Sume		case STATE_STOPPING:
177780715Sume		case STATE_OPENED:
177880715Sume			break;
177980715Sume		case STATE_ACK_RCVD:
178080715Sume			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
178180715Sume			break;
178280715Sume		default:
178380715Sume			printf(SPP_FMT "%s illegal %s in state %s\n",
178480715Sume			       SPP_ARGS(ifp), cp->name,
178580715Sume			       sppp_cp_type_name(h->type),
178680715Sume			       sppp_state_name(sp->state[cp->protoidx]));
1787271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
178880715Sume		}
178980715Sume		break;
179080715Sume	    }
179125944Sjoerg	case DISC_REQ:
179225944Sjoerg		if (cp->proto != PPP_LCP)
179325944Sjoerg			goto illegal;
179425944Sjoerg		/* Discard the packet. */
179525944Sjoerg		break;
179625944Sjoerg	case ECHO_REQ:
179725944Sjoerg		if (cp->proto != PPP_LCP)
179825944Sjoerg			goto illegal;
179925944Sjoerg		if (sp->state[cp->protoidx] != STATE_OPENED) {
180025944Sjoerg			if (debug)
180169211Sphk				log(-1, SPP_FMT "lcp echo req but lcp closed\n",
180240008Sjoerg				       SPP_ARGS(ifp));
1803271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
180425944Sjoerg			break;
180525944Sjoerg		}
180625944Sjoerg		if (len < 8) {
180725944Sjoerg			if (debug)
180869211Sphk				log(-1, SPP_FMT "invalid lcp echo request "
180925944Sjoerg				       "packet length: %d bytes\n",
181040008Sjoerg				       SPP_ARGS(ifp), len);
181125944Sjoerg			break;
181225944Sjoerg		}
181344145Sphk		if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
181444145Sphk		    ntohl (*(long*)(h+1)) == sp->lcp.magic) {
181525944Sjoerg			/* Line loopback mode detected. */
181640008Sjoerg			printf(SPP_FMT "loopback\n", SPP_ARGS(ifp));
181770199Sjhay			sp->pp_loopcnt = MAXALIVECNT * 5;
181825944Sjoerg			if_down (ifp);
181926018Sjoerg			sppp_qflush (&sp->pp_cpq);
18204910Swollman
182125944Sjoerg			/* Shut down the PPP link. */
182225944Sjoerg			/* XXX */
182325944Sjoerg			lcp.Down(sp);
182425944Sjoerg			lcp.Up(sp);
182525944Sjoerg			break;
182625944Sjoerg		}
182725944Sjoerg		*(long*)(h+1) = htonl (sp->lcp.magic);
182825944Sjoerg		if (debug)
182969211Sphk			log(-1, SPP_FMT "got lcp echo req, sending echo rep\n",
183040008Sjoerg			       SPP_ARGS(ifp));
183125944Sjoerg		sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1);
183225944Sjoerg		break;
183325944Sjoerg	case ECHO_REPLY:
183425944Sjoerg		if (cp->proto != PPP_LCP)
183525944Sjoerg			goto illegal;
183625944Sjoerg		if (h->ident != sp->lcp.echoid) {
1837271867Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
183825944Sjoerg			break;
183925944Sjoerg		}
184025944Sjoerg		if (len < 8) {
184125944Sjoerg			if (debug)
184269211Sphk				log(-1, SPP_FMT "lcp invalid echo reply "
184325944Sjoerg				       "packet length: %d bytes\n",
184440008Sjoerg				       SPP_ARGS(ifp), len);
184525944Sjoerg			break;
184625944Sjoerg		}
184725944Sjoerg		if (debug)
184869211Sphk			log(-1, SPP_FMT "lcp got echo rep\n",
184940008Sjoerg			       SPP_ARGS(ifp));
185044145Sphk		if (!(sp->lcp.opts & (1 << LCP_OPT_MAGIC)) ||
185144145Sphk		    ntohl (*(long*)(h+1)) != sp->lcp.magic)
185225944Sjoerg			sp->pp_alivecnt = 0;
185325944Sjoerg		break;
185425944Sjoerg	default:
185525944Sjoerg		/* Unknown packet type -- send Code-Reject packet. */
185625944Sjoerg	  illegal:
185725944Sjoerg		if (debug)
185869211Sphk			log(-1, SPP_FMT "%s send code-rej for 0x%x\n",
185940008Sjoerg			       SPP_ARGS(ifp), cp->name, h->type);
186078064Sume		sppp_cp_send(sp, cp->proto, CODE_REJ,
186178064Sume			     ++sp->pp_seq[cp->protoidx], m->m_pkthdr.len, h);
1862271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
186325944Sjoerg	}
18644910Swollman}
18654910Swollman
186625944Sjoerg
18674910Swollman/*
186825944Sjoerg * The generic part of all Up/Down/Open/Close/TO event handlers.
186925944Sjoerg * Basically, the state transition handling in the automaton.
18704910Swollman */
187125944Sjoergstatic void
187225944Sjoergsppp_up_event(const struct cp *cp, struct sppp *sp)
18734910Swollman{
187425944Sjoerg	STDDCL;
18754910Swollman
187625944Sjoerg	if (debug)
187740008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s up(%s)\n",
187840008Sjoerg		    SPP_ARGS(ifp), cp->name,
187925944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
188025944Sjoerg
188125944Sjoerg	switch (sp->state[cp->protoidx]) {
188225944Sjoerg	case STATE_INITIAL:
188325944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
188425944Sjoerg		break;
188525944Sjoerg	case STATE_STARTING:
188625944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
188725944Sjoerg		(cp->scr)(sp);
188825944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
188925944Sjoerg		break;
18904910Swollman	default:
189140008Sjoerg		printf(SPP_FMT "%s illegal up in state %s\n",
189240008Sjoerg		       SPP_ARGS(ifp), cp->name,
189325944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
189425944Sjoerg	}
189525944Sjoerg}
18964910Swollman
189725944Sjoergstatic void
189825944Sjoergsppp_down_event(const struct cp *cp, struct sppp *sp)
189925944Sjoerg{
190025944Sjoerg	STDDCL;
190125944Sjoerg
190225944Sjoerg	if (debug)
190340008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s down(%s)\n",
190440008Sjoerg		    SPP_ARGS(ifp), cp->name,
190525944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
190625944Sjoerg
190725944Sjoerg	switch (sp->state[cp->protoidx]) {
190825944Sjoerg	case STATE_CLOSED:
190925944Sjoerg	case STATE_CLOSING:
191025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_INITIAL);
19114910Swollman		break;
191225944Sjoerg	case STATE_STOPPED:
191341881Sphk		sppp_cp_change_state(cp, sp, STATE_STARTING);
191425944Sjoerg		(cp->tls)(sp);
191541881Sphk		break;
191625944Sjoerg	case STATE_STOPPING:
191725944Sjoerg	case STATE_REQ_SENT:
191825944Sjoerg	case STATE_ACK_RCVD:
191925944Sjoerg	case STATE_ACK_SENT:
192025944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
192125944Sjoerg		break;
192225944Sjoerg	case STATE_OPENED:
192325944Sjoerg		(cp->tld)(sp);
192425944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
192525944Sjoerg		break;
192625944Sjoerg	default:
192740008Sjoerg		printf(SPP_FMT "%s illegal down in state %s\n",
192840008Sjoerg		       SPP_ARGS(ifp), cp->name,
192925944Sjoerg		       sppp_state_name(sp->state[cp->protoidx]));
193025944Sjoerg	}
193125944Sjoerg}
19324910Swollman
193311189Sjkh
193425944Sjoergstatic void
193525944Sjoergsppp_open_event(const struct cp *cp, struct sppp *sp)
193625944Sjoerg{
193725944Sjoerg	STDDCL;
193825944Sjoerg
193925944Sjoerg	if (debug)
194040008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s open(%s)\n",
194140008Sjoerg		    SPP_ARGS(ifp), cp->name,
194225944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
194325944Sjoerg
194425944Sjoerg	switch (sp->state[cp->protoidx]) {
194525944Sjoerg	case STATE_INITIAL:
194641881Sphk		sppp_cp_change_state(cp, sp, STATE_STARTING);
194725944Sjoerg		(cp->tls)(sp);
19484910Swollman		break;
194925944Sjoerg	case STATE_STARTING:
195025944Sjoerg		break;
195125944Sjoerg	case STATE_CLOSED:
195225944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
195325944Sjoerg		(cp->scr)(sp);
195425944Sjoerg		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
195525944Sjoerg		break;
195625944Sjoerg	case STATE_STOPPED:
195774703Sjoerg		/*
195874703Sjoerg		 * Try escaping stopped state.  This seems to bite
195974703Sjoerg		 * people occasionally, in particular for IPCP,
196074703Sjoerg		 * presumably following previous IPCP negotiation
196174703Sjoerg		 * aborts.  Somehow, we must have missed a Down event
196274703Sjoerg		 * which would have caused a transition into starting
196374703Sjoerg		 * state, so as a bandaid we force the Down event now.
196474703Sjoerg		 * This effectively implements (something like the)
196574703Sjoerg		 * `restart' option mentioned in the state transition
196674703Sjoerg		 * table of RFC 1661.
196774703Sjoerg		 */
196874703Sjoerg		sppp_cp_change_state(cp, sp, STATE_STARTING);
196974703Sjoerg		(cp->tls)(sp);
197074703Sjoerg		break;
197125944Sjoerg	case STATE_STOPPING:
197225944Sjoerg	case STATE_REQ_SENT:
197325944Sjoerg	case STATE_ACK_RCVD:
197425944Sjoerg	case STATE_ACK_SENT:
197525944Sjoerg	case STATE_OPENED:
197625944Sjoerg		break;
197725944Sjoerg	case STATE_CLOSING:
197825944Sjoerg		sppp_cp_change_state(cp, sp, STATE_STOPPING);
197925944Sjoerg		break;
198025944Sjoerg	}
198125944Sjoerg}
19824910Swollman
198325944Sjoerg
198425944Sjoergstatic void
198525944Sjoergsppp_close_event(const struct cp *cp, struct sppp *sp)
198625944Sjoerg{
198725944Sjoerg	STDDCL;
198825944Sjoerg
198925944Sjoerg	if (debug)
199040008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s close(%s)\n",
199140008Sjoerg		    SPP_ARGS(ifp), cp->name,
199225944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]));
199325944Sjoerg
199425944Sjoerg	switch (sp->state[cp->protoidx]) {
199525944Sjoerg	case STATE_INITIAL:
199625944Sjoerg	case STATE_CLOSED:
199725944Sjoerg	case STATE_CLOSING:
19984910Swollman		break;
199925944Sjoerg	case STATE_STARTING:
200041881Sphk		sppp_cp_change_state(cp, sp, STATE_INITIAL);
200125944Sjoerg		(cp->tlf)(sp);
20024910Swollman		break;
200325944Sjoerg	case STATE_STOPPED:
200425944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSED);
20054910Swollman		break;
200625944Sjoerg	case STATE_STOPPING:
200725944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
20084910Swollman		break;
200925944Sjoerg	case STATE_OPENED:
201025944Sjoerg		(cp->tld)(sp);
2011102412Scharnier		/* FALLTHROUGH */
201225944Sjoerg	case STATE_REQ_SENT:
201325944Sjoerg	case STATE_ACK_RCVD:
201425944Sjoerg	case STATE_ACK_SENT:
201525944Sjoerg		sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
201678064Sume		sppp_cp_send(sp, cp->proto, TERM_REQ,
201778064Sume			     ++sp->pp_seq[cp->protoidx], 0, 0);
201825944Sjoerg		sppp_cp_change_state(cp, sp, STATE_CLOSING);
20194910Swollman		break;
20204910Swollman	}
20214910Swollman}
20224910Swollman
202325944Sjoergstatic void
202425944Sjoergsppp_to_event(const struct cp *cp, struct sppp *sp)
202525944Sjoerg{
202625944Sjoerg	STDDCL;
202725944Sjoerg
2028138745Srik	SPPP_LOCK(sp);
202925944Sjoerg	if (debug)
203040008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s TO(%s) rst_counter = %d\n",
203140008Sjoerg		    SPP_ARGS(ifp), cp->name,
203225944Sjoerg		    sppp_state_name(sp->state[cp->protoidx]),
203325944Sjoerg		    sp->rst_counter[cp->protoidx]);
203425944Sjoerg
203525944Sjoerg	if (--sp->rst_counter[cp->protoidx] < 0)
203625944Sjoerg		/* TO- event */
203725944Sjoerg		switch (sp->state[cp->protoidx]) {
203825944Sjoerg		case STATE_CLOSING:
203941881Sphk			sppp_cp_change_state(cp, sp, STATE_CLOSED);
204025944Sjoerg			(cp->tlf)(sp);
204125944Sjoerg			break;
204225944Sjoerg		case STATE_STOPPING:
204341881Sphk			sppp_cp_change_state(cp, sp, STATE_STOPPED);
204425944Sjoerg			(cp->tlf)(sp);
204525944Sjoerg			break;
204625944Sjoerg		case STATE_REQ_SENT:
204725944Sjoerg		case STATE_ACK_RCVD:
204825944Sjoerg		case STATE_ACK_SENT:
204941881Sphk			sppp_cp_change_state(cp, sp, STATE_STOPPED);
205025944Sjoerg			(cp->tlf)(sp);
205125944Sjoerg			break;
205225944Sjoerg		}
205325944Sjoerg	else
205425944Sjoerg		/* TO+ event */
205525944Sjoerg		switch (sp->state[cp->protoidx]) {
205625944Sjoerg		case STATE_CLOSING:
205725944Sjoerg		case STATE_STOPPING:
205878064Sume			sppp_cp_send(sp, cp->proto, TERM_REQ,
205978064Sume				     ++sp->pp_seq[cp->protoidx], 0, 0);
2060138745Srik			callout_reset(&sp->ch[cp->protoidx], sp->lcp.timeout,
2061138745Srik				      cp->TO, (void *)sp);
206225944Sjoerg			break;
206325944Sjoerg		case STATE_REQ_SENT:
206425944Sjoerg		case STATE_ACK_RCVD:
206525944Sjoerg			(cp->scr)(sp);
206625944Sjoerg			/* sppp_cp_change_state() will restart the timer */
206725944Sjoerg			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
206825944Sjoerg			break;
206925944Sjoerg		case STATE_ACK_SENT:
207025944Sjoerg			(cp->scr)(sp);
2071138745Srik			callout_reset(&sp->ch[cp->protoidx], sp->lcp.timeout,
2072138745Srik				      cp->TO, (void *)sp);
207325944Sjoerg			break;
207425944Sjoerg		}
207525944Sjoerg
2076138745Srik	SPPP_UNLOCK(sp);
207725944Sjoerg}
207825944Sjoerg
207911189Sjkh/*
208025944Sjoerg * Change the state of a control protocol in the state automaton.
208125944Sjoerg * Takes care of starting/stopping the restart timer.
208211189Sjkh */
2083105228Sphkstatic void
208425944Sjoergsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
208525944Sjoerg{
208625944Sjoerg	sp->state[cp->protoidx] = newstate;
208725944Sjoerg
2088138745Srik	callout_stop (&sp->ch[cp->protoidx]);
2089138745Srik
209025944Sjoerg	switch (newstate) {
209125944Sjoerg	case STATE_INITIAL:
209225944Sjoerg	case STATE_STARTING:
209325944Sjoerg	case STATE_CLOSED:
209425944Sjoerg	case STATE_STOPPED:
209525944Sjoerg	case STATE_OPENED:
209625944Sjoerg		break;
209725944Sjoerg	case STATE_CLOSING:
209825944Sjoerg	case STATE_STOPPING:
209925944Sjoerg	case STATE_REQ_SENT:
210025944Sjoerg	case STATE_ACK_RCVD:
210125944Sjoerg	case STATE_ACK_SENT:
2102138745Srik		callout_reset(&sp->ch[cp->protoidx], sp->lcp.timeout,
2103138745Srik			      cp->TO, (void *)sp);
210425944Sjoerg		break;
210525944Sjoerg	}
210625944Sjoerg}
210770199Sjhay
210870199Sjhay/*
210925944Sjoerg *--------------------------------------------------------------------------*
211025944Sjoerg *                                                                          *
211125944Sjoerg *                         The LCP implementation.                          *
211225944Sjoerg *                                                                          *
211325944Sjoerg *--------------------------------------------------------------------------*
211425944Sjoerg */
211525944Sjoergstatic void
2116138745Sriksppp_pp_up(struct sppp *sp)
2117138745Srik{
2118138745Srik	SPPP_LOCK(sp);
2119138745Srik	lcp.Up(sp);
2120138745Srik	SPPP_UNLOCK(sp);
2121138745Srik}
2122138745Srik
2123138745Srikstatic void
2124138745Sriksppp_pp_down(struct sppp *sp)
2125138745Srik{
2126138745Srik	SPPP_LOCK(sp);
2127138745Srik	lcp.Down(sp);
2128138745Srik	SPPP_UNLOCK(sp);
2129138745Srik}
2130138745Srik
2131138745Srikstatic void
213225944Sjoergsppp_lcp_init(struct sppp *sp)
213325944Sjoerg{
213425944Sjoerg	sp->lcp.opts = (1 << LCP_OPT_MAGIC);
213525944Sjoerg	sp->lcp.magic = 0;
213625944Sjoerg	sp->state[IDX_LCP] = STATE_INITIAL;
213725944Sjoerg	sp->fail_counter[IDX_LCP] = 0;
213878064Sume	sp->pp_seq[IDX_LCP] = 0;
213978064Sume	sp->pp_rseq[IDX_LCP] = 0;
214025944Sjoerg	sp->lcp.protos = 0;
214125944Sjoerg	sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
214230300Sjoerg
214344145Sphk	/* Note that these values are  relevant for all control protocols */
214444145Sphk	sp->lcp.timeout = 3 * hz;
214525944Sjoerg	sp->lcp.max_terminate = 2;
214625944Sjoerg	sp->lcp.max_configure = 10;
214725944Sjoerg	sp->lcp.max_failure = 10;
2148283291Sjkim 	callout_init(&sp->ch[IDX_LCP], 1);
214925944Sjoerg}
215025944Sjoerg
215125944Sjoergstatic void
215225944Sjoergsppp_lcp_up(struct sppp *sp)
215325944Sjoerg{
215425944Sjoerg	STDDCL;
215525944Sjoerg
215670199Sjhay	sp->pp_alivecnt = 0;
215770199Sjhay	sp->lcp.opts = (1 << LCP_OPT_MAGIC);
215870199Sjhay	sp->lcp.magic = 0;
215970199Sjhay	sp->lcp.protos = 0;
216070199Sjhay	sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
216125944Sjoerg	/*
216275321Sjoerg	 * If we are authenticator, negotiate LCP_AUTH
216375321Sjoerg	 */
216475321Sjoerg	if (sp->hisauth.proto != 0)
216575321Sjoerg		sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO);
216675321Sjoerg	else
216775321Sjoerg		sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
216875321Sjoerg	sp->pp_flags &= ~PP_NEEDAUTH;
216975321Sjoerg	/*
217030300Sjoerg	 * If this interface is passive or dial-on-demand, and we are
217130300Sjoerg	 * still in Initial state, it means we've got an incoming
217230300Sjoerg	 * call.  Activate the interface.
217325944Sjoerg	 */
217425944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) {
217525944Sjoerg		if (debug)
217625944Sjoerg			log(LOG_DEBUG,
217740008Sjoerg			    SPP_FMT "Up event", SPP_ARGS(ifp));
2178148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
217930300Sjoerg		if (sp->state[IDX_LCP] == STATE_INITIAL) {
218030300Sjoerg			if (debug)
218169211Sphk				log(-1, "(incoming call)\n");
218230300Sjoerg			sp->pp_flags |= PP_CALLIN;
218330300Sjoerg			lcp.Open(sp);
218430300Sjoerg		} else if (debug)
218569211Sphk			log(-1, "\n");
218688710Sjoerg	} else if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0 &&
218788710Sjoerg		   (sp->state[IDX_LCP] == STATE_INITIAL)) {
2188148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
218988710Sjoerg		lcp.Open(sp);
219025944Sjoerg	}
219125944Sjoerg
219225944Sjoerg	sppp_up_event(&lcp, sp);
219325944Sjoerg}
219425944Sjoerg
219525944Sjoergstatic void
219625944Sjoergsppp_lcp_down(struct sppp *sp)
219725944Sjoerg{
219825944Sjoerg	STDDCL;
219925944Sjoerg
220025944Sjoerg	sppp_down_event(&lcp, sp);
220125944Sjoerg
220225944Sjoerg	/*
220325944Sjoerg	 * If this is neither a dial-on-demand nor a passive
220425944Sjoerg	 * interface, simulate an ``ifconfig down'' action, so the
220525944Sjoerg	 * administrator can force a redial by another ``ifconfig
220625944Sjoerg	 * up''.  XXX For leased line operation, should we immediately
220725944Sjoerg	 * try to reopen the connection here?
220825944Sjoerg	 */
220925944Sjoerg	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
221025944Sjoerg		log(LOG_INFO,
221142066Sphk		    SPP_FMT "Down event, taking interface down.\n",
221240008Sjoerg		    SPP_ARGS(ifp));
221325944Sjoerg		if_down(ifp);
221425944Sjoerg	} else {
221525944Sjoerg		if (debug)
221625944Sjoerg			log(LOG_DEBUG,
221740008Sjoerg			    SPP_FMT "Down event (carrier loss)\n",
221840008Sjoerg			    SPP_ARGS(ifp));
221970199Sjhay		sp->pp_flags &= ~PP_CALLIN;
222070199Sjhay		if (sp->state[IDX_LCP] != STATE_INITIAL)
222170199Sjhay			lcp.Close(sp);
2222148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
222325944Sjoerg	}
222425944Sjoerg}
222525944Sjoerg
222625944Sjoergstatic void
222725944Sjoergsppp_lcp_open(struct sppp *sp)
222825944Sjoerg{
222925944Sjoerg	sppp_open_event(&lcp, sp);
223025944Sjoerg}
223125944Sjoerg
223225944Sjoergstatic void
223325944Sjoergsppp_lcp_close(struct sppp *sp)
223425944Sjoerg{
223525944Sjoerg	sppp_close_event(&lcp, sp);
223625944Sjoerg}
223725944Sjoerg
223825944Sjoergstatic void
223925944Sjoergsppp_lcp_TO(void *cookie)
224025944Sjoerg{
224125944Sjoerg	sppp_to_event(&lcp, (struct sppp *)cookie);
224225944Sjoerg}
224325944Sjoerg
224425944Sjoerg/*
224525944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
224625944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
224725944Sjoerg * caused action scn.  (The return value is used to make the state
224825944Sjoerg * transition decision in the state automaton.)
224925944Sjoerg */
225012820Sphkstatic int
225125944Sjoergsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
22524910Swollman{
225325944Sjoerg	STDDCL;
225411189Sjkh	u_char *buf, *r, *p;
225525944Sjoerg	int origlen, rlen;
225625944Sjoerg	u_long nmagic;
225730300Sjoerg	u_short authproto;
22584910Swollman
225911189Sjkh	len -= 4;
226025944Sjoerg	origlen = len;
226111189Sjkh	buf = r = malloc (len, M_TEMP, M_NOWAIT);
226211189Sjkh	if (! buf)
226311189Sjkh		return (0);
22644910Swollman
226525706Sjoerg	if (debug)
226640008Sjoerg		log(LOG_DEBUG, SPP_FMT "lcp parse opts: ",
226740008Sjoerg		    SPP_ARGS(ifp));
226825706Sjoerg
226925944Sjoerg	/* pass 1: check for things that need to be rejected */
227011189Sjkh	p = (void*) (h+1);
2271161556Scperciva	for (rlen=0; len >= 2 && p[1] >= 2 && len >= p[1];
2272161556Scperciva	    len-=p[1], p+=p[1]) {
227325944Sjoerg		if (debug)
227469211Sphk			log(-1, " %s ", sppp_lcp_opt_name(*p));
227511189Sjkh		switch (*p) {
227611189Sjkh		case LCP_OPT_MAGIC:
227725944Sjoerg			/* Magic number. */
227870199Sjhay			if (len >= 6 && p[1] == 6)
227970199Sjhay				continue;
228070199Sjhay			if (debug)
228170199Sjhay				log(-1, "[invalid] ");
228270199Sjhay			break;
228325944Sjoerg		case LCP_OPT_ASYNC_MAP:
228425944Sjoerg			/* Async control character map. */
228570199Sjhay			if (len >= 6 && p[1] == 6)
228625944Sjoerg				continue;
228725944Sjoerg			if (debug)
228869211Sphk				log(-1, "[invalid] ");
228925944Sjoerg			break;
229025944Sjoerg		case LCP_OPT_MRU:
229125944Sjoerg			/* Maximum receive unit. */
229225944Sjoerg			if (len >= 4 && p[1] == 4)
229325944Sjoerg				continue;
229425944Sjoerg			if (debug)
229569211Sphk				log(-1, "[invalid] ");
229625944Sjoerg			break;
229730300Sjoerg		case LCP_OPT_AUTH_PROTO:
229830300Sjoerg			if (len < 4) {
229930300Sjoerg				if (debug)
230069211Sphk					log(-1, "[invalid] ");
230130300Sjoerg				break;
230230300Sjoerg			}
230330300Sjoerg			authproto = (p[2] << 8) + p[3];
230430300Sjoerg			if (authproto == PPP_CHAP && p[1] != 5) {
230530300Sjoerg				if (debug)
230669211Sphk					log(-1, "[invalid chap len] ");
230730300Sjoerg				break;
230830300Sjoerg			}
230930300Sjoerg			if (sp->myauth.proto == 0) {
231030300Sjoerg				/* we are not configured to do auth */
231130300Sjoerg				if (debug)
231269211Sphk					log(-1, "[not configured] ");
231330300Sjoerg				break;
231430300Sjoerg			}
231530300Sjoerg			/*
231630300Sjoerg			 * Remote want us to authenticate, remember this,
231730300Sjoerg			 * so we stay in PHASE_AUTHENTICATE after LCP got
231830300Sjoerg			 * up.
231930300Sjoerg			 */
232030300Sjoerg			sp->pp_flags |= PP_NEEDAUTH;
232130300Sjoerg			continue;
232225944Sjoerg		default:
232325944Sjoerg			/* Others not supported. */
232425944Sjoerg			if (debug)
232569211Sphk				log(-1, "[rej] ");
232625944Sjoerg			break;
232725944Sjoerg		}
232825944Sjoerg		/* Add the option to rejected list. */
232925944Sjoerg		bcopy (p, r, p[1]);
233025944Sjoerg		r += p[1];
233125944Sjoerg		rlen += p[1];
233225944Sjoerg	}
233325944Sjoerg	if (rlen) {
233425944Sjoerg		if (debug)
233569211Sphk			log(-1, " send conf-rej\n");
233625944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
233725944Sjoerg		return 0;
233825944Sjoerg	} else if (debug)
233969211Sphk		log(-1, "\n");
234025944Sjoerg
234125944Sjoerg	/*
234225944Sjoerg	 * pass 2: check for option values that are unacceptable and
234325944Sjoerg	 * thus require to be nak'ed.
234425944Sjoerg	 */
234525944Sjoerg	if (debug)
234640008Sjoerg		log(LOG_DEBUG, SPP_FMT "lcp parse opt values: ",
234740008Sjoerg		    SPP_ARGS(ifp));
234825944Sjoerg
234925944Sjoerg	p = (void*) (h+1);
235025944Sjoerg	len = origlen;
2351161556Scperciva	for (rlen=0; len >= 2 && p[1] >= 2 && len >= p[1];
2352161556Scperciva	    len-=p[1], p+=p[1]) {
235325944Sjoerg		if (debug)
235469211Sphk			log(-1, " %s ", sppp_lcp_opt_name(*p));
235525944Sjoerg		switch (*p) {
235625944Sjoerg		case LCP_OPT_MAGIC:
235711189Sjkh			/* Magic number -- extract. */
235825944Sjoerg			nmagic = (u_long)p[2] << 24 |
235925944Sjoerg				(u_long)p[3] << 16 | p[4] << 8 | p[5];
236025944Sjoerg			if (nmagic != sp->lcp.magic) {
236170199Sjhay				sp->pp_loopcnt = 0;
236225706Sjoerg				if (debug)
236369211Sphk					log(-1, "0x%lx ", nmagic);
236411189Sjkh				continue;
236511189Sjkh			}
236670199Sjhay			if (debug && sp->pp_loopcnt < MAXALIVECNT*5)
236769211Sphk				log(-1, "[glitch] ");
236825944Sjoerg			++sp->pp_loopcnt;
236925944Sjoerg			/*
237025944Sjoerg			 * We negate our magic here, and NAK it.  If
237125944Sjoerg			 * we see it later in an NAK packet, we
237225944Sjoerg			 * suggest a new one.
237325944Sjoerg			 */
237425944Sjoerg			nmagic = ~sp->lcp.magic;
237525944Sjoerg			/* Gonna NAK it. */
237625944Sjoerg			p[2] = nmagic >> 24;
237725944Sjoerg			p[3] = nmagic >> 16;
237825944Sjoerg			p[4] = nmagic >> 8;
237925944Sjoerg			p[5] = nmagic;
238011189Sjkh			break;
238125944Sjoerg
238211189Sjkh		case LCP_OPT_ASYNC_MAP:
238388506Sjoerg			/*
238488506Sjoerg			 * Async control character map -- just ignore it.
238588506Sjoerg			 *
238688506Sjoerg			 * Quote from RFC 1662, chapter 6:
238788506Sjoerg			 * To enable this functionality, synchronous PPP
238888506Sjoerg			 * implementations MUST always respond to the
238988506Sjoerg			 * Async-Control-Character-Map Configuration
239088506Sjoerg			 * Option with the LCP Configure-Ack.  However,
239188506Sjoerg			 * acceptance of the Configuration Option does
239288506Sjoerg			 * not imply that the synchronous implementation
239388506Sjoerg			 * will do any ACCM mapping.  Instead, all such
239488506Sjoerg			 * octet mapping will be performed by the
239588506Sjoerg			 * asynchronous-to-synchronous converter.
239688506Sjoerg			 */
239788506Sjoerg			continue;
239825944Sjoerg
239911189Sjkh		case LCP_OPT_MRU:
240025944Sjoerg			/*
240125944Sjoerg			 * Maximum receive unit.  Always agreeable,
240225944Sjoerg			 * but ignored by now.
240325944Sjoerg			 */
240425944Sjoerg			sp->lcp.their_mru = p[2] * 256 + p[3];
240525706Sjoerg			if (debug)
240669211Sphk				log(-1, "%lu ", sp->lcp.their_mru);
240711189Sjkh			continue;
240830300Sjoerg
240930300Sjoerg		case LCP_OPT_AUTH_PROTO:
241030300Sjoerg			authproto = (p[2] << 8) + p[3];
241130300Sjoerg			if (sp->myauth.proto != authproto) {
241230300Sjoerg				/* not agreed, nak */
241330300Sjoerg				if (debug)
241469211Sphk					log(-1, "[mine %s != his %s] ",
241530300Sjoerg					       sppp_proto_name(sp->hisauth.proto),
241630300Sjoerg					       sppp_proto_name(authproto));
241730300Sjoerg				p[2] = sp->myauth.proto >> 8;
241830300Sjoerg				p[3] = sp->myauth.proto;
241930300Sjoerg				break;
242030300Sjoerg			}
242130300Sjoerg			if (authproto == PPP_CHAP && p[4] != CHAP_MD5) {
242230300Sjoerg				if (debug)
242369211Sphk					log(-1, "[chap not MD5] ");
242439981Sjoerg				p[4] = CHAP_MD5;
242530300Sjoerg				break;
242630300Sjoerg			}
242730300Sjoerg			continue;
242811189Sjkh		}
242925944Sjoerg		/* Add the option to nak'ed list. */
243025706Sjoerg		bcopy (p, r, p[1]);
243125706Sjoerg		r += p[1];
243211189Sjkh		rlen += p[1];
243312436Speter	}
243425706Sjoerg	if (rlen) {
243570199Sjhay		/*
243670199Sjhay		 * Local and remote magics equal -- loopback?
243770199Sjhay		 */
243870199Sjhay		if (sp->pp_loopcnt >= MAXALIVECNT*5) {
243970199Sjhay			if (sp->pp_loopcnt == MAXALIVECNT*5)
244070199Sjhay				printf (SPP_FMT "loopback\n",
244170199Sjhay					SPP_ARGS(ifp));
244270199Sjhay			if (ifp->if_flags & IFF_UP) {
244370199Sjhay				if_down(ifp);
244470199Sjhay				sppp_qflush(&sp->pp_cpq);
244570199Sjhay				/* XXX ? */
244670199Sjhay				lcp.Down(sp);
244770199Sjhay				lcp.Up(sp);
244870199Sjhay			}
2449131093Srik		} else if (!sp->pp_loopcnt &&
2450131093Srik			   ++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) {
245128036Sjoerg			if (debug)
245269211Sphk				log(-1, " max_failure (%d) exceeded, "
245328036Sjoerg				       "send conf-rej\n",
245428036Sjoerg				       sp->lcp.max_failure);
245528036Sjoerg			sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
245628036Sjoerg		} else {
245728036Sjoerg			if (debug)
245869211Sphk				log(-1, " send conf-nak\n");
245928036Sjoerg			sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
246028036Sjoerg		}
246125944Sjoerg	} else {
246225944Sjoerg		if (debug)
246369211Sphk			log(-1, " send conf-ack\n");
246428036Sjoerg		sp->fail_counter[IDX_LCP] = 0;
246525944Sjoerg		sp->pp_loopcnt = 0;
246625944Sjoerg		sppp_cp_send (sp, PPP_LCP, CONF_ACK,
246725944Sjoerg			      h->ident, origlen, h+1);
246825944Sjoerg	}
246925944Sjoerg
247011189Sjkh	free (buf, M_TEMP);
247111189Sjkh	return (rlen == 0);
24724910Swollman}
24734910Swollman
247425944Sjoerg/*
247525944Sjoerg * Analyze the LCP Configure-Reject option list, and adjust our
247625944Sjoerg * negotiation.
247725944Sjoerg */
247812820Sphkstatic void
247925944Sjoergsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
24804910Swollman{
248125944Sjoerg	STDDCL;
248225944Sjoerg	u_char *buf, *p;
24834910Swollman
248425944Sjoerg	len -= 4;
248525944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
248625944Sjoerg	if (!buf)
24874910Swollman		return;
248825944Sjoerg
248925944Sjoerg	if (debug)
249040008Sjoerg		log(LOG_DEBUG, SPP_FMT "lcp rej opts: ",
249140008Sjoerg		    SPP_ARGS(ifp));
249225944Sjoerg
249325944Sjoerg	p = (void*) (h+1);
2494161556Scperciva	for (; len >= 2 && p[1] >= 2 && len >= p[1];
2495161556Scperciva	    len -= p[1], p += p[1]) {
249625944Sjoerg		if (debug)
249769211Sphk			log(-1, " %s ", sppp_lcp_opt_name(*p));
249825944Sjoerg		switch (*p) {
249925944Sjoerg		case LCP_OPT_MAGIC:
250025944Sjoerg			/* Magic number -- can't use it, use 0 */
250125944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC);
250225944Sjoerg			sp->lcp.magic = 0;
250325944Sjoerg			break;
250425944Sjoerg		case LCP_OPT_MRU:
250525944Sjoerg			/*
250625944Sjoerg			 * Should not be rejected anyway, since we only
250725944Sjoerg			 * negotiate a MRU if explicitly requested by
250825944Sjoerg			 * peer.
250925944Sjoerg			 */
251025944Sjoerg			sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
251125944Sjoerg			break;
251230300Sjoerg		case LCP_OPT_AUTH_PROTO:
251330300Sjoerg			/*
251430300Sjoerg			 * Peer doesn't want to authenticate himself,
251530300Sjoerg			 * deny unless this is a dialout call, and
251630300Sjoerg			 * AUTHFLAG_NOCALLOUT is set.
251730300Sjoerg			 */
251830300Sjoerg			if ((sp->pp_flags & PP_CALLIN) == 0 &&
251930300Sjoerg			    (sp->hisauth.flags & AUTHFLAG_NOCALLOUT) != 0) {
252030300Sjoerg				if (debug)
252169211Sphk					log(-1, "[don't insist on auth "
252230300Sjoerg					       "for callout]");
252330300Sjoerg				sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
252430300Sjoerg				break;
252530300Sjoerg			}
252630300Sjoerg			if (debug)
252769211Sphk				log(-1, "[access denied]\n");
252830300Sjoerg			lcp.Close(sp);
252930300Sjoerg			break;
253025944Sjoerg		}
25314910Swollman	}
253225944Sjoerg	if (debug)
253369211Sphk		log(-1, "\n");
253425944Sjoerg	free (buf, M_TEMP);
253525944Sjoerg	return;
253625944Sjoerg}
253725944Sjoerg
253825944Sjoerg/*
253925944Sjoerg * Analyze the LCP Configure-NAK option list, and adjust our
254025944Sjoerg * negotiation.
254125944Sjoerg */
254225944Sjoergstatic void
254325944Sjoergsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
254425944Sjoerg{
254525944Sjoerg	STDDCL;
254625944Sjoerg	u_char *buf, *p;
254725944Sjoerg	u_long magic;
254825944Sjoerg
254925944Sjoerg	len -= 4;
255025944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
255125944Sjoerg	if (!buf)
255225944Sjoerg		return;
255325944Sjoerg
255425944Sjoerg	if (debug)
255540008Sjoerg		log(LOG_DEBUG, SPP_FMT "lcp nak opts: ",
255640008Sjoerg		    SPP_ARGS(ifp));
255725944Sjoerg
255825944Sjoerg	p = (void*) (h+1);
2559161556Scperciva	for (; len >= 2 && p[1] >= 2 && len >= p[1];
2560161556Scperciva	    len -= p[1], p += p[1]) {
256125706Sjoerg		if (debug)
256269211Sphk			log(-1, " %s ", sppp_lcp_opt_name(*p));
256325944Sjoerg		switch (*p) {
256425944Sjoerg		case LCP_OPT_MAGIC:
256525944Sjoerg			/* Magic number -- renegotiate */
256625944Sjoerg			if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
256725944Sjoerg			    len >= 6 && p[1] == 6) {
256825944Sjoerg				magic = (u_long)p[2] << 24 |
256925944Sjoerg					(u_long)p[3] << 16 | p[4] << 8 | p[5];
257025944Sjoerg				/*
257125944Sjoerg				 * If the remote magic is our negated one,
257225944Sjoerg				 * this looks like a loopback problem.
257325944Sjoerg				 * Suggest a new magic to make sure.
257425944Sjoerg				 */
257525944Sjoerg				if (magic == ~sp->lcp.magic) {
257625944Sjoerg					if (debug)
257769211Sphk						log(-1, "magic glitch ");
257835064Sphk					sp->lcp.magic = random();
257925944Sjoerg				} else {
258025944Sjoerg					sp->lcp.magic = magic;
258125944Sjoerg					if (debug)
258269211Sphk						log(-1, "%lu ", magic);
258325944Sjoerg				}
258425944Sjoerg			}
258525944Sjoerg			break;
258625944Sjoerg		case LCP_OPT_MRU:
258725944Sjoerg			/*
258825944Sjoerg			 * Peer wants to advise us to negotiate an MRU.
258925944Sjoerg			 * Agree on it if it's reasonable, or use
259025944Sjoerg			 * default otherwise.
259125944Sjoerg			 */
259225944Sjoerg			if (len >= 4 && p[1] == 4) {
259325944Sjoerg				u_int mru = p[2] * 256 + p[3];
259425944Sjoerg				if (debug)
259569211Sphk					log(-1, "%d ", mru);
259625944Sjoerg				if (mru < PP_MTU || mru > PP_MAX_MRU)
259725944Sjoerg					mru = PP_MTU;
259825944Sjoerg				sp->lcp.mru = mru;
259925944Sjoerg				sp->lcp.opts |= (1 << LCP_OPT_MRU);
260025944Sjoerg			}
260125944Sjoerg			break;
260230300Sjoerg		case LCP_OPT_AUTH_PROTO:
260330300Sjoerg			/*
260430300Sjoerg			 * Peer doesn't like our authentication method,
260530300Sjoerg			 * deny.
260630300Sjoerg			 */
260730300Sjoerg			if (debug)
260869211Sphk				log(-1, "[access denied]\n");
260930300Sjoerg			lcp.Close(sp);
261030300Sjoerg			break;
26114910Swollman		}
261225944Sjoerg	}
261325944Sjoerg	if (debug)
261469211Sphk		log(-1, "\n");
261525944Sjoerg	free (buf, M_TEMP);
261625944Sjoerg	return;
261725944Sjoerg}
261811189Sjkh
261925944Sjoergstatic void
262025944Sjoergsppp_lcp_tlu(struct sppp *sp)
262125944Sjoerg{
262242066Sphk	STDDCL;
262325944Sjoerg	int i;
262425944Sjoerg	u_long mask;
262525944Sjoerg
262625944Sjoerg	/* XXX ? */
262725944Sjoerg	if (! (ifp->if_flags & IFF_UP) &&
2628148887Srwatson	    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
262925944Sjoerg		/* Coming out of loopback mode. */
263025944Sjoerg		if_up(ifp);
263140008Sjoerg		printf (SPP_FMT "up\n", SPP_ARGS(ifp));
263225944Sjoerg	}
263325944Sjoerg
263425944Sjoerg	for (i = 0; i < IDX_COUNT; i++)
263525944Sjoerg		if ((cps[i])->flags & CP_QUAL)
263625944Sjoerg			(cps[i])->Open(sp);
263725944Sjoerg
263830300Sjoerg	if ((sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0 ||
263930300Sjoerg	    (sp->pp_flags & PP_NEEDAUTH) != 0)
264025944Sjoerg		sp->pp_phase = PHASE_AUTHENTICATE;
264125944Sjoerg	else
264225944Sjoerg		sp->pp_phase = PHASE_NETWORK;
264325944Sjoerg
264442066Sphk	if (debug)
264542066Sphk		log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp),
264642066Sphk		    sppp_phase_name(sp->pp_phase));
264725944Sjoerg
264830300Sjoerg	/*
264930300Sjoerg	 * Open all authentication protocols.  This is even required
265030300Sjoerg	 * if we already proceeded to network phase, since it might be
265130300Sjoerg	 * that remote wants us to authenticate, so we might have to
265230300Sjoerg	 * send a PAP request.  Undesired authentication protocols
265330300Sjoerg	 * don't do anything when they get an Open event.
265430300Sjoerg	 */
265530300Sjoerg	for (i = 0; i < IDX_COUNT; i++)
265630300Sjoerg		if ((cps[i])->flags & CP_AUTH)
265730300Sjoerg			(cps[i])->Open(sp);
265830300Sjoerg
265930300Sjoerg	if (sp->pp_phase == PHASE_NETWORK) {
266025944Sjoerg		/* Notify all NCPs. */
266125944Sjoerg		for (i = 0; i < IDX_COUNT; i++)
266288723Sjoerg			if (((cps[i])->flags & CP_NCP) &&
266388723Sjoerg			    /*
266488723Sjoerg			     * XXX
266588723Sjoerg			     * Hack to administratively disable IPv6 if
266688723Sjoerg			     * not desired.  Perhaps we should have another
266788723Sjoerg			     * flag for this, but right now, we can make
266888723Sjoerg			     * all struct cp's read/only.
266988723Sjoerg			     */
267088723Sjoerg			    (cps[i] != &ipv6cp ||
267188723Sjoerg			     (sp->confflags & CONF_ENABLE_IPV6)))
267225944Sjoerg				(cps[i])->Open(sp);
267325944Sjoerg	}
267425944Sjoerg
267525944Sjoerg	/* Send Up events to all started protos. */
267625944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
267788706Sjoerg		if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_LCP) == 0)
267825944Sjoerg			(cps[i])->Up(sp);
267925944Sjoerg
268042104Sphk	/* notify low-level driver of state change */
268142104Sphk	if (sp->pp_chg)
268242104Sphk		sp->pp_chg(sp, (int)sp->pp_phase);
268342104Sphk
268425944Sjoerg	if (sp->pp_phase == PHASE_NETWORK)
268525944Sjoerg		/* if no NCP is starting, close down */
268630300Sjoerg		sppp_lcp_check_and_close(sp);
268725944Sjoerg}
268825944Sjoerg
268925944Sjoergstatic void
269025944Sjoergsppp_lcp_tld(struct sppp *sp)
269125944Sjoerg{
269242066Sphk	STDDCL;
269325944Sjoerg	int i;
269425944Sjoerg	u_long mask;
269525944Sjoerg
269625944Sjoerg	sp->pp_phase = PHASE_TERMINATE;
269725944Sjoerg
269842066Sphk	if (debug)
269942066Sphk		log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp),
270042066Sphk		    sppp_phase_name(sp->pp_phase));
270125944Sjoerg
270225944Sjoerg	/*
270325944Sjoerg	 * Take upper layers down.  We send the Down event first and
270425944Sjoerg	 * the Close second to prevent the upper layers from sending
270525944Sjoerg	 * ``a flurry of terminate-request packets'', as the RFC
270625944Sjoerg	 * describes it.
270725944Sjoerg	 */
270825944Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
270988706Sjoerg		if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_LCP) == 0) {
271025944Sjoerg			(cps[i])->Down(sp);
271125944Sjoerg			(cps[i])->Close(sp);
271225944Sjoerg		}
271325944Sjoerg}
271425944Sjoerg
271525944Sjoergstatic void
271625944Sjoergsppp_lcp_tls(struct sppp *sp)
271725944Sjoerg{
271842066Sphk	STDDCL;
271925944Sjoerg
272025944Sjoerg	sp->pp_phase = PHASE_ESTABLISH;
272125944Sjoerg
272242066Sphk	if (debug)
272342066Sphk		log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp),
272442066Sphk		    sppp_phase_name(sp->pp_phase));
272525944Sjoerg
272625944Sjoerg	/* Notify lower layer if desired. */
272725944Sjoerg	if (sp->pp_tls)
272825944Sjoerg		(sp->pp_tls)(sp);
272941881Sphk	else
273041881Sphk		(sp->pp_up)(sp);
273125944Sjoerg}
273225944Sjoerg
273325944Sjoergstatic void
273425944Sjoergsppp_lcp_tlf(struct sppp *sp)
273525944Sjoerg{
273642066Sphk	STDDCL;
273725944Sjoerg
273825944Sjoerg	sp->pp_phase = PHASE_DEAD;
273942066Sphk	if (debug)
274042066Sphk		log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp),
274142066Sphk		    sppp_phase_name(sp->pp_phase));
274225944Sjoerg
274325944Sjoerg	/* Notify lower layer if desired. */
274425944Sjoerg	if (sp->pp_tlf)
274525944Sjoerg		(sp->pp_tlf)(sp);
274641881Sphk	else
274741881Sphk		(sp->pp_down)(sp);
274825944Sjoerg}
274925944Sjoerg
275025944Sjoergstatic void
275125944Sjoergsppp_lcp_scr(struct sppp *sp)
275225944Sjoerg{
275330300Sjoerg	char opt[6 /* magicnum */ + 4 /* mru */ + 5 /* chap */];
275425944Sjoerg	int i = 0;
275530300Sjoerg	u_short authproto;
275625944Sjoerg
275725944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
275825944Sjoerg		if (! sp->lcp.magic)
275935064Sphk			sp->lcp.magic = random();
276025944Sjoerg		opt[i++] = LCP_OPT_MAGIC;
276125944Sjoerg		opt[i++] = 6;
276225944Sjoerg		opt[i++] = sp->lcp.magic >> 24;
276325944Sjoerg		opt[i++] = sp->lcp.magic >> 16;
276425944Sjoerg		opt[i++] = sp->lcp.magic >> 8;
276525944Sjoerg		opt[i++] = sp->lcp.magic;
276625944Sjoerg	}
276725944Sjoerg
276825944Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_MRU)) {
276925944Sjoerg		opt[i++] = LCP_OPT_MRU;
277025944Sjoerg		opt[i++] = 4;
277125944Sjoerg		opt[i++] = sp->lcp.mru >> 8;
277225944Sjoerg		opt[i++] = sp->lcp.mru;
277325944Sjoerg	}
277425944Sjoerg
277530300Sjoerg	if (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) {
277630300Sjoerg		authproto = sp->hisauth.proto;
277730300Sjoerg		opt[i++] = LCP_OPT_AUTH_PROTO;
277830300Sjoerg		opt[i++] = authproto == PPP_CHAP? 5: 4;
277930300Sjoerg		opt[i++] = authproto >> 8;
278030300Sjoerg		opt[i++] = authproto;
278130300Sjoerg		if (authproto == PPP_CHAP)
278230300Sjoerg			opt[i++] = CHAP_MD5;
278330300Sjoerg	}
278430300Sjoerg
278578064Sume	sp->confid[IDX_LCP] = ++sp->pp_seq[IDX_LCP];
278625944Sjoerg	sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
278725944Sjoerg}
278825944Sjoerg
278925944Sjoerg/*
279030300Sjoerg * Check the open NCPs, return true if at least one NCP is open.
279130300Sjoerg */
279230300Sjoergstatic int
279330300Sjoergsppp_ncp_check(struct sppp *sp)
279430300Sjoerg{
279530300Sjoerg	int i, mask;
279630300Sjoerg
279730300Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
279888706Sjoerg		if ((sp->lcp.protos & mask) && (cps[i])->flags & CP_NCP)
279930300Sjoerg			return 1;
280030300Sjoerg	return 0;
280130300Sjoerg}
280230300Sjoerg
280330300Sjoerg/*
280425944Sjoerg * Re-check the open NCPs and see if we should terminate the link.
280525944Sjoerg * Called by the NCPs during their tlf action handling.
280625944Sjoerg */
280725944Sjoergstatic void
280830300Sjoergsppp_lcp_check_and_close(struct sppp *sp)
280925944Sjoerg{
281025944Sjoerg
281130300Sjoerg	if (sp->pp_phase < PHASE_NETWORK)
281230300Sjoerg		/* don't bother, we are already going down */
281330300Sjoerg		return;
281430300Sjoerg
281530300Sjoerg	if (sppp_ncp_check(sp))
281630300Sjoerg		return;
281730300Sjoerg
281825944Sjoerg	lcp.Close(sp);
281925944Sjoerg}
282070199Sjhay
282170199Sjhay/*
282225944Sjoerg *--------------------------------------------------------------------------*
282325944Sjoerg *                                                                          *
282425944Sjoerg *                        The IPCP implementation.                          *
282525944Sjoerg *                                                                          *
282625944Sjoerg *--------------------------------------------------------------------------*
282725944Sjoerg */
282825944Sjoerg
2829184682Sbz#ifdef INET
283025944Sjoergstatic void
283125944Sjoergsppp_ipcp_init(struct sppp *sp)
283225944Sjoerg{
283325944Sjoerg	sp->ipcp.opts = 0;
283425944Sjoerg	sp->ipcp.flags = 0;
283525944Sjoerg	sp->state[IDX_IPCP] = STATE_INITIAL;
283625944Sjoerg	sp->fail_counter[IDX_IPCP] = 0;
283778064Sume	sp->pp_seq[IDX_IPCP] = 0;
283878064Sume	sp->pp_rseq[IDX_IPCP] = 0;
2839283291Sjkim 	callout_init(&sp->ch[IDX_IPCP], 1);
284025944Sjoerg}
284125944Sjoerg
284225944Sjoergstatic void
284325944Sjoergsppp_ipcp_up(struct sppp *sp)
284425944Sjoerg{
284525944Sjoerg	sppp_up_event(&ipcp, sp);
284625944Sjoerg}
284725944Sjoerg
284825944Sjoergstatic void
284925944Sjoergsppp_ipcp_down(struct sppp *sp)
285025944Sjoerg{
285125944Sjoerg	sppp_down_event(&ipcp, sp);
285225944Sjoerg}
285325944Sjoerg
285425944Sjoergstatic void
285525944Sjoergsppp_ipcp_open(struct sppp *sp)
285625944Sjoerg{
285725944Sjoerg	STDDCL;
285825944Sjoerg	u_long myaddr, hisaddr;
285925944Sjoerg
286088534Sjoerg	sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN | IPCP_MYADDR_SEEN |
286188534Sjoerg			    IPCP_MYADDR_DYN | IPCP_VJ);
286288700Sjoerg	sp->ipcp.opts = 0;
286342104Sphk
286430300Sjoerg	sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
286525944Sjoerg	/*
286625944Sjoerg	 * If we don't have his address, this probably means our
286725944Sjoerg	 * interface doesn't want to talk IP at all.  (This could
286825944Sjoerg	 * be the case if somebody wants to speak only IPX, for
286925944Sjoerg	 * example.)  Don't open IPCP in this case.
287025944Sjoerg	 */
287125944Sjoerg	if (hisaddr == 0L) {
287225944Sjoerg		/* XXX this message should go away */
287325944Sjoerg		if (debug)
287440008Sjoerg			log(LOG_DEBUG, SPP_FMT "ipcp_open(): no IP interface\n",
287540008Sjoerg			    SPP_ARGS(ifp));
287625944Sjoerg		return;
287725944Sjoerg	}
287825944Sjoerg	if (myaddr == 0L) {
287925944Sjoerg		/*
288025944Sjoerg		 * I don't have an assigned address, so i need to
288125944Sjoerg		 * negotiate my address.
288225944Sjoerg		 */
288325944Sjoerg		sp->ipcp.flags |= IPCP_MYADDR_DYN;
288425944Sjoerg		sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
288542104Sphk	} else
288642104Sphk		sp->ipcp.flags |= IPCP_MYADDR_SEEN;
288788723Sjoerg	if (sp->confflags & CONF_ENABLE_VJ) {
288888534Sjoerg		sp->ipcp.opts |= (1 << IPCP_OPT_COMPRESSION);
288988534Sjoerg		sp->ipcp.max_state = MAX_STATES - 1;
289088534Sjoerg		sp->ipcp.compress_cid = 1;
289188534Sjoerg	}
289225944Sjoerg	sppp_open_event(&ipcp, sp);
289325944Sjoerg}
289425944Sjoerg
289525944Sjoergstatic void
289625944Sjoergsppp_ipcp_close(struct sppp *sp)
289725944Sjoerg{
289825944Sjoerg	sppp_close_event(&ipcp, sp);
289925944Sjoerg	if (sp->ipcp.flags & IPCP_MYADDR_DYN)
290025944Sjoerg		/*
290125944Sjoerg		 * My address was dynamic, clear it again.
290225944Sjoerg		 */
290325944Sjoerg		sppp_set_ip_addr(sp, 0L);
290425944Sjoerg}
290525944Sjoerg
290625944Sjoergstatic void
290725944Sjoergsppp_ipcp_TO(void *cookie)
290825944Sjoerg{
290925944Sjoerg	sppp_to_event(&ipcp, (struct sppp *)cookie);
291025944Sjoerg}
291125944Sjoerg
291225944Sjoerg/*
291325944Sjoerg * Analyze a configure request.  Return true if it was agreeable, and
291425944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and
291525944Sjoerg * caused action scn.  (The return value is used to make the state
291625944Sjoerg * transition decision in the state automaton.)
291725944Sjoerg */
291825944Sjoergstatic int
291925944Sjoergsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
292025944Sjoerg{
292125944Sjoerg	u_char *buf, *r, *p;
2922147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
292325944Sjoerg	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
292425944Sjoerg	u_long hisaddr, desiredaddr;
292542104Sphk	int gotmyaddr = 0;
292688534Sjoerg	int desiredcomp;
292725944Sjoerg
292825944Sjoerg	len -= 4;
292925944Sjoerg	origlen = len;
293025944Sjoerg	/*
293125944Sjoerg	 * Make sure to allocate a buf that can at least hold a
293225944Sjoerg	 * conf-nak with an `address' option.  We might need it below.
293325944Sjoerg	 */
293425944Sjoerg	buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
293525944Sjoerg	if (! buf)
293625944Sjoerg		return (0);
293725944Sjoerg
293825944Sjoerg	/* pass 1: see if we can recognize them */
293925944Sjoerg	if (debug)
294040008Sjoerg		log(LOG_DEBUG, SPP_FMT "ipcp parse opts: ",
294140008Sjoerg		    SPP_ARGS(ifp));
294225944Sjoerg	p = (void*) (h+1);
2943161556Scperciva	for (rlen=0; len >= 2 && p[1] >= 2 && len >= p[1];
2944161556Scperciva	    len-=p[1], p+=p[1]) {
294525944Sjoerg		if (debug)
294669211Sphk			log(-1, " %s ", sppp_ipcp_opt_name(*p));
294725944Sjoerg		switch (*p) {
294888534Sjoerg		case IPCP_OPT_COMPRESSION:
294988723Sjoerg			if (!(sp->confflags & CONF_ENABLE_VJ)) {
295088534Sjoerg				/* VJ compression administratively disabled */
295188534Sjoerg				if (debug)
295288534Sjoerg					log(-1, "[locally disabled] ");
295388534Sjoerg				break;
295488534Sjoerg			}
295588534Sjoerg			/*
295688534Sjoerg			 * In theory, we should only conf-rej an
295788534Sjoerg			 * option that is shorter than RFC 1618
295888534Sjoerg			 * requires (i.e. < 4), and should conf-nak
295988534Sjoerg			 * anything else that is not VJ.  However,
296088534Sjoerg			 * since our algorithm always uses the
296188534Sjoerg			 * original option to NAK it with new values,
296288534Sjoerg			 * things would become more complicated.  In
2963298995Spfg			 * practice, the only commonly implemented IP
296488534Sjoerg			 * compression option is VJ anyway, so the
296588534Sjoerg			 * difference is negligible.
296688534Sjoerg			 */
296788534Sjoerg			if (len >= 6 && p[1] == 6) {
296888534Sjoerg				/*
296988534Sjoerg				 * correctly formed compression option
297088534Sjoerg				 * that could be VJ compression
297188534Sjoerg				 */
297288534Sjoerg				continue;
297388534Sjoerg			}
297488534Sjoerg			if (debug)
297588534Sjoerg				log(-1,
297688534Sjoerg				    "optlen %d [invalid/unsupported] ",
297788534Sjoerg				    p[1]);
297888534Sjoerg			break;
297925944Sjoerg		case IPCP_OPT_ADDRESS:
298025944Sjoerg			if (len >= 6 && p[1] == 6) {
298125944Sjoerg				/* correctly formed address option */
298225944Sjoerg				continue;
298325944Sjoerg			}
298425706Sjoerg			if (debug)
298569211Sphk				log(-1, "[invalid] ");
298611189Sjkh			break;
298725944Sjoerg		default:
298825944Sjoerg			/* Others not supported. */
298925944Sjoerg			if (debug)
299069211Sphk				log(-1, "[rej] ");
29914910Swollman			break;
29924910Swollman		}
299325944Sjoerg		/* Add the option to rejected list. */
299425944Sjoerg		bcopy (p, r, p[1]);
299525944Sjoerg		r += p[1];
299625944Sjoerg		rlen += p[1];
299725944Sjoerg	}
299825944Sjoerg	if (rlen) {
299925944Sjoerg		if (debug)
300069211Sphk			log(-1, " send conf-rej\n");
300125944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf);
300225944Sjoerg		return 0;
300325944Sjoerg	} else if (debug)
300469211Sphk		log(-1, "\n");
300525944Sjoerg
300625944Sjoerg	/* pass 2: parse option values */
300730300Sjoerg	sppp_get_ip_addrs(sp, 0, &hisaddr, 0);
300825944Sjoerg	if (debug)
300940008Sjoerg		log(LOG_DEBUG, SPP_FMT "ipcp parse opt values: ",
301040008Sjoerg		       SPP_ARGS(ifp));
301125944Sjoerg	p = (void*) (h+1);
301225944Sjoerg	len = origlen;
3013161556Scperciva	for (rlen=0; len >= 2 && p[1] >= 2 && len >= p[1];
3014161556Scperciva	    len-=p[1], p+=p[1]) {
301525944Sjoerg		if (debug)
301669211Sphk			log(-1, " %s ", sppp_ipcp_opt_name(*p));
301725944Sjoerg		switch (*p) {
301888534Sjoerg		case IPCP_OPT_COMPRESSION:
301988534Sjoerg			desiredcomp = p[2] << 8 | p[3];
302088534Sjoerg			/* We only support VJ */
302188534Sjoerg			if (desiredcomp == IPCP_COMP_VJ) {
302288534Sjoerg				if (debug)
302388534Sjoerg					log(-1, "VJ [ack] ");
302488534Sjoerg				sp->ipcp.flags |= IPCP_VJ;
302588599Sjoerg				sl_compress_init(sp->pp_comp, p[4]);
302688534Sjoerg				sp->ipcp.max_state = p[4];
302788534Sjoerg				sp->ipcp.compress_cid = p[5];
302888534Sjoerg				continue;
302988534Sjoerg			}
303088534Sjoerg			if (debug)
303188534Sjoerg				log(-1,
303288534Sjoerg				    "compproto %#04x [not supported] ",
303388534Sjoerg				    desiredcomp);
303488534Sjoerg			p[2] = IPCP_COMP_VJ >> 8;
303588534Sjoerg			p[3] = IPCP_COMP_VJ;
303688534Sjoerg			p[4] = sp->ipcp.max_state;
303788534Sjoerg			p[5] = sp->ipcp.compress_cid;
303888534Sjoerg			break;
303925944Sjoerg		case IPCP_OPT_ADDRESS:
304042104Sphk			/* This is the address he wants in his end */
304125944Sjoerg			desiredaddr = p[2] << 24 | p[3] << 16 |
304225944Sjoerg				p[4] << 8 | p[5];
304333928Sphk			if (desiredaddr == hisaddr ||
304488702Sjoerg			    (hisaddr >= 1 && hisaddr <= 254 && desiredaddr != 0)) {
304525944Sjoerg				/*
304625944Sjoerg				 * Peer's address is same as our value,
304788702Sjoerg				 * or we have set it to 0.0.0.* to
304833928Sphk				 * indicate that we do not really care,
304925944Sjoerg				 * this is agreeable.  Gonna conf-ack
305025944Sjoerg				 * it.
305125944Sjoerg				 */
305225944Sjoerg				if (debug)
305369211Sphk					log(-1, "%s [ack] ",
305442104Sphk						sppp_dotted_quad(hisaddr));
305525944Sjoerg				/* record that we've seen it already */
305625944Sjoerg				sp->ipcp.flags |= IPCP_HISADDR_SEEN;
305725944Sjoerg				continue;
305825944Sjoerg			}
305925944Sjoerg			/*
306025944Sjoerg			 * The address wasn't agreeable.  This is either
306125944Sjoerg			 * he sent us 0.0.0.0, asking to assign him an
306225944Sjoerg			 * address, or he send us another address not
306325944Sjoerg			 * matching our value.  Either case, we gonna
306425944Sjoerg			 * conf-nak it with our value.
306542104Sphk			 * XXX: we should "rej" if hisaddr == 0
306625944Sjoerg			 */
306725944Sjoerg			if (debug) {
306825944Sjoerg				if (desiredaddr == 0)
306969211Sphk					log(-1, "[addr requested] ");
307025944Sjoerg				else
307169211Sphk					log(-1, "%s [not agreed] ",
307242104Sphk						sppp_dotted_quad(desiredaddr));
307325944Sjoerg
307425944Sjoerg			}
307544235Sphk			p[2] = hisaddr >> 24;
307644235Sphk			p[3] = hisaddr >> 16;
307744235Sphk			p[4] = hisaddr >> 8;
307844235Sphk			p[5] = hisaddr;
307911189Sjkh			break;
308025706Sjoerg		}
308125944Sjoerg		/* Add the option to nak'ed list. */
308225944Sjoerg		bcopy (p, r, p[1]);
308325944Sjoerg		r += p[1];
308425944Sjoerg		rlen += p[1];
308525944Sjoerg	}
308625944Sjoerg
308725944Sjoerg	/*
308825944Sjoerg	 * If we are about to conf-ack the request, but haven't seen
308925944Sjoerg	 * his address so far, gonna conf-nak it instead, with the
309025944Sjoerg	 * `address' option present and our idea of his address being
309125944Sjoerg	 * filled in there, to request negotiation of both addresses.
309225944Sjoerg	 *
309325944Sjoerg	 * XXX This can result in an endless req - nak loop if peer
309425944Sjoerg	 * doesn't want to send us his address.  Q: What should we do
309525944Sjoerg	 * about it?  XXX  A: implement the max-failure counter.
309625944Sjoerg	 */
309742104Sphk	if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN) && !gotmyaddr) {
309825944Sjoerg		buf[0] = IPCP_OPT_ADDRESS;
309925944Sjoerg		buf[1] = 6;
310025944Sjoerg		buf[2] = hisaddr >> 24;
310125944Sjoerg		buf[3] = hisaddr >> 16;
310225944Sjoerg		buf[4] = hisaddr >> 8;
310325944Sjoerg		buf[5] = hisaddr;
310425944Sjoerg		rlen = 6;
310525706Sjoerg		if (debug)
310669211Sphk			log(-1, "still need hisaddr ");
310725944Sjoerg	}
310825944Sjoerg
310925944Sjoerg	if (rlen) {
311025706Sjoerg		if (debug)
311169211Sphk			log(-1, " send conf-nak\n");
311225944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf);
311325944Sjoerg	} else {
311425706Sjoerg		if (debug)
311569211Sphk			log(-1, " send conf-ack\n");
311625944Sjoerg		sppp_cp_send (sp, PPP_IPCP, CONF_ACK,
311725944Sjoerg			      h->ident, origlen, h+1);
311825944Sjoerg	}
311925944Sjoerg
312025944Sjoerg	free (buf, M_TEMP);
312125944Sjoerg	return (rlen == 0);
312225944Sjoerg}
312325944Sjoerg
312425944Sjoerg/*
312525944Sjoerg * Analyze the IPCP Configure-Reject option list, and adjust our
312625944Sjoerg * negotiation.
312725944Sjoerg */
312825944Sjoergstatic void
312925944Sjoergsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
313025944Sjoerg{
313125944Sjoerg	u_char *buf, *p;
3132147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
313325944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
313425944Sjoerg
313525944Sjoerg	len -= 4;
313625944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
313725944Sjoerg	if (!buf)
313825944Sjoerg		return;
313925944Sjoerg
314025944Sjoerg	if (debug)
314140008Sjoerg		log(LOG_DEBUG, SPP_FMT "ipcp rej opts: ",
314240008Sjoerg		    SPP_ARGS(ifp));
314325944Sjoerg
314425944Sjoerg	p = (void*) (h+1);
3145161556Scperciva	for (; len >= 2 && p[1] >= 2 && len >= p[1];
3146161556Scperciva	    len -= p[1], p += p[1]) {
314725706Sjoerg		if (debug)
314869211Sphk			log(-1, " %s ", sppp_ipcp_opt_name(*p));
314925944Sjoerg		switch (*p) {
315088534Sjoerg		case IPCP_OPT_COMPRESSION:
315188534Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESSION);
315288534Sjoerg			break;
315325944Sjoerg		case IPCP_OPT_ADDRESS:
315425944Sjoerg			/*
315525944Sjoerg			 * Peer doesn't grok address option.  This is
315625944Sjoerg			 * bad.  XXX  Should we better give up here?
315742104Sphk			 * XXX We could try old "addresses" option...
315825944Sjoerg			 */
315925944Sjoerg			sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS);
316025944Sjoerg			break;
316125944Sjoerg		}
31624910Swollman	}
316325944Sjoerg	if (debug)
316469211Sphk		log(-1, "\n");
316525944Sjoerg	free (buf, M_TEMP);
316625944Sjoerg	return;
31674910Swollman}
31684910Swollman
316925944Sjoerg/*
317025944Sjoerg * Analyze the IPCP Configure-NAK option list, and adjust our
317125944Sjoerg * negotiation.
317225944Sjoerg */
317312820Sphkstatic void
317425944Sjoergsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
31754910Swollman{
317625944Sjoerg	u_char *buf, *p;
3177147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
317825944Sjoerg	int debug = ifp->if_flags & IFF_DEBUG;
317988534Sjoerg	int desiredcomp;
318025944Sjoerg	u_long wantaddr;
31814910Swollman
318225944Sjoerg	len -= 4;
318325944Sjoerg	buf = malloc (len, M_TEMP, M_NOWAIT);
318425944Sjoerg	if (!buf)
318525944Sjoerg		return;
318625944Sjoerg
318725944Sjoerg	if (debug)
318840008Sjoerg		log(LOG_DEBUG, SPP_FMT "ipcp nak opts: ",
318940008Sjoerg		    SPP_ARGS(ifp));
319025944Sjoerg
319125944Sjoerg	p = (void*) (h+1);
3192161556Scperciva	for (; len >= 2 && p[1] >= 2 && len >= p[1];
3193161556Scperciva	    len -= p[1], p += p[1]) {
319425944Sjoerg		if (debug)
319569211Sphk			log(-1, " %s ", sppp_ipcp_opt_name(*p));
319625944Sjoerg		switch (*p) {
319788534Sjoerg		case IPCP_OPT_COMPRESSION:
319888534Sjoerg			if (len >= 6 && p[1] == 6) {
319988534Sjoerg				desiredcomp = p[2] << 8 | p[3];
320088534Sjoerg				if (debug)
320188534Sjoerg					log(-1, "[wantcomp %#04x] ",
320288534Sjoerg						desiredcomp);
320388534Sjoerg				if (desiredcomp == IPCP_COMP_VJ) {
320488599Sjoerg					sl_compress_init(sp->pp_comp, p[4]);
320588534Sjoerg					sp->ipcp.max_state = p[4];
320688534Sjoerg					sp->ipcp.compress_cid = p[5];
320788534Sjoerg					if (debug)
320888534Sjoerg						log(-1, "[agree] ");
320988534Sjoerg				} else
321088534Sjoerg					sp->ipcp.opts &=
321188534Sjoerg						~(1 << IPCP_OPT_COMPRESSION);
321288534Sjoerg			}
321388534Sjoerg			break;
321425944Sjoerg		case IPCP_OPT_ADDRESS:
321525944Sjoerg			/*
321625944Sjoerg			 * Peer doesn't like our local IP address.  See
321725944Sjoerg			 * if we can do something for him.  We'll drop
321825944Sjoerg			 * him our address then.
321925944Sjoerg			 */
322025944Sjoerg			if (len >= 6 && p[1] == 6) {
322125944Sjoerg				wantaddr = p[2] << 24 | p[3] << 16 |
322225944Sjoerg					p[4] << 8 | p[5];
322325944Sjoerg				sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
322425944Sjoerg				if (debug)
322569211Sphk					log(-1, "[wantaddr %s] ",
322630300Sjoerg					       sppp_dotted_quad(wantaddr));
322725944Sjoerg				/*
322825944Sjoerg				 * When doing dynamic address assignment,
322925944Sjoerg				 * we accept his offer.  Otherwise, we
323025944Sjoerg				 * ignore it and thus continue to negotiate
323125944Sjoerg				 * our already existing value.
323242104Sphk			 	 * XXX: Bogus, if he said no once, he'll
323342104Sphk				 * just say no again, might as well die.
323425944Sjoerg				 */
323525944Sjoerg				if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
323625944Sjoerg					sppp_set_ip_addr(sp, wantaddr);
323725944Sjoerg					if (debug)
323869211Sphk						log(-1, "[agree] ");
323942104Sphk					sp->ipcp.flags |= IPCP_MYADDR_SEEN;
324025944Sjoerg				}
324125944Sjoerg			}
324225944Sjoerg			break;
324325944Sjoerg		}
324425944Sjoerg	}
324525944Sjoerg	if (debug)
324669211Sphk		log(-1, "\n");
324725944Sjoerg	free (buf, M_TEMP);
324825944Sjoerg	return;
32494910Swollman}
32504910Swollman
325112820Sphkstatic void
325225944Sjoergsppp_ipcp_tlu(struct sppp *sp)
32534910Swollman{
325442104Sphk	/* we are up - notify isdn daemon */
325542104Sphk	if (sp->pp_con)
325642104Sphk		sp->pp_con(sp);
32574910Swollman}
32584910Swollman
325925944Sjoergstatic void
326025944Sjoergsppp_ipcp_tld(struct sppp *sp)
326125944Sjoerg{
326225944Sjoerg}
326325944Sjoerg
326425944Sjoergstatic void
326525944Sjoergsppp_ipcp_tls(struct sppp *sp)
326625944Sjoerg{
326725944Sjoerg	/* indicate to LCP that it must stay alive */
326825944Sjoerg	sp->lcp.protos |= (1 << IDX_IPCP);
326925944Sjoerg}
327025944Sjoerg
327125944Sjoergstatic void
327225944Sjoergsppp_ipcp_tlf(struct sppp *sp)
327325944Sjoerg{
327425944Sjoerg	/* we no longer need LCP */
327525944Sjoerg	sp->lcp.protos &= ~(1 << IDX_IPCP);
327630300Sjoerg	sppp_lcp_check_and_close(sp);
327725944Sjoerg}
327825944Sjoerg
327925944Sjoergstatic void
328025944Sjoergsppp_ipcp_scr(struct sppp *sp)
328125944Sjoerg{
328225944Sjoerg	char opt[6 /* compression */ + 6 /* address */];
328325944Sjoerg	u_long ouraddr;
328425944Sjoerg	int i = 0;
328525944Sjoerg
328688534Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
328788534Sjoerg		opt[i++] = IPCP_OPT_COMPRESSION;
328888534Sjoerg		opt[i++] = 6;
328988534Sjoerg		opt[i++] = IPCP_COMP_VJ >> 8;
329088534Sjoerg		opt[i++] = IPCP_COMP_VJ;
329188534Sjoerg		opt[i++] = sp->ipcp.max_state;
329288534Sjoerg		opt[i++] = sp->ipcp.compress_cid;
329388534Sjoerg	}
329425944Sjoerg	if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
329530300Sjoerg		sppp_get_ip_addrs(sp, &ouraddr, 0, 0);
329625944Sjoerg		opt[i++] = IPCP_OPT_ADDRESS;
329725944Sjoerg		opt[i++] = 6;
329825944Sjoerg		opt[i++] = ouraddr >> 24;
329925944Sjoerg		opt[i++] = ouraddr >> 16;
330025944Sjoerg		opt[i++] = ouraddr >> 8;
330125944Sjoerg		opt[i++] = ouraddr;
330225944Sjoerg	}
330325944Sjoerg
330478064Sume	sp->confid[IDX_IPCP] = ++sp->pp_seq[IDX_IPCP];
330525944Sjoerg	sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
330625944Sjoerg}
3307184682Sbz#else /* !INET */
3308184682Sbzstatic void
3309184682Sbzsppp_ipcp_init(struct sppp *sp)
3310184682Sbz{
3311184682Sbz}
331225944Sjoerg
3313184682Sbzstatic void
3314184682Sbzsppp_ipcp_up(struct sppp *sp)
3315184682Sbz{
3316184682Sbz}
3317184682Sbz
3318184682Sbzstatic void
3319184682Sbzsppp_ipcp_down(struct sppp *sp)
3320184682Sbz{
3321184682Sbz}
3322184682Sbz
3323184682Sbzstatic void
3324184682Sbzsppp_ipcp_open(struct sppp *sp)
3325184682Sbz{
3326184682Sbz}
3327184682Sbz
3328184682Sbzstatic void
3329184682Sbzsppp_ipcp_close(struct sppp *sp)
3330184682Sbz{
3331184682Sbz}
3332184682Sbz
3333184682Sbzstatic void
3334184682Sbzsppp_ipcp_TO(void *cookie)
3335184682Sbz{
3336184682Sbz}
3337184682Sbz
3338184682Sbzstatic int
3339184682Sbzsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
3340184682Sbz{
3341184682Sbz	return (0);
3342184682Sbz}
3343184682Sbz
3344184682Sbzstatic void
3345184682Sbzsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
3346184682Sbz{
3347184682Sbz}
3348184682Sbz
3349184682Sbzstatic void
3350184682Sbzsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
3351184682Sbz{
3352184682Sbz}
3353184682Sbz
3354184682Sbzstatic void
3355184682Sbzsppp_ipcp_tlu(struct sppp *sp)
3356184682Sbz{
3357184682Sbz}
3358184682Sbz
3359184682Sbzstatic void
3360184682Sbzsppp_ipcp_tld(struct sppp *sp)
3361184682Sbz{
3362184682Sbz}
3363184682Sbz
3364184682Sbzstatic void
3365184682Sbzsppp_ipcp_tls(struct sppp *sp)
3366184682Sbz{
3367184682Sbz}
3368184682Sbz
3369184682Sbzstatic void
3370184682Sbzsppp_ipcp_tlf(struct sppp *sp)
3371184682Sbz{
3372184682Sbz}
3373184682Sbz
3374184682Sbzstatic void
3375184682Sbzsppp_ipcp_scr(struct sppp *sp)
3376184682Sbz{
3377184682Sbz}
3378184682Sbz#endif
3379184682Sbz
338070199Sjhay/*
338130300Sjoerg *--------------------------------------------------------------------------*
338230300Sjoerg *                                                                          *
338378064Sume *                      The IPv6CP implementation.                          *
338478064Sume *                                                                          *
338578064Sume *--------------------------------------------------------------------------*
338678064Sume */
338778064Sume
338878064Sume#ifdef INET6
338978064Sumestatic void
339078064Sumesppp_ipv6cp_init(struct sppp *sp)
339178064Sume{
339278064Sume	sp->ipv6cp.opts = 0;
339378064Sume	sp->ipv6cp.flags = 0;
339478064Sume	sp->state[IDX_IPV6CP] = STATE_INITIAL;
339578064Sume	sp->fail_counter[IDX_IPV6CP] = 0;
339678064Sume	sp->pp_seq[IDX_IPV6CP] = 0;
339778064Sume	sp->pp_rseq[IDX_IPV6CP] = 0;
3398283291Sjkim 	callout_init(&sp->ch[IDX_IPV6CP], 1);
339978064Sume}
340078064Sume
340178064Sumestatic void
340278064Sumesppp_ipv6cp_up(struct sppp *sp)
340378064Sume{
340478064Sume	sppp_up_event(&ipv6cp, sp);
340578064Sume}
340678064Sume
340778064Sumestatic void
340878064Sumesppp_ipv6cp_down(struct sppp *sp)
340978064Sume{
341078064Sume	sppp_down_event(&ipv6cp, sp);
341178064Sume}
341278064Sume
341378064Sumestatic void
341478064Sumesppp_ipv6cp_open(struct sppp *sp)
341578064Sume{
341678064Sume	STDDCL;
341778064Sume	struct in6_addr myaddr, hisaddr;
341878064Sume
341978064Sume#ifdef IPV6CP_MYIFID_DYN
342078064Sume	sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN);
342178064Sume#else
342278064Sume	sp->ipv6cp.flags &= ~IPV6CP_MYIFID_SEEN;
342378064Sume#endif
342478064Sume
342578064Sume	sppp_get_ip6_addrs(sp, &myaddr, &hisaddr, 0);
342678064Sume	/*
342778064Sume	 * If we don't have our address, this probably means our
342878064Sume	 * interface doesn't want to talk IPv6 at all.  (This could
342978064Sume	 * be the case if somebody wants to speak only IPX, for
343078064Sume	 * example.)  Don't open IPv6CP in this case.
343178064Sume	 */
343278064Sume	if (IN6_IS_ADDR_UNSPECIFIED(&myaddr)) {
343378064Sume		/* XXX this message should go away */
343478064Sume		if (debug)
343578064Sume			log(LOG_DEBUG, SPP_FMT "ipv6cp_open(): no IPv6 interface\n",
343678064Sume			    SPP_ARGS(ifp));
343778064Sume		return;
343878064Sume	}
343978064Sume
344078064Sume	sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
344178064Sume	sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
344278064Sume	sppp_open_event(&ipv6cp, sp);
344378064Sume}
344478064Sume
344578064Sumestatic void
344678064Sumesppp_ipv6cp_close(struct sppp *sp)
344778064Sume{
344878064Sume	sppp_close_event(&ipv6cp, sp);
344978064Sume}
345078064Sume
345178064Sumestatic void
345278064Sumesppp_ipv6cp_TO(void *cookie)
345378064Sume{
345478064Sume	sppp_to_event(&ipv6cp, (struct sppp *)cookie);
345578064Sume}
345678064Sume
345778064Sume/*
345878064Sume * Analyze a configure request.  Return true if it was agreeable, and
345978064Sume * caused action sca, false if it has been rejected or nak'ed, and
346078064Sume * caused action scn.  (The return value is used to make the state
346178064Sume * transition decision in the state automaton.)
346278064Sume */
346378064Sumestatic int
346478064Sumesppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
346578064Sume{
346678064Sume	u_char *buf, *r, *p;
3467147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
346878064Sume	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
346978064Sume	struct in6_addr myaddr, desiredaddr, suggestaddr;
347078064Sume	int ifidcount;
347178064Sume	int type;
347278064Sume	int collision, nohisaddr;
3473165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
347478064Sume
347578064Sume	len -= 4;
347678064Sume	origlen = len;
347778064Sume	/*
347878064Sume	 * Make sure to allocate a buf that can at least hold a
347978064Sume	 * conf-nak with an `address' option.  We might need it below.
348078064Sume	 */
348178064Sume	buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
348278064Sume	if (! buf)
348378064Sume		return (0);
348478064Sume
348578064Sume	/* pass 1: see if we can recognize them */
348678064Sume	if (debug)
348778064Sume		log(LOG_DEBUG, SPP_FMT "ipv6cp parse opts:",
348878064Sume		    SPP_ARGS(ifp));
348978064Sume	p = (void*) (h+1);
349078064Sume	ifidcount = 0;
3491161556Scperciva	for (rlen=0; len >= 2 && p[1] >= 2 && len >= p[1];
3492161556Scperciva	    len-=p[1], p+=p[1]) {
349378064Sume		if (debug)
349478176Sume			log(-1, " %s", sppp_ipv6cp_opt_name(*p));
349578064Sume		switch (*p) {
349678064Sume		case IPV6CP_OPT_IFID:
349778064Sume			if (len >= 10 && p[1] == 10 && ifidcount == 0) {
349878064Sume				/* correctly formed address option */
349978064Sume				ifidcount++;
350078064Sume				continue;
350178064Sume			}
350278064Sume			if (debug)
350378176Sume				log(-1, " [invalid]");
350478064Sume			break;
350578064Sume#ifdef notyet
350678064Sume		case IPV6CP_OPT_COMPRESSION:
350778064Sume			if (len >= 4 && p[1] >= 4) {
350878064Sume				/* correctly formed compress option */
350978064Sume				continue;
351078064Sume			}
351178064Sume			if (debug)
351278176Sume				log(-1, " [invalid]");
351378064Sume			break;
351478064Sume#endif
351578064Sume		default:
351678064Sume			/* Others not supported. */
351778064Sume			if (debug)
351878176Sume				log(-1, " [rej]");
351978064Sume			break;
352078064Sume		}
352178064Sume		/* Add the option to rejected list. */
352278064Sume		bcopy (p, r, p[1]);
352378064Sume		r += p[1];
352478064Sume		rlen += p[1];
352578064Sume	}
352678064Sume	if (rlen) {
352778064Sume		if (debug)
352878176Sume			log(-1, " send conf-rej\n");
352978064Sume		sppp_cp_send (sp, PPP_IPV6CP, CONF_REJ, h->ident, rlen, buf);
353078064Sume		goto end;
353178064Sume	} else if (debug)
353278176Sume		log(-1, "\n");
353378064Sume
353478064Sume	/* pass 2: parse option values */
353578064Sume	sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
353678064Sume	if (debug)
353778064Sume		log(LOG_DEBUG, SPP_FMT "ipv6cp parse opt values: ",
353878064Sume		    SPP_ARGS(ifp));
353978064Sume	p = (void*) (h+1);
354078064Sume	len = origlen;
354178064Sume	type = CONF_ACK;
3542161556Scperciva	for (rlen=0; len >= 2 && p[1] >= 2 && len >= p[1];
3543161556Scperciva	    len-=p[1], p+=p[1]) {
354478064Sume		if (debug)
354578176Sume			log(-1, " %s", sppp_ipv6cp_opt_name(*p));
354678064Sume		switch (*p) {
354778064Sume#ifdef notyet
354878064Sume		case IPV6CP_OPT_COMPRESSION:
354978064Sume			continue;
355078064Sume#endif
355178064Sume		case IPV6CP_OPT_IFID:
355278064Sume			bzero(&desiredaddr, sizeof(desiredaddr));
355378064Sume			bcopy(&p[2], &desiredaddr.s6_addr[8], 8);
355478064Sume			collision = (bcmp(&desiredaddr.s6_addr[8],
355578064Sume					  &myaddr.s6_addr[8], 8) == 0);
355678064Sume			nohisaddr = IN6_IS_ADDR_UNSPECIFIED(&desiredaddr);
355778064Sume
355878064Sume			desiredaddr.s6_addr16[0] = htons(0xfe80);
3559148385Sume			(void)in6_setscope(&desiredaddr, SP2IFP(sp), NULL);
356078064Sume
356178064Sume			if (!collision && !nohisaddr) {
356278064Sume				/* no collision, hisaddr known - Conf-Ack */
356378064Sume				type = CONF_ACK;
356478064Sume
356578064Sume				if (debug) {
356678176Sume					log(-1, " %s [%s]",
3567165118Sbz					    ip6_sprintf(ip6buf, &desiredaddr),
3568165118Sbz					    sppp_cp_type_name(type));
356978064Sume				}
357078064Sume				continue;
357178064Sume			}
357278064Sume
3573250131Seadler			bzero(&suggestaddr, sizeof(suggestaddr));
357478064Sume			if (collision && nohisaddr) {
357578064Sume				/* collision, hisaddr unknown - Conf-Rej */
357678064Sume				type = CONF_REJ;
357778064Sume				bzero(&p[2], 8);
357878064Sume			} else {
357978064Sume				/*
358078064Sume				 * - no collision, hisaddr unknown, or
358178064Sume				 * - collision, hisaddr known
358278064Sume				 * Conf-Nak, suggest hisaddr
358378064Sume				 */
358478064Sume				type = CONF_NAK;
358578064Sume				sppp_suggest_ip6_addr(sp, &suggestaddr);
358678064Sume				bcopy(&suggestaddr.s6_addr[8], &p[2], 8);
358778064Sume			}
358878064Sume			if (debug)
3589165118Sbz				log(-1, " %s [%s]",
3590165118Sbz				    ip6_sprintf(ip6buf, &desiredaddr),
3591165118Sbz				    sppp_cp_type_name(type));
359278064Sume			break;
359378064Sume		}
359478064Sume		/* Add the option to nak'ed list. */
359578064Sume		bcopy (p, r, p[1]);
359678064Sume		r += p[1];
359778064Sume		rlen += p[1];
359878064Sume	}
359978064Sume
360078064Sume	if (rlen == 0 && type == CONF_ACK) {
360178064Sume		if (debug)
360278176Sume			log(-1, " send %s\n", sppp_cp_type_name(type));
360378064Sume		sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, origlen, h+1);
360478064Sume	} else {
360578064Sume#ifdef DIAGNOSTIC
360678064Sume		if (type == CONF_ACK)
360778064Sume			panic("IPv6CP RCR: CONF_ACK with non-zero rlen");
360878064Sume#endif
360978064Sume
361078064Sume		if (debug) {
361178176Sume			log(-1, " send %s suggest %s\n",
3612165118Sbz			    sppp_cp_type_name(type),
3613165118Sbz			    ip6_sprintf(ip6buf, &suggestaddr));
361478064Sume		}
361578064Sume		sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, rlen, buf);
361678064Sume	}
361778064Sume
361878064Sume end:
361978064Sume	free (buf, M_TEMP);
362078064Sume	return (rlen == 0);
362178064Sume}
362278064Sume
362378064Sume/*
362478064Sume * Analyze the IPv6CP Configure-Reject option list, and adjust our
362578064Sume * negotiation.
362678064Sume */
362778064Sumestatic void
362878064Sumesppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
362978064Sume{
363078064Sume	u_char *buf, *p;
3631147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
363278064Sume	int debug = ifp->if_flags & IFF_DEBUG;
363378064Sume
363478064Sume	len -= 4;
363578064Sume	buf = malloc (len, M_TEMP, M_NOWAIT);
363678064Sume	if (!buf)
363778064Sume		return;
363878064Sume
363978064Sume	if (debug)
364078064Sume		log(LOG_DEBUG, SPP_FMT "ipv6cp rej opts:",
364178064Sume		    SPP_ARGS(ifp));
364278064Sume
364378064Sume	p = (void*) (h+1);
3644161556Scperciva	for (; len >= 2 && p[1] >= 2 && len >= p[1];
3645161556Scperciva	    len -= p[1], p += p[1]) {
364678064Sume		if (debug)
364778176Sume			log(-1, " %s", sppp_ipv6cp_opt_name(*p));
364878064Sume		switch (*p) {
364978064Sume		case IPV6CP_OPT_IFID:
365078064Sume			/*
365178064Sume			 * Peer doesn't grok address option.  This is
365278064Sume			 * bad.  XXX  Should we better give up here?
365378064Sume			 */
365478064Sume			sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_IFID);
365578064Sume			break;
365678064Sume#ifdef notyet
365778064Sume		case IPV6CP_OPT_COMPRESS:
365878064Sume			sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_COMPRESS);
365978064Sume			break;
366078064Sume#endif
366178064Sume		}
366278064Sume	}
366378064Sume	if (debug)
366478176Sume		log(-1, "\n");
366578064Sume	free (buf, M_TEMP);
366678064Sume	return;
366778064Sume}
366878064Sume
366978064Sume/*
367078064Sume * Analyze the IPv6CP Configure-NAK option list, and adjust our
367178064Sume * negotiation.
367278064Sume */
367378064Sumestatic void
367478064Sumesppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
367578064Sume{
367678064Sume	u_char *buf, *p;
3677147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
367878064Sume	int debug = ifp->if_flags & IFF_DEBUG;
367978064Sume	struct in6_addr suggestaddr;
3680165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
368178064Sume
368278064Sume	len -= 4;
368378064Sume	buf = malloc (len, M_TEMP, M_NOWAIT);
368478064Sume	if (!buf)
368578064Sume		return;
368678064Sume
368778064Sume	if (debug)
368878064Sume		log(LOG_DEBUG, SPP_FMT "ipv6cp nak opts:",
368978064Sume		    SPP_ARGS(ifp));
369078064Sume
369178064Sume	p = (void*) (h+1);
3692161556Scperciva	for (; len >= 2 && p[1] >= 2 && len >= p[1];
3693161556Scperciva	    len -= p[1], p += p[1]) {
369478064Sume		if (debug)
369578176Sume			log(-1, " %s", sppp_ipv6cp_opt_name(*p));
369678064Sume		switch (*p) {
369778064Sume		case IPV6CP_OPT_IFID:
369878064Sume			/*
369978064Sume			 * Peer doesn't like our local ifid.  See
370078064Sume			 * if we can do something for him.  We'll drop
370178064Sume			 * him our address then.
370278064Sume			 */
370378064Sume			if (len < 10 || p[1] != 10)
370478064Sume				break;
370578064Sume			bzero(&suggestaddr, sizeof(suggestaddr));
370678064Sume			suggestaddr.s6_addr16[0] = htons(0xfe80);
3707148385Sume			(void)in6_setscope(&suggestaddr, SP2IFP(sp), NULL);
370878064Sume			bcopy(&p[2], &suggestaddr.s6_addr[8], 8);
370978064Sume
371078064Sume			sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
371178064Sume			if (debug)
371278176Sume				log(-1, " [suggestaddr %s]",
3713165118Sbz				       ip6_sprintf(ip6buf, &suggestaddr));
371478064Sume#ifdef IPV6CP_MYIFID_DYN
371578064Sume			/*
371678064Sume			 * When doing dynamic address assignment,
371778064Sume			 * we accept his offer.
371878064Sume			 */
371978064Sume			if (sp->ipv6cp.flags & IPV6CP_MYIFID_DYN) {
372078064Sume				struct in6_addr lastsuggest;
372178064Sume				/*
372278064Sume				 * If <suggested myaddr from peer> equals to
372378064Sume				 * <hisaddr we have suggested last time>,
372478064Sume				 * we have a collision.  generate new random
372578064Sume				 * ifid.
372678064Sume				 */
372778064Sume				sppp_suggest_ip6_addr(&lastsuggest);
372878064Sume				if (IN6_ARE_ADDR_EQUAL(&suggestaddr,
372978064Sume						       lastsuggest)) {
373078064Sume					if (debug)
373178176Sume						log(-1, " [random]");
373278064Sume					sppp_gen_ip6_addr(sp, &suggestaddr);
373378064Sume				}
373478064Sume				sppp_set_ip6_addr(sp, &suggestaddr, 0);
373578064Sume				if (debug)
373678176Sume					log(-1, " [agree]");
373778064Sume				sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
373878064Sume			}
373978064Sume#else
374078064Sume			/*
374178064Sume			 * Since we do not do dynamic address assignment,
374278064Sume			 * we ignore it and thus continue to negotiate
374378064Sume			 * our already existing value.  This can possibly
374478064Sume			 * go into infinite request-reject loop.
374578064Sume			 *
374678064Sume			 * This is not likely because we normally use
374778064Sume			 * ifid based on MAC-address.
374878064Sume			 * If you have no ethernet card on the node, too bad.
374978064Sume			 * XXX should we use fail_counter?
375078064Sume			 */
375178064Sume#endif
375278064Sume			break;
375378064Sume#ifdef notyet
375478064Sume		case IPV6CP_OPT_COMPRESS:
375578064Sume			/*
375678064Sume			 * Peer wants different compression parameters.
375778064Sume			 */
375878064Sume			break;
375978064Sume#endif
376078064Sume		}
376178064Sume	}
376278064Sume	if (debug)
376378176Sume		log(-1, "\n");
376478064Sume	free (buf, M_TEMP);
376578064Sume	return;
376678064Sume}
376778064Sumestatic void
376878064Sumesppp_ipv6cp_tlu(struct sppp *sp)
376978064Sume{
377078064Sume	/* we are up - notify isdn daemon */
377178064Sume	if (sp->pp_con)
377278064Sume		sp->pp_con(sp);
377378064Sume}
377478064Sume
377578064Sumestatic void
377678064Sumesppp_ipv6cp_tld(struct sppp *sp)
377778064Sume{
377878064Sume}
377978064Sume
378078064Sumestatic void
378178064Sumesppp_ipv6cp_tls(struct sppp *sp)
378278064Sume{
378378064Sume	/* indicate to LCP that it must stay alive */
378478064Sume	sp->lcp.protos |= (1 << IDX_IPV6CP);
378578064Sume}
378678064Sume
378778064Sumestatic void
378878064Sumesppp_ipv6cp_tlf(struct sppp *sp)
378978064Sume{
379078064Sume
379178064Sume#if 0	/* need #if 0 to close IPv6CP properly */
379278064Sume	/* we no longer need LCP */
379378064Sume	sp->lcp.protos &= ~(1 << IDX_IPV6CP);
379478064Sume	sppp_lcp_check_and_close(sp);
379578064Sume#endif
379678064Sume}
379778064Sume
379878064Sumestatic void
379978064Sumesppp_ipv6cp_scr(struct sppp *sp)
380078064Sume{
380178064Sume	char opt[10 /* ifid */ + 4 /* compression, minimum */];
380278064Sume	struct in6_addr ouraddr;
380378064Sume	int i = 0;
380478064Sume
380578064Sume	if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) {
380678064Sume		sppp_get_ip6_addrs(sp, &ouraddr, 0, 0);
380778064Sume		opt[i++] = IPV6CP_OPT_IFID;
380878064Sume		opt[i++] = 10;
380978064Sume		bcopy(&ouraddr.s6_addr[8], &opt[i], 8);
381078064Sume		i += 8;
381178064Sume	}
381278064Sume
381378064Sume#ifdef notyet
381478064Sume	if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_COMPRESSION)) {
381578064Sume		opt[i++] = IPV6CP_OPT_COMPRESSION;
381678064Sume		opt[i++] = 4;
381778064Sume		opt[i++] = 0;   /* TBD */
381878064Sume		opt[i++] = 0;   /* TBD */
381978064Sume		/* variable length data may follow */
382078064Sume	}
382178064Sume#endif
382278064Sume
382378064Sume	sp->confid[IDX_IPV6CP] = ++sp->pp_seq[IDX_IPV6CP];
382478064Sume	sppp_cp_send(sp, PPP_IPV6CP, CONF_REQ, sp->confid[IDX_IPV6CP], i, &opt);
382578064Sume}
382678064Sume#else /*INET6*/
382778064Sumestatic void sppp_ipv6cp_init(struct sppp *sp)
382878064Sume{
382978064Sume}
383078064Sume
383178064Sumestatic void sppp_ipv6cp_up(struct sppp *sp)
383278064Sume{
383378064Sume}
383478064Sume
383578064Sumestatic void sppp_ipv6cp_down(struct sppp *sp)
383678064Sume{
383778064Sume}
383878064Sume
383978064Sume
384078064Sumestatic void sppp_ipv6cp_open(struct sppp *sp)
384178064Sume{
384278064Sume}
384378064Sume
384478064Sumestatic void sppp_ipv6cp_close(struct sppp *sp)
384578064Sume{
384678064Sume}
384778064Sume
384878064Sumestatic void sppp_ipv6cp_TO(void *sp)
384978064Sume{
385078064Sume}
385178064Sume
385278064Sumestatic int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
385378064Sume{
385478064Sume	return 0;
385578064Sume}
385678064Sume
385778064Sumestatic void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
385878064Sume{
385978064Sume}
386078064Sume
386178064Sumestatic void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
386278064Sume{
386378064Sume}
386478064Sume
386578064Sumestatic void sppp_ipv6cp_tlu(struct sppp *sp)
386678064Sume{
386778064Sume}
386878064Sume
386978064Sumestatic void sppp_ipv6cp_tld(struct sppp *sp)
387078064Sume{
387178064Sume}
387278064Sume
387378064Sumestatic void sppp_ipv6cp_tls(struct sppp *sp)
387478064Sume{
387578064Sume}
387678064Sume
387778064Sumestatic void sppp_ipv6cp_tlf(struct sppp *sp)
387878064Sume{
387978064Sume}
388078064Sume
388178064Sumestatic void sppp_ipv6cp_scr(struct sppp *sp)
388278064Sume{
388378064Sume}
388478064Sume#endif /*INET6*/
388578064Sume
388678064Sume/*
388778064Sume *--------------------------------------------------------------------------*
388878064Sume *                                                                          *
388930300Sjoerg *                        The CHAP implementation.                          *
389030300Sjoerg *                                                                          *
389130300Sjoerg *--------------------------------------------------------------------------*
389230300Sjoerg */
389330300Sjoerg
389430300Sjoerg/*
389530300Sjoerg * The authentication protocols don't employ a full-fledged state machine as
389630300Sjoerg * the control protocols do, since they do have Open and Close events, but
389730300Sjoerg * not Up and Down, nor are they explicitly terminated.  Also, use of the
389830300Sjoerg * authentication protocols may be different in both directions (this makes
389930300Sjoerg * sense, think of a machine that never accepts incoming calls but only
390030300Sjoerg * calls out, it doesn't require the called party to authenticate itself).
390130300Sjoerg *
390230300Sjoerg * Our state machine for the local authentication protocol (we are requesting
390330300Sjoerg * the peer to authenticate) looks like:
390430300Sjoerg *
390530300Sjoerg *						    RCA-
390630300Sjoerg *	      +--------------------------------------------+
390730300Sjoerg *	      V					    scn,tld|
390830300Sjoerg *	  +--------+			       Close   +---------+ RCA+
390930300Sjoerg *	  |	   |<----------------------------------|	 |------+
391030300Sjoerg *   +--->| Closed |				TO*    | Opened	 | sca	|
391130300Sjoerg *   |	  |	   |-----+		       +-------|	 |<-----+
391230300Sjoerg *   |	  +--------+ irc |		       |       +---------+
391330300Sjoerg *   |	    ^		 |		       |	   ^
391430300Sjoerg *   |	    |		 |		       |	   |
391530300Sjoerg *   |	    |		 |		       |	   |
391630300Sjoerg *   |	 TO-|		 |		       |	   |
391730300Sjoerg *   |	    |tld  TO+	 V		       |	   |
391830300Sjoerg *   |	    |	+------->+		       |	   |
391930300Sjoerg *   |	    |	|	 |		       |	   |
392030300Sjoerg *   |	  +--------+	 V		       |	   |
392130300Sjoerg *   |	  |	   |<----+<--------------------+	   |
392230300Sjoerg *   |	  | Req-   | scr				   |
392330300Sjoerg *   |	  | Sent   |					   |
392430300Sjoerg *   |	  |	   |					   |
392530300Sjoerg *   |	  +--------+					   |
392630300Sjoerg *   | RCA- |	| RCA+					   |
392730300Sjoerg *   +------+	+------------------------------------------+
392830300Sjoerg *   scn,tld	  sca,irc,ict,tlu
392930300Sjoerg *
393030300Sjoerg *
393130300Sjoerg *   with:
393230300Sjoerg *
393330300Sjoerg *	Open:	LCP reached authentication phase
393430300Sjoerg *	Close:	LCP reached terminate phase
393530300Sjoerg *
393630300Sjoerg *	RCA+:	received reply (pap-req, chap-response), acceptable
393730300Sjoerg *	RCN:	received reply (pap-req, chap-response), not acceptable
393830300Sjoerg *	TO+:	timeout with restart counter >= 0
393930300Sjoerg *	TO-:	timeout with restart counter < 0
394030300Sjoerg *	TO*:	reschedule timeout for CHAP
394130300Sjoerg *
394230300Sjoerg *	scr:	send request packet (none for PAP, chap-challenge)
394330300Sjoerg *	sca:	send ack packet (pap-ack, chap-success)
394430300Sjoerg *	scn:	send nak packet (pap-nak, chap-failure)
394530300Sjoerg *	ict:	initialize re-challenge timer (CHAP only)
394630300Sjoerg *
394730300Sjoerg *	tlu:	this-layer-up, LCP reaches network phase
394830300Sjoerg *	tld:	this-layer-down, LCP enters terminate phase
394930300Sjoerg *
395030300Sjoerg * Note that in CHAP mode, after sending a new challenge, while the state
395130300Sjoerg * automaton falls back into Req-Sent state, it doesn't signal a tld
395230300Sjoerg * event to LCP, so LCP remains in network phase.  Only after not getting
395330300Sjoerg * any response (or after getting an unacceptable response), CHAP closes,
395430300Sjoerg * causing LCP to enter terminate phase.
395530300Sjoerg *
395630300Sjoerg * With PAP, there is no initial request that can be sent.  The peer is
395730300Sjoerg * expected to send one based on the successful negotiation of PAP as
395830300Sjoerg * the authentication protocol during the LCP option negotiation.
395930300Sjoerg *
396030300Sjoerg * Incoming authentication protocol requests (remote requests
396130300Sjoerg * authentication, we are peer) don't employ a state machine at all,
396230300Sjoerg * they are simply answered.  Some peers [Ascend P50 firmware rev
396330300Sjoerg * 4.50] react allergically when sending IPCP requests while they are
396430300Sjoerg * still in authentication phase (thereby violating the standard that
396530300Sjoerg * demands that these NCP packets are to be discarded), so we keep
396630300Sjoerg * track of the peer demanding us to authenticate, and only proceed to
396730300Sjoerg * phase network once we've seen a positive acknowledge for the
396830300Sjoerg * authentication.
396930300Sjoerg */
397030300Sjoerg
397130300Sjoerg/*
397230300Sjoerg * Handle incoming CHAP packets.
397330300Sjoerg */
3974105228Sphkstatic void
397530300Sjoergsppp_chap_input(struct sppp *sp, struct mbuf *m)
397630300Sjoerg{
397730300Sjoerg	STDDCL;
397830300Sjoerg	struct lcp_header *h;
3979241686Sandre	int len;
398030300Sjoerg	u_char *value, *name, digest[AUTHKEYLEN], dsize;
398130300Sjoerg	int value_len, name_len;
398230300Sjoerg	MD5_CTX ctx;
398330300Sjoerg
398430300Sjoerg	len = m->m_pkthdr.len;
398530300Sjoerg	if (len < 4) {
398630300Sjoerg		if (debug)
398730300Sjoerg			log(LOG_DEBUG,
398840008Sjoerg			    SPP_FMT "chap invalid packet length: %d bytes\n",
398940008Sjoerg			    SPP_ARGS(ifp), len);
399030300Sjoerg		return;
399130300Sjoerg	}
399230300Sjoerg	h = mtod (m, struct lcp_header*);
399330300Sjoerg	if (len > ntohs (h->len))
399430300Sjoerg		len = ntohs (h->len);
399530300Sjoerg
399630300Sjoerg	switch (h->type) {
399730300Sjoerg	/* challenge, failure and success are his authproto */
399830300Sjoerg	case CHAP_CHALLENGE:
399930300Sjoerg		value = 1 + (u_char*)(h+1);
400030300Sjoerg		value_len = value[-1];
400130300Sjoerg		name = value + value_len;
400230300Sjoerg		name_len = len - value_len - 5;
400330300Sjoerg		if (name_len < 0) {
400430300Sjoerg			if (debug) {
400530300Sjoerg				log(LOG_DEBUG,
400640008Sjoerg				    SPP_FMT "chap corrupted challenge "
400730300Sjoerg				    "<%s id=0x%x len=%d",
400840008Sjoerg				    SPP_ARGS(ifp),
400930300Sjoerg				    sppp_auth_type_name(PPP_CHAP, h->type),
401030300Sjoerg				    h->ident, ntohs(h->len));
401144145Sphk				sppp_print_bytes((u_char*) (h+1), len-4);
401269211Sphk				log(-1, ">\n");
401330300Sjoerg			}
401430300Sjoerg			break;
401530300Sjoerg		}
401670199Sjhay
401730300Sjoerg		if (debug) {
401830300Sjoerg			log(LOG_DEBUG,
401940008Sjoerg			    SPP_FMT "chap input <%s id=0x%x len=%d name=",
402040008Sjoerg			    SPP_ARGS(ifp),
402130300Sjoerg			    sppp_auth_type_name(PPP_CHAP, h->type), h->ident,
402230300Sjoerg			    ntohs(h->len));
402330300Sjoerg			sppp_print_string((char*) name, name_len);
402469211Sphk			log(-1, " value-size=%d value=", value_len);
402530300Sjoerg			sppp_print_bytes(value, value_len);
402669211Sphk			log(-1, ">\n");
402730300Sjoerg		}
402830300Sjoerg
402930300Sjoerg		/* Compute reply value. */
403030300Sjoerg		MD5Init(&ctx);
403130300Sjoerg		MD5Update(&ctx, &h->ident, 1);
403230300Sjoerg		MD5Update(&ctx, sp->myauth.secret,
403330300Sjoerg			  sppp_strnlen(sp->myauth.secret, AUTHKEYLEN));
403430300Sjoerg		MD5Update(&ctx, value, value_len);
403530300Sjoerg		MD5Final(digest, &ctx);
403630300Sjoerg		dsize = sizeof digest;
403730300Sjoerg
403830300Sjoerg		sppp_auth_send(&chap, sp, CHAP_RESPONSE, h->ident,
403930300Sjoerg			       sizeof dsize, (const char *)&dsize,
404030300Sjoerg			       sizeof digest, digest,
404140008Sjoerg			       (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN),
404230300Sjoerg			       sp->myauth.name,
404330300Sjoerg			       0);
404430300Sjoerg		break;
404530300Sjoerg
404630300Sjoerg	case CHAP_SUCCESS:
404730300Sjoerg		if (debug) {
404840008Sjoerg			log(LOG_DEBUG, SPP_FMT "chap success",
404940008Sjoerg			    SPP_ARGS(ifp));
405030300Sjoerg			if (len > 4) {
405169211Sphk				log(-1, ": ");
405230300Sjoerg				sppp_print_string((char*)(h + 1), len - 4);
405330300Sjoerg			}
405469211Sphk			log(-1, "\n");
405530300Sjoerg		}
4056138745Srik		SPPP_LOCK(sp);
405730300Sjoerg		sp->pp_flags &= ~PP_NEEDAUTH;
405830300Sjoerg		if (sp->myauth.proto == PPP_CHAP &&
405932169Sgj		    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) &&
406030300Sjoerg		    (sp->lcp.protos & (1 << IDX_CHAP)) == 0) {
406130300Sjoerg			/*
406230300Sjoerg			 * We are authenticator for CHAP but didn't
406330300Sjoerg			 * complete yet.  Leave it to tlu to proceed
406430300Sjoerg			 * to network phase.
406530300Sjoerg			 */
4066138745Srik			SPPP_UNLOCK(sp);
406730300Sjoerg			break;
406830300Sjoerg		}
4069138745Srik		SPPP_UNLOCK(sp);
407030300Sjoerg		sppp_phase_network(sp);
407130300Sjoerg		break;
407230300Sjoerg
407330300Sjoerg	case CHAP_FAILURE:
407430300Sjoerg		if (debug) {
407540008Sjoerg			log(LOG_INFO, SPP_FMT "chap failure",
407640008Sjoerg			    SPP_ARGS(ifp));
407730300Sjoerg			if (len > 4) {
407869211Sphk				log(-1, ": ");
407930300Sjoerg				sppp_print_string((char*)(h + 1), len - 4);
408030300Sjoerg			}
408169211Sphk			log(-1, "\n");
408230300Sjoerg		} else
408340008Sjoerg			log(LOG_INFO, SPP_FMT "chap failure\n",
408440008Sjoerg			    SPP_ARGS(ifp));
408530300Sjoerg		/* await LCP shutdown by authenticator */
408630300Sjoerg		break;
408730300Sjoerg
408830300Sjoerg	/* response is my authproto */
408930300Sjoerg	case CHAP_RESPONSE:
409030300Sjoerg		value = 1 + (u_char*)(h+1);
409130300Sjoerg		value_len = value[-1];
409230300Sjoerg		name = value + value_len;
409330300Sjoerg		name_len = len - value_len - 5;
409430300Sjoerg		if (name_len < 0) {
409530300Sjoerg			if (debug) {
409630300Sjoerg				log(LOG_DEBUG,
409740008Sjoerg				    SPP_FMT "chap corrupted response "
409830300Sjoerg				    "<%s id=0x%x len=%d",
409940008Sjoerg				    SPP_ARGS(ifp),
410030300Sjoerg				    sppp_auth_type_name(PPP_CHAP, h->type),
410130300Sjoerg				    h->ident, ntohs(h->len));
410244145Sphk				sppp_print_bytes((u_char*)(h+1), len-4);
410369211Sphk				log(-1, ">\n");
410430300Sjoerg			}
410530300Sjoerg			break;
410630300Sjoerg		}
410730300Sjoerg		if (h->ident != sp->confid[IDX_CHAP]) {
410830300Sjoerg			if (debug)
410930300Sjoerg				log(LOG_DEBUG,
411040008Sjoerg				    SPP_FMT "chap dropping response for old ID "
411130300Sjoerg				    "(got %d, expected %d)\n",
411240008Sjoerg				    SPP_ARGS(ifp),
411330300Sjoerg				    h->ident, sp->confid[IDX_CHAP]);
411430300Sjoerg			break;
411530300Sjoerg		}
411630300Sjoerg		if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)
411730300Sjoerg		    || bcmp(name, sp->hisauth.name, name_len) != 0) {
411840008Sjoerg			log(LOG_INFO, SPP_FMT "chap response, his name ",
411940008Sjoerg			    SPP_ARGS(ifp));
412030300Sjoerg			sppp_print_string(name, name_len);
412169211Sphk			log(-1, " != expected ");
412230300Sjoerg			sppp_print_string(sp->hisauth.name,
412330300Sjoerg					  sppp_strnlen(sp->hisauth.name, AUTHNAMELEN));
412469211Sphk			log(-1, "\n");
412570199Sjhay		}
412630300Sjoerg		if (debug) {
412740008Sjoerg			log(LOG_DEBUG, SPP_FMT "chap input(%s) "
412830300Sjoerg			    "<%s id=0x%x len=%d name=",
412940008Sjoerg			    SPP_ARGS(ifp),
413030300Sjoerg			    sppp_state_name(sp->state[IDX_CHAP]),
413130300Sjoerg			    sppp_auth_type_name(PPP_CHAP, h->type),
413230300Sjoerg			    h->ident, ntohs (h->len));
413330300Sjoerg			sppp_print_string((char*)name, name_len);
413469211Sphk			log(-1, " value-size=%d value=", value_len);
413530300Sjoerg			sppp_print_bytes(value, value_len);
413669211Sphk			log(-1, ">\n");
413730300Sjoerg		}
413830300Sjoerg		if (value_len != AUTHKEYLEN) {
413930300Sjoerg			if (debug)
414030300Sjoerg				log(LOG_DEBUG,
414140008Sjoerg				    SPP_FMT "chap bad hash value length: "
414230300Sjoerg				    "%d bytes, should be %d\n",
414340008Sjoerg				    SPP_ARGS(ifp), value_len,
414430300Sjoerg				    AUTHKEYLEN);
414530300Sjoerg			break;
414630300Sjoerg		}
414730300Sjoerg
414830300Sjoerg		MD5Init(&ctx);
414930300Sjoerg		MD5Update(&ctx, &h->ident, 1);
415030300Sjoerg		MD5Update(&ctx, sp->hisauth.secret,
415130300Sjoerg			  sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN));
415230300Sjoerg		MD5Update(&ctx, sp->myauth.challenge, AUTHKEYLEN);
415330300Sjoerg		MD5Final(digest, &ctx);
415430300Sjoerg
415530300Sjoerg#define FAILMSG "Failed..."
415630300Sjoerg#define SUCCMSG "Welcome!"
415730300Sjoerg
415830300Sjoerg		if (value_len != sizeof digest ||
415930300Sjoerg		    bcmp(digest, value, value_len) != 0) {
416030300Sjoerg			/* action scn, tld */
416130300Sjoerg			sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident,
416230300Sjoerg				       sizeof(FAILMSG) - 1, (u_char *)FAILMSG,
416330300Sjoerg				       0);
416430300Sjoerg			chap.tld(sp);
416530300Sjoerg			break;
416630300Sjoerg		}
416730300Sjoerg		/* action sca, perhaps tlu */
416830300Sjoerg		if (sp->state[IDX_CHAP] == STATE_REQ_SENT ||
416930300Sjoerg		    sp->state[IDX_CHAP] == STATE_OPENED)
417030300Sjoerg			sppp_auth_send(&chap, sp, CHAP_SUCCESS, h->ident,
417130300Sjoerg				       sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG,
417230300Sjoerg				       0);
417330300Sjoerg		if (sp->state[IDX_CHAP] == STATE_REQ_SENT) {
417430300Sjoerg			sppp_cp_change_state(&chap, sp, STATE_OPENED);
417530300Sjoerg			chap.tlu(sp);
417630300Sjoerg		}
417730300Sjoerg		break;
417830300Sjoerg
417930300Sjoerg	default:
418030300Sjoerg		/* Unknown CHAP packet type -- ignore. */
418130300Sjoerg		if (debug) {
418240008Sjoerg			log(LOG_DEBUG, SPP_FMT "chap unknown input(%s) "
418330300Sjoerg			    "<0x%x id=0x%xh len=%d",
418440008Sjoerg			    SPP_ARGS(ifp),
418530300Sjoerg			    sppp_state_name(sp->state[IDX_CHAP]),
418630300Sjoerg			    h->type, h->ident, ntohs(h->len));
418744145Sphk			sppp_print_bytes((u_char*)(h+1), len-4);
418869211Sphk			log(-1, ">\n");
418930300Sjoerg		}
419030300Sjoerg		break;
419130300Sjoerg
419230300Sjoerg	}
419330300Sjoerg}
419430300Sjoerg
419530300Sjoergstatic void
419630300Sjoergsppp_chap_init(struct sppp *sp)
419730300Sjoerg{
419830300Sjoerg	/* Chap doesn't have STATE_INITIAL at all. */
419930300Sjoerg	sp->state[IDX_CHAP] = STATE_CLOSED;
420030300Sjoerg	sp->fail_counter[IDX_CHAP] = 0;
420178064Sume	sp->pp_seq[IDX_CHAP] = 0;
420278064Sume	sp->pp_rseq[IDX_CHAP] = 0;
4203283291Sjkim 	callout_init(&sp->ch[IDX_CHAP], 1);
420430300Sjoerg}
420530300Sjoerg
420630300Sjoergstatic void
420730300Sjoergsppp_chap_open(struct sppp *sp)
420830300Sjoerg{
420930300Sjoerg	if (sp->myauth.proto == PPP_CHAP &&
421030300Sjoerg	    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
421130300Sjoerg		/* we are authenticator for CHAP, start it */
421230300Sjoerg		chap.scr(sp);
421330300Sjoerg		sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
421430300Sjoerg		sppp_cp_change_state(&chap, sp, STATE_REQ_SENT);
421530300Sjoerg	}
421630300Sjoerg	/* nothing to be done if we are peer, await a challenge */
421730300Sjoerg}
421830300Sjoerg
421930300Sjoergstatic void
422030300Sjoergsppp_chap_close(struct sppp *sp)
422130300Sjoerg{
422230300Sjoerg	if (sp->state[IDX_CHAP] != STATE_CLOSED)
422330300Sjoerg		sppp_cp_change_state(&chap, sp, STATE_CLOSED);
422430300Sjoerg}
422530300Sjoerg
422630300Sjoergstatic void
422730300Sjoergsppp_chap_TO(void *cookie)
422830300Sjoerg{
422930300Sjoerg	struct sppp *sp = (struct sppp *)cookie;
423030300Sjoerg	STDDCL;
423130300Sjoerg
4232138745Srik	SPPP_LOCK(sp);
423330300Sjoerg	if (debug)
423440008Sjoerg		log(LOG_DEBUG, SPP_FMT "chap TO(%s) rst_counter = %d\n",
423540008Sjoerg		    SPP_ARGS(ifp),
423630300Sjoerg		    sppp_state_name(sp->state[IDX_CHAP]),
423730300Sjoerg		    sp->rst_counter[IDX_CHAP]);
423830300Sjoerg
423930300Sjoerg	if (--sp->rst_counter[IDX_CHAP] < 0)
424030300Sjoerg		/* TO- event */
424130300Sjoerg		switch (sp->state[IDX_CHAP]) {
424230300Sjoerg		case STATE_REQ_SENT:
424330300Sjoerg			chap.tld(sp);
424430300Sjoerg			sppp_cp_change_state(&chap, sp, STATE_CLOSED);
424530300Sjoerg			break;
424630300Sjoerg		}
424730300Sjoerg	else
424830300Sjoerg		/* TO+ (or TO*) event */
424930300Sjoerg		switch (sp->state[IDX_CHAP]) {
425030300Sjoerg		case STATE_OPENED:
425130300Sjoerg			/* TO* event */
425230300Sjoerg			sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
4253102412Scharnier			/* FALLTHROUGH */
425430300Sjoerg		case STATE_REQ_SENT:
425530300Sjoerg			chap.scr(sp);
425630300Sjoerg			/* sppp_cp_change_state() will restart the timer */
425730300Sjoerg			sppp_cp_change_state(&chap, sp, STATE_REQ_SENT);
425830300Sjoerg			break;
425930300Sjoerg		}
426030300Sjoerg
4261138745Srik	SPPP_UNLOCK(sp);
426230300Sjoerg}
426330300Sjoerg
426430300Sjoergstatic void
426530300Sjoergsppp_chap_tlu(struct sppp *sp)
426630300Sjoerg{
426730300Sjoerg	STDDCL;
4268241686Sandre	int i;
426930300Sjoerg
427040010Sjoerg	i = 0;
427130300Sjoerg	sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
427230300Sjoerg
427330300Sjoerg	/*
427430300Sjoerg	 * Some broken CHAP implementations (Conware CoNet, firmware
427530300Sjoerg	 * 4.0.?) don't want to re-authenticate their CHAP once the
427630300Sjoerg	 * initial challenge-response exchange has taken place.
427730300Sjoerg	 * Provide for an option to avoid rechallenges.
427830300Sjoerg	 */
427930300Sjoerg	if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) {
428030300Sjoerg		/*
428130300Sjoerg		 * Compute the re-challenge timeout.  This will yield
428230300Sjoerg		 * a number between 300 and 810 seconds.
428330300Sjoerg		 */
428430300Sjoerg		i = 300 + ((unsigned)(random() & 0xff00) >> 7);
4285138745Srik		callout_reset(&sp->ch[IDX_CHAP], i * hz, chap.TO, (void *)sp);
428630300Sjoerg	}
428730300Sjoerg
428830300Sjoerg	if (debug) {
428930300Sjoerg		log(LOG_DEBUG,
429040008Sjoerg		    SPP_FMT "chap %s, ",
429140008Sjoerg		    SPP_ARGS(ifp),
429230300Sjoerg		    sp->pp_phase == PHASE_NETWORK? "reconfirmed": "tlu");
429330300Sjoerg		if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0)
429469211Sphk			log(-1, "next re-challenge in %d seconds\n", i);
429530300Sjoerg		else
4296298995Spfg			log(-1, "re-challenging suppressed\n");
429730300Sjoerg	}
429830300Sjoerg
4299138745Srik	SPPP_LOCK(sp);
430030300Sjoerg	/* indicate to LCP that we need to be closed down */
430130300Sjoerg	sp->lcp.protos |= (1 << IDX_CHAP);
430230300Sjoerg
430330300Sjoerg	if (sp->pp_flags & PP_NEEDAUTH) {
430430300Sjoerg		/*
430530300Sjoerg		 * Remote is authenticator, but his auth proto didn't
430630300Sjoerg		 * complete yet.  Defer the transition to network
430730300Sjoerg		 * phase.
430830300Sjoerg		 */
4309138745Srik		SPPP_UNLOCK(sp);
431030300Sjoerg		return;
431130300Sjoerg	}
4312138745Srik	SPPP_UNLOCK(sp);
431330300Sjoerg
431430300Sjoerg	/*
431530300Sjoerg	 * If we are already in phase network, we are done here.  This
431630300Sjoerg	 * is the case if this is a dummy tlu event after a re-challenge.
431730300Sjoerg	 */
431830300Sjoerg	if (sp->pp_phase != PHASE_NETWORK)
431930300Sjoerg		sppp_phase_network(sp);
432030300Sjoerg}
432130300Sjoerg
432230300Sjoergstatic void
432330300Sjoergsppp_chap_tld(struct sppp *sp)
432430300Sjoerg{
432530300Sjoerg	STDDCL;
432630300Sjoerg
432730300Sjoerg	if (debug)
432840008Sjoerg		log(LOG_DEBUG, SPP_FMT "chap tld\n", SPP_ARGS(ifp));
4329138745Srik	callout_stop(&sp->ch[IDX_CHAP]);
433030300Sjoerg	sp->lcp.protos &= ~(1 << IDX_CHAP);
433130300Sjoerg
433230300Sjoerg	lcp.Close(sp);
433330300Sjoerg}
433430300Sjoerg
433530300Sjoergstatic void
433630300Sjoergsppp_chap_scr(struct sppp *sp)
433730300Sjoerg{
433830300Sjoerg	u_long *ch, seed;
433930300Sjoerg	u_char clen;
434030300Sjoerg
434130300Sjoerg	/* Compute random challenge. */
434230300Sjoerg	ch = (u_long *)sp->myauth.challenge;
434335064Sphk	read_random(&seed, sizeof seed);
434430300Sjoerg	ch[0] = seed ^ random();
434530300Sjoerg	ch[1] = seed ^ random();
434630300Sjoerg	ch[2] = seed ^ random();
434730300Sjoerg	ch[3] = seed ^ random();
434830300Sjoerg	clen = AUTHKEYLEN;
434930300Sjoerg
435078064Sume	sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP];
435130300Sjoerg
435230300Sjoerg	sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP],
435330300Sjoerg		       sizeof clen, (const char *)&clen,
435440008Sjoerg		       (size_t)AUTHKEYLEN, sp->myauth.challenge,
435540008Sjoerg		       (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN),
435630300Sjoerg		       sp->myauth.name,
435730300Sjoerg		       0);
435830300Sjoerg}
435970199Sjhay
436070199Sjhay/*
436130300Sjoerg *--------------------------------------------------------------------------*
436230300Sjoerg *                                                                          *
436330300Sjoerg *                        The PAP implementation.                           *
436430300Sjoerg *                                                                          *
436530300Sjoerg *--------------------------------------------------------------------------*
436630300Sjoerg */
436730300Sjoerg/*
436830300Sjoerg * For PAP, we need to keep a little state also if we are the peer, not the
436930300Sjoerg * authenticator.  This is since we don't get a request to authenticate, but
437030300Sjoerg * have to repeatedly authenticate ourself until we got a response (or the
437130300Sjoerg * retry counter is expired).
437230300Sjoerg */
437330300Sjoerg
437430300Sjoerg/*
437530300Sjoerg * Handle incoming PAP packets.  */
437630300Sjoergstatic void
437730300Sjoergsppp_pap_input(struct sppp *sp, struct mbuf *m)
437830300Sjoerg{
437930300Sjoerg	STDDCL;
438030300Sjoerg	struct lcp_header *h;
4381241686Sandre	int len;
438230300Sjoerg	u_char *name, *passwd, mlen;
438330300Sjoerg	int name_len, passwd_len;
438430300Sjoerg
438530300Sjoerg	len = m->m_pkthdr.len;
438630300Sjoerg	if (len < 5) {
438730300Sjoerg		if (debug)
438830300Sjoerg			log(LOG_DEBUG,
438940008Sjoerg			    SPP_FMT "pap invalid packet length: %d bytes\n",
439040008Sjoerg			    SPP_ARGS(ifp), len);
439130300Sjoerg		return;
439230300Sjoerg	}
439330300Sjoerg	h = mtod (m, struct lcp_header*);
439430300Sjoerg	if (len > ntohs (h->len))
439530300Sjoerg		len = ntohs (h->len);
439630300Sjoerg	switch (h->type) {
439730300Sjoerg	/* PAP request is my authproto */
439830300Sjoerg	case PAP_REQ:
439930300Sjoerg		name = 1 + (u_char*)(h+1);
440030300Sjoerg		name_len = name[-1];
440130300Sjoerg		passwd = name + name_len + 1;
440230300Sjoerg		if (name_len > len - 6 ||
440330300Sjoerg		    (passwd_len = passwd[-1]) > len - 6 - name_len) {
440430300Sjoerg			if (debug) {
440540008Sjoerg				log(LOG_DEBUG, SPP_FMT "pap corrupted input "
440630300Sjoerg				    "<%s id=0x%x len=%d",
440740008Sjoerg				    SPP_ARGS(ifp),
440830300Sjoerg				    sppp_auth_type_name(PPP_PAP, h->type),
440930300Sjoerg				    h->ident, ntohs(h->len));
441044145Sphk				sppp_print_bytes((u_char*)(h+1), len-4);
441169211Sphk				log(-1, ">\n");
441230300Sjoerg			}
441330300Sjoerg			break;
441430300Sjoerg		}
441530300Sjoerg		if (debug) {
441640008Sjoerg			log(LOG_DEBUG, SPP_FMT "pap input(%s) "
441730300Sjoerg			    "<%s id=0x%x len=%d name=",
441840008Sjoerg			    SPP_ARGS(ifp),
441930300Sjoerg			    sppp_state_name(sp->state[IDX_PAP]),
442030300Sjoerg			    sppp_auth_type_name(PPP_PAP, h->type),
442130300Sjoerg			    h->ident, ntohs(h->len));
442230300Sjoerg			sppp_print_string((char*)name, name_len);
442369211Sphk			log(-1, " passwd=");
442430300Sjoerg			sppp_print_string((char*)passwd, passwd_len);
442569211Sphk			log(-1, ">\n");
442630300Sjoerg		}
442774774Sjoerg		if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN) ||
442874774Sjoerg		    passwd_len != sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN) ||
442930300Sjoerg		    bcmp(name, sp->hisauth.name, name_len) != 0 ||
443030300Sjoerg		    bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) {
443130300Sjoerg			/* action scn, tld */
443230300Sjoerg			mlen = sizeof(FAILMSG) - 1;
443330300Sjoerg			sppp_auth_send(&pap, sp, PAP_NAK, h->ident,
443430300Sjoerg				       sizeof mlen, (const char *)&mlen,
443530300Sjoerg				       sizeof(FAILMSG) - 1, (u_char *)FAILMSG,
443630300Sjoerg				       0);
443730300Sjoerg			pap.tld(sp);
443830300Sjoerg			break;
443930300Sjoerg		}
444030300Sjoerg		/* action sca, perhaps tlu */
444130300Sjoerg		if (sp->state[IDX_PAP] == STATE_REQ_SENT ||
444230300Sjoerg		    sp->state[IDX_PAP] == STATE_OPENED) {
444330300Sjoerg			mlen = sizeof(SUCCMSG) - 1;
444430300Sjoerg			sppp_auth_send(&pap, sp, PAP_ACK, h->ident,
444530300Sjoerg				       sizeof mlen, (const char *)&mlen,
444630300Sjoerg				       sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG,
444730300Sjoerg				       0);
444830300Sjoerg		}
444930300Sjoerg		if (sp->state[IDX_PAP] == STATE_REQ_SENT) {
445030300Sjoerg			sppp_cp_change_state(&pap, sp, STATE_OPENED);
445130300Sjoerg			pap.tlu(sp);
445230300Sjoerg		}
445330300Sjoerg		break;
445430300Sjoerg
445530300Sjoerg	/* ack and nak are his authproto */
445630300Sjoerg	case PAP_ACK:
4457138745Srik		callout_stop(&sp->pap_my_to_ch);
445830300Sjoerg		if (debug) {
445940008Sjoerg			log(LOG_DEBUG, SPP_FMT "pap success",
446040008Sjoerg			    SPP_ARGS(ifp));
446130300Sjoerg			name_len = *((char *)h);
446230300Sjoerg			if (len > 5 && name_len) {
446369211Sphk				log(-1, ": ");
446430300Sjoerg				sppp_print_string((char*)(h+1), name_len);
446530300Sjoerg			}
446669211Sphk			log(-1, "\n");
446730300Sjoerg		}
4468138745Srik		SPPP_LOCK(sp);
446930300Sjoerg		sp->pp_flags &= ~PP_NEEDAUTH;
447030300Sjoerg		if (sp->myauth.proto == PPP_PAP &&
447132169Sgj		    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) &&
447230300Sjoerg		    (sp->lcp.protos & (1 << IDX_PAP)) == 0) {
447330300Sjoerg			/*
447430300Sjoerg			 * We are authenticator for PAP but didn't
447530300Sjoerg			 * complete yet.  Leave it to tlu to proceed
447630300Sjoerg			 * to network phase.
447730300Sjoerg			 */
4478138745Srik			SPPP_UNLOCK(sp);
447930300Sjoerg			break;
448030300Sjoerg		}
4481138745Srik		SPPP_UNLOCK(sp);
448230300Sjoerg		sppp_phase_network(sp);
448330300Sjoerg		break;
448430300Sjoerg
448530300Sjoerg	case PAP_NAK:
4486138745Srik		callout_stop (&sp->pap_my_to_ch);
448730300Sjoerg		if (debug) {
448840008Sjoerg			log(LOG_INFO, SPP_FMT "pap failure",
448940008Sjoerg			    SPP_ARGS(ifp));
449030300Sjoerg			name_len = *((char *)h);
449130300Sjoerg			if (len > 5 && name_len) {
449269211Sphk				log(-1, ": ");
449330300Sjoerg				sppp_print_string((char*)(h+1), name_len);
449430300Sjoerg			}
449569211Sphk			log(-1, "\n");
449630300Sjoerg		} else
449740008Sjoerg			log(LOG_INFO, SPP_FMT "pap failure\n",
449840008Sjoerg			    SPP_ARGS(ifp));
449930300Sjoerg		/* await LCP shutdown by authenticator */
450030300Sjoerg		break;
450130300Sjoerg
450230300Sjoerg	default:
450330300Sjoerg		/* Unknown PAP packet type -- ignore. */
450430300Sjoerg		if (debug) {
450540008Sjoerg			log(LOG_DEBUG, SPP_FMT "pap corrupted input "
450630300Sjoerg			    "<0x%x id=0x%x len=%d",
450740008Sjoerg			    SPP_ARGS(ifp),
450830300Sjoerg			    h->type, h->ident, ntohs(h->len));
450944145Sphk			sppp_print_bytes((u_char*)(h+1), len-4);
451069211Sphk			log(-1, ">\n");
451130300Sjoerg		}
451230300Sjoerg		break;
451330300Sjoerg
451430300Sjoerg	}
451530300Sjoerg}
451630300Sjoerg
451730300Sjoergstatic void
451830300Sjoergsppp_pap_init(struct sppp *sp)
451930300Sjoerg{
452030300Sjoerg	/* PAP doesn't have STATE_INITIAL at all. */
452130300Sjoerg	sp->state[IDX_PAP] = STATE_CLOSED;
452230300Sjoerg	sp->fail_counter[IDX_PAP] = 0;
452378064Sume	sp->pp_seq[IDX_PAP] = 0;
452478064Sume	sp->pp_rseq[IDX_PAP] = 0;
4525283291Sjkim 	callout_init(&sp->ch[IDX_PAP], 1);
4526283291Sjkim 	callout_init(&sp->pap_my_to_ch, 1);
452730300Sjoerg}
452830300Sjoerg
452930300Sjoergstatic void
453030300Sjoergsppp_pap_open(struct sppp *sp)
453130300Sjoerg{
453230300Sjoerg	if (sp->hisauth.proto == PPP_PAP &&
453330300Sjoerg	    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
453430300Sjoerg		/* we are authenticator for PAP, start our timer */
453530300Sjoerg		sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
453630300Sjoerg		sppp_cp_change_state(&pap, sp, STATE_REQ_SENT);
453730300Sjoerg	}
453830300Sjoerg	if (sp->myauth.proto == PPP_PAP) {
453930300Sjoerg		/* we are peer, send a request, and start a timer */
454030300Sjoerg		pap.scr(sp);
4541138745Srik		callout_reset(&sp->pap_my_to_ch, sp->lcp.timeout,
4542138745Srik			      sppp_pap_my_TO, (void *)sp);
454330300Sjoerg	}
454430300Sjoerg}
454530300Sjoerg
454630300Sjoergstatic void
454730300Sjoergsppp_pap_close(struct sppp *sp)
454830300Sjoerg{
454930300Sjoerg	if (sp->state[IDX_PAP] != STATE_CLOSED)
455030300Sjoerg		sppp_cp_change_state(&pap, sp, STATE_CLOSED);
455130300Sjoerg}
455230300Sjoerg
455330300Sjoerg/*
455430300Sjoerg * That's the timeout routine if we are authenticator.  Since the
455530300Sjoerg * authenticator is basically passive in PAP, we can't do much here.
455630300Sjoerg */
455730300Sjoergstatic void
455830300Sjoergsppp_pap_TO(void *cookie)
455930300Sjoerg{
456030300Sjoerg	struct sppp *sp = (struct sppp *)cookie;
456130300Sjoerg	STDDCL;
456230300Sjoerg
4563138745Srik	SPPP_LOCK(sp);
456430300Sjoerg	if (debug)
456540008Sjoerg		log(LOG_DEBUG, SPP_FMT "pap TO(%s) rst_counter = %d\n",
456640008Sjoerg		    SPP_ARGS(ifp),
456730300Sjoerg		    sppp_state_name(sp->state[IDX_PAP]),
456830300Sjoerg		    sp->rst_counter[IDX_PAP]);
456930300Sjoerg
457030300Sjoerg	if (--sp->rst_counter[IDX_PAP] < 0)
457130300Sjoerg		/* TO- event */
457230300Sjoerg		switch (sp->state[IDX_PAP]) {
457330300Sjoerg		case STATE_REQ_SENT:
457430300Sjoerg			pap.tld(sp);
457530300Sjoerg			sppp_cp_change_state(&pap, sp, STATE_CLOSED);
457630300Sjoerg			break;
457730300Sjoerg		}
457830300Sjoerg	else
457930300Sjoerg		/* TO+ event, not very much we could do */
458030300Sjoerg		switch (sp->state[IDX_PAP]) {
458130300Sjoerg		case STATE_REQ_SENT:
458230300Sjoerg			/* sppp_cp_change_state() will restart the timer */
458330300Sjoerg			sppp_cp_change_state(&pap, sp, STATE_REQ_SENT);
458430300Sjoerg			break;
458530300Sjoerg		}
458630300Sjoerg
4587138745Srik	SPPP_UNLOCK(sp);
458830300Sjoerg}
458930300Sjoerg
459030300Sjoerg/*
459130300Sjoerg * That's the timeout handler if we are peer.  Since the peer is active,
459230300Sjoerg * we need to retransmit our PAP request since it is apparently lost.
459330300Sjoerg * XXX We should impose a max counter.
459430300Sjoerg */
459530300Sjoergstatic void
459630300Sjoergsppp_pap_my_TO(void *cookie)
459730300Sjoerg{
459830300Sjoerg	struct sppp *sp = (struct sppp *)cookie;
459930300Sjoerg	STDDCL;
460030300Sjoerg
460130300Sjoerg	if (debug)
460240008Sjoerg		log(LOG_DEBUG, SPP_FMT "pap peer TO\n",
460340008Sjoerg		    SPP_ARGS(ifp));
460430300Sjoerg
4605138745Srik	SPPP_LOCK(sp);
460630300Sjoerg	pap.scr(sp);
4607138745Srik	SPPP_UNLOCK(sp);
460830300Sjoerg}
460930300Sjoerg
461030300Sjoergstatic void
461130300Sjoergsppp_pap_tlu(struct sppp *sp)
461230300Sjoerg{
461330300Sjoerg	STDDCL;
461430300Sjoerg
461530300Sjoerg	sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
461630300Sjoerg
461730300Sjoerg	if (debug)
461840008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s tlu\n",
461940008Sjoerg		    SPP_ARGS(ifp), pap.name);
462030300Sjoerg
4621138745Srik	SPPP_LOCK(sp);
462230300Sjoerg	/* indicate to LCP that we need to be closed down */
462330300Sjoerg	sp->lcp.protos |= (1 << IDX_PAP);
462430300Sjoerg
462530300Sjoerg	if (sp->pp_flags & PP_NEEDAUTH) {
462630300Sjoerg		/*
462730300Sjoerg		 * Remote is authenticator, but his auth proto didn't
462830300Sjoerg		 * complete yet.  Defer the transition to network
462930300Sjoerg		 * phase.
463030300Sjoerg		 */
4631138745Srik		SPPP_UNLOCK(sp);
463230300Sjoerg		return;
463330300Sjoerg	}
4634138745Srik	SPPP_UNLOCK(sp);
463530300Sjoerg	sppp_phase_network(sp);
463630300Sjoerg}
463730300Sjoerg
463830300Sjoergstatic void
463930300Sjoergsppp_pap_tld(struct sppp *sp)
464030300Sjoerg{
464130300Sjoerg	STDDCL;
464230300Sjoerg
464330300Sjoerg	if (debug)
464440008Sjoerg		log(LOG_DEBUG, SPP_FMT "pap tld\n", SPP_ARGS(ifp));
4645138745Srik	callout_stop (&sp->ch[IDX_PAP]);
4646138745Srik	callout_stop (&sp->pap_my_to_ch);
464730300Sjoerg	sp->lcp.protos &= ~(1 << IDX_PAP);
464830300Sjoerg
464930300Sjoerg	lcp.Close(sp);
465030300Sjoerg}
465130300Sjoerg
465230300Sjoergstatic void
465330300Sjoergsppp_pap_scr(struct sppp *sp)
465430300Sjoerg{
465530300Sjoerg	u_char idlen, pwdlen;
465630300Sjoerg
465778064Sume	sp->confid[IDX_PAP] = ++sp->pp_seq[IDX_PAP];
465830300Sjoerg	pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN);
465930300Sjoerg	idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN);
466030300Sjoerg
466130300Sjoerg	sppp_auth_send(&pap, sp, PAP_REQ, sp->confid[IDX_PAP],
466230300Sjoerg		       sizeof idlen, (const char *)&idlen,
466340008Sjoerg		       (size_t)idlen, sp->myauth.name,
466430300Sjoerg		       sizeof pwdlen, (const char *)&pwdlen,
466540008Sjoerg		       (size_t)pwdlen, sp->myauth.secret,
466630300Sjoerg		       0);
466730300Sjoerg}
466870199Sjhay
466970199Sjhay/*
467025944Sjoerg * Random miscellaneous functions.
467125944Sjoerg */
467225944Sjoerg
46734910Swollman/*
467430300Sjoerg * Send a PAP or CHAP proto packet.
467530300Sjoerg *
467630300Sjoerg * Varadic function, each of the elements for the ellipsis is of type
467740008Sjoerg * ``size_t mlen, const u_char *msg''.  Processing will stop iff
467830300Sjoerg * mlen == 0.
467942104Sphk * NOTE: never declare variadic functions with types subject to type
468042104Sphk * promotion (i.e. u_char). This is asking for big trouble depending
468142104Sphk * on the architecture you are on...
468230300Sjoerg */
468330300Sjoerg
468430300Sjoergstatic void
468542104Sphksppp_auth_send(const struct cp *cp, struct sppp *sp,
468642104Sphk               unsigned int type, unsigned int id,
468730300Sjoerg	       ...)
468830300Sjoerg{
468930300Sjoerg	STDDCL;
469030300Sjoerg	struct ppp_header *h;
469130300Sjoerg	struct lcp_header *lh;
469230300Sjoerg	struct mbuf *m;
469330300Sjoerg	u_char *p;
469430300Sjoerg	int len;
469542104Sphk	unsigned int mlen;
469630300Sjoerg	const char *msg;
469730300Sjoerg	va_list ap;
469830300Sjoerg
4699243882Sglebius	MGETHDR (m, M_NOWAIT, MT_DATA);
470030300Sjoerg	if (! m)
470130300Sjoerg		return;
470230300Sjoerg	m->m_pkthdr.rcvif = 0;
470330300Sjoerg
470430300Sjoerg	h = mtod (m, struct ppp_header*);
470530300Sjoerg	h->address = PPP_ALLSTATIONS;		/* broadcast address */
470630300Sjoerg	h->control = PPP_UI;			/* Unnumbered Info */
470730300Sjoerg	h->protocol = htons(cp->proto);
470830300Sjoerg
470930300Sjoerg	lh = (struct lcp_header*)(h + 1);
471030300Sjoerg	lh->type = type;
471130300Sjoerg	lh->ident = id;
471230300Sjoerg	p = (u_char*) (lh+1);
471330300Sjoerg
471430300Sjoerg	va_start(ap, id);
471530300Sjoerg	len = 0;
471630300Sjoerg
471742104Sphk	while ((mlen = (unsigned int)va_arg(ap, size_t)) != 0) {
471830300Sjoerg		msg = va_arg(ap, const char *);
471930300Sjoerg		len += mlen;
472030300Sjoerg		if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) {
472130300Sjoerg			va_end(ap);
472230300Sjoerg			m_freem(m);
472330300Sjoerg			return;
472430300Sjoerg		}
472530300Sjoerg
472630300Sjoerg		bcopy(msg, p, mlen);
472730300Sjoerg		p += mlen;
472830300Sjoerg	}
472930300Sjoerg	va_end(ap);
473030300Sjoerg
473130300Sjoerg	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
473230300Sjoerg	lh->len = htons (LCP_HEADER_LEN + len);
473330300Sjoerg
473430300Sjoerg	if (debug) {
473540008Sjoerg		log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d",
473640008Sjoerg		    SPP_ARGS(ifp), cp->name,
473730300Sjoerg		    sppp_auth_type_name(cp->proto, lh->type),
473830300Sjoerg		    lh->ident, ntohs(lh->len));
473944145Sphk		sppp_print_bytes((u_char*) (lh+1), len);
474069211Sphk		log(-1, ">\n");
474130300Sjoerg	}
474269152Sjlemon	if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
4743271867Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
474430300Sjoerg}
474530300Sjoerg
474630300Sjoerg/*
474725944Sjoerg * Flush interface queue.
47484910Swollman */
474912820Sphkstatic void
475025944Sjoergsppp_qflush(struct ifqueue *ifq)
47514910Swollman{
475225944Sjoerg	struct mbuf *m, *n;
47534910Swollman
475425944Sjoerg	n = ifq->ifq_head;
475525944Sjoerg	while ((m = n)) {
4756268787Skevlo		n = m->m_nextpkt;
475725944Sjoerg		m_freem (m);
475811189Sjkh	}
475925944Sjoerg	ifq->ifq_head = 0;
476025944Sjoerg	ifq->ifq_tail = 0;
476125944Sjoerg	ifq->ifq_len = 0;
476225944Sjoerg}
476325944Sjoerg
476425944Sjoerg/*
476525944Sjoerg * Send keepalive packets, every 10 seconds.
476625944Sjoerg */
476725944Sjoergstatic void
476825944Sjoergsppp_keepalive(void *dummy)
476925944Sjoerg{
4770138745Srik	struct sppp *sp = (struct sppp*)dummy;
4771147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
477225944Sjoerg
4773138745Srik	SPPP_LOCK(sp);
4774138745Srik	/* Keepalive mode disabled or channel down? */
4775138745Srik	if (! (sp->pp_flags & PP_KEEPALIVE) ||
4776148887Srwatson	    ! (ifp->if_drv_flags & IFF_DRV_RUNNING))
4777138745Srik		goto out;
477825944Sjoerg
4779139365Srik	if (sp->pp_mode == PP_FR) {
4780139365Srik		sppp_fr_keepalive (sp);
4781139365Srik		goto out;
4782139365Srik	}
4783139365Srik
4784138745Srik	/* No keepalive in PPP mode if LCP not opened yet. */
4785138745Srik	if (sp->pp_mode != IFF_CISCO &&
4786138745Srik	    sp->pp_phase < PHASE_AUTHENTICATE)
4787138745Srik		goto out;
478825944Sjoerg
4789138745Srik	if (sp->pp_alivecnt == MAXALIVECNT) {
4790138745Srik		/* No keepalive packets got.  Stop the interface. */
4791138745Srik		printf (SPP_FMT "down\n", SPP_ARGS(ifp));
4792138745Srik		if_down (ifp);
4793138745Srik		sppp_qflush (&sp->pp_cpq);
4794138745Srik		if (sp->pp_mode != IFF_CISCO) {
4795138745Srik			/* XXX */
4796138745Srik			/* Shut down the PPP link. */
4797138745Srik			lcp.Down(sp);
4798138745Srik			/* Initiate negotiation. XXX */
4799138745Srik			lcp.Up(sp);
48004910Swollman		}
48014910Swollman	}
4802138745Srik	if (sp->pp_alivecnt <= MAXALIVECNT)
4803138745Srik		++sp->pp_alivecnt;
4804138745Srik	if (sp->pp_mode == IFF_CISCO)
4805138745Srik		sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ,
4806138745Srik			 ++sp->pp_seq[IDX_LCP],	sp->pp_rseq[IDX_LCP]);
4807138745Srik	else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
4808351026Semaste		uint32_t nmagic = htonl(sp->lcp.magic);
4809138745Srik		sp->lcp.echoid = ++sp->pp_seq[IDX_LCP];
4810138745Srik		sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
4811138745Srik			sp->lcp.echoid, 4, &nmagic);
4812138745Srik	}
4813138745Srikout:
4814138745Srik	SPPP_UNLOCK(sp);
4815138745Srik 	callout_reset(&sp->keepalive_callout, hz * 10, sppp_keepalive,
4816138745Srik		      (void *)sp);
48174910Swollman}
48184910Swollman
481925944Sjoerg/*
482025944Sjoerg * Get both IP addresses.
482125944Sjoerg */
4822139365Srikvoid
482330300Sjoergsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask)
482425944Sjoerg{
4825147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
482625944Sjoerg	struct ifaddr *ifa;
482730300Sjoerg	struct sockaddr_in *si, *sm;
482825944Sjoerg	u_long ssrc, ddst;
482925944Sjoerg
483040010Sjoerg	sm = NULL;
483125944Sjoerg	ssrc = ddst = 0L;
483225944Sjoerg	/*
483325944Sjoerg	 * Pick the first AF_INET address from the list,
483425944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
483525944Sjoerg	 */
4836298075Spfg	si = NULL;
4837195070Srwatson	if_addr_rlock(ifp);
483842065Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
483925944Sjoerg		if (ifa->ifa_addr->sa_family == AF_INET) {
484025944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
484130300Sjoerg			sm = (struct sockaddr_in *)ifa->ifa_netmask;
484225944Sjoerg			if (si)
484325944Sjoerg				break;
484425944Sjoerg		}
484525944Sjoerg	if (ifa) {
484630300Sjoerg		if (si && si->sin_addr.s_addr) {
484725944Sjoerg			ssrc = si->sin_addr.s_addr;
484830300Sjoerg			if (srcmask)
484930300Sjoerg				*srcmask = ntohl(sm->sin_addr.s_addr);
485030300Sjoerg		}
485125944Sjoerg
485225944Sjoerg		si = (struct sockaddr_in *)ifa->ifa_dstaddr;
485325944Sjoerg		if (si && si->sin_addr.s_addr)
485425944Sjoerg			ddst = si->sin_addr.s_addr;
485525944Sjoerg	}
4856195070Srwatson	if_addr_runlock(ifp);
485725944Sjoerg
485825944Sjoerg	if (dst) *dst = ntohl(ddst);
485925944Sjoerg	if (src) *src = ntohl(ssrc);
486025944Sjoerg}
486125944Sjoerg
4862184682Sbz#ifdef INET
486325944Sjoerg/*
4864241686Sandre * Set my IP address.
486525944Sjoerg */
486625944Sjoergstatic void
486725944Sjoergsppp_set_ip_addr(struct sppp *sp, u_long src)
486825944Sjoerg{
486942104Sphk	STDDCL;
487025944Sjoerg	struct ifaddr *ifa;
487125944Sjoerg	struct sockaddr_in *si;
487284318Sjlemon	struct in_ifaddr *ia;
487325944Sjoerg
487425944Sjoerg	/*
487525944Sjoerg	 * Pick the first AF_INET address from the list,
487625944Sjoerg	 * aliases don't make any sense on a p2p link anyway.
487725944Sjoerg	 */
4878298075Spfg	si = NULL;
4879195070Srwatson	if_addr_rlock(ifp);
4880194813Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
4881194813Srwatson		if (ifa->ifa_addr->sa_family == AF_INET) {
488225944Sjoerg			si = (struct sockaddr_in *)ifa->ifa_addr;
4883194813Srwatson			if (si != NULL) {
4884194813Srwatson				ifa_ref(ifa);
488525944Sjoerg				break;
4886194813Srwatson			}
488725944Sjoerg		}
488840008Sjoerg	}
4889195070Srwatson	if_addr_runlock(ifp);
489040008Sjoerg
4891194813Srwatson	if (ifa != NULL) {
489242104Sphk		int error;
4893194813Srwatson
489442104Sphk		/* delete old route */
489542104Sphk		error = rtinit(ifa, (int)RTM_DELETE, RTF_HOST);
4896194813Srwatson		if (debug && error) {
489742104Sphk			log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit DEL failed, error=%d\n",
489842104Sphk		    		SPP_ARGS(ifp), error);
489942104Sphk		}
490042104Sphk
490142104Sphk		/* set new address */
490225944Sjoerg		si->sin_addr.s_addr = htonl(src);
490384318Sjlemon		ia = ifatoia(ifa);
4904194951Srwatson		IN_IFADDR_WLOCK();
490584318Sjlemon		LIST_REMOVE(ia, ia_hash);
490684318Sjlemon		LIST_INSERT_HEAD(INADDR_HASH(si->sin_addr.s_addr), ia, ia_hash);
4907194951Srwatson		IN_IFADDR_WUNLOCK();
490825944Sjoerg
490942104Sphk		/* add new route */
491070199Sjhay		error = rtinit(ifa, (int)RTM_ADD, RTF_HOST);
4911194813Srwatson		if (debug && error) {
491242104Sphk			log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d",
491342104Sphk		    		SPP_ARGS(ifp), error);
491442104Sphk		}
4915194813Srwatson		ifa_free(ifa);
491642104Sphk	}
491788599Sjoerg}
4918184682Sbz#endif
491978064Sume
492078064Sume#ifdef INET6
492178064Sume/*
492278064Sume * Get both IPv6 addresses.
492378064Sume */
492478064Sumestatic void
492578064Sumesppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst,
492678064Sume		   struct in6_addr *srcmask)
492778064Sume{
4928147256Sbrooks	struct ifnet *ifp = SP2IFP(sp);
492978064Sume	struct ifaddr *ifa;
493078064Sume	struct sockaddr_in6 *si, *sm;
493178064Sume	struct in6_addr ssrc, ddst;
493278064Sume
493378064Sume	sm = NULL;
493478064Sume	bzero(&ssrc, sizeof(ssrc));
493578064Sume	bzero(&ddst, sizeof(ddst));
493678064Sume	/*
493778064Sume	 * Pick the first link-local AF_INET6 address from the list,
493878064Sume	 * aliases don't make any sense on a p2p link anyway.
493978064Sume	 */
4940194813Srwatson	si = NULL;
4941195070Srwatson	if_addr_rlock(ifp);
4942160377Sbrooks	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
494378064Sume		if (ifa->ifa_addr->sa_family == AF_INET6) {
494478064Sume			si = (struct sockaddr_in6 *)ifa->ifa_addr;
494578064Sume			sm = (struct sockaddr_in6 *)ifa->ifa_netmask;
494678064Sume			if (si && IN6_IS_ADDR_LINKLOCAL(&si->sin6_addr))
494778064Sume				break;
494878064Sume		}
494978064Sume	if (ifa) {
495078064Sume		if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) {
495178064Sume			bcopy(&si->sin6_addr, &ssrc, sizeof(ssrc));
495278064Sume			if (srcmask) {
495378064Sume				bcopy(&sm->sin6_addr, srcmask,
495478064Sume				      sizeof(*srcmask));
495578064Sume			}
495678064Sume		}
495778064Sume
495878064Sume		si = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
495978064Sume		if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr))
496078064Sume			bcopy(&si->sin6_addr, &ddst, sizeof(ddst));
496178064Sume	}
496278064Sume
496378064Sume	if (dst)
496478064Sume		bcopy(&ddst, dst, sizeof(*dst));
496578064Sume	if (src)
496678064Sume		bcopy(&ssrc, src, sizeof(*src));
4967195070Srwatson	if_addr_runlock(ifp);
496870199Sjhay}
496942104Sphk
497078064Sume#ifdef IPV6CP_MYIFID_DYN
497178064Sume/*
497278064Sume * Generate random ifid.
497378064Sume */
497478064Sumestatic void
497578064Sumesppp_gen_ip6_addr(struct sppp *sp, struct in6_addr *addr)
497678064Sume{
497778064Sume	/* TBD */
497878064Sume}
497978064Sume
498078064Sume/*
4981241686Sandre * Set my IPv6 address.
498278064Sume */
498378064Sumestatic void
498478064Sumesppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src)
498578064Sume{
498678064Sume	STDDCL;
498778064Sume	struct ifaddr *ifa;
498878064Sume	struct sockaddr_in6 *sin6;
498978064Sume
499078064Sume	/*
499178064Sume	 * Pick the first link-local AF_INET6 address from the list,
499278064Sume	 * aliases don't make any sense on a p2p link anyway.
499378064Sume	 */
499478064Sume
499578064Sume	sin6 = NULL;
4996195070Srwatson	if_addr_rlock(ifp);
4997194813Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
4998194813Srwatson		if (ifa->ifa_addr->sa_family == AF_INET6) {
499978064Sume			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
5000194813Srwatson			if (sin6 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
5001194813Srwatson				ifa_ref(ifa);
500278064Sume				break;
5003194813Srwatson			}
500478064Sume		}
500578064Sume	}
5006195070Srwatson	if_addr_runlock(ifp);
500778064Sume
5008194813Srwatson	if (ifa != NULL) {
500978064Sume		int error;
501078064Sume		struct sockaddr_in6 new_sin6 = *sin6;
501178064Sume
501278064Sume		bcopy(src, &new_sin6.sin6_addr, sizeof(new_sin6.sin6_addr));
501378064Sume		error = in6_ifinit(ifp, ifatoia6(ifa), &new_sin6, 1);
5014194813Srwatson		if (debug && error) {
501578064Sume			log(LOG_DEBUG, SPP_FMT "sppp_set_ip6_addr: in6_ifinit "
501678064Sume			    " failed, error=%d\n", SPP_ARGS(ifp), error);
501778064Sume		}
5018194813Srwatson		ifa_free(ifa);
501978064Sume	}
502078064Sume}
502178064Sume#endif
502278064Sume
502378064Sume/*
502478064Sume * Suggest a candidate address to be used by peer.
502578064Sume */
502678064Sumestatic void
502778064Sumesppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *suggest)
502878064Sume{
502978064Sume	struct in6_addr myaddr;
503078064Sume	struct timeval tv;
503178064Sume
503278064Sume	sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
503378064Sume
503478064Sume	myaddr.s6_addr[8] &= ~0x02;	/* u bit to "local" */
503578064Sume	microtime(&tv);
503678064Sume	if ((tv.tv_usec & 0xff) == 0 && (tv.tv_sec & 0xff) == 0) {
503778064Sume		myaddr.s6_addr[14] ^= 0xff;
503878064Sume		myaddr.s6_addr[15] ^= 0xff;
503978064Sume	} else {
504078064Sume		myaddr.s6_addr[14] ^= (tv.tv_usec & 0xff);
504178064Sume		myaddr.s6_addr[15] ^= (tv.tv_sec & 0xff);
504278064Sume	}
504378064Sume	if (suggest)
504478064Sume		bcopy(&myaddr, suggest, sizeof(myaddr));
504578064Sume}
504678064Sume#endif /*INET6*/
504778064Sume
504830300Sjoergstatic int
504938343Sbdesppp_params(struct sppp *sp, u_long cmd, void *data)
505030300Sjoerg{
505138343Sbde	u_long subcmd;
505230300Sjoerg	struct ifreq *ifr = (struct ifreq *)data;
505388600Sjoerg	struct spppreq *spr;
505488600Sjoerg	int rv = 0;
505530300Sjoerg
5056298075Spfg	if ((spr = malloc(sizeof(struct spppreq), M_TEMP, M_NOWAIT)) == NULL)
505788600Sjoerg		return (EAGAIN);
505830300Sjoerg	/*
5059332288Sbrooks	 * ifr_data_get_ptr(ifr) is supposed to point to a struct spppreq.
506030300Sjoerg	 * Check the cmd word first before attempting to fetch all the
506130300Sjoerg	 * data.
506230300Sjoerg	 */
5063332288Sbrooks	rv = fueword(ifr_data_get_ptr(ifr), &subcmd);
5064273784Skib	if (rv == -1) {
506588600Sjoerg		rv = EFAULT;
506688600Sjoerg		goto quit;
506788600Sjoerg	}
506830300Sjoerg
5069332288Sbrooks	if (copyin(ifr_data_get_ptr(ifr), spr, sizeof(struct spppreq)) != 0) {
507088600Sjoerg		rv = EFAULT;
507188600Sjoerg		goto quit;
507288600Sjoerg	}
507330300Sjoerg
507430300Sjoerg	switch (subcmd) {
5075170490Smjacob	case (u_long)SPPPIOGDEFS:
507688600Sjoerg		if (cmd != SIOCGIFGENERIC) {
507788600Sjoerg			rv = EINVAL;
507888600Sjoerg			break;
507988600Sjoerg		}
508030300Sjoerg		/*
508130300Sjoerg		 * We copy over the entire current state, but clean
508230300Sjoerg		 * out some of the stuff we don't wanna pass up.
508330300Sjoerg		 * Remember, SIOCGIFGENERIC is unprotected, and can be
508430300Sjoerg		 * called by any user.  No need to ever get PAP or
508530300Sjoerg		 * CHAP secrets back to userland anyway.
508630300Sjoerg		 */
508788600Sjoerg		spr->defs.pp_phase = sp->pp_phase;
508888723Sjoerg		spr->defs.enable_vj = (sp->confflags & CONF_ENABLE_VJ) != 0;
508988723Sjoerg		spr->defs.enable_ipv6 = (sp->confflags & CONF_ENABLE_IPV6) != 0;
509088600Sjoerg		spr->defs.lcp = sp->lcp;
509188600Sjoerg		spr->defs.ipcp = sp->ipcp;
509288600Sjoerg		spr->defs.ipv6cp = sp->ipv6cp;
509388600Sjoerg		spr->defs.myauth = sp->myauth;
509488600Sjoerg		spr->defs.hisauth = sp->hisauth;
509588600Sjoerg		bzero(spr->defs.myauth.secret, AUTHKEYLEN);
509688600Sjoerg		bzero(spr->defs.myauth.challenge, AUTHKEYLEN);
509788600Sjoerg		bzero(spr->defs.hisauth.secret, AUTHKEYLEN);
509888600Sjoerg		bzero(spr->defs.hisauth.challenge, AUTHKEYLEN);
509988550Sjoerg		/*
510088550Sjoerg		 * Fixup the LCP timeout value to milliseconds so
510188550Sjoerg		 * spppcontrol doesn't need to bother about the value
510288550Sjoerg		 * of "hz".  We do the reverse calculation below when
510388550Sjoerg		 * setting it.
510488550Sjoerg		 */
510588600Sjoerg		spr->defs.lcp.timeout = sp->lcp.timeout * 1000 / hz;
5106332288Sbrooks		rv = copyout(spr, ifr_data_get_ptr(ifr),
5107332288Sbrooks		    sizeof(struct spppreq));
510888600Sjoerg		break;
510930300Sjoerg
5110170490Smjacob	case (u_long)SPPPIOSDEFS:
511188600Sjoerg		if (cmd != SIOCSIFGENERIC) {
511288600Sjoerg			rv = EINVAL;
511388600Sjoerg			break;
511488600Sjoerg		}
511530300Sjoerg		/*
511688550Sjoerg		 * We have a very specific idea of which fields we
511788550Sjoerg		 * allow being passed back from userland, so to not
511888550Sjoerg		 * clobber our current state.  For one, we only allow
511988550Sjoerg		 * setting anything if LCP is in dead or establish
512088550Sjoerg		 * phase.  Once the authentication negotiations
512188550Sjoerg		 * started, the authentication settings must not be
512288550Sjoerg		 * changed again.  (The administrator can force an
512330300Sjoerg		 * ifconfig down in order to get LCP back into dead
512430300Sjoerg		 * phase.)
512530300Sjoerg		 *
512630300Sjoerg		 * Also, we only allow for authentication parameters to be
512730300Sjoerg		 * specified.
512830300Sjoerg		 *
512930300Sjoerg		 * XXX Should allow to set or clear pp_flags.
513030300Sjoerg		 *
513130300Sjoerg		 * Finally, if the respective authentication protocol to
513230300Sjoerg		 * be used is set differently than 0, but the secret is
513330300Sjoerg		 * passed as all zeros, we don't trash the existing secret.
513430300Sjoerg		 * This allows an administrator to change the system name
513530300Sjoerg		 * only without clobbering the secret (which he didn't get
513630300Sjoerg		 * back in a previous SPPPIOGDEFS call).  However, the
513730300Sjoerg		 * secrets are cleared if the authentication protocol is
513888550Sjoerg		 * reset to 0.  */
513988550Sjoerg		if (sp->pp_phase != PHASE_DEAD &&
514088600Sjoerg		    sp->pp_phase != PHASE_ESTABLISH) {
514188600Sjoerg			rv = EBUSY;
514288600Sjoerg			break;
514388600Sjoerg		}
514430300Sjoerg
514588600Sjoerg		if ((spr->defs.myauth.proto != 0 && spr->defs.myauth.proto != PPP_PAP &&
514688600Sjoerg		     spr->defs.myauth.proto != PPP_CHAP) ||
514788600Sjoerg		    (spr->defs.hisauth.proto != 0 && spr->defs.hisauth.proto != PPP_PAP &&
514888600Sjoerg		     spr->defs.hisauth.proto != PPP_CHAP)) {
514988600Sjoerg			rv = EINVAL;
515088600Sjoerg			break;
515188600Sjoerg		}
515230300Sjoerg
515388600Sjoerg		if (spr->defs.myauth.proto == 0)
515430300Sjoerg			/* resetting myauth */
515530300Sjoerg			bzero(&sp->myauth, sizeof sp->myauth);
515630300Sjoerg		else {
515730300Sjoerg			/* setting/changing myauth */
515888600Sjoerg			sp->myauth.proto = spr->defs.myauth.proto;
515988600Sjoerg			bcopy(spr->defs.myauth.name, sp->myauth.name, AUTHNAMELEN);
516088600Sjoerg			if (spr->defs.myauth.secret[0] != '\0')
516188600Sjoerg				bcopy(spr->defs.myauth.secret, sp->myauth.secret,
516230300Sjoerg				      AUTHKEYLEN);
516330300Sjoerg		}
516488600Sjoerg		if (spr->defs.hisauth.proto == 0)
516530300Sjoerg			/* resetting hisauth */
516630300Sjoerg			bzero(&sp->hisauth, sizeof sp->hisauth);
516730300Sjoerg		else {
516830300Sjoerg			/* setting/changing hisauth */
516988600Sjoerg			sp->hisauth.proto = spr->defs.hisauth.proto;
517088600Sjoerg			sp->hisauth.flags = spr->defs.hisauth.flags;
517188600Sjoerg			bcopy(spr->defs.hisauth.name, sp->hisauth.name, AUTHNAMELEN);
517288600Sjoerg			if (spr->defs.hisauth.secret[0] != '\0')
517388600Sjoerg				bcopy(spr->defs.hisauth.secret, sp->hisauth.secret,
517430300Sjoerg				      AUTHKEYLEN);
517530300Sjoerg		}
517688550Sjoerg		/* set LCP restart timer timeout */
517788600Sjoerg		if (spr->defs.lcp.timeout != 0)
517888600Sjoerg			sp->lcp.timeout = spr->defs.lcp.timeout * hz / 1000;
517988723Sjoerg		/* set VJ enable and IPv6 disable flags */
518088723Sjoerg#ifdef INET
518188723Sjoerg		if (spr->defs.enable_vj)
518288723Sjoerg			sp->confflags |= CONF_ENABLE_VJ;
518388723Sjoerg		else
518488723Sjoerg			sp->confflags &= ~CONF_ENABLE_VJ;
518588723Sjoerg#endif
518688723Sjoerg#ifdef INET6
518788723Sjoerg		if (spr->defs.enable_ipv6)
518888723Sjoerg			sp->confflags |= CONF_ENABLE_IPV6;
518988723Sjoerg		else
519088723Sjoerg			sp->confflags &= ~CONF_ENABLE_IPV6;
519196349Sjoerg#endif
519230300Sjoerg		break;
519330300Sjoerg
519430300Sjoerg	default:
519588600Sjoerg		rv = EINVAL;
519630300Sjoerg	}
519730300Sjoerg
519888600Sjoerg quit:
519988600Sjoerg	free(spr, M_TEMP);
520088600Sjoerg
520188600Sjoerg	return (rv);
520230300Sjoerg}
520330300Sjoerg
520430300Sjoergstatic void
520530300Sjoergsppp_phase_network(struct sppp *sp)
520630300Sjoerg{
520742066Sphk	STDDCL;
520830300Sjoerg	int i;
520930300Sjoerg	u_long mask;
521030300Sjoerg
521130300Sjoerg	sp->pp_phase = PHASE_NETWORK;
521230300Sjoerg
521342066Sphk	if (debug)
521442066Sphk		log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp),
521542066Sphk		    sppp_phase_name(sp->pp_phase));
521630300Sjoerg
521730300Sjoerg	/* Notify NCPs now. */
521830300Sjoerg	for (i = 0; i < IDX_COUNT; i++)
521930300Sjoerg		if ((cps[i])->flags & CP_NCP)
522030300Sjoerg			(cps[i])->Open(sp);
522130300Sjoerg
522230300Sjoerg	/* Send Up events to all NCPs. */
522330300Sjoerg	for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
522488706Sjoerg		if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_NCP))
522530300Sjoerg			(cps[i])->Up(sp);
522630300Sjoerg
522730300Sjoerg	/* if no NCP is starting, all this was in vain, close down */
522830300Sjoerg	sppp_lcp_check_and_close(sp);
522930300Sjoerg}
523030300Sjoerg
523170199Sjhay
523225706Sjoergstatic const char *
523325944Sjoergsppp_cp_type_name(u_char type)
52344910Swollman{
523530300Sjoerg	static char buf[12];
52364910Swollman	switch (type) {
523730300Sjoerg	case CONF_REQ:   return "conf-req";
523830300Sjoerg	case CONF_ACK:   return "conf-ack";
523930300Sjoerg	case CONF_NAK:   return "conf-nak";
524030300Sjoerg	case CONF_REJ:   return "conf-rej";
524130300Sjoerg	case TERM_REQ:   return "term-req";
524230300Sjoerg	case TERM_ACK:   return "term-ack";
524330300Sjoerg	case CODE_REJ:   return "code-rej";
524430300Sjoerg	case PROTO_REJ:  return "proto-rej";
524530300Sjoerg	case ECHO_REQ:   return "echo-req";
524630300Sjoerg	case ECHO_REPLY: return "echo-reply";
524730300Sjoerg	case DISC_REQ:   return "discard-req";
52484910Swollman	}
524944145Sphk	snprintf (buf, sizeof(buf), "cp/0x%x", type);
525030300Sjoerg	return buf;
52514910Swollman}
52524910Swollman
525325706Sjoergstatic const char *
525430300Sjoergsppp_auth_type_name(u_short proto, u_char type)
525530300Sjoerg{
525630300Sjoerg	static char buf[12];
525730300Sjoerg	switch (proto) {
525830300Sjoerg	case PPP_CHAP:
525930300Sjoerg		switch (type) {
526030300Sjoerg		case CHAP_CHALLENGE:	return "challenge";
526130300Sjoerg		case CHAP_RESPONSE:	return "response";
526230300Sjoerg		case CHAP_SUCCESS:	return "success";
526330300Sjoerg		case CHAP_FAILURE:	return "failure";
526430300Sjoerg		}
526530300Sjoerg	case PPP_PAP:
526630300Sjoerg		switch (type) {
526730300Sjoerg		case PAP_REQ:		return "req";
526830300Sjoerg		case PAP_ACK:		return "ack";
526930300Sjoerg		case PAP_NAK:		return "nak";
527030300Sjoerg		}
527130300Sjoerg	}
527244145Sphk	snprintf (buf, sizeof(buf), "auth/0x%x", type);
527330300Sjoerg	return buf;
527430300Sjoerg}
527530300Sjoerg
527630300Sjoergstatic const char *
527725944Sjoergsppp_lcp_opt_name(u_char opt)
52784910Swollman{
527930300Sjoerg	static char buf[12];
528025944Sjoerg	switch (opt) {
528130300Sjoerg	case LCP_OPT_MRU:		return "mru";
528230300Sjoerg	case LCP_OPT_ASYNC_MAP:		return "async-map";
528330300Sjoerg	case LCP_OPT_AUTH_PROTO:	return "auth-proto";
528430300Sjoerg	case LCP_OPT_QUAL_PROTO:	return "qual-proto";
528530300Sjoerg	case LCP_OPT_MAGIC:		return "magic";
528630300Sjoerg	case LCP_OPT_PROTO_COMP:	return "proto-comp";
528730300Sjoerg	case LCP_OPT_ADDR_COMP:		return "addr-comp";
52884910Swollman	}
528944145Sphk	snprintf (buf, sizeof(buf), "lcp/0x%x", opt);
529030300Sjoerg	return buf;
52914910Swollman}
52924910Swollman
5293184682Sbz#ifdef INET
529425944Sjoergstatic const char *
529525944Sjoergsppp_ipcp_opt_name(u_char opt)
529625944Sjoerg{
529730300Sjoerg	static char buf[12];
529825944Sjoerg	switch (opt) {
529930300Sjoerg	case IPCP_OPT_ADDRESSES:	return "addresses";
530030300Sjoerg	case IPCP_OPT_COMPRESSION:	return "compression";
530130300Sjoerg	case IPCP_OPT_ADDRESS:		return "address";
530225944Sjoerg	}
530344145Sphk	snprintf (buf, sizeof(buf), "ipcp/0x%x", opt);
530430300Sjoerg	return buf;
530525944Sjoerg}
5306184682Sbz#endif
530725944Sjoerg
530878064Sume#ifdef INET6
530925944Sjoergstatic const char *
531078064Sumesppp_ipv6cp_opt_name(u_char opt)
531178064Sume{
531278064Sume	static char buf[12];
531378064Sume	switch (opt) {
531478064Sume	case IPV6CP_OPT_IFID:		return "ifid";
531578064Sume	case IPV6CP_OPT_COMPRESSION:	return "compression";
531678064Sume	}
531778064Sume	sprintf (buf, "0x%x", opt);
531878064Sume	return buf;
531978064Sume}
532078064Sume#endif
532178064Sume
532278064Sumestatic const char *
532325944Sjoergsppp_state_name(int state)
532425944Sjoerg{
532525944Sjoerg	switch (state) {
532625944Sjoerg	case STATE_INITIAL:	return "initial";
532725944Sjoerg	case STATE_STARTING:	return "starting";
532825944Sjoerg	case STATE_CLOSED:	return "closed";
532925944Sjoerg	case STATE_STOPPED:	return "stopped";
533025944Sjoerg	case STATE_CLOSING:	return "closing";
533125944Sjoerg	case STATE_STOPPING:	return "stopping";
533225944Sjoerg	case STATE_REQ_SENT:	return "req-sent";
533325944Sjoerg	case STATE_ACK_RCVD:	return "ack-rcvd";
533425944Sjoerg	case STATE_ACK_SENT:	return "ack-sent";
533525944Sjoerg	case STATE_OPENED:	return "opened";
533625944Sjoerg	}
533725944Sjoerg	return "illegal";
533825944Sjoerg}
533925944Sjoerg
534025944Sjoergstatic const char *
534125944Sjoergsppp_phase_name(enum ppp_phase phase)
534225944Sjoerg{
534325944Sjoerg	switch (phase) {
534425944Sjoerg	case PHASE_DEAD:	return "dead";
534525944Sjoerg	case PHASE_ESTABLISH:	return "establish";
534625944Sjoerg	case PHASE_TERMINATE:	return "terminate";
534725944Sjoerg	case PHASE_AUTHENTICATE: return "authenticate";
534825944Sjoerg	case PHASE_NETWORK:	return "network";
534925944Sjoerg	}
535025944Sjoerg	return "illegal";
535125944Sjoerg}
535225944Sjoerg
535325944Sjoergstatic const char *
535425944Sjoergsppp_proto_name(u_short proto)
535525944Sjoerg{
535625944Sjoerg	static char buf[12];
535725944Sjoerg	switch (proto) {
535825944Sjoerg	case PPP_LCP:	return "lcp";
535925944Sjoerg	case PPP_IPCP:	return "ipcp";
536030300Sjoerg	case PPP_PAP:	return "pap";
536130300Sjoerg	case PPP_CHAP:	return "chap";
536278064Sume	case PPP_IPV6CP: return "ipv6cp";
536325944Sjoerg	}
536444145Sphk	snprintf(buf, sizeof(buf), "proto/0x%x", (unsigned)proto);
536525944Sjoerg	return buf;
536625944Sjoerg}
536725944Sjoerg
536812820Sphkstatic void
536930300Sjoergsppp_print_bytes(const u_char *p, u_short len)
53704910Swollman{
537144145Sphk	if (len)
537269211Sphk		log(-1, " %*D", len, p, "-");
53734910Swollman}
537425944Sjoerg
537530300Sjoergstatic void
537630300Sjoergsppp_print_string(const char *p, u_short len)
537730300Sjoerg{
537830300Sjoerg	u_char c;
537930300Sjoerg
538030300Sjoerg	while (len-- > 0) {
538130300Sjoerg		c = *p++;
538230300Sjoerg		/*
538330300Sjoerg		 * Print only ASCII chars directly.  RFC 1994 recommends
538430300Sjoerg		 * using only them, but we don't rely on it.  */
538530300Sjoerg		if (c < ' ' || c > '~')
538669211Sphk			log(-1, "\\x%x", c);
538730300Sjoerg		else
538869211Sphk			log(-1, "%c", c);
538930300Sjoerg	}
539030300Sjoerg}
539130300Sjoerg
5392184682Sbz#ifdef INET
539330300Sjoergstatic const char *
539430300Sjoergsppp_dotted_quad(u_long addr)
539530300Sjoerg{
539630300Sjoerg	static char s[16];
539730300Sjoerg	sprintf(s, "%d.%d.%d.%d",
539840008Sjoerg		(int)((addr >> 24) & 0xff),
539940008Sjoerg		(int)((addr >> 16) & 0xff),
540040008Sjoerg		(int)((addr >> 8) & 0xff),
540138372Sbde		(int)(addr & 0xff));
540230300Sjoerg	return s;
540330300Sjoerg}
5404184682Sbz#endif
540530300Sjoerg
540630300Sjoergstatic int
540730300Sjoergsppp_strnlen(u_char *p, int max)
540830300Sjoerg{
540930300Sjoerg	int len;
541030300Sjoerg
541130300Sjoerg	for (len = 0; len < max && *p; ++p)
541230300Sjoerg		++len;
541330300Sjoerg	return len;
541430300Sjoerg}
541530300Sjoerg
541630300Sjoerg/* a dummy, used to drop uninteresting events */
541730300Sjoergstatic void
541830300Sjoergsppp_null(struct sppp *unused)
541930300Sjoerg{
542030300Sjoerg	/* do just nothing */
542130300Sjoerg}
5422