if_spppsubr.c revision 4952
14910Swollman/*
24910Swollman * Synchronous PPP/Cisco link level subroutines.
34910Swollman * Keepalive protocol implemented in both Cisco and PPP modes.
44910Swollman *
54910Swollman * Copyright (C) 1994 Cronyx Ltd.
64910Swollman * Author: Serge Vakulenko, <vak@zebub.msk.su>
74910Swollman *
84910Swollman * This software is distributed with NO WARRANTIES, not even the implied
94910Swollman * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
104910Swollman *
114910Swollman * Authors grant any other persons or organisations permission to use
124910Swollman * or modify this software as long as this message is kept with the software,
134910Swollman * all derivative works or modified versions.
144910Swollman *
154910Swollman * Version 1.1, Thu Oct 27 21:13:59 MSK 1994
164910Swollman */
174910Swollman#undef DEBUG
184910Swollman
194910Swollman#include <sys/param.h>
204952Sbde#include <sys/systm.h>
214952Sbde#include <sys/kernel.h>
224910Swollman#include <sys/ioctl.h>
234910Swollman#include <sys/socket.h>
244910Swollman#include <sys/mbuf.h>
254910Swollman
264910Swollman#include <net/if.h>
274910Swollman#include <net/netisr.h>
284910Swollman#include <net/if_types.h>
294910Swollman
304910Swollman#ifdef INET
314910Swollman#include <netinet/in.h>
324910Swollman#include <netinet/in_systm.h>
334910Swollman#include <netinet/in_var.h>
344910Swollman#include <netinet/ip.h>
354910Swollman#include <netinet/tcp.h>
364910Swollman#include <netinet/if_ether.h>
374910Swollman#endif
384910Swollman
394910Swollman#ifdef NS
404910Swollman#include <netns/ns.h>
414910Swollman#include <netns/ns_if.h>
424910Swollman#endif
434910Swollman
444910Swollman#ifdef ISO
454910Swollman#include <netiso/argo_debug.h>
464910Swollman#include <netiso/iso.h>
474910Swollman#include <netiso/iso_var.h>
484910Swollman#include <netiso/iso_snpac.h>
494910Swollman#endif
504910Swollman
514910Swollman#include <net/if_sppp.h>
524910Swollman
534910Swollman#ifdef DEBUG
544910Swollman#define print(s)        printf s
554910Swollman#else
564910Swollman#define print(s)        /*void*/
574910Swollman#endif
584910Swollman
594910Swollman#define MAXALIVECNT     3               /* max. alive packets */
604910Swollman
614910Swollman#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
624910Swollman#define PPP_UI          0x03            /* Unnumbered Information */
634910Swollman#define PPP_IP          0x0021          /* Internet Protocol */
644910Swollman#define PPP_ISO         0x0023          /* ISO OSI Protocol */
654910Swollman#define PPP_XNS         0x0025          /* Xerox NS Protocol */
664910Swollman#define PPP_LCP         0xc021          /* Link Control Protocol */
674910Swollman#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
684910Swollman
694910Swollman#define LCP_CONF_REQ    1               /* PPP LCP configure request */
704910Swollman#define LCP_CONF_ACK    2               /* PPP LCP configure acknowledge */
714910Swollman#define LCP_CONF_NAK    3               /* PPP LCP configure negative ack */
724910Swollman#define LCP_CONF_REJ    4               /* PPP LCP configure reject */
734910Swollman#define LCP_TERM_REQ    5               /* PPP LCP terminate request */
744910Swollman#define LCP_TERM_ACK    6               /* PPP LCP terminate acknowledge */
754910Swollman#define LCP_CODE_REJ    7               /* PPP LCP code reject */
764910Swollman#define LCP_PROTO_REJ   8               /* PPP LCP protocol reject */
774910Swollman#define LCP_ECHO_REQ    9               /* PPP LCP echo request */
784910Swollman#define LCP_ECHO_REPLY  10              /* PPP LCP echo reply */
794910Swollman#define LCP_DISC_REQ    11              /* PPP LCP discard request */
804910Swollman
814910Swollman#define LCP_OPT_MRU             1       /* maximum receive unit */
824910Swollman#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
834910Swollman#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
844910Swollman#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
854910Swollman#define LCP_OPT_MAGIC           5       /* magic number */
864910Swollman#define LCP_OPT_RESERVED        6       /* reserved */
874910Swollman#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
884910Swollman#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
894910Swollman
904910Swollman#define IPCP_CONF_REQ   LCP_CONF_REQ    /* PPP IPCP configure request */
914910Swollman#define IPCP_CONF_ACK   LCP_CONF_ACK    /* PPP IPCP configure acknowledge */
924910Swollman#define IPCP_CONF_NAK   LCP_CONF_NAK    /* PPP IPCP configure negative ack */
934910Swollman#define IPCP_CONF_REJ   LCP_CONF_REJ    /* PPP IPCP configure reject */
944910Swollman#define IPCP_TERM_REQ   LCP_TERM_REQ    /* PPP IPCP terminate request */
954910Swollman#define IPCP_TERM_ACK   LCP_TERM_ACK    /* PPP IPCP terminate acknowledge */
964910Swollman#define IPCP_CODE_REJ   LCP_CODE_REJ    /* PPP IPCP code reject */
974910Swollman
984910Swollman#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
994910Swollman#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
1004910Swollman#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
1014910Swollman#define CISCO_ADDR_REQ          0       /* Cisco address request */
1024910Swollman#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
1034910Swollman#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
1044910Swollman
1054910Swollmanstruct ppp_header {
1064910Swollman	unsigned char address;
1074910Swollman	unsigned char control;
1084910Swollman	unsigned short protocol;
1094910Swollman};
1104910Swollman#define PPP_HEADER_LEN          sizeof (struct ppp_header)
1114910Swollman
1124910Swollmanstruct lcp_header {
1134910Swollman	unsigned char type;
1144910Swollman	unsigned char ident;
1154910Swollman	unsigned short len;
1164910Swollman};
1174910Swollman#define LCP_HEADER_LEN          sizeof (struct lcp_header)
1184910Swollman
1194910Swollmanstruct cisco_packet {
1204910Swollman	unsigned long type;
1214910Swollman	unsigned long par1;
1224910Swollman	unsigned long par2;
1234910Swollman	unsigned short rel;
1244910Swollman	unsigned short time0;
1254910Swollman	unsigned short time1;
1264910Swollman};
1274910Swollman#define CISCO_PACKET_LEN 18
1284910Swollman
1294910Swollmanstruct sppp *spppq;
1304910Swollman
1314910Swollmanextern void if_down (struct ifnet *ifp);
1324910Swollman
1334910Swollman/*
1344910Swollman * The following disgusting hack gets around the problem that IP TOS
1354910Swollman * can't be set yet.  We want to put "interactive" traffic on a high
1364910Swollman * priority queue.  To decide if traffic is interactive, we check that
1374910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
1384910Swollman */
1394910Swollmanstatic unsigned short interactive_ports[8] = {
1404910Swollman	0,	513,	0,	0,
1414910Swollman	0,	21,	0,	23,
1424910Swollman};
1434910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
1444910Swollman
1454910Swollmanvoid sppp_keepalive (caddr_t dummy1, int dummy2);
1464910Swollmanvoid sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type,
1474910Swollman	unsigned char ident, unsigned short len, void *data);
1484910Swollmanvoid sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
1494910Swollmanvoid sppp_lcp_input (struct sppp *sp, struct mbuf *m);
1504910Swollmanvoid sppp_cisco_input (struct sppp *sp, struct mbuf *m);
1514910Swollmanvoid sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h);
1524910Swollmanvoid sppp_ipcp_input (struct sppp *sp, struct mbuf *m);
1534910Swollmanvoid sppp_lcp_open (struct sppp *sp);
1544910Swollmanvoid sppp_ipcp_open (struct sppp *sp);
1554910Swollmanint sppp_lcp_conf_unknown_options (int len, unsigned char *p);
1564910Swollmanvoid sppp_cp_timeout (caddr_t arg, int dummy);
1574910Swollmanchar *sppp_lcp_type_name (unsigned char type);
1584910Swollmanchar *sppp_ipcp_type_name (unsigned char type);
1594910Swollmanvoid sppp_print_bytes (unsigned char *p, unsigned short len);
1604910Swollman
1614910Swollman/*
1624910Swollman * Flush interface queue.
1634910Swollman */
1644910Swollmanstatic void qflush (struct ifqueue *ifq)
1654910Swollman{
1664910Swollman	struct mbuf *m, *n;
1674910Swollman
1684910Swollman	n = ifq->ifq_head;
1694910Swollman	while ((m = n)) {
1704910Swollman		n = m->m_act;
1714910Swollman		m_freem (m);
1724910Swollman	}
1734910Swollman	ifq->ifq_head = 0;
1744910Swollman	ifq->ifq_tail = 0;
1754910Swollman	ifq->ifq_len = 0;
1764910Swollman}
1774910Swollman
1784910Swollman/*
1794910Swollman * Process the received packet.
1804910Swollman */
1814910Swollmanvoid sppp_input (struct ifnet *ifp, struct mbuf *m)
1824910Swollman{
1834910Swollman	struct ppp_header *h;
1844910Swollman	struct sppp *sp;
1854910Swollman	struct ifqueue *inq = 0;
1864910Swollman
1874910Swollman	ifp->if_lastchange = time;
1884910Swollman	if (ifp->if_flags & IFF_UP)
1894910Swollman		/* Count received bytes, add FCS and one flag */
1904910Swollman		ifp->if_ibytes += m->m_pkthdr.len + 3;
1914910Swollman
1924910Swollman	if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
1934910Swollman		/* Too small packet, drop it. */
1944910Swollman		if (ifp->if_flags & IFF_DEBUG)
1954910Swollman			printf ("%s%d: input packet is too small, %d bytes\n",
1964910Swollman				ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
1974910Swollmandrop:           ++ifp->if_iqdrops;
1984910Swollman		m_freem (m);
1994910Swollman		return;
2004910Swollman	}
2014910Swollman
2024910Swollman	/* Get PPP header. */
2034910Swollman	h = mtod (m, struct ppp_header*);
2044910Swollman	m_adj (m, PPP_HEADER_LEN);
2054910Swollman
2064910Swollman	switch (h->address) {
2074910Swollman	default:        /* Invalid PPP packet. */
2084910Swollmaninvalid:        if (ifp->if_flags & IFF_DEBUG)
2094910Swollman			printf ("%s%d: invalid input packet <0x%x 0x%x 0x%x>\n",
2104910Swollman				ifp->if_name, ifp->if_unit,
2114910Swollman				h->address, h->control, ntohs (h->protocol));
2124910Swollman		goto drop;
2134910Swollman	case PPP_ALLSTATIONS:
2144910Swollman		if (h->control != PPP_UI)
2154910Swollman			goto invalid;
2164910Swollman		sp = (struct sppp*) ifp;
2174910Swollman		switch (ntohs (h->protocol)) {
2184910Swollman		default:
2194910Swollman			if (sp->lcp.state == LCP_STATE_OPENED)
2204910Swollman				sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
2214910Swollman					++sp->pp_seq, m->m_pkthdr.len - 2,
2224910Swollman					&h->protocol);
2234910Swollman			if (ifp->if_flags & IFF_DEBUG)
2244910Swollman				printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n",
2254910Swollman					ifp->if_name, ifp->if_unit,
2264910Swollman					h->address, h->control, ntohs (h->protocol));
2274910Swollman			++ifp->if_noproto;
2284910Swollman			goto drop;
2294910Swollman		case PPP_LCP:
2304910Swollman			sppp_lcp_input ((struct sppp*) ifp, m);
2314910Swollman			m_freem (m);
2324910Swollman			return;
2334910Swollman#ifdef INET
2344910Swollman		case PPP_IPCP:
2354910Swollman			if (sp->lcp.state == LCP_STATE_OPENED)
2364910Swollman				sppp_ipcp_input ((struct sppp*) ifp, m);
2374910Swollman			m_freem (m);
2384910Swollman			return;
2394910Swollman		case PPP_IP:
2404910Swollman			if (sp->ipcp.state == IPCP_STATE_OPENED) {
2414910Swollman				schednetisr (NETISR_IP);
2424910Swollman				inq = &ipintrq;
2434910Swollman			}
2444910Swollman			break;
2454910Swollman#endif
2464910Swollman#ifdef NS
2474910Swollman		case PPP_XNS:
2484910Swollman			/* XNS IDPCP not implemented yet */
2494910Swollman			if (sp->lcp.state == LCP_STATE_OPENED) {
2504910Swollman				schednetisr (NETISR_NS);
2514910Swollman				inq = &nsintrq;
2524910Swollman			}
2534910Swollman			break;
2544910Swollman#endif
2554910Swollman#ifdef ISO
2564910Swollman		case PPP_ISO:
2574910Swollman			/* OSI NLCP not implemented yet */
2584910Swollman			if (sp->lcp.state == LCP_STATE_OPENED) {
2594910Swollman				schednetisr (NETISR_ISO);
2604910Swollman				inq = &clnlintrq;
2614910Swollman			}
2624910Swollman			break;
2634910Swollman#endif
2644910Swollman		}
2654910Swollman		break;
2664910Swollman	case CISCO_MULTICAST:
2674910Swollman	case CISCO_UNICAST:
2684910Swollman		/* Don't check the control field here (RFC 1547). */
2694910Swollman		switch (ntohs (h->protocol)) {
2704910Swollman		default:
2714910Swollman			++ifp->if_noproto;
2724910Swollman			goto invalid;
2734910Swollman		case CISCO_KEEPALIVE:
2744910Swollman			sppp_cisco_input ((struct sppp*) ifp, m);
2754910Swollman			m_freem (m);
2764910Swollman			return;
2774910Swollman#ifdef INET
2784910Swollman		case ETHERTYPE_IP:
2794910Swollman			schednetisr (NETISR_IP);
2804910Swollman			inq = &ipintrq;
2814910Swollman			break;
2824910Swollman#endif
2834910Swollman#ifdef NS
2844910Swollman		case ETHERTYPE_NS:
2854910Swollman			schednetisr (NETISR_NS);
2864910Swollman			inq = &nsintrq;
2874910Swollman			break;
2884910Swollman#endif
2894910Swollman		}
2904910Swollman		break;
2914910Swollman	}
2924910Swollman
2934910Swollman	if (! (ifp->if_flags & IFF_UP) || ! inq)
2944910Swollman		goto drop;
2954910Swollman
2964910Swollman	/* Check queue. */
2974910Swollman	if (IF_QFULL (inq)) {
2984910Swollman		/* Queue overflow. */
2994910Swollman		if (ifp->if_flags & IFF_DEBUG)
3004910Swollman			printf ("%s%d: protocol queue overflow\n",
3014910Swollman				ifp->if_name, ifp->if_unit);
3024910Swollman		IF_DROP (inq);
3034910Swollman		goto drop;
3044910Swollman	}
3054910Swollman	IF_ENQUEUE (inq, m);
3064910Swollman}
3074910Swollman
3084910Swollman/*
3094910Swollman * Enqueue transmit packet.
3104910Swollman */
3114910Swollmanint sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)
3124910Swollman{
3134910Swollman	struct sppp *sp = (struct sppp*) ifp;
3144910Swollman	struct ppp_header *h;
3154910Swollman	struct ifqueue *ifq;
3164910Swollman	int s = splimp ();
3174910Swollman
3184910Swollman	if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) {
3194910Swollman		m_freem (m);
3204910Swollman		splx (s);
3214910Swollman		return (ENETDOWN);
3224910Swollman	}
3234910Swollman
3244910Swollman	ifq = &ifp->if_snd;
3254910Swollman#ifdef INET
3264910Swollman	/*
3274910Swollman	 * Put low delay, telnet, rlogin and ftp control packets
3284910Swollman	 * in front of the queue.
3294910Swollman	 */
3304910Swollman	{
3314910Swollman	struct ip *ip = mtod (m, struct ip*);
3324910Swollman	struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
3334910Swollman
3344910Swollman	if (! IF_QFULL (&sp->pp_fastq) && ((ip->ip_tos & IPTOS_LOWDELAY) ||
3354910Swollman	    ip->ip_p == IPPROTO_TCP &&
3364910Swollman	    m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) &&
3374910Swollman	    (INTERACTIVE (ntohs (tcp->th_sport)) ||
3384910Swollman	    INTERACTIVE (ntohs (tcp->th_dport)))))
3394910Swollman		ifq = &sp->pp_fastq;
3404910Swollman	}
3414910Swollman#endif
3424910Swollman
3434910Swollman	/*
3444910Swollman	 * Prepend general data packet PPP header. For now, IP only.
3454910Swollman	 */
3464910Swollman	M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT);
3474910Swollman	if (! m) {
3484910Swollman		if (ifp->if_flags & IFF_DEBUG)
3494910Swollman			printf ("%s%d: no memory for transmit header\n",
3504910Swollman				ifp->if_name, ifp->if_unit);
3514910Swollman		splx (s);
3524910Swollman		return (ENOBUFS);
3534910Swollman	}
3544910Swollman	h = mtod (m, struct ppp_header*);
3554910Swollman	if (sp->pp_flags & PP_CISCO) {
3564910Swollman		h->address = CISCO_MULTICAST;        /* broadcast address */
3574910Swollman		h->control = 0;
3584910Swollman	} else {
3594910Swollman		h->address = PPP_ALLSTATIONS;        /* broadcast address */
3604910Swollman		h->control = PPP_UI;                 /* Unnumbered Info */
3614910Swollman	}
3624910Swollman
3634910Swollman	switch (dst->sa_family) {
3644910Swollman#ifdef INET
3654910Swollman	case AF_INET:   /* Internet Protocol */
3664910Swollman		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
3674910Swollman			ETHERTYPE_IP : PPP_IP);
3684910Swollman		break;
3694910Swollman#endif
3704910Swollman#ifdef NS
3714910Swollman	case AF_NS:     /* Xerox NS Protocol */
3724910Swollman		h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
3734910Swollman			ETHERTYPE_NS : PPP_XNS);
3744910Swollman		break;
3754910Swollman#endif
3764910Swollman#ifdef ISO
3774910Swollman	case AF_ISO:    /* ISO OSI Protocol */
3784910Swollman		if (sp->pp_flags & PP_CISCO)
3794910Swollman			goto nosupport;
3804910Swollman		h->protocol = htons (PPP_ISO);
3814910Swollman		break;
3824910Swollman#endif
3834910Swollman	default:
3844910Swollman		m_freem (m);
3854910Swollman		splx (s);
3864910Swollman		return (EAFNOSUPPORT);
3874910Swollman	}
3884910Swollman
3894910Swollman	/*
3904910Swollman	 * Queue message on interface, and start output if interface
3914910Swollman	 * not yet active.
3924910Swollman	 */
3934910Swollman	if (IF_QFULL (ifq)) {
3944910Swollman		IF_DROP (&ifp->if_snd);
3954910Swollman		m_freem (m);
3964910Swollman		splx (s);
3974910Swollman		return (ENOBUFS);
3984910Swollman	}
3994910Swollman	IF_ENQUEUE (ifq, m);
4004910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
4014910Swollman		(*ifp->if_start) (ifp);
4024910Swollman
4034910Swollman	/*
4044910Swollman	 * Count output packets and bytes.
4054910Swollman	 * The packet length includes header, FCS and 1 flag,
4064910Swollman	 * according to RFC 1333.
4074910Swollman	 */
4084910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
4094910Swollman	ifp->if_lastchange = time;
4104910Swollman	splx (s);
4114910Swollman	return (0);
4124910Swollman}
4134910Swollman
4144910Swollmanvoid sppp_attach (struct ifnet *ifp)
4154910Swollman{
4164910Swollman	struct sppp *sp = (struct sppp*) ifp;
4174910Swollman
4184910Swollman	/* Initialize keepalive handler. */
4194910Swollman	if (! spppq)
4204910Swollman		timeout (sppp_keepalive, 0, hz * 10);
4214910Swollman
4224910Swollman	/* Insert new entry into the keepalive list. */
4234910Swollman	sp->pp_next = spppq;
4244910Swollman	spppq = sp;
4254910Swollman
4264910Swollman	sp->pp_if.if_type = IFT_PPP;
4274910Swollman	sp->pp_if.if_output = sppp_output;
4284910Swollman	sp->pp_fastq.ifq_maxlen = 32;
4294910Swollman	sp->pp_loopcnt = 0;
4304910Swollman	sp->pp_alivecnt = 0;
4314910Swollman	sp->lcp.magic = time.tv_sec + time.tv_usec;
4324910Swollman	sp->lcp.rmagic = 0;
4334910Swollman	sp->pp_seq = sp->lcp.magic;
4344910Swollman	sp->pp_rseq = 0;
4354910Swollman}
4364910Swollman
4374910Swollmanvoid sppp_detach (struct ifnet *ifp)
4384910Swollman{
4394910Swollman	struct sppp **q, *p, *sp = (struct sppp*) ifp;
4404910Swollman
4414910Swollman	/* Remove the entry from the keepalive list. */
4424910Swollman	for (q = &spppq; (p = *q); q = &p->pp_next)
4434910Swollman		if (p == sp) {
4444910Swollman			*q = p->pp_next;
4454910Swollman			break;
4464910Swollman		}
4474910Swollman
4484910Swollman	/* Stop keepalive handler. */
4494910Swollman	if (! spppq)
4504910Swollman		untimeout (sppp_keepalive, 0);
4514910Swollman	untimeout (sppp_cp_timeout, (caddr_t) sp);
4524910Swollman}
4534910Swollman
4544910Swollman/*
4554910Swollman * Flush the interface output queue.
4564910Swollman */
4574910Swollmanvoid sppp_flush (struct ifnet *ifp)
4584910Swollman{
4594910Swollman	struct sppp *sp = (struct sppp*) ifp;
4604910Swollman
4614910Swollman	qflush (&sp->pp_if.if_snd);
4624910Swollman	qflush (&sp->pp_fastq);
4634910Swollman}
4644910Swollman
4654910Swollman/*
4664910Swollman * Get next packet to send.
4674910Swollman */
4684910Swollmanstruct mbuf *sppp_dequeue (struct ifnet *ifp)
4694910Swollman{
4704910Swollman	struct sppp *sp = (struct sppp*) ifp;
4714910Swollman	struct mbuf *m;
4724910Swollman	int s = splimp ();
4734910Swollman
4744910Swollman	IF_DEQUEUE (&sp->pp_fastq, m);
4754910Swollman	if (! m)
4764910Swollman		IF_DEQUEUE (&sp->pp_if.if_snd, m);
4774910Swollman	splx (s);
4784910Swollman	return (m);
4794910Swollman}
4804910Swollman
4814910Swollman/*
4824910Swollman * Send keepalive packets, every 10 seconds.
4834910Swollman */
4844910Swollmanvoid sppp_keepalive (caddr_t dummy1, int dummy2)
4854910Swollman{
4864910Swollman	struct sppp *sp;
4874910Swollman	int s = splimp ();
4884910Swollman
4894910Swollman	for (sp=spppq; sp; sp=sp->pp_next) {
4904910Swollman		struct ifnet *ifp = &sp->pp_if;
4914910Swollman
4924910Swollman		if (! (sp->pp_flags & PP_KEEPALIVE) ||
4934910Swollman		    ! (ifp->if_flags & IFF_RUNNING) ||
4944910Swollman		    sp->lcp.state != LCP_STATE_OPENED)
4954910Swollman			continue;
4964910Swollman
4974910Swollman		if (sp->pp_alivecnt == MAXALIVECNT) {
4984910Swollman			/* No keepalive packets got.  Stop the interface. */
4994910Swollman			printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
5004910Swollman			if_down (ifp);
5014910Swollman			qflush (&sp->pp_fastq);
5024910Swollman		}
5034910Swollman		if (sp->pp_loopcnt >= MAXALIVECNT)
5044910Swollman			printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
5054910Swollman
5064910Swollman		if (sp->pp_alivecnt <= MAXALIVECNT)
5074910Swollman			++sp->pp_alivecnt;
5084910Swollman		if (sp->pp_flags & PP_CISCO)
5094910Swollman			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
5104910Swollman				sp->pp_rseq);
5114910Swollman		else if (sp->lcp.state == LCP_STATE_OPENED) {
5124910Swollman			long nmagic = htonl (sp->lcp.magic);
5134910Swollman			sp->lcp.lastid = ++sp->pp_seq;
5144910Swollman			sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
5154910Swollman				sp->lcp.lastid, 4, &nmagic);
5164910Swollman		}
5174910Swollman	}
5184910Swollman	splx (s);
5194910Swollman	timeout (sppp_keepalive, 0, hz * 10);
5204910Swollman}
5214910Swollman
5224910Swollman/*
5234910Swollman * Handle incoming PPP Link Control Protocol packets.
5244910Swollman */
5254910Swollmanvoid sppp_lcp_input (struct sppp *sp, struct mbuf *m)
5264910Swollman{
5274910Swollman	struct lcp_header *h;
5284910Swollman	struct ifnet *ifp = &sp->pp_if;
5294910Swollman	int len = m->m_pkthdr.len;
5304910Swollman	unsigned char *p;
5314910Swollman
5324910Swollman	if (len < 4) {
5334910Swollman		if (ifp->if_flags & IFF_DEBUG)
5344910Swollman			printf ("%s%d: invalid lcp packet length: %d bytes\n",
5354910Swollman				ifp->if_name, ifp->if_unit, len);
5364910Swollman		return;
5374910Swollman	}
5384910Swollman	h = mtod (m, struct lcp_header*);
5394910Swollman	if (ifp->if_flags & IFF_DEBUG) {
5404910Swollman		printf ("%s%d: lcp input: %d bytes <%s id=%xh len=%xh",
5414910Swollman			ifp->if_name, ifp->if_unit, len,
5424910Swollman			sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
5434910Swollman		if (len > 4)
5444910Swollman			sppp_print_bytes ((unsigned char*) (h+1), len-4);
5454910Swollman		printf (">\n");
5464910Swollman	}
5474910Swollman	if (len > ntohs (h->len))
5484910Swollman		len = ntohs (h->len);
5494910Swollman	switch (h->type) {
5504910Swollman	default:
5514910Swollman		/* Unknown packet type -- send Code-Reject packet. */
5524910Swollman		sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, len, h);
5534910Swollman		break;
5544910Swollman	case LCP_CONF_REQ:
5554910Swollman		if (len < 4) {
5564910Swollman			if (ifp->if_flags & IFF_DEBUG)
5574910Swollman				printf ("%s%d: invalid lcp configure request packet length: %d bytes\n",
5584910Swollman					ifp->if_name, ifp->if_unit, len);
5594910Swollman			return;
5604910Swollman		}
5614910Swollman		if (len>4 && sppp_lcp_conf_unknown_options (len-4, (unsigned char*) (h+1))) {
5624910Swollman			sppp_lcp_conf_rej (sp, h);
5634910Swollman			if (sp->lcp.state == LCP_STATE_OPENED)
5644910Swollman				/* Initiate renegotiation. */
5654910Swollman				sppp_lcp_open (sp);
5664910Swollman			if (sp->lcp.state != LCP_STATE_ACK_RCVD) {
5674910Swollman				/* Go to closed state. */
5684910Swollman				sp->lcp.state = LCP_STATE_CLOSED;
5694910Swollman				sp->ipcp.state = IPCP_STATE_CLOSED;
5704910Swollman			}
5714910Swollman		} else {
5724910Swollman			/* Extract remote magic number. */
5734910Swollman			p = (unsigned char*) (h+1);
5744910Swollman			if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4)
5754910Swollman				sp->lcp.rmagic = (unsigned long)p[2] << 24 |
5764910Swollman					(unsigned long)p[3] << 16 |
5774910Swollman					p[4] << 8 | p[5];
5784910Swollman			if (sp->lcp.rmagic == sp->lcp.magic) {
5794910Swollman				/* Local and remote magics are equal -- loop? */
5804910Swollman				sp->lcp.rmagic = ~sp->lcp.magic;
5814910Swollman				/* Send Configure-Nack packet. */
5824910Swollman				p[2] = sp->lcp.rmagic >> 24;
5834910Swollman				p[3] = sp->lcp.rmagic >> 16;
5844910Swollman				p[4] = sp->lcp.rmagic >> 8;
5854910Swollman				p[5] = sp->lcp.rmagic;
5864910Swollman				sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
5874910Swollman					h->ident, len-4, h+1);
5884910Swollman				if (sp->lcp.state != LCP_STATE_ACK_RCVD) {
5894910Swollman					/* Go to closed state. */
5904910Swollman					sp->lcp.state = LCP_STATE_CLOSED;
5914910Swollman					sp->ipcp.state = IPCP_STATE_CLOSED;
5924910Swollman				}
5934910Swollman			} else {
5944910Swollman				/* Send Configure-Ack packet. */
5954910Swollman				sp->pp_loopcnt = 0;
5964910Swollman				sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
5974910Swollman					h->ident, len-4, h+1);
5984910Swollman				if (sp->lcp.state == LCP_STATE_OPENED)
5994910Swollman					/* Initiate renegotiation. */
6004910Swollman					sppp_lcp_open (sp);
6014910Swollman				/* Change the state. */
6024910Swollman				if (sp->lcp.state == LCP_STATE_ACK_RCVD) {
6034910Swollman					sp->lcp.state = LCP_STATE_OPENED;
6044910Swollman					sppp_ipcp_open (sp);
6054910Swollman				} else
6064910Swollman					sp->lcp.state = LCP_STATE_ACK_SENT;
6074910Swollman			}
6084910Swollman		}
6094910Swollman		break;
6104910Swollman	case LCP_CONF_ACK:
6114910Swollman		if (h->ident != sp->pp_seq)
6124910Swollman			return;
6134910Swollman		untimeout (sppp_cp_timeout, (caddr_t) sp);
6144910Swollman		switch (sp->lcp.state) {
6154910Swollman		case LCP_STATE_CLOSED:
6164910Swollman			sp->lcp.state = LCP_STATE_ACK_RCVD;
6174910Swollman			break;
6184910Swollman		case LCP_STATE_ACK_SENT:
6194910Swollman			sp->lcp.state = LCP_STATE_OPENED;
6204910Swollman			sppp_ipcp_open (sp);
6214910Swollman			break;
6224910Swollman		case LCP_STATE_ACK_RCVD:
6234910Swollman		case LCP_STATE_OPENED:
6244910Swollman			/* Initiate renegotiation. */
6254910Swollman			sppp_lcp_open (sp);
6264910Swollman			/* Go to closed state. */
6274910Swollman			sp->lcp.state = LCP_STATE_CLOSED;
6284910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
6294910Swollman			break;
6304910Swollman		}
6314910Swollman		break;
6324910Swollman	case LCP_CONF_NAK:
6334910Swollman		if (h->ident != sp->pp_seq)
6344910Swollman			return;
6354910Swollman		p = (unsigned char*) (h+1);
6364910Swollman		if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
6374910Swollman			sp->lcp.rmagic = (unsigned long)p[2] << 24 |
6384910Swollman				(unsigned long)p[3] << 16 |
6394910Swollman				p[4] << 8 | p[5];
6404910Swollman			if (sp->lcp.rmagic == ~sp->lcp.magic) {
6414910Swollman				if (ifp->if_flags & IFF_DEBUG)
6424910Swollman					printf ("%s%d: conf nak: magic glitch\n",
6434910Swollman						ifp->if_name, ifp->if_unit);
6444910Swollman				++sp->pp_loopcnt;
6454910Swollman				sp->lcp.magic = time.tv_sec + time.tv_usec;
6464910Swollman			}
6474910Swollman		}
6484910Swollman		/* Fall through. */
6494910Swollman	case LCP_CONF_REJ:
6504910Swollman		if (h->ident != sp->pp_seq)
6514910Swollman			return;
6524910Swollman		untimeout (sppp_cp_timeout, (caddr_t) sp);
6534910Swollman		/* Initiate renegotiation. */
6544910Swollman		sppp_lcp_open (sp);
6554910Swollman		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
6564910Swollman			/* Go to closed state. */
6574910Swollman			sp->lcp.state = LCP_STATE_CLOSED;
6584910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
6594910Swollman		}
6604910Swollman		break;
6614910Swollman	case LCP_TERM_REQ:
6624910Swollman		/* Send Terminate-Ack packet. */
6634910Swollman		sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0);
6644910Swollman		if (sp->lcp.state == LCP_STATE_OPENED)
6654910Swollman			/* Initiate renegotiation. */
6664910Swollman			sppp_lcp_open (sp);
6674910Swollman		/* Go to closed state. */
6684910Swollman		sp->lcp.state = LCP_STATE_CLOSED;
6694910Swollman		sp->ipcp.state = IPCP_STATE_CLOSED;
6704910Swollman		break;
6714910Swollman	case LCP_TERM_ACK:
6724910Swollman		if (h->ident != sp->pp_seq)
6734910Swollman			return;
6744910Swollman		if (sp->lcp.state == LCP_STATE_OPENED)
6754910Swollman			/* Initiate renegotiation. */
6764910Swollman			sppp_lcp_open (sp);
6774910Swollman		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
6784910Swollman			/* Go to closed state. */
6794910Swollman			sp->lcp.state = LCP_STATE_CLOSED;
6804910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
6814910Swollman		}
6824910Swollman		break;
6834910Swollman	case LCP_CODE_REJ:
6844910Swollman	case LCP_PROTO_REJ:
6854910Swollman		/* Ignore for now. */
6864910Swollman		break;
6874910Swollman	case LCP_DISC_REQ:
6884910Swollman		/* Discard the packet. */
6894910Swollman		break;
6904910Swollman	case LCP_ECHO_REQ:
6914910Swollman		if (len < 8) {
6924910Swollman			if (ifp->if_flags & IFF_DEBUG)
6934910Swollman				printf ("%s%d: invalid lcp echo request packet length: %d bytes\n",
6944910Swollman					ifp->if_name, ifp->if_unit, len);
6954910Swollman			return;
6964910Swollman		}
6974910Swollman		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
6984910Swollman			if (ifp->if_flags & IFF_DEBUG)
6994910Swollman				printf ("%s%d: echo reply: magic glitch\n",
7004910Swollman					ifp->if_name, ifp->if_unit);
7014910Swollman			++sp->pp_loopcnt;
7024910Swollman		}
7034910Swollman		*(long*)(h+1) = htonl (sp->lcp.magic);
7044910Swollman		sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
7054910Swollman		break;
7064910Swollman	case LCP_ECHO_REPLY:
7074910Swollman		if (h->ident != sp->lcp.lastid)
7084910Swollman			return;
7094910Swollman		if (len < 8) {
7104910Swollman			if (ifp->if_flags & IFF_DEBUG)
7114910Swollman				printf ("%s%d: invalid lcp echo reply packet length: %d bytes\n",
7124910Swollman					ifp->if_name, ifp->if_unit, len);
7134910Swollman			return;
7144910Swollman		}
7154910Swollman		if (ntohl (*(long*)(h+1)) == sp->lcp.magic)
7164910Swollman			return;
7174910Swollman		if (! (ifp->if_flags & IFF_UP) &&
7184910Swollman		    (ifp->if_flags & IFF_RUNNING)) {
7194910Swollman			ifp->if_flags |= IFF_UP;
7204910Swollman			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
7214910Swollman		}
7224910Swollman		sp->pp_alivecnt = 0;
7234910Swollman		break;
7244910Swollman	}
7254910Swollman}
7264910Swollman
7274910Swollman/*
7284910Swollman * Handle incoming Cisco keepalive protocol packets.
7294910Swollman */
7304910Swollmanvoid sppp_cisco_input (struct sppp *sp, struct mbuf *m)
7314910Swollman{
7324910Swollman	struct cisco_packet *h;
7334910Swollman	struct ifaddr *ifa;
7344910Swollman	struct ifnet *ifp = &sp->pp_if;
7354910Swollman
7364910Swollman	if (m->m_pkthdr.len != CISCO_PACKET_LEN) {
7374910Swollman		if (ifp->if_flags & IFF_DEBUG)
7384910Swollman			printf ("%s%d: invalid cisco packet length: %d bytes\n",
7394910Swollman				ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
7404910Swollman		return;
7414910Swollman	}
7424910Swollman	h = mtod (m, struct cisco_packet*);
7434910Swollman	if (ifp->if_flags & IFF_DEBUG)
7444910Swollman		printf ("%s%d: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n",
7454910Swollman			ifp->if_name, ifp->if_unit, m->m_pkthdr.len,
7464910Swollman			ntohl (h->type), h->par1, h->par2, h->rel,
7474910Swollman			h->time0, h->time1);
7484910Swollman	switch (ntohl (h->type)) {
7494910Swollman	default:
7504910Swollman		if (ifp->if_flags & IFF_DEBUG)
7514910Swollman			printf ("%s%d: unknown cisco packet type: 0x%x\n",
7524910Swollman				ifp->if_name, ifp->if_unit, ntohl (h->type));
7534910Swollman		break;
7544910Swollman	case CISCO_ADDR_REPLY:
7554910Swollman		/* Reply on address request, ignore */
7564910Swollman		break;
7574910Swollman	case CISCO_KEEPALIVE_REQ:
7584910Swollman		if (! (ifp->if_flags & IFF_UP) &&
7594910Swollman		    (ifp->if_flags & IFF_RUNNING)) {
7604910Swollman			ifp->if_flags |= IFF_UP;
7614910Swollman			printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
7624910Swollman		}
7634910Swollman		sp->pp_alivecnt = 0;
7644910Swollman		sp->pp_rseq = ntohl (h->par1);
7654910Swollman		if (sp->pp_seq == sp->pp_rseq) {
7664910Swollman			/* Local and remote sequence numbers are equal.
7674910Swollman			 * Probably, the line is in loopback mode. */
7684910Swollman			++sp->pp_loopcnt;
7694910Swollman
7704910Swollman			/* Generate new local sequence number */
7714910Swollman			sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
7724910Swollman		} else
7734910Swollman			sp->pp_loopcnt = 0;
7744910Swollman		break;
7754910Swollman	case CISCO_ADDR_REQ:
7764910Swollman		for (ifa=ifp->if_addrlist; ifa; ifa=ifa->ifa_next)
7774910Swollman			if (ifa->ifa_addr->sa_family == AF_INET)
7784910Swollman				break;
7794910Swollman		if (! ifa) {
7804910Swollman			if (ifp->if_flags & IFF_DEBUG)
7814910Swollman				printf ("%s%d: unknown address for cisco request\n",
7824910Swollman					ifp->if_name, ifp->if_unit);
7834910Swollman			return;
7844910Swollman		}
7854910Swollman		sppp_cisco_send (sp, CISCO_ADDR_REPLY,
7864910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr),
7874910Swollman			ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr));
7884910Swollman		break;
7894910Swollman	}
7904910Swollman}
7914910Swollman
7924910Swollman/*
7934910Swollman * Send PPP LCP packet.
7944910Swollman */
7954910Swollmanvoid sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type,
7964910Swollman	unsigned char ident, unsigned short len, void *data)
7974910Swollman{
7984910Swollman	struct ppp_header *h;
7994910Swollman	struct lcp_header *lh;
8004910Swollman	struct mbuf *m;
8014910Swollman	struct ifnet *ifp = &sp->pp_if;
8024910Swollman
8034910Swollman	if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
8044910Swollman		len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
8054910Swollman	MGETHDR (m, M_DONTWAIT, MT_DATA);
8064910Swollman	if (! m)
8074910Swollman		return;
8084910Swollman	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
8094910Swollman	m->m_pkthdr.rcvif = 0;
8104910Swollman
8114910Swollman	h = mtod (m, struct ppp_header*);
8124910Swollman	h->address = PPP_ALLSTATIONS;        /* broadcast address */
8134910Swollman	h->control = PPP_UI;                 /* Unnumbered Info */
8144910Swollman	h->protocol = htons (proto);         /* Link Control Protocol */
8154910Swollman
8164910Swollman	lh = (struct lcp_header*) (h + 1);
8174910Swollman	lh->type = type;
8184910Swollman	lh->ident = ident;
8194910Swollman	lh->len = htons (LCP_HEADER_LEN + len);
8204910Swollman	if (len)
8214910Swollman		bcopy (data, lh+1, len);
8224910Swollman
8234910Swollman	if (ifp->if_flags & IFF_DEBUG) {
8244910Swollman		printf ("%s%d: %s output <%s id=%xh len=%xh",
8254910Swollman			ifp->if_name, ifp->if_unit,
8264910Swollman			proto==PPP_LCP ? "lcp" : "ipcp",
8274910Swollman			proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
8284910Swollman			sppp_ipcp_type_name (lh->type), lh->ident,
8294910Swollman			ntohs (lh->len));
8304910Swollman		if (len)
8314910Swollman			sppp_print_bytes ((unsigned char*) (lh+1), len);
8324910Swollman		printf (">\n");
8334910Swollman	}
8344910Swollman	if (IF_QFULL (&sp->pp_fastq)) {
8354910Swollman		IF_DROP (&ifp->if_snd);
8364910Swollman		m_freem (m);
8374910Swollman	} else
8384910Swollman		IF_ENQUEUE (&sp->pp_fastq, m);
8394910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
8404910Swollman		(*ifp->if_start) (ifp);
8414910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
8424910Swollman}
8434910Swollman
8444910Swollman/*
8454910Swollman * Send Cisco keepalive packet.
8464910Swollman */
8474910Swollmanvoid sppp_cisco_send (struct sppp *sp, int type, long par1, long par2)
8484910Swollman{
8494910Swollman	struct ppp_header *h;
8504910Swollman	struct cisco_packet *ch;
8514910Swollman	struct mbuf *m;
8524910Swollman	struct ifnet *ifp = &sp->pp_if;
8534910Swollman	unsigned long t = (time.tv_sec - boottime.tv_sec) * 1000;
8544910Swollman
8554910Swollman	MGETHDR (m, M_DONTWAIT, MT_DATA);
8564910Swollman	if (! m)
8574910Swollman		return;
8584910Swollman	m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
8594910Swollman	m->m_pkthdr.rcvif = 0;
8604910Swollman
8614910Swollman	h = mtod (m, struct ppp_header*);
8624910Swollman	h->address = CISCO_MULTICAST;
8634910Swollman	h->control = 0;
8644910Swollman	h->protocol = htons (CISCO_KEEPALIVE);
8654910Swollman
8664910Swollman	ch = (struct cisco_packet*) (h + 1);
8674910Swollman	ch->type = htonl (type);
8684910Swollman	ch->par1 = htonl (par1);
8694910Swollman	ch->par2 = htonl (par2);
8704910Swollman	ch->rel = -1;
8714910Swollman	ch->time0 = htons ((unsigned short) (t >> 16));
8724910Swollman	ch->time1 = htons ((unsigned short) t);
8734910Swollman
8744910Swollman	if (ifp->if_flags & IFF_DEBUG)
8754910Swollman		printf ("%s%d: cisco output: <%xh %xh %xh %xh %xh-%xh>\n",
8764910Swollman			ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
8774910Swollman			ch->par2, ch->rel, ch->time0, ch->time1);
8784910Swollman
8794910Swollman	if (IF_QFULL (&sp->pp_fastq)) {
8804910Swollman		IF_DROP (&ifp->if_snd);
8814910Swollman		m_freem (m);
8824910Swollman	} else
8834910Swollman		IF_ENQUEUE (&sp->pp_fastq, m);
8844910Swollman	if (! (ifp->if_flags & IFF_OACTIVE))
8854910Swollman		(*ifp->if_start) (ifp);
8864910Swollman	ifp->if_obytes += m->m_pkthdr.len + 3;
8874910Swollman}
8884910Swollman
8894910Swollman/*
8904910Swollman * Process an ioctl request.  Called on low priority level.
8914910Swollman */
8924910Swollmanint sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data)
8934910Swollman{
8944910Swollman	struct ifreq *ifr = (struct ifreq*) data;
8954910Swollman	struct sppp *sp;
8964910Swollman	int s;
8974910Swollman
8984910Swollman	switch (cmd) {
8994910Swollman	default:
9004910Swollman		return (EINVAL);
9014910Swollman
9024910Swollman	case SIOCSIFADDR:
9034910Swollman	case SIOCAIFADDR:
9044910Swollman	case SIOCSIFDSTADDR:
9054910Swollman		break;
9064910Swollman
9074910Swollman	case SIOCSIFFLAGS:
9084910Swollman		s = splimp ();
9094910Swollman		if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) {
9104910Swollman			/* Interface is stopping. */
9114910Swollman			sp = (struct sppp*) ifp;
9124910Swollman			sp->lcp.state = LCP_STATE_CLOSED;
9134910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
9144910Swollman			sppp_cp_send (sp, PPP_LCP, LCP_TERM_REQ, ++sp->pp_seq,
9154910Swollman				0, 0);
9164910Swollman		} else if ((ifp->if_flags & IFF_UP) && ! (ifp->if_flags & IFF_RUNNING)) {
9174910Swollman			/* Interface is starting. */
9184910Swollman			sp = (struct sppp*) ifp;
9194910Swollman			sp->lcp.state = LCP_STATE_CLOSED;
9204910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
9214910Swollman			sppp_lcp_open (sp);
9224910Swollman		}
9234910Swollman		splx (s);
9244910Swollman		break;
9254910Swollman
9264910Swollman#ifdef SIOCSIFMTU
9274910Swollman#ifndef ifr_mtu
9284910Swollman#define ifr_mtu ifr_metric
9294910Swollman#endif
9304910Swollman	case SIOCSIFMTU:
9314910Swollman		if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > PP_MTU)
9324910Swollman			return (EINVAL);
9334910Swollman		ifp->if_mtu = ifr->ifr_mtu;
9344910Swollman		break;
9354910Swollman#endif
9364910Swollman#ifdef SLIOCSETMTU
9374910Swollman	case SLIOCSETMTU:
9384910Swollman		if (*(short*)data < 128 || *(short*)data > PP_MTU)
9394910Swollman			return (EINVAL);
9404910Swollman		ifp->if_mtu = *(short*)data;
9414910Swollman		break;
9424910Swollman#endif
9434910Swollman#ifdef SIOCGIFMTU
9444910Swollman	case SIOCGIFMTU:
9454910Swollman		ifr->ifr_mtu = ifp->if_mtu;
9464910Swollman		break;
9474910Swollman#endif
9484910Swollman#ifdef SLIOCGETMTU
9494910Swollman	case SLIOCGETMTU:
9504910Swollman		*(short*)data = ifp->if_mtu;
9514910Swollman		break;
9524910Swollman#endif
9534910Swollman#ifdef MULTICAST
9544910Swollman	case SIOCADDMULTI:
9554910Swollman	case SIOCDELMULTI:
9564910Swollman		break;
9574910Swollman#endif
9584910Swollman	}
9594910Swollman	return (0);
9604910Swollman}
9614910Swollman
9624910Swollmanint sppp_lcp_conf_unknown_options (int len, unsigned char *p)
9634910Swollman{
9644910Swollman	/* Analyze the LCP Configure-Request options list
9654910Swollman	 * for the presence of unknown options. */
9664910Swollman	while (len > 0) {
9674910Swollman		if (*p != LCP_OPT_MAGIC)
9684910Swollman			return (1);
9694910Swollman		len -= p[1];
9704910Swollman		p += p[1];
9714910Swollman	}
9724910Swollman	return (0);
9734910Swollman}
9744910Swollman
9754910Swollmanvoid sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h)
9764910Swollman{
9774910Swollman	/* The LCP Configure-Request contains unknown options.
9784910Swollman	 * Send Configure-reject packet, containing only unknown options. */
9794910Swollman	unsigned char buf [PP_MTU], *r = buf, *p = (void*) (h+1);
9804910Swollman	unsigned rlen = 0, len = h->len - 4;
9814910Swollman
9824910Swollman	while (len > 0) {
9834910Swollman		if (*p != LCP_OPT_MAGIC) {
9844910Swollman			bcopy (p, r, p[1]);
9854910Swollman			r += p[1];
9864910Swollman		}
9874910Swollman		len -= p[1];
9884910Swollman		p += p[1];
9894910Swollman	}
9904910Swollman	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);
9914910Swollman}
9924910Swollman
9934910Swollmanvoid sppp_ipcp_input (struct sppp *sp, struct mbuf *m)
9944910Swollman{
9954910Swollman	struct lcp_header *h;
9964910Swollman	struct ifnet *ifp = &sp->pp_if;
9974910Swollman	int len = m->m_pkthdr.len;
9984910Swollman
9994910Swollman	if (len < 4) {
10004910Swollman		/* if (ifp->if_flags & IFF_DEBUG) */
10014910Swollman			printf ("%s%d: invalid ipcp packet length: %d bytes\n",
10024910Swollman				ifp->if_name, ifp->if_unit, len);
10034910Swollman		return;
10044910Swollman	}
10054910Swollman	h = mtod (m, struct lcp_header*);
10064910Swollman	if (ifp->if_flags & IFF_DEBUG) {
10074910Swollman		printf ("%s%d: ipcp input: %d bytes <%s id=%xh len=%xh",
10084910Swollman			ifp->if_name, ifp->if_unit, len,
10094910Swollman			sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
10104910Swollman		if (len > 4)
10114910Swollman			sppp_print_bytes ((unsigned char*) (h+1), len-4);
10124910Swollman		printf (">\n");
10134910Swollman	}
10144910Swollman	if (len > ntohs (h->len))
10154910Swollman		len = ntohs (h->len);
10164910Swollman	switch (h->type) {
10174910Swollman	default:
10184910Swollman		/* Unknown packet type -- send Code-Reject packet. */
10194910Swollman		sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
10204910Swollman		break;
10214910Swollman	case IPCP_CONF_REQ:
10224910Swollman		if (len < 4) {
10234910Swollman			if (ifp->if_flags & IFF_DEBUG)
10244910Swollman				printf ("%s%d: invalid ipcp configure request packet length: %d bytes\n",
10254910Swollman					ifp->if_name, ifp->if_unit, len);
10264910Swollman			return;
10274910Swollman		}
10284910Swollman		if (len > 4) {
10294910Swollman			sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
10304910Swollman				len-4, h+1);
10314910Swollman			if (sp->lcp.state == LCP_STATE_OPENED &&
10324910Swollman			    sp->ipcp.state == IPCP_STATE_OPENED)
10334910Swollman				/* Initiate renegotiation. */
10344910Swollman				sppp_ipcp_open (sp);
10354910Swollman			if (sp->ipcp.state != IPCP_STATE_ACK_RCVD)
10364910Swollman				/* Go to closed state. */
10374910Swollman				sp->ipcp.state = IPCP_STATE_CLOSED;
10384910Swollman		} else {
10394910Swollman			/* Send Configure-Ack packet. */
10404910Swollman			sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
10414910Swollman				0, 0);
10424910Swollman			if (sp->lcp.state == LCP_STATE_OPENED &&
10434910Swollman			    sp->ipcp.state == IPCP_STATE_OPENED)
10444910Swollman				/* Initiate renegotiation. */
10454910Swollman				sppp_ipcp_open (sp);
10464910Swollman			/* Change the state. */
10474910Swollman			sp->ipcp.state = (sp->ipcp.state == IPCP_STATE_ACK_RCVD) ?
10484910Swollman				IPCP_STATE_OPENED : IPCP_STATE_ACK_SENT;
10494910Swollman		}
10504910Swollman		break;
10514910Swollman	case IPCP_CONF_ACK:
10524910Swollman		untimeout (sppp_cp_timeout, (caddr_t) sp);
10534910Swollman		switch (sp->ipcp.state) {
10544910Swollman		case IPCP_STATE_CLOSED:
10554910Swollman			sp->ipcp.state = IPCP_STATE_ACK_RCVD;
10564910Swollman			break;
10574910Swollman		case IPCP_STATE_ACK_SENT:
10584910Swollman			sp->ipcp.state = IPCP_STATE_OPENED;
10594910Swollman			break;
10604910Swollman		case IPCP_STATE_ACK_RCVD:
10614910Swollman		case IPCP_STATE_OPENED:
10624910Swollman			if (sp->lcp.state == LCP_STATE_OPENED)
10634910Swollman				/* Initiate renegotiation. */
10644910Swollman				sppp_ipcp_open (sp);
10654910Swollman			/* Go to closed state. */
10664910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
10674910Swollman			break;
10684910Swollman		}
10694910Swollman		break;
10704910Swollman	case IPCP_CONF_NAK:
10714910Swollman	case IPCP_CONF_REJ:
10724910Swollman		untimeout (sppp_cp_timeout, (caddr_t) sp);
10734910Swollman		/* Initiate renegotiation. */
10744910Swollman		sppp_ipcp_open (sp);
10754910Swollman		if (sp->lcp.state == LCP_STATE_OPENED)
10764910Swollman			/* Initiate renegotiation. */
10774910Swollman			sppp_ipcp_open (sp);
10784910Swollman		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
10794910Swollman			/* Go to closed state. */
10804910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
10814910Swollman		break;
10824910Swollman	case IPCP_TERM_REQ:
10834910Swollman		/* Send Terminate-Ack packet. */
10844910Swollman		sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0);
10854910Swollman		if (sp->lcp.state == LCP_STATE_OPENED &&
10864910Swollman		    sp->ipcp.state == IPCP_STATE_OPENED)
10874910Swollman			/* Initiate renegotiation. */
10884910Swollman			sppp_ipcp_open (sp);
10894910Swollman		/* Go to closed state. */
10904910Swollman		sp->ipcp.state = IPCP_STATE_CLOSED;
10914910Swollman		break;
10924910Swollman	case IPCP_TERM_ACK:
10934910Swollman		if (sp->lcp.state == LCP_STATE_OPENED &&
10944910Swollman		    sp->ipcp.state == IPCP_STATE_OPENED)
10954910Swollman			/* Initiate renegotiation. */
10964910Swollman			sppp_ipcp_open (sp);
10974910Swollman		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
10984910Swollman			/* Go to closed state. */
10994910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
11004910Swollman		break;
11014910Swollman	case IPCP_CODE_REJ:
11024910Swollman		/* Ignore for now. */
11034910Swollman		break;
11044910Swollman	}
11054910Swollman}
11064910Swollman
11074910Swollmanvoid sppp_lcp_open (struct sppp *sp)
11084910Swollman{
11094910Swollman	char opt[6];
11104910Swollman
11114910Swollman	/* Make new magic number. */
11124910Swollman	sp->lcp.magic = time.tv_sec + time.tv_usec;
11134910Swollman	opt[0] = LCP_OPT_MAGIC;
11144910Swollman	opt[1] = sizeof (opt);
11154910Swollman	opt[2] = sp->lcp.magic >> 24;
11164910Swollman	opt[3] = sp->lcp.magic >> 16;
11174910Swollman	opt[4] = sp->lcp.magic >> 8;
11184910Swollman	opt[5] = sp->lcp.magic;
11194910Swollman	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, ++sp->pp_seq,
11204910Swollman		sizeof (opt), &opt);
11214910Swollman	timeout (sppp_cp_timeout, (caddr_t) sp, hz * 5);
11224910Swollman}
11234910Swollman
11244910Swollmanvoid sppp_ipcp_open (struct sppp *sp)
11254910Swollman{
11264910Swollman	sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, ++sp->pp_seq, 0, 0);
11274910Swollman	timeout (sppp_cp_timeout, (caddr_t) sp, hz * 5);
11284910Swollman}
11294910Swollman
11304910Swollman/*
11314910Swollman * Process PPP control protocol timeouts.
11324910Swollman */
11334910Swollmanvoid sppp_cp_timeout (caddr_t arg, int dummy)
11344910Swollman{
11354910Swollman	struct sppp *sp = (struct sppp*) arg;
11364910Swollman	struct ifnet *ifp = &sp->pp_if;
11374910Swollman	int s = splimp ();
11384910Swollman
11394910Swollman	switch (sp->lcp.state) {
11404910Swollman	case LCP_STATE_CLOSED:
11414910Swollman		/* No ACK for Configure-Request, retry. */
11424910Swollman		sppp_lcp_open (sp);
11434910Swollman		break;
11444910Swollman	case LCP_STATE_ACK_RCVD:
11454910Swollman		/* ACK got, but no Configure-Request for peer, retry. */
11464910Swollman		sppp_lcp_open (sp);
11474910Swollman		sp->lcp.state = LCP_STATE_CLOSED;
11484910Swollman		break;
11494910Swollman	case LCP_STATE_ACK_SENT:
11504910Swollman		/* ACK sent but no ACK for Configure-Request, retry. */
11514910Swollman		sppp_lcp_open (sp);
11524910Swollman		break;
11534910Swollman	case LCP_STATE_OPENED:
11544910Swollman		/* LCP is already OK, try IPCP. */
11554910Swollman		switch (sp->ipcp.state) {
11564910Swollman		case IPCP_STATE_CLOSED:
11574910Swollman			/* No ACK for Configure-Request, retry. */
11584910Swollman			sppp_ipcp_open (sp);
11594910Swollman			break;
11604910Swollman		case IPCP_STATE_ACK_RCVD:
11614910Swollman			/* ACK got, but no Configure-Request for peer, retry. */
11624910Swollman			sppp_ipcp_open (sp);
11634910Swollman			sp->ipcp.state = IPCP_STATE_CLOSED;
11644910Swollman			break;
11654910Swollman		case IPCP_STATE_ACK_SENT:
11664910Swollman			/* ACK sent but no ACK for Configure-Request, retry. */
11674910Swollman			sppp_ipcp_open (sp);
11684910Swollman			break;
11694910Swollman		case IPCP_STATE_OPENED:
11704910Swollman			/* IPCP is OK. */
11714910Swollman			break;
11724910Swollman		}
11734910Swollman		break;
11744910Swollman	}
11754910Swollman	splx (s);
11764910Swollman}
11774910Swollman
11784910Swollmanchar *sppp_lcp_type_name (unsigned char type)
11794910Swollman{
11804910Swollman	static char buf [8];
11814910Swollman	switch (type) {
11824910Swollman	case LCP_CONF_REQ:   return ("conf-req");
11834910Swollman	case LCP_CONF_ACK:   return ("conf-ack");
11844910Swollman	case LCP_CONF_NAK:   return ("conf-nack");
11854910Swollman	case LCP_CONF_REJ:   return ("conf-rej");
11864910Swollman	case LCP_TERM_REQ:   return ("term-req");
11874910Swollman	case LCP_TERM_ACK:   return ("term-ack");
11884910Swollman	case LCP_CODE_REJ:   return ("code-rej");
11894910Swollman	case LCP_PROTO_REJ:  return ("proto-rej");
11904910Swollman	case LCP_ECHO_REQ:   return ("echo-req");
11914910Swollman	case LCP_ECHO_REPLY: return ("echo-reply");
11924910Swollman	case LCP_DISC_REQ:   return ("discard-req");
11934910Swollman	}
11944910Swollman	sprintf (buf, "%xh", type);
11954910Swollman	return (buf);
11964910Swollman}
11974910Swollman
11984910Swollmanchar *sppp_ipcp_type_name (unsigned char type)
11994910Swollman{
12004910Swollman	static char buf [8];
12014910Swollman	switch (type) {
12024910Swollman	case IPCP_CONF_REQ:   return ("conf-req");
12034910Swollman	case IPCP_CONF_ACK:   return ("conf-ack");
12044910Swollman	case IPCP_CONF_NAK:   return ("conf-nack");
12054910Swollman	case IPCP_CONF_REJ:   return ("conf-rej");
12064910Swollman	case IPCP_TERM_REQ:   return ("term-req");
12074910Swollman	case IPCP_TERM_ACK:   return ("term-ack");
12084910Swollman	case IPCP_CODE_REJ:   return ("code-rej");
12094910Swollman	}
12104910Swollman	sprintf (buf, "%xh", type);
12114910Swollman	return (buf);
12124910Swollman}
12134910Swollman
12144910Swollmanvoid sppp_print_bytes (unsigned char *p, unsigned short len)
12154910Swollman{
12164910Swollman	printf (" %x", *p++);
12174910Swollman	while (--len > 0)
12184910Swollman		printf ("-%x", *p++);
12194910Swollman}
1220