if_spppsubr.c revision 25706
1141104Sharti/*
294589Sobrien * Synchronous PPP/Cisco link level subroutines.
394589Sobrien * Keepalive protocol implemented in both Cisco and PPP modes.
45814Sjkh *
51590Srgrimes * Copyright (C) 1994 Cronyx Ltd.
61590Srgrimes * Author: Serge Vakulenko, <vak@zebub.msk.su>
71590Srgrimes *
81590Srgrimes * This software is distributed with NO WARRANTIES, not even the implied
91590Srgrimes * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
101590Srgrimes *
111590Srgrimes * Authors grant any other persons or organisations permission to use
121590Srgrimes * or modify this software as long as this message is kept with the software,
131590Srgrimes * all derivative works or modified versions.
141590Srgrimes *
151590Srgrimes * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
161590Srgrimes *
171590Srgrimes * $Id: if_spppsubr.c,v 1.17 1997/03/24 11:33:16 bde Exp $
181590Srgrimes */
191590Srgrimes
201590Srgrimes#include <sys/param.h>
211590Srgrimes#include <sys/systm.h>
221590Srgrimes#include <sys/kernel.h>
231590Srgrimes#include <sys/sockio.h>
241590Srgrimes#include <sys/socket.h>
251590Srgrimes#include <sys/syslog.h>
261590Srgrimes#include <sys/mbuf.h>
271590Srgrimes
281590Srgrimes#include <net/if.h>
291590Srgrimes#include <net/netisr.h>
301590Srgrimes#include <net/if_types.h>
311590Srgrimes
321590Srgrimes#ifdef INET
331590Srgrimes#include <netinet/in.h>
341590Srgrimes#include <netinet/in_systm.h>
351590Srgrimes#include <netinet/in_var.h>
361590Srgrimes#include <netinet/ip.h>
371590Srgrimes#include <netinet/tcp.h>
3862833Swsanchez#include <netinet/if_ether.h>
3962833Swsanchez#endif
401590Srgrimes
411590Srgrimes#ifdef IPX
4262833Swsanchez#include <netipx/ipx.h>
4394587Sobrien#include <netipx/ipx_if.h>
441590Srgrimes#endif
4535483Simp
46103503Sjmallett#ifdef NS
4735483Simp#include <netns/ns.h>
4835483Simp#include <netns/ns_if.h>
491590Srgrimes#endif
501590Srgrimes
511590Srgrimes#ifdef ISO
521590Srgrimes#include <netiso/argo_debug.h>
531590Srgrimes#include <netiso/iso.h>
54144467Sharti#include <netiso/iso_var.h>
551590Srgrimes#include <netiso/iso_snpac.h>
56144467Sharti#endif
57144467Sharti
58144467Sharti#include <net/if_sppp.h>
59144467Sharti
60144467Sharti#define MAXALIVECNT     3               /* max. alive packets */
61144467Sharti
62144467Sharti#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
631590Srgrimes#define PPP_UI          0x03            /* Unnumbered Information */
64144467Sharti#define PPP_IP          0x0021          /* Internet Protocol */
65144467Sharti#define PPP_ISO         0x0023          /* ISO OSI Protocol */
66144467Sharti#define PPP_XNS         0x0025          /* Xerox NS Protocol */
67144467Sharti#define PPP_IPX         0x002b          /* Novell IPX Protocol */
68144467Sharti#define PPP_LCP         0xc021          /* Link Control Protocol */
691590Srgrimes#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
70144467Sharti
71144467Sharti#define LCP_CONF_REQ    1               /* PPP LCP configure request */
72144467Sharti#define LCP_CONF_ACK    2               /* PPP LCP configure acknowledge */
73144467Sharti#define LCP_CONF_NAK    3               /* PPP LCP configure negative ack */
741590Srgrimes#define LCP_CONF_REJ    4               /* PPP LCP configure reject */
75144467Sharti#define LCP_TERM_REQ    5               /* PPP LCP terminate request */
761590Srgrimes#define LCP_TERM_ACK    6               /* PPP LCP terminate acknowledge */
77144467Sharti#define LCP_CODE_REJ    7               /* PPP LCP code reject */
781590Srgrimes#define LCP_PROTO_REJ   8               /* PPP LCP protocol reject */
79144467Sharti#define LCP_ECHO_REQ    9               /* PPP LCP echo request */
80144467Sharti#define LCP_ECHO_REPLY  10              /* PPP LCP echo reply */
81144467Sharti#define LCP_DISC_REQ    11              /* PPP LCP discard request */
821590Srgrimes
83144467Sharti#define LCP_OPT_MRU             1       /* maximum receive unit */
84144467Sharti#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
85144467Sharti#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
86144467Sharti#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
871590Srgrimes#define LCP_OPT_MAGIC           5       /* magic number */
88144467Sharti#define LCP_OPT_RESERVED        6       /* reserved */
89144467Sharti#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
90144467Sharti#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
911590Srgrimes
92144467Sharti#define IPCP_CONF_REQ   LCP_CONF_REQ    /* PPP IPCP configure request */
93144467Sharti#define IPCP_CONF_ACK   LCP_CONF_ACK    /* PPP IPCP configure acknowledge */
94144467Sharti#define IPCP_CONF_NAK   LCP_CONF_NAK    /* PPP IPCP configure negative ack */
951590Srgrimes#define IPCP_CONF_REJ   LCP_CONF_REJ    /* PPP IPCP configure reject */
96144467Sharti#define IPCP_TERM_REQ   LCP_TERM_REQ    /* PPP IPCP terminate request */
971590Srgrimes#define IPCP_TERM_ACK   LCP_TERM_ACK    /* PPP IPCP terminate acknowledge */
98144467Sharti#define IPCP_CODE_REJ   LCP_CODE_REJ    /* PPP IPCP code reject */
991590Srgrimes
1001590Srgrimes#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
101144494Sharti#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
1021590Srgrimes#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
103141104Sharti#define CISCO_ADDR_REQ          0       /* Cisco address request */
1041590Srgrimes#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
105107447Sru#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
106104475Sphk
107107447Srustruct ppp_header {
1081590Srgrimes	u_char address;
109141104Sharti	u_char control;
11094506Scharnier	u_short protocol;
1115814Sjkh};
112144665Sharti#define PPP_HEADER_LEN          sizeof (struct ppp_header)
1131590Srgrimes
1145814Sjkhstruct lcp_header {
115141104Sharti	u_char type;
11680381Ssheldonh	u_char ident;
11794506Scharnier	u_short len;
118141104Sharti};
119141104Sharti#define LCP_HEADER_LEN          sizeof (struct lcp_header)
120142457Sharti
121146056Shartistruct cisco_packet {
1221590Srgrimes	u_long type;
123141104Sharti	u_long par1;
124141104Sharti	u_long par2;
1251590Srgrimes	u_short rel;
126141104Sharti	u_short time0;
127141104Sharti	u_short time1;
1281590Srgrimes};
129141104Sharti#define CISCO_PACKET_LEN 18
130146056Sharti
131141104Shartistatic struct sppp *spppq;
132141104Sharti
133141104Sharti/*
1341590Srgrimes * The following disgusting hack gets around the problem that IP TOS
135146057Sharti * can't be set yet.  We want to put "interactive" traffic on a high
136146057Sharti * priority queue.  To decide if traffic is interactive, we check that
137146057Sharti * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
1381590Srgrimes */
139146057Shartistatic u_short interactive_ports[8] = {
140146057Sharti	0,	513,	0,	0,
141146057Sharti	0,	21,	0,	23,
142146057Sharti};
143146057Sharti#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
144146057Sharti
145146057Sharti/*
146146057Sharti * Timeout routine activation macros.
147146057Sharti */
148144483Sharti#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \
149144483Sharti			timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \
150144483Sharti			(p)->pp_flags |= PP_TIMO; }
151144483Sharti#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \
152144483Sharti			untimeout (sppp_cp_timeout, (void*) (p)); \
153144483Sharti			(p)->pp_flags &= ~PP_TIMO; }
154144483Sharti
155144483Shartistatic void sppp_keepalive (void *dummy);
156144483Shartistatic void sppp_cp_send (struct sppp *sp, u_short proto, u_char type,
157144483Sharti	u_char ident, u_short len, void *data);
158144483Shartistatic void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
159144483Shartistatic void sppp_lcp_input (struct sppp *sp, struct mbuf *m);
160144665Shartistatic void sppp_cisco_input (struct sppp *sp, struct mbuf *m);
161144483Shartistatic void sppp_ipcp_input (struct sppp *sp, struct mbuf *m);
162144483Shartistatic void sppp_lcp_open (struct sppp *sp);
163144483Shartistatic void sppp_ipcp_open (struct sppp *sp);
164144483Shartistatic int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
165144483Sharti	int len, u_long *magic);
166144483Shartistatic void sppp_cp_timeout (void *arg);
167144483Shartistatic const char *sppp_lcp_type_name (u_char type);
168144483Shartistatic const char *sppp_ipcp_type_name (u_char type);
169144483Shartistatic void sppp_print_bytes (u_char *p, u_short len);
170144483Shartistatic int sppp_output (struct ifnet *ifp, struct mbuf *m,
171144483Sharti	struct sockaddr *dst, struct rtentry *rt);
172144483Sharti
173144483Sharti/*
174144483Sharti * Flush interface queue.
175144483Sharti */
176144483Shartistatic void
177144483Shartiqflush(struct ifqueue *ifq)
178144483Sharti{
179144483Sharti	struct mbuf *m, *n;
180144483Sharti
181144483Sharti	n = ifq->ifq_head;
182144483Sharti	while ((m = n)) {
183144483Sharti		n = m->m_act;
184144483Sharti		m_freem (m);
185146061Sharti	}
186144483Sharti	ifq->ifq_head = 0;
187144483Sharti	ifq->ifq_tail = 0;
188144483Sharti	ifq->ifq_len = 0;
189144483Sharti}
190144483Sharti
191144483Sharti/*
192144483Sharti * Process the received packet.
193144483Sharti */
194144483Shartivoid
195144483Shartisppp_input(struct ifnet *ifp, struct mbuf *m)
196144483Sharti{
197144483Sharti	struct ppp_header *h;
198144483Sharti	struct sppp *sp = (struct sppp*) ifp;
199146061Sharti	struct ifqueue *inq = 0;
200144483Sharti	int s;
201144483Sharti
202144483Sharti	if (ifp->if_flags & IFF_UP)
203144483Sharti		/* Count received bytes, add FCS and one flag */
204144483Sharti		ifp->if_ibytes += m->m_pkthdr.len + 3;
205144483Sharti
206144483Sharti	if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
207144483Sharti		/* Too small packet, drop it. */
208144483Sharti		if (ifp->if_flags & IFF_DEBUG)
209144483Sharti			log(LOG_DEBUG,
210144483Sharti			    "%s%d: input packet is too small, %d bytes\n",
211144483Sharti			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
212144483Shartidrop:           ++ifp->if_iqdrops;
213144483Sharti		m_freem (m);
214144483Sharti		return;
215144483Sharti	}
216144483Sharti
217144483Sharti	/* Get PPP header. */
218144483Sharti	h = mtod (m, struct ppp_header*);
219144483Sharti	m_adj (m, PPP_HEADER_LEN);
220144483Sharti
221144483Sharti	switch (h->address) {
222144483Sharti	default:        /* Invalid PPP packet. */
223144483Shartiinvalid:        if (ifp->if_flags & IFF_DEBUG)
224144483Sharti			log(LOG_DEBUG,
225144483Sharti			    "%s%d: invalid input packet "
226144483Sharti			    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
227144483Sharti			    ifp->if_name, ifp->if_unit,
228144483Sharti			    h->address, h->control, ntohs(h->protocol));
229144483Sharti		goto drop;
230144483Sharti	case PPP_ALLSTATIONS:
231144483Sharti		if (h->control != PPP_UI)
232144483Sharti			goto invalid;
233144483Sharti		if (sp->pp_flags & PP_CISCO) {
234144483Sharti			if (ifp->if_flags & IFF_DEBUG)
235144483Sharti				log(LOG_DEBUG,
236144483Sharti				    "%s%d: PPP packet in Cisco mode "
237144483Sharti				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
238144483Sharti				    ifp->if_name, ifp->if_unit,
239144483Sharti				    h->address, h->control, ntohs(h->protocol));
240144483Sharti			goto drop;
241144483Sharti		}
242144483Sharti		switch (ntohs (h->protocol)) {
243144483Sharti		default:
244144483Sharti			if (sp->lcp.state == LCP_STATE_OPENED)
245144494Sharti				sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
246144494Sharti					++sp->pp_seq, m->m_pkthdr.len + 2,
247144483Sharti					&h->protocol);
248144483Sharti			if (ifp->if_flags & IFF_DEBUG)
249146061Sharti				log(LOG_DEBUG,
250146061Sharti				    "%s%d: invalid input protocol "
251144483Sharti				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
252144483Sharti				    ifp->if_name, ifp->if_unit,
253144483Sharti				    h->address, h->control, ntohs(h->protocol));
254146061Sharti			++ifp->if_noproto;
255144483Sharti			goto drop;
256144494Sharti		case PPP_LCP:
257144494Sharti			sppp_lcp_input ((struct sppp*) ifp, m);
258144483Sharti			m_freem (m);
259144483Sharti			return;
260144483Sharti#ifdef INET
261144483Sharti		case PPP_IPCP:
262144483Sharti			if (sp->lcp.state == LCP_STATE_OPENED)
263144483Sharti				sppp_ipcp_input ((struct sppp*) ifp, m);
264144483Sharti			m_freem (m);
265144483Sharti			return;
266144483Sharti		case PPP_IP:
267144483Sharti			if (sp->ipcp.state == IPCP_STATE_OPENED) {
268144483Sharti				schednetisr (NETISR_IP);
269144483Sharti				inq = &ipintrq;
270144483Sharti			}
271144483Sharti			break;
272144483Sharti#endif
273144483Sharti#ifdef IPX
274144483Sharti		case PPP_IPX:
275144483Sharti			/* IPX IPXCP not implemented yet */
276144483Sharti			if (sp->lcp.state == LCP_STATE_OPENED) {
277144483Sharti				schednetisr (NETISR_IPX);
278144483Sharti				inq = &ipxintrq;
279144483Sharti			}
280144483Sharti			break;
281144483Sharti#endif
282144483Sharti#ifdef NS
283144483Sharti		case PPP_XNS:
284144483Sharti			/* XNS IDPCP not implemented yet */
285144483Sharti			if (sp->lcp.state == LCP_STATE_OPENED) {
286144483Sharti				schednetisr (NETISR_NS);
287144483Sharti				inq = &nsintrq;
288144483Sharti			}
289144483Sharti			break;
290144483Sharti#endif
291144483Sharti#ifdef ISO
292144483Sharti		case PPP_ISO:
293144483Sharti			/* OSI NLCP not implemented yet */
294144483Sharti			if (sp->lcp.state == LCP_STATE_OPENED) {
295144483Sharti				schednetisr (NETISR_ISO);
296144483Sharti				inq = &clnlintrq;
297144483Sharti			}
298144483Sharti			break;
299144483Sharti#endif
300144483Sharti		}
301144483Sharti		break;
302144483Sharti	case CISCO_MULTICAST:
303144483Sharti	case CISCO_UNICAST:
304144483Sharti		/* Don't check the control field here (RFC 1547). */
305144483Sharti		if (! (sp->pp_flags & PP_CISCO)) {
306144483Sharti			if (ifp->if_flags & IFF_DEBUG)
307144483Sharti				log(LOG_DEBUG,
308144483Sharti				    "%s%d: Cisco packet in PPP mode "
3098874Srgrimes				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
3101590Srgrimes				    ifp->if_name, ifp->if_unit,
311144467Sharti				    h->address, h->control, ntohs(h->protocol));
312144467Sharti			goto drop;
313144467Sharti		}
314144467Sharti		switch (ntohs (h->protocol)) {
315144467Sharti		default:
3161590Srgrimes			++ifp->if_noproto;
31718730Ssteve			goto invalid;
31818730Ssteve		case CISCO_KEEPALIVE:
31918730Ssteve			sppp_cisco_input ((struct sppp*) ifp, m);
32018730Ssteve			m_freem (m);
321138232Sharti			return;
3221590Srgrimes#ifdef INET
3231590Srgrimes		case ETHERTYPE_IP:
3241590Srgrimes			schednetisr (NETISR_IP);
3251590Srgrimes			inq = &ipintrq;
3261590Srgrimes			break;
3271590Srgrimes#endif
328144467Sharti#ifdef IPX
3291590Srgrimes		case ETHERTYPE_IPX:
3301590Srgrimes			schednetisr (NETISR_IPX);
331144467Sharti			inq = &ipxintrq;
332144467Sharti			break;
333144467Sharti#endif
334144467Sharti#ifdef NS
335144467Sharti		case ETHERTYPE_NS:
336144467Sharti			schednetisr (NETISR_NS);
3371590Srgrimes			inq = &nsintrq;
3381590Srgrimes			break;
339144467Sharti#endif
340146061Sharti		}
341144467Sharti		break;
342144467Sharti	}
3431590Srgrimes
3441590Srgrimes	if (! (ifp->if_flags & IFF_UP) || ! inq)
3451590Srgrimes		goto drop;
3461590Srgrimes
347144483Sharti	/* Check queue. */
348144467Sharti	s = splimp ();
349144467Sharti	if (IF_QFULL (inq)) {
350144467Sharti		/* Queue overflow. */
351144467Sharti		IF_DROP (inq);
352144467Sharti		splx (s);
353144467Sharti		if (ifp->if_flags & IFF_DEBUG)
354144467Sharti			log(LOG_DEBUG, "%s%d: protocol queue overflow\n",
355144741Sharti				ifp->if_name, ifp->if_unit);
356144467Sharti		goto drop;
357144467Sharti	}
358144467Sharti	IF_ENQUEUE (inq, m);
359144467Sharti	splx (s);
360144467Sharti}
361144467Sharti
362144467Sharti/*
363144467Sharti * Enqueue transmit packet.
364144467Sharti */
365144741Shartistatic int
366144467Shartisppp_output(struct ifnet *ifp, struct mbuf *m,
36718730Ssteve	    struct sockaddr *dst, struct rtentry *rt)
368144467Sharti{
36918730Ssteve	struct sppp *sp = (struct sppp*) ifp;
370144467Sharti	struct ppp_header *h;
371144467Sharti	struct ifqueue *ifq;
372144467Sharti	int s = splimp ();
373144467Sharti
374144467Sharti	if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) {
375144467Sharti		m_freem (m);
376144467Sharti		splx (s);
377144467Sharti		return (ENETDOWN);
378144741Sharti	}
379144467Sharti
380144467Sharti	ifq = &ifp->if_snd;
381144467Sharti#ifdef INET
3821590Srgrimes	/*
3831590Srgrimes	 * Put low delay, telnet, rlogin and ftp control packets
384144467Sharti	 * in front of the queue.
385144467Sharti	 */
386144467Sharti	if (dst->sa_family == AF_INET) {
387144467Sharti		struct ip *ip = mtod (m, struct ip*);
388144483Sharti		struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
389146059Sharti
390146059Sharti		if (! IF_QFULL (&sp->pp_fastq) &&
3911590Srgrimes		    ((ip->ip_tos & IPTOS_LOWDELAY) ||
392144467Sharti	    	    ip->ip_p == IPPROTO_TCP &&
393144656Sharti	    	    m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) &&
394138916Sharti	    	    (INTERACTIVE (ntohs (tcp->th_sport)) ||
395138916Sharti	    	    INTERACTIVE (ntohs (tcp->th_dport)))))
396144494Sharti			ifq = &sp->pp_fastq;
397138916Sharti	}
398146061Sharti#endif
3991590Srgrimes
400137572Sphk	/*
401104475Sphk	 * Prepend general data packet PPP header. For now, IP only.
402104475Sphk	 */
403104475Sphk	M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT);
404146061Sharti	if (! m) {
4051590Srgrimes		if (ifp->if_flags & IFF_DEBUG)
4061590Srgrimes			log(LOG_DEBUG, "%s%d: no memory for transmit header\n",
4071590Srgrimes				ifp->if_name, ifp->if_unit);
408146061Sharti		splx (s);
4091590Srgrimes		return (ENOBUFS);
410146061Sharti	}
4111590Srgrimes	h = mtod (m, struct ppp_header*);
4121590Srgrimes	if (sp->pp_flags & PP_CISCO) {
4131590Srgrimes		h->address = CISCO_MULTICAST;        /* broadcast address */
414137202Sharti		h->control = 0;
415137202Sharti	} else {
416138232Sharti		h->address = PPP_ALLSTATIONS;        /* broadcast address */
41718730Ssteve		h->control = PPP_UI;                 /* Unnumbered Info */
4181590Srgrimes	}
419137252Sharti
420137252Sharti	switch (dst->sa_family) {
421137252Sharti#ifdef INET
4228874Srgrimes	case AF_INET:   /* Internet Protocol */
423138916Sharti		if (sp->pp_flags & PP_CISCO)
424138916Sharti			h->protocol = htons (ETHERTYPE_IP);
425138916Sharti		else if (sp->ipcp.state == IPCP_STATE_OPENED)
4261590Srgrimes			h->protocol = htons (PPP_IP);
427144494Sharti		else {
4281590Srgrimes			m_freem (m);
429144656Sharti			splx (s);
430144656Sharti			return (ENETDOWN);
431144656Sharti		}
4321590Srgrimes		break;
433137605Sharti#endif
434137605Sharti#ifdef NS
435137605Sharti	case AF_NS:     /* Xerox NS Protocol */
4361590Srgrimes		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
43718730Ssteve			ETHERTYPE_NS : PPP_XNS);
4381590Srgrimes		break;
4391590Srgrimes#endif
44018730Ssteve#ifdef IPX
4411590Srgrimes	case AF_IPX:     /* Novell IPX Protocol */
44218730Ssteve		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
4431590Srgrimes			ETHERTYPE_IPX : PPP_IPX);
4441590Srgrimes		break;
4451590Srgrimes#endif
44618730Ssteve#ifdef ISO
44718730Ssteve	case AF_ISO:    /* ISO OSI Protocol */
44818730Ssteve		if (sp->pp_flags & PP_CISCO)
44918730Ssteve			goto nosupport;
45018730Ssteve		h->protocol = htons (PPP_ISO);
45118730Ssteve		break;
452103503Sjmallettnosupport:
45318730Ssteve#endif
454138232Sharti	default:
45518730Ssteve		m_freem (m);
45618730Ssteve		splx (s);
45718730Ssteve		return (EAFNOSUPPORT);
45818730Ssteve	}
45918730Ssteve
46018730Ssteve	/*
46118730Ssteve	 * Queue message on interface, and start output if interface
462103503Sjmallett	 * not yet active.
463103503Sjmallett	 */
46418730Ssteve	if (IF_QFULL (ifq)) {
465146129Sharti		IF_DROP (&ifp->if_snd);
466146129Sharti		m_freem (m);
467146129Sharti		splx (s);
468146129Sharti		return (ENOBUFS);
469146129Sharti	}
470146129Sharti	IF_ENQUEUE (ifq, m);
471146129Sharti	if (! (ifp->if_flags & IFF_OACTIVE))
472146129Sharti		(*ifp->if_start) (ifp);
473146129Sharti
474146129Sharti	/*
475146129Sharti	 * Count output packets and bytes.
476146129Sharti	 * The packet length includes header, FCS and 1 flag,
477146129Sharti	 * according to RFC 1333.
478146129Sharti	 */
479146129Sharti	ifp->if_obytes += m->m_pkthdr.len + 3;
48092921Simp	splx (s);
48192921Simp	return (0);
48292921Simp}
483144483Sharti
48492921Simpvoid
48592921Simpsppp_attach(struct ifnet *ifp)
486146129Sharti{
4871590Srgrimes	struct sppp *sp = (struct sppp*) ifp;
488144467Sharti
489146129Sharti	/* Initialize keepalive handler. */
490146129Sharti	if (! spppq)
491146129Sharti		timeout (sppp_keepalive, 0, hz * 10);
492146129Sharti
493146129Sharti	/* Insert new entry into the keepalive list. */
494146129Sharti	sp->pp_next = spppq;
495146129Sharti	spppq = sp;
496146129Sharti
497146129Sharti	sp->pp_if.if_type = IFT_PPP;
498146129Sharti	sp->pp_if.if_output = sppp_output;
499146129Sharti	sp->pp_fastq.ifq_maxlen = 32;
500146129Sharti	sp->pp_loopcnt = 0;
501146129Sharti	sp->pp_alivecnt = 0;
502146129Sharti	sp->pp_seq = 0;
503146129Sharti	sp->pp_rseq = 0;
504146129Sharti	sp->lcp.magic = 0;
505146129Sharti	sp->lcp.state = LCP_STATE_CLOSED;
506146129Sharti	sp->ipcp.state = IPCP_STATE_CLOSED;
507146129Sharti}
508146129Sharti
509146129Shartivoid
510146129Shartisppp_detach(struct ifnet *ifp)
511146129Sharti{
512146129Sharti	struct sppp **q, *p, *sp = (struct sppp*) ifp;
513146129Sharti
514146129Sharti	/* Remove the entry from the keepalive list. */
515146129Sharti	for (q = &spppq; (p = *q); q = &p->pp_next)
516146129Sharti		if (p == sp) {
517146129Sharti			*q = p->pp_next;
518146129Sharti			break;
519146129Sharti		}
520146129Sharti
521146129Sharti	/* Stop keepalive handler. */
522146129Sharti	if (! spppq)
523146129Sharti		untimeout (sppp_keepalive, 0);
524146129Sharti	UNTIMO (sp);
525146129Sharti}
526146129Sharti
527146129Sharti/*
528146129Sharti * Flush the interface output queue.
529146129Sharti */
530146129Shartivoid
531146129Shartisppp_flush(struct ifnet *ifp)
532146129Sharti{
533146129Sharti	struct sppp *sp = (struct sppp*) ifp;
534146129Sharti
535146129Sharti	qflush (&sp->pp_if.if_snd);
536146129Sharti	qflush (&sp->pp_fastq);
537146129Sharti}
538146129Sharti
539146129Sharti/*
540146129Sharti * Check if the output queue is empty.
541146129Sharti */
542146129Shartiint
543146129Shartisppp_isempty(struct ifnet *ifp)
544146129Sharti{
545146129Sharti	struct sppp *sp = (struct sppp*) ifp;
546146129Sharti	int empty, s = splimp ();
547146129Sharti
548146129Sharti	empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head;
549146129Sharti	splx (s);
550146129Sharti	return (empty);
551146129Sharti}
552146129Sharti
553146129Sharti/*
554146129Sharti * Get next packet to send.
555146129Sharti */
556146129Shartistruct mbuf *
557146129Shartisppp_dequeue(struct ifnet *ifp)
558146129Sharti{
559146129Sharti	struct sppp *sp = (struct sppp*) ifp;
560146129Sharti	struct mbuf *m;
561146129Sharti	int s = splimp ();
562146129Sharti
563146129Sharti	IF_DEQUEUE (&sp->pp_fastq, m);
564146129Sharti	if (! m)
565146129Sharti		IF_DEQUEUE (&sp->pp_if.if_snd, m);
566146129Sharti	splx (s);
567146129Sharti	return (m);
568146129Sharti}
569146129Sharti
570146129Sharti/*
571146129Sharti * Send keepalive packets, every 10 seconds.
572146129Sharti */
573146129Shartistatic void
574146129Shartisppp_keepalive(void *dummy)
575146129Sharti{
576146129Sharti	struct sppp *sp;
577146129Sharti	int s = splimp ();
578146129Sharti
579146129Sharti	for (sp=spppq; sp; sp=sp->pp_next) {
580146129Sharti		struct ifnet *ifp = &sp->pp_if;
581137605Sharti
582144467Sharti		/* Keepalive mode disabled or channel down? */
583144467Sharti		if (! (sp->pp_flags & PP_KEEPALIVE) ||
584137605Sharti		    ! (ifp->if_flags & IFF_RUNNING))
585137605Sharti			continue;
586137605Sharti
587137605Sharti		/* No keepalive in PPP mode if LCP not opened yet. */
588137605Sharti		if (! (sp->pp_flags & PP_CISCO) &&
589137605Sharti		    sp->lcp.state != LCP_STATE_OPENED)
590137605Sharti			continue;
591137605Sharti
592144467Sharti		if (sp->pp_alivecnt == MAXALIVECNT) {
5931590Srgrimes			/* No keepalive packets got.  Stop the interface. */
594137252Sharti			printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
5951590Srgrimes			if_down (ifp);
5961590Srgrimes			qflush (&sp->pp_fastq);
5971590Srgrimes			if (! (sp->pp_flags & PP_CISCO)) {
5981590Srgrimes				/* Shut down the PPP link. */
5991590Srgrimes				sp->lcp.state = LCP_STATE_CLOSED;
6001590Srgrimes				sp->ipcp.state = IPCP_STATE_CLOSED;
601104696Sjmallett				UNTIMO (sp);
6021590Srgrimes				/* Initiate negotiation. */
603144741Sharti				sppp_lcp_open (sp);
604144467Sharti			}
605144467Sharti		}
6068874Srgrimes		if (sp->pp_alivecnt <= MAXALIVECNT)
607144467Sharti			++sp->pp_alivecnt;
608144467Sharti		if (sp->pp_flags & PP_CISCO)
609144467Sharti			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
610137605Sharti				sp->pp_rseq);
611144467Sharti		else if (sp->lcp.state == LCP_STATE_OPENED) {
612144741Sharti			long nmagic = htonl (sp->lcp.magic);
613144741Sharti			sp->lcp.echoid = ++sp->pp_seq;
614144741Sharti			sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
615144741Sharti				sp->lcp.echoid, 4, &nmagic);
616144741Sharti		}
6171590Srgrimes	}
618144467Sharti	splx (s);
619144467Sharti	timeout (sppp_keepalive, 0, hz * 10);
620144467Sharti}
621144467Sharti
622144467Sharti/*
623144467Sharti * Handle incoming PPP Link Control Protocol packets.
624144467Sharti */
625144467Shartistatic void
626144657Shartisppp_lcp_input(struct sppp *sp, struct mbuf *m)
627144467Sharti{
628144467Sharti	struct lcp_header *h;
6298874Srgrimes	struct ifnet *ifp = &sp->pp_if;
630144467Sharti	int len = m->m_pkthdr.len, debug = ifp->if_flags & IFF_DEBUG;
631144467Sharti	u_char *p, opt[6];
632144467Sharti	u_long rmagic;
633144467Sharti
634144467Sharti	if (len < 4) {
635144467Sharti		if (debug)
6368874Srgrimes			log(LOG_DEBUG,
637144467Sharti			    "%s%d: invalid lcp packet length: %d bytes\n",
638144467Sharti			    ifp->if_name, ifp->if_unit, len);
639144467Sharti		return;
640144467Sharti	}
641144467Sharti	h = mtod (m, struct lcp_header*);
642144467Sharti	if (debug) {
643144467Sharti		const char *state = "unknown";
644144467Sharti		switch (sp->lcp.state) {
645144467Sharti		case LCP_STATE_CLOSED:   state = "closed";	break;
646144467Sharti		case LCP_STATE_ACK_RCVD: state = "ack-rcvd";	break;
647144467Sharti		case LCP_STATE_ACK_SENT: state = "ack-sent";	break;
6481590Srgrimes		case LCP_STATE_OPENED:   state = "opened";	break;
649144467Sharti		}
650144467Sharti		log(LOG_DEBUG,
651144467Sharti		    "%s%d: lcp input(%s): %d bytes <%s id=0x%x len=0x%x",
6521590Srgrimes		    ifp->if_name, ifp->if_unit, state, len,
653144467Sharti		    sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
65418730Ssteve		if (len > 4)
655144467Sharti			sppp_print_bytes ((u_char*) (h+1), len-4);
656144741Sharti		addlog(">\n");
657144741Sharti	}
658144741Sharti	if (len > ntohs (h->len))
659144741Sharti		len = ntohs (h->len);
660144741Sharti	switch (h->type) {
6611590Srgrimes	default:
662144467Sharti		/* Unknown packet type -- send Code-Reject packet. */
663144467Sharti		if (debug)
664144467Sharti			addlog("%s%d: sending lcp code rej\n",
665144467Sharti			       ifp->if_name, ifp->if_unit);
6661590Srgrimes		sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq,
6671590Srgrimes			m->m_pkthdr.len, h);
668144467Sharti		break;
6691590Srgrimes	case LCP_CONF_REQ:
6701590Srgrimes		if (len < 4) {
6711590Srgrimes			if (debug)
6721590Srgrimes				addlog("%s%d: invalid lcp configure request "
6731590Srgrimes				       "packet length: %d bytes\n",
6741590Srgrimes				       ifp->if_name, ifp->if_unit, len);
6751590Srgrimes			break;
6761590Srgrimes		}
6771590Srgrimes		rmagic = 0xd00ddeed; /* in case LCP fails */
6781590Srgrimes		if (len > 4 &&
6791590Srgrimes		    !sppp_lcp_conf_parse_options (sp, h, len, &rmagic))
68094594Sobrien			goto badreq;
681142993Sharti		if (rmagic == sp->lcp.magic) {
6821590Srgrimes			/* Local and remote magics equal -- loopback? */
6831590Srgrimes			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
6841590Srgrimes				printf ("%s%d: loopback\n",
6851590Srgrimes					ifp->if_name, ifp->if_unit);
6861590Srgrimes				sp->pp_loopcnt = 0;
6871590Srgrimes				if (ifp->if_flags & IFF_UP) {
6881590Srgrimes					if_down (ifp);
6891590Srgrimes					qflush (&sp->pp_fastq);
6901590Srgrimes				}
6911590Srgrimes			} else if (debug) {
6921590Srgrimes				addlog("%s%d: conf req: magic glitch, "
6931590Srgrimes				       "sending config nak\n",
694144741Sharti				       ifp->if_name, ifp->if_unit);
6951590Srgrimes			}
696144467Sharti			++sp->pp_loopcnt;
697141258Sharti
698141258Sharti			/* MUST send Conf-Nack packet. */
699144467Sharti			rmagic = ~sp->lcp.magic;
700141258Sharti			opt[0] = LCP_OPT_MAGIC;
701144467Sharti			opt[1] = sizeof (opt);
702141258Sharti			opt[2] = rmagic >> 24;
703141258Sharti			opt[3] = rmagic >> 16;
704144467Sharti			opt[4] = rmagic >> 8;
705144467Sharti			opt[5] = rmagic;
706144467Sharti			sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
7071590Srgrimes				h->ident, sizeof (opt), &opt);
708144467Sharti		  badreq:
7091590Srgrimes			switch (sp->lcp.state) {
710144467Sharti			case LCP_STATE_OPENED:
711144467Sharti				/* Initiate renegotiation. */
712144467Sharti				sppp_lcp_open (sp);
713144467Sharti				/* fall through... */
714144467Sharti			case LCP_STATE_ACK_SENT:
715144467Sharti				/* Go to closed state. */
716144467Sharti				sp->lcp.state = LCP_STATE_CLOSED;
717144467Sharti				sp->ipcp.state = IPCP_STATE_CLOSED;
7181590Srgrimes			}
7191590Srgrimes			break;
720144467Sharti		}
721144467Sharti		/* Send Configure-Ack packet. */
722144467Sharti		if (debug)
723144467Sharti			addlog("%s%d: sending configure ack\n",
7241590Srgrimes			       ifp->if_name, ifp->if_unit);
725144467Sharti		sp->pp_loopcnt = 0;
7261590Srgrimes		sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
727144467Sharti				h->ident, len-4, h+1);
728144467Sharti		/* Change the state. */
729144467Sharti		switch (sp->lcp.state) {
730144467Sharti		case LCP_STATE_CLOSED:
731144467Sharti			sp->lcp.state = LCP_STATE_ACK_SENT;
732142457Sharti			break;
733146027Sharti		case LCP_STATE_ACK_RCVD:
734144467Sharti			sp->lcp.state = LCP_STATE_OPENED;
735142457Sharti			sppp_ipcp_open (sp);
736144467Sharti			break;
7371590Srgrimes		case LCP_STATE_OPENED:
738144467Sharti			/* Remote magic changed -- close session. */
7391590Srgrimes			sp->lcp.state = LCP_STATE_CLOSED;
740144467Sharti			sp->ipcp.state = IPCP_STATE_CLOSED;
741144467Sharti			/* Initiate renegotiation. */
742144467Sharti			sppp_lcp_open (sp);
743144467Sharti			/* An ACK has already been sent. */
744144467Sharti			sp->lcp.state = LCP_STATE_ACK_SENT;
745144467Sharti			break;
746132839Sharti		}
747144467Sharti		break;
748144467Sharti	case LCP_CONF_ACK:
749144467Sharti		if (h->ident != sp->lcp.confid) {
750132839Sharti			if (debug)
751144467Sharti				addlog("%s%d: lcp id mismatch 0x%x != 0x%x\n",
752144467Sharti				       ifp->if_name, ifp->if_unit,
753144467Sharti				       h->ident, sp->lcp.confid);
754132839Sharti			break;
755144467Sharti		}
756144467Sharti		UNTIMO (sp);
757144467Sharti		if (! (ifp->if_flags & IFF_UP) &&
758144467Sharti		    (ifp->if_flags & IFF_RUNNING)) {
759144467Sharti			/* Coming out of loopback mode. */
760144467Sharti			ifp->if_flags |= IFF_UP;
761144467Sharti			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
762144741Sharti		}
763144467Sharti		switch (sp->lcp.state) {
764144467Sharti		case LCP_STATE_CLOSED:
765144467Sharti			sp->lcp.state = LCP_STATE_ACK_RCVD;
766144467Sharti			TIMO (sp, 5);
767144467Sharti			break;
7681590Srgrimes		case LCP_STATE_ACK_SENT:
7691590Srgrimes			sp->lcp.state = LCP_STATE_OPENED;
770144467Sharti			sppp_ipcp_open (sp);
771144467Sharti			break;
7721590Srgrimes		}
773144467Sharti		break;
774144467Sharti	case LCP_CONF_NAK:
7751590Srgrimes		if (h->ident != sp->lcp.confid) {
77618730Ssteve			if (debug)
7771590Srgrimes				addlog("%s%d: lcp id mismatch 0x%x != 0x%x\n",
778144467Sharti				       ifp->if_name, ifp->if_unit,
7791590Srgrimes				       h->ident, sp->lcp.confid);
780144467Sharti			break;
781144467Sharti		}
782144467Sharti		p = (u_char*) (h+1);
783144467Sharti		if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
784144467Sharti			rmagic = (u_long)p[2] << 24 |
785144467Sharti				(u_long)p[3] << 16 | p[4] << 8 | p[5];
786144467Sharti			if (rmagic == ~sp->lcp.magic) {
787144467Sharti				if (debug)
788144467Sharti					addlog("%s%d: conf nak: magic glitch\n",
789144467Sharti					       ifp->if_name, ifp->if_unit);
790144467Sharti				sp->lcp.magic += time.tv_sec + time.tv_usec;
791144467Sharti			} else
792144467Sharti				sp->lcp.magic = rmagic;
793144467Sharti			}
794144467Sharti		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
795144467Sharti			/* Go to closed state. */
796144467Sharti			sp->lcp.state = LCP_STATE_CLOSED;
797144467Sharti			sp->ipcp.state = IPCP_STATE_CLOSED;
798144467Sharti		}
799144467Sharti		/* The link will be renegotiated after timeout,
800144467Sharti		 * to avoid endless req-nack loop. */
801144467Sharti		if (debug)
802144467Sharti			addlog("%s%d: sleeping due to nak\n",
803144657Sharti			       ifp->if_name, ifp->if_unit);
804144467Sharti		UNTIMO (sp);
805144467Sharti		TIMO (sp, 2);
806144467Sharti		break;
807144467Sharti	case LCP_CONF_REJ:
808144467Sharti		if (h->ident != sp->lcp.confid) {
809144467Sharti			if (debug)
810144467Sharti				addlog("%s%d: lcp id mismatch 0x%x != 0x%x\n",
811144467Sharti				       ifp->if_name, ifp->if_unit,
812144467Sharti				       h->ident, sp->lcp.confid);
813144467Sharti			break;
814144467Sharti		}
815144467Sharti		UNTIMO (sp);
816144467Sharti		/* Initiate renegotiation. */
817144467Sharti		if (debug)
818144467Sharti			addlog("%s%d: reopening lcp\n",
819144467Sharti			       ifp->if_name, ifp->if_unit);
820144467Sharti		sppp_lcp_open (sp);
821144467Sharti		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
822144467Sharti			/* Go to closed state. */
823144467Sharti			sp->lcp.state = LCP_STATE_CLOSED;
824144467Sharti			sp->ipcp.state = IPCP_STATE_CLOSED;
825144467Sharti		}
826144467Sharti		break;
827144467Sharti	case LCP_TERM_REQ:
828144467Sharti		UNTIMO (sp);
829144467Sharti		/* Send Terminate-Ack packet. */
830144467Sharti		if (debug)
831144467Sharti			addlog("%s%d: sending terminate-ack\n",
832144467Sharti			       ifp->if_name, ifp->if_unit);
833144467Sharti		sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0);
834144467Sharti		/* Go to closed state. */
835144467Sharti		sp->lcp.state = LCP_STATE_CLOSED;
836144467Sharti		sp->ipcp.state = IPCP_STATE_CLOSED;
837144467Sharti		/* Initiate renegotiation. */
838144467Sharti		sppp_lcp_open (sp);
8391590Srgrimes		break;
840144467Sharti	case LCP_TERM_ACK:
841144467Sharti	case LCP_CODE_REJ:
842144467Sharti	case LCP_PROTO_REJ:
8431590Srgrimes		if (debug)
844144467Sharti			addlog("%s%d: ignoring lcp code 0x%x\n",
8451590Srgrimes			       ifp->if_name, ifp->if_unit, h->type);
84618730Ssteve		/* Ignore for now. */
8471590Srgrimes		break;
8481590Srgrimes	case LCP_DISC_REQ:
849144467Sharti		/* Discard the packet. */
8501590Srgrimes		break;
851144467Sharti	case LCP_ECHO_REQ:
852144467Sharti		if (sp->lcp.state != LCP_STATE_OPENED) {
8531590Srgrimes			if (debug)
854144467Sharti				addlog("%s%d: lcp echo req but lcp close\n",
8551590Srgrimes				       ifp->if_name, ifp->if_unit);
8561590Srgrimes			break;
857144467Sharti		}
85818730Ssteve		if (len < 8) {
85918730Ssteve			if (debug)
86018730Ssteve				addlog("%s%d: invalid lcp echo request "
86118730Ssteve				       "packet length: %d bytes\n",
86218730Ssteve				       ifp->if_name, ifp->if_unit, len);
86318730Ssteve			break;
86418730Ssteve		}
865104696Sjmallett		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
86618730Ssteve			/* Line loopback mode detected. */
867138232Sharti			printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
868144467Sharti			if_down (ifp);
869137202Sharti			qflush (&sp->pp_fastq);
870144467Sharti
87118730Ssteve			/* Shut down the PPP link. */
872144467Sharti			sp->lcp.state = LCP_STATE_CLOSED;
873144467Sharti			sp->ipcp.state = IPCP_STATE_CLOSED;
874144467Sharti			UNTIMO (sp);
875144467Sharti			/* Initiate negotiation. */
876144467Sharti			sppp_lcp_open (sp);
877144467Sharti			break;
878144467Sharti		}
879144467Sharti		*(long*)(h+1) = htonl (sp->lcp.magic);
88018730Ssteve		if (debug)
88118730Ssteve			addlog("%s%d: got lcp echo req, sending echo rep\n",
88218730Ssteve			       ifp->if_name, ifp->if_unit);
883144467Sharti		sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
8841590Srgrimes		break;
8851590Srgrimes	case LCP_ECHO_REPLY:
8861590Srgrimes		if (h->ident != sp->lcp.echoid)
8871590Srgrimes			break;
8881590Srgrimes		if (len < 8) {
8891590Srgrimes			if (debug)
8901590Srgrimes				addlog("%s%d: invalid lcp echo reply "
8911590Srgrimes				       "packet length: %d bytes\n",
8921590Srgrimes				       ifp->if_name, ifp->if_unit, len);
8931590Srgrimes			break;
8941590Srgrimes		}
8951590Srgrimes		if (debug)
8961590Srgrimes			addlog("%s%d: got lcp echo rep\n",
8971590Srgrimes			       ifp->if_name, ifp->if_unit);
8981590Srgrimes		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
8991590Srgrimes			sp->pp_alivecnt = 0;
9001590Srgrimes		break;
9011590Srgrimes	}
902104696Sjmallett}
9031590Srgrimes
904144467Sharti/*
905144467Sharti * Handle incoming Cisco keepalive protocol packets.
9061590Srgrimes */
907144657Shartistatic void
908144657Shartisppp_cisco_input(struct sppp *sp, struct mbuf *m)
909144657Sharti{
910144467Sharti	struct cisco_packet *h;
911144467Sharti	struct ifaddr *ifa;
912144467Sharti	struct ifnet *ifp = &sp->pp_if;
913144467Sharti	int debug = ifp->if_flags & IFF_DEBUG;
914144467Sharti
915144467Sharti	if (m->m_pkthdr.len != CISCO_PACKET_LEN) {
916144467Sharti		if (debug)
917144467Sharti			log(LOG_DEBUG,
918144467Sharti			    "%s%d: invalid cisco packet length: %d bytes\n",
919144467Sharti			    ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
920144467Sharti		return;
921144467Sharti	}
9228874Srgrimes	h = mtod (m, struct cisco_packet*);
923144467Sharti	if (debug)
924144467Sharti		log(LOG_DEBUG,
925144467Sharti		    "%s%d: cisco input: %d bytes "
926144467Sharti		    "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
927144467Sharti		    ifp->if_name, ifp->if_unit, m->m_pkthdr.len,
928144467Sharti		    ntohl (h->type), h->par1, h->par2, h->rel,
929144467Sharti		    h->time0, h->time1);
930144467Sharti	switch (ntohl (h->type)) {
931144467Sharti	default:
9328874Srgrimes		if (debug)
933144467Sharti			addlog("%s%d: unknown cisco packet type: 0x%lx\n",
934144467Sharti			       ifp->if_name, ifp->if_unit, ntohl (h->type));
935144467Sharti		break;
936144467Sharti	case CISCO_ADDR_REPLY:
937144467Sharti		/* Reply on address request, ignore */
938144467Sharti		break;
9391590Srgrimes	case CISCO_KEEPALIVE_REQ:
940144467Sharti		sp->pp_alivecnt = 0;
941144467Sharti		sp->pp_rseq = ntohl (h->par1);
942144467Sharti		if (sp->pp_seq == sp->pp_rseq) {
943144467Sharti			/* Local and remote sequence numbers are equal.
9441590Srgrimes			 * Probably, the line is in loopback mode. */
9451590Srgrimes			if (sp->pp_loopcnt >= MAXALIVECNT) {
946144467Sharti				printf ("%s%d: loopback\n",
947144657Sharti					ifp->if_name, ifp->if_unit);
948144467Sharti				sp->pp_loopcnt = 0;
949144467Sharti				if (ifp->if_flags & IFF_UP) {
950144467Sharti					if_down (ifp);
951144467Sharti					qflush (&sp->pp_fastq);
952144467Sharti				}
953144467Sharti			}
954144467Sharti			++sp->pp_loopcnt;
955144467Sharti
956144467Sharti			/* Generate new local sequence number */
957144467Sharti			sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
958144467Sharti			break;
959144467Sharti		}
960144467Sharti			sp->pp_loopcnt = 0;
961144467Sharti		if (! (ifp->if_flags & IFF_UP) &&
9621590Srgrimes		    (ifp->if_flags & IFF_RUNNING)) {
9631590Srgrimes			ifp->if_flags |= IFF_UP;
964144467Sharti			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
965144665Sharti		}
966144665Sharti		break;
967144467Sharti	case CISCO_ADDR_REQ:
968144467Sharti		for (ifa=ifp->if_addrhead.tqh_first; ifa;
969144467Sharti		     ifa=ifa->ifa_link.tqe_next)
970144467Sharti			if (ifa->ifa_addr->sa_family == AF_INET)
971144467Sharti				break;
972144467Sharti		if (! ifa) {
973144467Sharti			if (debug)
974144467Sharti				addlog("%s%d: unknown address for cisco request\n",
975144467Sharti				       ifp->if_name, ifp->if_unit);
976144467Sharti			return;
977144467Sharti		}
978144467Sharti		sppp_cisco_send (sp, CISCO_ADDR_REPLY,
979144467Sharti			ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr),
980144467Sharti			ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr));
981144467Sharti		break;
982144467Sharti	}
983144467Sharti}
984144467Sharti
985144467Sharti/*
986144467Sharti * Send PPP LCP packet.
987144467Sharti */
988144467Shartistatic void
989144665Shartisppp_cp_send(struct sppp *sp, u_short proto, u_char type,
990144665Sharti	     u_char ident, u_short len, void *data)
991144467Sharti{
992144467Sharti	struct ppp_header *h;
993144467Sharti	struct lcp_header *lh;
994144467Sharti	struct mbuf *m;
995144467Sharti	struct ifnet *ifp = &sp->pp_if;
996144467Sharti	int debug = ifp->if_flags & IFF_DEBUG;
997144467Sharti
998144494Sharti	if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
999144467Sharti		len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
1000144467Sharti	MGETHDR (m, M_DONTWAIT, MT_DATA);
1001144467Sharti	if (! m)
1002144467Sharti		return;
1003144467Sharti	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
1004144467Sharti	m->m_pkthdr.rcvif = 0;
1005144467Sharti
1006144467Sharti	h = mtod (m, struct ppp_header*);
1007144467Sharti	h->address = PPP_ALLSTATIONS;        /* broadcast address */
1008144467Sharti	h->control = PPP_UI;                 /* Unnumbered Info */
1009144657Sharti	h->protocol = htons (proto);         /* Link Control Protocol */
1010144467Sharti
1011144467Sharti	lh = (struct lcp_header*) (h + 1);
1012144467Sharti	lh->type = type;
1013144467Sharti	lh->ident = ident;
1014144467Sharti	lh->len = htons (LCP_HEADER_LEN + len);
1015144467Sharti	if (len)
1016144467Sharti		bcopy (data, lh+1, len);
1017144665Sharti
1018144665Sharti	if (debug) {
101918730Ssteve		log(LOG_DEBUG, "%s%d: %s output <%s id=%xh len=%xh",
1020144467Sharti			ifp->if_name, ifp->if_unit,
1021144467Sharti			proto==PPP_LCP ? "lcp" : "ipcp",
1022144467Sharti			proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
1023144467Sharti			sppp_ipcp_type_name (lh->type), lh->ident,
1024144467Sharti			ntohs (lh->len));
1025144467Sharti		if (len)
1026144467Sharti			sppp_print_bytes ((u_char*) (lh+1), len);
1027144467Sharti		addlog(">\n");
102818730Ssteve	}
1029144467Sharti	if (IF_QFULL (&sp->pp_fastq)) {
1030144467Sharti		IF_DROP (&ifp->if_snd);
1031144494Sharti		m_freem (m);
1032144467Sharti	} else
1033144665Sharti		IF_ENQUEUE (&sp->pp_fastq, m);
1034144665Sharti	if (! (ifp->if_flags & IFF_OACTIVE))
1035144467Sharti		(*ifp->if_start) (ifp);
1036144467Sharti	ifp->if_obytes += m->m_pkthdr.len + 3;
1037144467Sharti}
1038144467Sharti
1039144467Sharti/*
1040144467Sharti * Send Cisco keepalive packet.
10411590Srgrimes */
1042144467Shartistatic void
1043144467Shartisppp_cisco_send(struct sppp *sp, int type, long par1, long par2)
1044144467Sharti{
1045144467Sharti	struct ppp_header *h;
1046144467Sharti	struct cisco_packet *ch;
1047144467Sharti	struct mbuf *m;
1048144467Sharti	struct ifnet *ifp = &sp->pp_if;
10491590Srgrimes	u_long t = (time.tv_sec - boottime.tv_sec) * 1000;
1050144467Sharti	int debug = ifp->if_flags & IFF_DEBUG;
10511590Srgrimes
10521590Srgrimes	MGETHDR (m, M_DONTWAIT, MT_DATA);
10531590Srgrimes	if (! m)
1054144467Sharti		return;
1055144467Sharti	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
1056144467Sharti	m->m_pkthdr.rcvif = 0;
10571590Srgrimes
1058144467Sharti	h = mtod (m, struct ppp_header*);
1059144467Sharti	h->address = CISCO_MULTICAST;
1060144467Sharti	h->control = 0;
1061144467Sharti	h->protocol = htons (CISCO_KEEPALIVE);
1062144467Sharti
1063144467Sharti	ch = (struct cisco_packet*) (h + 1);
1064144467Sharti	ch->type = htonl (type);
1065144467Sharti	ch->par1 = htonl (par1);
1066144467Sharti	ch->par2 = htonl (par2);
1067144467Sharti	ch->rel = -1;
1068144467Sharti	ch->time0 = htons ((u_short) (t >> 16));
1069144467Sharti	ch->time1 = htons ((u_short) t);
1070144467Sharti
1071144467Sharti	if (debug)
1072144467Sharti		log(LOG_DEBUG,
1073144467Sharti		    "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n",
1074144467Sharti			ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
1075144467Sharti			ch->par2, ch->rel, ch->time0, ch->time1);
1076144467Sharti
1077144467Sharti	if (IF_QFULL (&sp->pp_fastq)) {
1078144467Sharti		IF_DROP (&ifp->if_snd);
1079144467Sharti		m_freem (m);
1080144467Sharti	} else
1081144467Sharti		IF_ENQUEUE (&sp->pp_fastq, m);
1082144467Sharti	if (! (ifp->if_flags & IFF_OACTIVE))
1083144467Sharti		(*ifp->if_start) (ifp);
10841590Srgrimes	ifp->if_obytes += m->m_pkthdr.len + 3;
1085143703Sharti}
1086144657Sharti
1087144657Sharti/*
1088144467Sharti * Process an ioctl request.  Called on low priority level.
1089144467Sharti */
1090144467Shartiint
1091144467Shartisppp_ioctl(struct ifnet *ifp, int cmd, void *data)
1092144467Sharti{
1093144467Sharti	struct ifreq *ifr = (struct ifreq*) data;
1094144467Sharti	struct sppp *sp = (struct sppp*) ifp;
1095144467Sharti	int s, going_up, going_down;
1096146027Sharti
1097146027Sharti	switch (cmd) {
1098144467Sharti	default:
10991590Srgrimes		return (ENOTTY);
1100144467Sharti
1101144467Sharti	case SIOCAIFADDR:
1102144467Sharti	case SIOCSIFDSTADDR:
11031590Srgrimes		break;
1104144467Sharti
1105144467Sharti	case SIOCSIFADDR:
1106144467Sharti		ifp->if_flags |= IFF_UP;
1107144467Sharti		/* fall through... */
1108144467Sharti
1109144467Sharti	case SIOCSIFFLAGS:
1110144467Sharti		s = splimp ();
11111590Srgrimes		going_up   = (ifp->if_flags & IFF_UP) &&
1112144467Sharti			     ! (ifp->if_flags & IFF_RUNNING);
11131590Srgrimes		going_down = ! (ifp->if_flags & IFF_UP) &&
1114144657Sharti			      (ifp->if_flags & IFF_RUNNING);
1115144467Sharti		if (going_up || going_down) {
1116144467Sharti			/* Shut down the PPP link. */
1117144467Sharti			ifp->if_flags &= ~IFF_RUNNING;
1118144467Sharti			sp->lcp.state = LCP_STATE_CLOSED;
1119144467Sharti			sp->ipcp.state = IPCP_STATE_CLOSED;
1120144467Sharti			UNTIMO (sp);
1121144467Sharti		}
11228874Srgrimes		if (going_up) {
1123144657Sharti			/* Interface is starting -- initiate negotiation. */
1124144467Sharti			ifp->if_flags |= IFF_RUNNING;
1125144467Sharti			if (!(sp->pp_flags & PP_CISCO))
1126144467Sharti				sppp_lcp_open (sp);
1127144467Sharti		}
1128144467Sharti		splx (s);
11291590Srgrimes		break;
11301590Srgrimes
1131144467Sharti#ifdef SIOCSIFMTU
1132144467Sharti#ifndef ifr_mtu
11331590Srgrimes#define ifr_mtu ifr_metric
1134104696Sjmallett#endif
11351590Srgrimes	case SIOCSIFMTU:
11361590Srgrimes		if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > PP_MTU)
11371590Srgrimes			return (EINVAL);
11381590Srgrimes		ifp->if_mtu = ifr->ifr_mtu;
11391590Srgrimes		break;
11401590Srgrimes#endif
1141104696Sjmallett#ifdef SLIOCSETMTU
11421590Srgrimes	case SLIOCSETMTU:
1143144467Sharti		if (*(short*)data < 128 || *(short*)data > PP_MTU)
1144144467Sharti			return (EINVAL);
11451590Srgrimes		ifp->if_mtu = *(short*)data;
1146144467Sharti		break;
1147144467Sharti#endif
1148144467Sharti#ifdef SIOCGIFMTU
1149144467Sharti	case SIOCGIFMTU:
1150144467Sharti		ifr->ifr_mtu = ifp->if_mtu;
1151144467Sharti		break;
1152144467Sharti#endif
11538874Srgrimes#ifdef SLIOCGETMTU
1154144467Sharti	case SLIOCGETMTU:
1155144467Sharti		*(short*)data = ifp->if_mtu;
1156144467Sharti		break;
1157144467Sharti#endif
11581590Srgrimes	case SIOCADDMULTI:
1159144467Sharti	case SIOCDELMULTI:
1160144467Sharti		break;
1161144467Sharti	}
11621590Srgrimes	return (0);
1163144467Sharti}
1164144467Sharti
1165144467Sharti/*
1166144467Sharti * Analyze the LCP Configure-Request options list
1167144467Sharti * for the presence of unknown options.
1168144467Sharti * If the request contains unknown options, build and
11691590Srgrimes * send Configure-reject packet, containing only unknown options.
1170144467Sharti */
1171144467Shartistatic int
1172144467Shartisppp_lcp_conf_parse_options(struct sppp *sp, struct lcp_header *h,
11731590Srgrimes			    int len, u_long *magic)
1174144467Sharti{
1175144467Sharti	u_char *buf, *r, *p;
11761590Srgrimes	struct ifnet *ifp = &sp->pp_if;
1177144467Sharti	int rlen, debug = ifp->if_flags & IFF_DEBUG;
1178144467Sharti
1179144467Sharti	len -= 4;
1180144467Sharti	buf = r = malloc (len, M_TEMP, M_NOWAIT);
1181144467Sharti	if (! buf)
1182144467Sharti		return (0);
1183144467Sharti
1184144467Sharti	if (debug)
1185144467Sharti		addlog("%s%d: lcp parse opts: ", ifp->if_name, ifp->if_unit);
1186144467Sharti
1187144467Sharti	p = (void*) (h+1);
1188144467Sharti	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
1189144467Sharti		switch (*p) {
1190144467Sharti		case LCP_OPT_MAGIC:
1191144467Sharti			/* Magic number -- extract. */
11921590Srgrimes			if (debug)
11931590Srgrimes				addlog(" magicnum: ");
11941590Srgrimes			if (len >= 6 && p[1] == 6) {
11951590Srgrimes				*magic = (u_long)p[2] << 24 |
1196144467Sharti					(u_long)p[3] << 16 | p[4] << 8 | p[5];
1197144467Sharti				if (debug)
11988874Srgrimes					addlog("0x%x", *magic);
11991590Srgrimes				continue;
12001590Srgrimes			}
12011590Srgrimes			if (debug)
12021590Srgrimes				addlog("invalid");
12031590Srgrimes			break;
12041590Srgrimes		case LCP_OPT_ASYNC_MAP:
12051590Srgrimes			/* Async control character map -- check to be zero. */
12061590Srgrimes			if (debug)
12071590Srgrimes				addlog(" asyncmap: ");
1208104696Sjmallett			if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&
12091590Srgrimes			    ! p[4] && ! p[5]) {
1210138232Sharti				if (debug)
1211144467Sharti					addlog("empty (ack)");
1212144467Sharti				continue;
1213144467Sharti			}
1214144467Sharti			if (debug)
1215144467Sharti				addlog("non-empty (rej)");
1216144467Sharti			break;
1217144657Sharti		case LCP_OPT_MRU:
1218144467Sharti			/* Maximum receive unit -- always OK. */
1219144467Sharti			if (debug)
1220144467Sharti				addlog(" mru (ignored)");
1221144467Sharti			continue;
1222144467Sharti		default:
1223144467Sharti			/* Others not supported. */
1224144467Sharti			if (debug)
1225144467Sharti				addlog(" unknown 0x%x", *p);
1226144467Sharti			break;
1227144467Sharti		}
1228144467Sharti		/* Add the option to rejected list. */
1229144467Sharti		bcopy (p, r, p[1]);
1230144467Sharti		r += p[1];
1231144467Sharti		rlen += p[1];
123218730Ssteve	}
1233144467Sharti	if (rlen) {
1234144467Sharti		if (debug)
1235144467Sharti			addlog(", send lcp configure nak\n");
1236144467Sharti		sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, h->ident, rlen, buf);
1237144467Sharti	} else if (debug)
1238144467Sharti		addlog("\n");
1239144467Sharti	free (buf, M_TEMP);
1240144467Sharti	return (rlen == 0);
1241144467Sharti}
1242144467Sharti
1243144467Shartistatic void
1244144467Shartisppp_ipcp_input(struct sppp *sp, struct mbuf *m)
1245144467Sharti{
1246144467Sharti	struct lcp_header *h;
1247144467Sharti	struct ifnet *ifp = &sp->pp_if;
1248144467Sharti	int len = m->m_pkthdr.len, debug = ifp->if_flags & IFF_DEBUG;;
1249144467Sharti
1250144467Sharti	if (len < 4) {
1251144467Sharti		printf ("%s%d: invalid ipcp packet length: %d bytes\n",
1252144467Sharti			ifp->if_name, ifp->if_unit, len);
1253144467Sharti		return;
1254144467Sharti	}
125535483Simp	h = mtod (m, struct lcp_header*);
1256144467Sharti	if (debug) {
1257144467Sharti		log(LOG_DEBUG,
1258144467Sharti		    "%s%d: ipcp input: %d bytes <%s id=0x%x len=0x%x",
125935483Simp		    ifp->if_name, ifp->if_unit, len,
1260144467Sharti		    sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
1261144467Sharti		if (len > 4)
1262144467Sharti			sppp_print_bytes ((u_char*) (h+1), len-4);
1263144467Sharti		addlog(">\n");
1264144467Sharti	}
12651590Srgrimes	if (len > ntohs (h->len))
1266144467Sharti		len = ntohs (h->len);
12671590Srgrimes	switch (h->type) {
12681590Srgrimes	default:
1269144467Sharti		/* Unknown packet type -- send Code-Reject packet. */
1270144467Sharti		if (debug)
12711590Srgrimes			addlog("%s%d: ipcp unknown type 0x%x, sending code rej\n",
12721590Srgrimes			       ifp->if_name, ifp->if_unit, h->type);
12731590Srgrimes		sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
12741590Srgrimes		break;
12751590Srgrimes	case IPCP_CONF_REQ:
12761590Srgrimes		if (len < 4) {
12771590Srgrimes			if (debug)
12781590Srgrimes				addlog("%s%d: invalid ipcp configure "
1279104696Sjmallett				       "request packet length: %d bytes\n",
12801590Srgrimes				       ifp->if_name, ifp->if_unit, len);
1281146129Sharti			return;
1282146129Sharti		}
12838874Srgrimes		if (len > 4) {
1284144467Sharti			if (debug)
1285146061Sharti				addlog("%s%d: rejecting ipcp conf req len=%d\n",
12868874Srgrimes				       ifp->if_name, ifp->if_unit, len);
1287144467Sharti			sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
1288144467Sharti				len-4, h+1);
1289144467Sharti
1290144467Sharti			switch (sp->ipcp.state) {
1291144467Sharti			case IPCP_STATE_OPENED:
1292144467Sharti				/* Initiate renegotiation. */
12931590Srgrimes				sppp_ipcp_open (sp);
12948874Srgrimes				/* fall through... */
12951590Srgrimes			case IPCP_STATE_ACK_SENT:
1296144467Sharti				/* Go to closed state. */
1297144467Sharti				sp->ipcp.state = IPCP_STATE_CLOSED;
1298144467Sharti			}
1299144467Sharti		} else {
13001590Srgrimes			if (debug)
1301144657Sharti				addlog("%s%d: sending ipcp conf ack\n",
1302144467Sharti				       ifp->if_name, ifp->if_unit);
1303144467Sharti			/* Send Configure-Ack packet. */
1304144467Sharti			sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
13051590Srgrimes				0, 0);
13061590Srgrimes			/* Change the state. */
1307146129Sharti			if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)
1308146129Sharti				sp->ipcp.state = IPCP_STATE_OPENED;
1309146129Sharti			else
1310146129Sharti				sp->ipcp.state = IPCP_STATE_ACK_SENT;
1311146129Sharti		}
1312146129Sharti		break;
1313146129Sharti	case IPCP_CONF_ACK:
1314146129Sharti		if (h->ident != sp->ipcp.confid) {
1315146129Sharti			if (debug)
1316146129Sharti				addlog("%s%d: ipcp id mismatch 0x%x != 0x%x\n",
1317146129Sharti				       ifp->if_name, ifp->if_unit,
1318146129Sharti				       h->ident, sp->ipcp.confid);
1319146129Sharti			break;
1320146129Sharti		}
1321146129Sharti		UNTIMO (sp);
1322146129Sharti		switch (sp->ipcp.state) {
1323146129Sharti		case IPCP_STATE_CLOSED:
1324146129Sharti			sp->ipcp.state = IPCP_STATE_ACK_RCVD;
1325146129Sharti			TIMO (sp, 5);
1326146129Sharti			break;
1327146129Sharti		case IPCP_STATE_ACK_SENT:
1328146129Sharti			sp->ipcp.state = IPCP_STATE_OPENED;
1329146129Sharti			break;
1330146129Sharti		}
1331146129Sharti		break;
1332146129Sharti	case IPCP_CONF_NAK:
1333146129Sharti	case IPCP_CONF_REJ:
1334146058Sharti		if (h->ident != sp->ipcp.confid) {
1335144467Sharti			if (debug)
1336146058Sharti				addlog("%s%d: ipcp id mismatch 0x%x != 0x%x\n",
1337144467Sharti				       ifp->if_name, ifp->if_unit,
1338144665Sharti				       h->ident, sp->ipcp.confid);
1339144665Sharti			break;
1340144665Sharti		}
1341144665Sharti		if (debug)
1342144467Sharti			addlog("%s%d: got ipcp conf %s, reopening ipcp\n",
1343144467Sharti			       ifp->if_name, ifp->if_unit,
1344144467Sharti			       (h->type == IPCP_CONF_NAK? "nak": "rej"));
1345146129Sharti		UNTIMO (sp);
1346146129Sharti			/* Initiate renegotiation. */
1347144665Sharti			sppp_ipcp_open (sp);
1348144665Sharti		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
1349144665Sharti			/* Go to closed state. */
1350144665Sharti			sp->ipcp.state = IPCP_STATE_CLOSED;
1351144665Sharti		break;
1352144467Sharti	case IPCP_TERM_REQ:
1353144665Sharti		/* Send Terminate-Ack packet. */
1354144665Sharti		if (debug)
1355144665Sharti			addlog("%s%d: got ipcp term req\n",
1356144665Sharti			       ifp->if_name, ifp->if_unit);
1357144665Sharti		sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0);
1358144665Sharti		/* Go to closed state. */
1359104475Sphk		sp->ipcp.state = IPCP_STATE_CLOSED;
1360144665Sharti			/* Initiate renegotiation. */
1361104475Sphk			sppp_ipcp_open (sp);
1362144665Sharti		break;
13638874Srgrimes	case IPCP_TERM_ACK:
1364137202Sharti		/* Ignore for now. */
1365144665Sharti		if (debug)
1366144665Sharti			addlog("%s%d: ignoring ipcp term ack\n",
1367144665Sharti			       ifp->if_name, ifp->if_unit);
1368144665Sharti	case IPCP_CODE_REJ:
1369144665Sharti		/* Ignore for now. */
1370144665Sharti		if (debug)
1371144665Sharti			addlog("%s%d: ignoring ipcp code rej\n",
1372144665Sharti			       ifp->if_name, ifp->if_unit);
1373144665Sharti		break;
1374144665Sharti	}
1375144665Sharti}
13761590Srgrimes
1377144665Shartistatic void
1378137202Shartisppp_lcp_open(struct sppp *sp)
1379144665Sharti{
1380144467Sharti	char opt[6];
1381144665Sharti
1382144665Sharti	if (! sp->lcp.magic)
1383144665Sharti	sp->lcp.magic = time.tv_sec + time.tv_usec;
13841590Srgrimes	opt[0] = LCP_OPT_MAGIC;
13851590Srgrimes	opt[1] = sizeof (opt);
1386144467Sharti	opt[2] = sp->lcp.magic >> 24;
1387144467Sharti	opt[3] = sp->lcp.magic >> 16;
1388144467Sharti	opt[4] = sp->lcp.magic >> 8;
1389144467Sharti	opt[5] = sp->lcp.magic;
1390144494Sharti	sp->lcp.confid = ++sp->pp_seq;
1391144467Sharti	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,
1392144467Sharti		sizeof (opt), &opt);
13931590Srgrimes	TIMO (sp, 2);
13941590Srgrimes}
13951590Srgrimes
1396144467Shartistatic void
1397144467Shartisppp_ipcp_open(struct sppp *sp)
13981590Srgrimes{
13991590Srgrimes	sp->ipcp.confid = ++sp->pp_seq;
14001590Srgrimes	sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0);
1401104696Sjmallett	TIMO (sp, 2);
14021590Srgrimes}
1403144467Sharti
1404144467Sharti/*
14058874Srgrimes * Process PPP control protocol timeouts.
1406144467Sharti */
1407144467Shartistatic void
14081590Srgrimessppp_cp_timeout(void *arg)
1409144657Sharti{
1410144657Sharti	struct sppp *sp = (struct sppp*) arg;
1411144467Sharti	int s = splimp ();
1412144467Sharti
1413144467Sharti	sp->pp_flags &= ~PP_TIMO;
1414144467Sharti	if (! (sp->pp_if.if_flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) {
1415144467Sharti		splx (s);
1416144467Sharti		return;
1417144467Sharti	}
1418144657Sharti	switch (sp->lcp.state) {
1419144657Sharti	case LCP_STATE_CLOSED:
1420144657Sharti		/* No ACK for Configure-Request, retry. */
1421144657Sharti		sppp_lcp_open (sp);
14221590Srgrimes		break;
1423144467Sharti	case LCP_STATE_ACK_RCVD:
1424144467Sharti		/* ACK got, but no Configure-Request for peer, retry. */
1425144467Sharti		sppp_lcp_open (sp);
1426144467Sharti		sp->lcp.state = LCP_STATE_CLOSED;
1427144467Sharti		break;
1428144467Sharti	case LCP_STATE_ACK_SENT:
1429144467Sharti		/* ACK sent but no ACK for Configure-Request, retry. */
1430144467Sharti		sppp_lcp_open (sp);
1431144467Sharti		break;
1432144467Sharti	case LCP_STATE_OPENED:
1433144467Sharti		/* LCP is already OK, try IPCP. */
1434144467Sharti		switch (sp->ipcp.state) {
1435144467Sharti		case IPCP_STATE_CLOSED:
14361590Srgrimes			/* No ACK for Configure-Request, retry. */
1437144467Sharti			sppp_ipcp_open (sp);
14381590Srgrimes			break;
14391590Srgrimes		case IPCP_STATE_ACK_RCVD:
1440144467Sharti			/* ACK got, but no Configure-Request for peer, retry. */
1441144467Sharti			sppp_ipcp_open (sp);
1442144494Sharti			sp->ipcp.state = IPCP_STATE_CLOSED;
1443144494Sharti			break;
14441590Srgrimes		case IPCP_STATE_ACK_SENT:
14451590Srgrimes			/* ACK sent but no ACK for Configure-Request, retry. */
14461590Srgrimes			sppp_ipcp_open (sp);
14471590Srgrimes			break;
14481590Srgrimes		case IPCP_STATE_OPENED:
1449104696Sjmallett			/* IPCP is OK. */
14501590Srgrimes			break;
145118730Ssteve		}
1452144467Sharti		break;
1453144467Sharti	}
1454144467Sharti	splx (s);
1455144467Sharti}
1456144467Sharti
1457144467Shartistatic const char *
1458144467Shartisppp_lcp_type_name(u_char type)
1459144467Sharti{
1460144467Sharti	static char buf [12];
1461144467Sharti	switch (type) {
1462144467Sharti	case LCP_CONF_REQ:   return ("conf-req");
14638874Srgrimes	case LCP_CONF_ACK:   return ("conf-ack");
1464144467Sharti	case LCP_CONF_NAK:   return ("conf-nack");
14658874Srgrimes	case LCP_CONF_REJ:   return ("conf-rej");
1466144467Sharti	case LCP_TERM_REQ:   return ("term-req");
1467144657Sharti	case LCP_TERM_ACK:   return ("term-ack");
1468144467Sharti	case LCP_CODE_REJ:   return ("code-rej");
1469144657Sharti	case LCP_PROTO_REJ:  return ("proto-rej");
1470144657Sharti	case LCP_ECHO_REQ:   return ("echo-req");
1471144467Sharti	case LCP_ECHO_REPLY: return ("echo-reply");
1472144467Sharti	case LCP_DISC_REQ:   return ("discard-req");
1473144494Sharti	}
1474144467Sharti	sprintf (buf, "0x%x", type);
1475144467Sharti	return (buf);
1476144467Sharti}
1477144467Sharti
1478144467Shartistatic const char *
1479144467Shartisppp_ipcp_type_name(u_char type)
1480144467Sharti{
1481144467Sharti	static char buf [12];
1482144467Sharti	switch (type) {
1483144467Sharti	case IPCP_CONF_REQ:   return ("conf-req");
1484144467Sharti	case IPCP_CONF_ACK:   return ("conf-ack");
1485137202Sharti	case IPCP_CONF_NAK:   return ("conf-nack");
14861590Srgrimes	case IPCP_CONF_REJ:   return ("conf-rej");
1487144467Sharti	case IPCP_TERM_REQ:   return ("term-req");
1488144467Sharti	case IPCP_TERM_ACK:   return ("term-ack");
14891590Srgrimes	case IPCP_CODE_REJ:   return ("code-rej");
1490144467Sharti	}
1491144657Sharti	sprintf (buf, "0x%x", type);
1492144657Sharti	return (buf);
1493144467Sharti}
1494144467Sharti
1495144467Shartistatic void
1496144467Shartisppp_print_bytes(u_char *p, u_short len)
1497144467Sharti{
1498144467Sharti	addlog(" %x", *p++);
1499144467Sharti	while (--len > 0)
15008874Srgrimes		addlog("-%x", *p++);
1501144467Sharti}
1502144467Sharti