if_spppsubr.c revision 16288
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 * 1511189Sjkh * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 1616288Sgpalmer * 1716288Sgpalmer * $Id$ 184910Swollman */ 194910Swollman#undef DEBUG 204910Swollman 214910Swollman#include <sys/param.h> 224952Sbde#include <sys/systm.h> 234952Sbde#include <sys/kernel.h> 244910Swollman#include <sys/ioctl.h> 254910Swollman#include <sys/socket.h> 264910Swollman#include <sys/mbuf.h> 274910Swollman 284910Swollman#include <net/if.h> 294910Swollman#include <net/netisr.h> 304910Swollman#include <net/if_types.h> 314910Swollman 324910Swollman#ifdef INET 334910Swollman#include <netinet/in.h> 344910Swollman#include <netinet/in_systm.h> 354910Swollman#include <netinet/in_var.h> 364910Swollman#include <netinet/ip.h> 374910Swollman#include <netinet/tcp.h> 384910Swollman#include <netinet/if_ether.h> 394910Swollman#endif 404910Swollman 4111819Sjulian#ifdef IPX 4211819Sjulian#include <netipx/ipx.h> 4311819Sjulian#include <netipx/ipx_if.h> 4411819Sjulian#endif 4511819Sjulian 464910Swollman#ifdef NS 474910Swollman#include <netns/ns.h> 484910Swollman#include <netns/ns_if.h> 494910Swollman#endif 504910Swollman 514910Swollman#ifdef ISO 524910Swollman#include <netiso/argo_debug.h> 534910Swollman#include <netiso/iso.h> 544910Swollman#include <netiso/iso_var.h> 554910Swollman#include <netiso/iso_snpac.h> 564910Swollman#endif 574910Swollman 584910Swollman#include <net/if_sppp.h> 594910Swollman 604910Swollman#ifdef DEBUG 614910Swollman#define print(s) printf s 624910Swollman#else 6311189Sjkh#define print(s) {/*void*/} 644910Swollman#endif 654910Swollman 664910Swollman#define MAXALIVECNT 3 /* max. alive packets */ 674910Swollman 684910Swollman#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ 694910Swollman#define PPP_UI 0x03 /* Unnumbered Information */ 704910Swollman#define PPP_IP 0x0021 /* Internet Protocol */ 714910Swollman#define PPP_ISO 0x0023 /* ISO OSI Protocol */ 724910Swollman#define PPP_XNS 0x0025 /* Xerox NS Protocol */ 7312495Speter#define PPP_IPX 0x002b /* Novell IPX Protocol */ 744910Swollman#define PPP_LCP 0xc021 /* Link Control Protocol */ 754910Swollman#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ 764910Swollman 774910Swollman#define LCP_CONF_REQ 1 /* PPP LCP configure request */ 784910Swollman#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ 794910Swollman#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ 804910Swollman#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ 814910Swollman#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ 824910Swollman#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ 834910Swollman#define LCP_CODE_REJ 7 /* PPP LCP code reject */ 844910Swollman#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ 854910Swollman#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ 864910Swollman#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ 874910Swollman#define LCP_DISC_REQ 11 /* PPP LCP discard request */ 884910Swollman 894910Swollman#define LCP_OPT_MRU 1 /* maximum receive unit */ 904910Swollman#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ 914910Swollman#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ 924910Swollman#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ 934910Swollman#define LCP_OPT_MAGIC 5 /* magic number */ 944910Swollman#define LCP_OPT_RESERVED 6 /* reserved */ 954910Swollman#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ 964910Swollman#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ 974910Swollman 984910Swollman#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ 994910Swollman#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ 1004910Swollman#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ 1014910Swollman#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ 1024910Swollman#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ 1034910Swollman#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ 1044910Swollman#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ 1054910Swollman 1064910Swollman#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ 1074910Swollman#define CISCO_UNICAST 0x0f /* Cisco unicast address */ 1084910Swollman#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ 1094910Swollman#define CISCO_ADDR_REQ 0 /* Cisco address request */ 1104910Swollman#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ 1114910Swollman#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ 1124910Swollman 1134910Swollmanstruct ppp_header { 11411189Sjkh u_char address; 11511189Sjkh u_char control; 11611189Sjkh u_short protocol; 1174910Swollman}; 1184910Swollman#define PPP_HEADER_LEN sizeof (struct ppp_header) 1194910Swollman 1204910Swollmanstruct lcp_header { 12111189Sjkh u_char type; 12211189Sjkh u_char ident; 12311189Sjkh u_short len; 1244910Swollman}; 1254910Swollman#define LCP_HEADER_LEN sizeof (struct lcp_header) 1264910Swollman 1274910Swollmanstruct cisco_packet { 12811189Sjkh u_long type; 12911189Sjkh u_long par1; 13011189Sjkh u_long par2; 13111189Sjkh u_short rel; 13211189Sjkh u_short time0; 13311189Sjkh u_short time1; 1344910Swollman}; 1354910Swollman#define CISCO_PACKET_LEN 18 1364910Swollman 13712820Sphkstatic struct sppp *spppq; 1384910Swollman 1394910Swollman/* 1404910Swollman * The following disgusting hack gets around the problem that IP TOS 1414910Swollman * can't be set yet. We want to put "interactive" traffic on a high 1424910Swollman * priority queue. To decide if traffic is interactive, we check that 1434910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 1444910Swollman */ 14511189Sjkhstatic u_short interactive_ports[8] = { 1464910Swollman 0, 513, 0, 0, 1474910Swollman 0, 21, 0, 23, 1484910Swollman}; 1494910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 1504910Swollman 15111189Sjkh/* 15211189Sjkh * Timeout routine activation macros. 15311189Sjkh */ 15411189Sjkh#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \ 15511189Sjkh timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \ 15611189Sjkh (p)->pp_flags |= PP_TIMO; } 15711189Sjkh#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \ 15811189Sjkh untimeout (sppp_cp_timeout, (void*) (p)); \ 15911189Sjkh (p)->pp_flags &= ~PP_TIMO; } 16011189Sjkh 16112820Sphkstatic void sppp_keepalive (void *dummy); 16212820Sphkstatic void sppp_cp_send (struct sppp *sp, u_short proto, u_char type, 16311189Sjkh u_char ident, u_short len, void *data); 16412820Sphkstatic void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); 16512820Sphkstatic void sppp_lcp_input (struct sppp *sp, struct mbuf *m); 16612820Sphkstatic void sppp_cisco_input (struct sppp *sp, struct mbuf *m); 16712820Sphkstatic void sppp_ipcp_input (struct sppp *sp, struct mbuf *m); 16812820Sphkstatic void sppp_lcp_open (struct sppp *sp); 16912820Sphkstatic void sppp_ipcp_open (struct sppp *sp); 17012820Sphkstatic int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, 17111189Sjkh int len, u_long *magic); 17212820Sphkstatic void sppp_cp_timeout (void *arg); 17312820Sphkstatic char *sppp_lcp_type_name (u_char type); 17412820Sphkstatic char *sppp_ipcp_type_name (u_char type); 17512820Sphkstatic void sppp_print_bytes (u_char *p, u_short len); 17612820Sphkstatic int sppp_output (struct ifnet *ifp, struct mbuf *m, 17712820Sphk struct sockaddr *dst, struct rtentry *rt); 1784910Swollman 1794910Swollman/* 1804910Swollman * Flush interface queue. 1814910Swollman */ 1824910Swollmanstatic void qflush (struct ifqueue *ifq) 1834910Swollman{ 1844910Swollman struct mbuf *m, *n; 1854910Swollman 1864910Swollman n = ifq->ifq_head; 1874910Swollman while ((m = n)) { 1884910Swollman n = m->m_act; 1894910Swollman m_freem (m); 1904910Swollman } 1914910Swollman ifq->ifq_head = 0; 1924910Swollman ifq->ifq_tail = 0; 1934910Swollman ifq->ifq_len = 0; 1944910Swollman} 1954910Swollman 1964910Swollman/* 1974910Swollman * Process the received packet. 1984910Swollman */ 1994910Swollmanvoid sppp_input (struct ifnet *ifp, struct mbuf *m) 2004910Swollman{ 2014910Swollman struct ppp_header *h; 20211189Sjkh struct sppp *sp = (struct sppp*) ifp; 2034910Swollman struct ifqueue *inq = 0; 20411189Sjkh int s; 2054910Swollman 2064910Swollman if (ifp->if_flags & IFF_UP) 2074910Swollman /* Count received bytes, add FCS and one flag */ 2084910Swollman ifp->if_ibytes += m->m_pkthdr.len + 3; 2094910Swollman 2104910Swollman if (m->m_pkthdr.len <= PPP_HEADER_LEN) { 2114910Swollman /* Too small packet, drop it. */ 2124910Swollman if (ifp->if_flags & IFF_DEBUG) 2134910Swollman printf ("%s%d: input packet is too small, %d bytes\n", 2144910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 2154910Swollmandrop: ++ifp->if_iqdrops; 2164910Swollman m_freem (m); 2174910Swollman return; 2184910Swollman } 2194910Swollman 2204910Swollman /* Get PPP header. */ 2214910Swollman h = mtod (m, struct ppp_header*); 2224910Swollman m_adj (m, PPP_HEADER_LEN); 2234910Swollman 2244910Swollman switch (h->address) { 2254910Swollman default: /* Invalid PPP packet. */ 2264910Swollmaninvalid: if (ifp->if_flags & IFF_DEBUG) 2274910Swollman printf ("%s%d: invalid input packet <0x%x 0x%x 0x%x>\n", 2284910Swollman ifp->if_name, ifp->if_unit, 2294910Swollman h->address, h->control, ntohs (h->protocol)); 2304910Swollman goto drop; 2314910Swollman case PPP_ALLSTATIONS: 2324910Swollman if (h->control != PPP_UI) 2334910Swollman goto invalid; 23411189Sjkh if (sp->pp_flags & PP_CISCO) { 23511189Sjkh if (ifp->if_flags & IFF_DEBUG) 23611189Sjkh printf ("%s%d: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", 23711189Sjkh ifp->if_name, ifp->if_unit, 23811189Sjkh h->address, h->control, ntohs (h->protocol)); 23911189Sjkh goto drop; 24011189Sjkh } 2414910Swollman switch (ntohs (h->protocol)) { 2424910Swollman default: 2434910Swollman if (sp->lcp.state == LCP_STATE_OPENED) 2444910Swollman sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, 24511189Sjkh ++sp->pp_seq, m->m_pkthdr.len + 2, 2464910Swollman &h->protocol); 2474910Swollman if (ifp->if_flags & IFF_DEBUG) 2484910Swollman printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n", 2494910Swollman ifp->if_name, ifp->if_unit, 2504910Swollman h->address, h->control, ntohs (h->protocol)); 2514910Swollman ++ifp->if_noproto; 2524910Swollman goto drop; 2534910Swollman case PPP_LCP: 2544910Swollman sppp_lcp_input ((struct sppp*) ifp, m); 2554910Swollman m_freem (m); 2564910Swollman return; 2574910Swollman#ifdef INET 2584910Swollman case PPP_IPCP: 2594910Swollman if (sp->lcp.state == LCP_STATE_OPENED) 2604910Swollman sppp_ipcp_input ((struct sppp*) ifp, m); 2614910Swollman m_freem (m); 2624910Swollman return; 2634910Swollman case PPP_IP: 2644910Swollman if (sp->ipcp.state == IPCP_STATE_OPENED) { 2654910Swollman schednetisr (NETISR_IP); 2664910Swollman inq = &ipintrq; 2674910Swollman } 2684910Swollman break; 2694910Swollman#endif 27012495Speter#ifdef IPX 27112495Speter case PPP_IPX: 27212495Speter /* IPX IPXCP not implemented yet */ 27312495Speter if (sp->lcp.state == LCP_STATE_OPENED) { 27412495Speter schednetisr (NETISR_IPX); 27512495Speter inq = &ipxintrq; 27612495Speter } 27712495Speter break; 27812495Speter#endif 2794910Swollman#ifdef NS 2804910Swollman case PPP_XNS: 2814910Swollman /* XNS IDPCP not implemented yet */ 2824910Swollman if (sp->lcp.state == LCP_STATE_OPENED) { 2834910Swollman schednetisr (NETISR_NS); 2844910Swollman inq = &nsintrq; 2854910Swollman } 2864910Swollman break; 2874910Swollman#endif 2884910Swollman#ifdef ISO 2894910Swollman case PPP_ISO: 2904910Swollman /* OSI NLCP not implemented yet */ 2914910Swollman if (sp->lcp.state == LCP_STATE_OPENED) { 2924910Swollman schednetisr (NETISR_ISO); 2934910Swollman inq = &clnlintrq; 2944910Swollman } 2954910Swollman break; 2964910Swollman#endif 2974910Swollman } 2984910Swollman break; 2994910Swollman case CISCO_MULTICAST: 3004910Swollman case CISCO_UNICAST: 3014910Swollman /* Don't check the control field here (RFC 1547). */ 30211189Sjkh if (! (sp->pp_flags & PP_CISCO)) { 30311189Sjkh if (ifp->if_flags & IFF_DEBUG) 30411189Sjkh printf ("%s%d: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", 30511189Sjkh ifp->if_name, ifp->if_unit, 30611189Sjkh h->address, h->control, ntohs (h->protocol)); 30711189Sjkh goto drop; 30811189Sjkh } 3094910Swollman switch (ntohs (h->protocol)) { 3104910Swollman default: 3114910Swollman ++ifp->if_noproto; 3124910Swollman goto invalid; 3134910Swollman case CISCO_KEEPALIVE: 3144910Swollman sppp_cisco_input ((struct sppp*) ifp, m); 3154910Swollman m_freem (m); 3164910Swollman return; 3174910Swollman#ifdef INET 3184910Swollman case ETHERTYPE_IP: 3194910Swollman schednetisr (NETISR_IP); 3204910Swollman inq = &ipintrq; 3214910Swollman break; 3224910Swollman#endif 32312495Speter#ifdef IPX 32412495Speter case ETHERTYPE_IPX: 32512495Speter schednetisr (NETISR_IPX); 32612495Speter inq = &ipxintrq; 32712495Speter break; 32812495Speter#endif 3294910Swollman#ifdef NS 3304910Swollman case ETHERTYPE_NS: 3314910Swollman schednetisr (NETISR_NS); 3324910Swollman inq = &nsintrq; 3334910Swollman break; 3344910Swollman#endif 3354910Swollman } 3364910Swollman break; 3374910Swollman } 3384910Swollman 3394910Swollman if (! (ifp->if_flags & IFF_UP) || ! inq) 3404910Swollman goto drop; 3414910Swollman 3424910Swollman /* Check queue. */ 34311189Sjkh s = splimp (); 3444910Swollman if (IF_QFULL (inq)) { 3454910Swollman /* Queue overflow. */ 34611189Sjkh IF_DROP (inq); 34711189Sjkh splx (s); 3484910Swollman if (ifp->if_flags & IFF_DEBUG) 3494910Swollman printf ("%s%d: protocol queue overflow\n", 3504910Swollman ifp->if_name, ifp->if_unit); 3514910Swollman goto drop; 3524910Swollman } 3534910Swollman IF_ENQUEUE (inq, m); 35411189Sjkh splx (s); 3554910Swollman} 3564910Swollman 3574910Swollman/* 3584910Swollman * Enqueue transmit packet. 3594910Swollman */ 36012820Sphkstatic int 36112820Sphksppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) 3624910Swollman{ 3634910Swollman struct sppp *sp = (struct sppp*) ifp; 3644910Swollman struct ppp_header *h; 3654910Swollman struct ifqueue *ifq; 3664910Swollman int s = splimp (); 3674910Swollman 3684910Swollman if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) { 3694910Swollman m_freem (m); 3704910Swollman splx (s); 3714910Swollman return (ENETDOWN); 3724910Swollman } 3734910Swollman 3744910Swollman ifq = &ifp->if_snd; 3754910Swollman#ifdef INET 3764910Swollman /* 3774910Swollman * Put low delay, telnet, rlogin and ftp control packets 3784910Swollman * in front of the queue. 3794910Swollman */ 38012436Speter if (dst->sa_family == AF_INET) { 38112436Speter struct ip *ip = mtod (m, struct ip*); 38212436Speter struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); 3834910Swollman 38412436Speter if (! IF_QFULL (&sp->pp_fastq) && 38512436Speter ((ip->ip_tos & IPTOS_LOWDELAY) || 38612436Speter ip->ip_p == IPPROTO_TCP && 38712436Speter m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) && 38812436Speter (INTERACTIVE (ntohs (tcp->th_sport)) || 38912436Speter INTERACTIVE (ntohs (tcp->th_dport))))) 39012436Speter ifq = &sp->pp_fastq; 3914910Swollman } 3924910Swollman#endif 3934910Swollman 3944910Swollman /* 3954910Swollman * Prepend general data packet PPP header. For now, IP only. 3964910Swollman */ 3974910Swollman M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); 3984910Swollman if (! m) { 3994910Swollman if (ifp->if_flags & IFF_DEBUG) 4004910Swollman printf ("%s%d: no memory for transmit header\n", 4014910Swollman ifp->if_name, ifp->if_unit); 4024910Swollman splx (s); 4034910Swollman return (ENOBUFS); 4044910Swollman } 4054910Swollman h = mtod (m, struct ppp_header*); 4064910Swollman if (sp->pp_flags & PP_CISCO) { 4074910Swollman h->address = CISCO_MULTICAST; /* broadcast address */ 4084910Swollman h->control = 0; 4094910Swollman } else { 4104910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 4114910Swollman h->control = PPP_UI; /* Unnumbered Info */ 4124910Swollman } 4134910Swollman 4144910Swollman switch (dst->sa_family) { 4154910Swollman#ifdef INET 4164910Swollman case AF_INET: /* Internet Protocol */ 41711189Sjkh if (sp->pp_flags & PP_CISCO) 41811189Sjkh h->protocol = htons (ETHERTYPE_IP); 41911189Sjkh else if (sp->ipcp.state == IPCP_STATE_OPENED) 42011189Sjkh h->protocol = htons (PPP_IP); 42111189Sjkh else { 42211189Sjkh m_freem (m); 42311189Sjkh splx (s); 42411189Sjkh return (ENETDOWN); 42511189Sjkh } 4264910Swollman break; 4274910Swollman#endif 4284910Swollman#ifdef NS 4294910Swollman case AF_NS: /* Xerox NS Protocol */ 4304910Swollman h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 4314910Swollman ETHERTYPE_NS : PPP_XNS); 4324910Swollman break; 4334910Swollman#endif 43411819Sjulian#ifdef IPX 43512495Speter case AF_IPX: /* Novell IPX Protocol */ 43611819Sjulian h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 43712495Speter ETHERTYPE_IPX : PPP_IPX); 43811819Sjulian break; 43911819Sjulian#endif 4404910Swollman#ifdef ISO 4414910Swollman case AF_ISO: /* ISO OSI Protocol */ 4424910Swollman if (sp->pp_flags & PP_CISCO) 4434910Swollman goto nosupport; 4444910Swollman h->protocol = htons (PPP_ISO); 4454910Swollman break; 44612820Sphknosupport: 4474910Swollman#endif 4484910Swollman default: 4494910Swollman m_freem (m); 4504910Swollman splx (s); 4514910Swollman return (EAFNOSUPPORT); 4524910Swollman } 4534910Swollman 4544910Swollman /* 4554910Swollman * Queue message on interface, and start output if interface 4564910Swollman * not yet active. 4574910Swollman */ 4584910Swollman if (IF_QFULL (ifq)) { 4594910Swollman IF_DROP (&ifp->if_snd); 4604910Swollman m_freem (m); 4614910Swollman splx (s); 4624910Swollman return (ENOBUFS); 4634910Swollman } 4644910Swollman IF_ENQUEUE (ifq, m); 4654910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 4664910Swollman (*ifp->if_start) (ifp); 4674910Swollman 4684910Swollman /* 4694910Swollman * Count output packets and bytes. 4704910Swollman * The packet length includes header, FCS and 1 flag, 4714910Swollman * according to RFC 1333. 4724910Swollman */ 4734910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 4744910Swollman splx (s); 4754910Swollman return (0); 4764910Swollman} 4774910Swollman 4784910Swollmanvoid sppp_attach (struct ifnet *ifp) 4794910Swollman{ 4804910Swollman struct sppp *sp = (struct sppp*) ifp; 4814910Swollman 4824910Swollman /* Initialize keepalive handler. */ 4834910Swollman if (! spppq) 48411189Sjkh timeout (sppp_keepalive, 0, hz * 10); 4854910Swollman 4864910Swollman /* Insert new entry into the keepalive list. */ 4874910Swollman sp->pp_next = spppq; 4884910Swollman spppq = sp; 4894910Swollman 4904910Swollman sp->pp_if.if_type = IFT_PPP; 4914910Swollman sp->pp_if.if_output = sppp_output; 4924910Swollman sp->pp_fastq.ifq_maxlen = 32; 4934910Swollman sp->pp_loopcnt = 0; 4944910Swollman sp->pp_alivecnt = 0; 49511189Sjkh sp->pp_seq = 0; 4964910Swollman sp->pp_rseq = 0; 49711189Sjkh sp->lcp.magic = 0; 49811189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 49911189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 5004910Swollman} 5014910Swollman 50212820Sphkvoid 50312820Sphksppp_detach (struct ifnet *ifp) 5044910Swollman{ 5054910Swollman struct sppp **q, *p, *sp = (struct sppp*) ifp; 5064910Swollman 5074910Swollman /* Remove the entry from the keepalive list. */ 5084910Swollman for (q = &spppq; (p = *q); q = &p->pp_next) 5094910Swollman if (p == sp) { 5104910Swollman *q = p->pp_next; 5114910Swollman break; 5124910Swollman } 5134910Swollman 5144910Swollman /* Stop keepalive handler. */ 5154910Swollman if (! spppq) 51611189Sjkh untimeout (sppp_keepalive, 0); 51711189Sjkh UNTIMO (sp); 5184910Swollman} 5194910Swollman 5204910Swollman/* 5214910Swollman * Flush the interface output queue. 5224910Swollman */ 5234910Swollmanvoid sppp_flush (struct ifnet *ifp) 5244910Swollman{ 5254910Swollman struct sppp *sp = (struct sppp*) ifp; 5264910Swollman 5274910Swollman qflush (&sp->pp_if.if_snd); 5284910Swollman qflush (&sp->pp_fastq); 5294910Swollman} 5304910Swollman 5314910Swollman/* 53211189Sjkh * Check if the output queue is empty. 53311189Sjkh */ 53412820Sphkint 53512820Sphksppp_isempty (struct ifnet *ifp) 53611189Sjkh{ 53711189Sjkh struct sppp *sp = (struct sppp*) ifp; 53811189Sjkh int empty, s = splimp (); 53911189Sjkh 54011189Sjkh empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head; 54111189Sjkh splx (s); 54211189Sjkh return (empty); 54311189Sjkh} 54411189Sjkh 54511189Sjkh/* 5464910Swollman * Get next packet to send. 5474910Swollman */ 5484910Swollmanstruct mbuf *sppp_dequeue (struct ifnet *ifp) 5494910Swollman{ 5504910Swollman struct sppp *sp = (struct sppp*) ifp; 5514910Swollman struct mbuf *m; 5524910Swollman int s = splimp (); 5534910Swollman 5544910Swollman IF_DEQUEUE (&sp->pp_fastq, m); 5554910Swollman if (! m) 5564910Swollman IF_DEQUEUE (&sp->pp_if.if_snd, m); 5574910Swollman splx (s); 5584910Swollman return (m); 5594910Swollman} 5604910Swollman 5614910Swollman/* 5624910Swollman * Send keepalive packets, every 10 seconds. 5634910Swollman */ 56411189Sjkhvoid sppp_keepalive (void *dummy) 5654910Swollman{ 5664910Swollman struct sppp *sp; 5674910Swollman int s = splimp (); 5684910Swollman 5694910Swollman for (sp=spppq; sp; sp=sp->pp_next) { 5704910Swollman struct ifnet *ifp = &sp->pp_if; 5714910Swollman 57211189Sjkh /* Keepalive mode disabled or channel down? */ 5734910Swollman if (! (sp->pp_flags & PP_KEEPALIVE) || 57411189Sjkh ! (ifp->if_flags & IFF_RUNNING)) 57511189Sjkh continue; 57611189Sjkh 57711189Sjkh /* No keepalive in PPP mode if LCP not opened yet. */ 57811189Sjkh if (! (sp->pp_flags & PP_CISCO) && 5794910Swollman sp->lcp.state != LCP_STATE_OPENED) 5804910Swollman continue; 5814910Swollman 5824910Swollman if (sp->pp_alivecnt == MAXALIVECNT) { 5834910Swollman /* No keepalive packets got. Stop the interface. */ 5844910Swollman printf ("%s%d: down\n", ifp->if_name, ifp->if_unit); 5854910Swollman if_down (ifp); 5864910Swollman qflush (&sp->pp_fastq); 58711189Sjkh if (! (sp->pp_flags & PP_CISCO)) { 58811189Sjkh /* Shut down the PPP link. */ 58911189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 59011189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 59111189Sjkh UNTIMO (sp); 59211189Sjkh /* Initiate negotiation. */ 59311189Sjkh sppp_lcp_open (sp); 59411189Sjkh } 5954910Swollman } 5964910Swollman if (sp->pp_alivecnt <= MAXALIVECNT) 5974910Swollman ++sp->pp_alivecnt; 5984910Swollman if (sp->pp_flags & PP_CISCO) 5994910Swollman sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, 6004910Swollman sp->pp_rseq); 6014910Swollman else if (sp->lcp.state == LCP_STATE_OPENED) { 6024910Swollman long nmagic = htonl (sp->lcp.magic); 60311189Sjkh sp->lcp.echoid = ++sp->pp_seq; 6044910Swollman sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, 60511189Sjkh sp->lcp.echoid, 4, &nmagic); 6064910Swollman } 6074910Swollman } 6084910Swollman splx (s); 60911189Sjkh timeout (sppp_keepalive, 0, hz * 10); 6104910Swollman} 6114910Swollman 6124910Swollman/* 6134910Swollman * Handle incoming PPP Link Control Protocol packets. 6144910Swollman */ 6154910Swollmanvoid sppp_lcp_input (struct sppp *sp, struct mbuf *m) 6164910Swollman{ 6174910Swollman struct lcp_header *h; 6184910Swollman struct ifnet *ifp = &sp->pp_if; 6194910Swollman int len = m->m_pkthdr.len; 62011189Sjkh u_char *p, opt[6]; 62111189Sjkh u_long rmagic; 6224910Swollman 6234910Swollman if (len < 4) { 6244910Swollman if (ifp->if_flags & IFF_DEBUG) 6254910Swollman printf ("%s%d: invalid lcp packet length: %d bytes\n", 6264910Swollman ifp->if_name, ifp->if_unit, len); 6274910Swollman return; 6284910Swollman } 6294910Swollman h = mtod (m, struct lcp_header*); 6304910Swollman if (ifp->if_flags & IFF_DEBUG) { 63111189Sjkh char state = '?'; 63211189Sjkh switch (sp->lcp.state) { 63311189Sjkh case LCP_STATE_CLOSED: state = 'C'; break; 63411189Sjkh case LCP_STATE_ACK_RCVD: state = 'R'; break; 63511189Sjkh case LCP_STATE_ACK_SENT: state = 'S'; break; 63611189Sjkh case LCP_STATE_OPENED: state = 'O'; break; 63711189Sjkh } 63811189Sjkh printf ("%s%d: lcp input(%c): %d bytes <%s id=%xh len=%xh", 63911189Sjkh ifp->if_name, ifp->if_unit, state, len, 6404910Swollman sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); 6414910Swollman if (len > 4) 64211189Sjkh sppp_print_bytes ((u_char*) (h+1), len-4); 6434910Swollman printf (">\n"); 6444910Swollman } 6454910Swollman if (len > ntohs (h->len)) 6464910Swollman len = ntohs (h->len); 6474910Swollman switch (h->type) { 6484910Swollman default: 6494910Swollman /* Unknown packet type -- send Code-Reject packet. */ 65011189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, 65111189Sjkh m->m_pkthdr.len, h); 6524910Swollman break; 6534910Swollman case LCP_CONF_REQ: 6544910Swollman if (len < 4) { 6554910Swollman if (ifp->if_flags & IFF_DEBUG) 6564910Swollman printf ("%s%d: invalid lcp configure request packet length: %d bytes\n", 6574910Swollman ifp->if_name, ifp->if_unit, len); 65811189Sjkh break; 6594910Swollman } 66011189Sjkh if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) 66111189Sjkh goto badreq; 66211189Sjkh if (rmagic == sp->lcp.magic) { 66311189Sjkh /* Local and remote magics equal -- loopback? */ 66411189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT*5) { 66511189Sjkh printf ("%s%d: loopback\n", 66611189Sjkh ifp->if_name, ifp->if_unit); 66711189Sjkh sp->pp_loopcnt = 0; 66811189Sjkh if (ifp->if_flags & IFF_UP) { 66911189Sjkh if_down (ifp); 67011189Sjkh qflush (&sp->pp_fastq); 67111189Sjkh } 67211189Sjkh } else if (ifp->if_flags & IFF_DEBUG) 67311189Sjkh printf ("%s%d: conf req: magic glitch\n", 67411189Sjkh ifp->if_name, ifp->if_unit); 67511189Sjkh ++sp->pp_loopcnt; 67611189Sjkh 67711189Sjkh /* MUST send Conf-Nack packet. */ 67811189Sjkh rmagic = ~sp->lcp.magic; 67911189Sjkh opt[0] = LCP_OPT_MAGIC; 68011189Sjkh opt[1] = sizeof (opt); 68111189Sjkh opt[2] = rmagic >> 24; 68211189Sjkh opt[3] = rmagic >> 16; 68311189Sjkh opt[4] = rmagic >> 8; 68411189Sjkh opt[5] = rmagic; 68511189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, 68611189Sjkh h->ident, sizeof (opt), &opt); 68711189Sjkhbadreq: 68811189Sjkh switch (sp->lcp.state) { 68911189Sjkh case LCP_STATE_OPENED: 6904910Swollman /* Initiate renegotiation. */ 6914910Swollman sppp_lcp_open (sp); 69211189Sjkh /* fall through... */ 69311189Sjkh case LCP_STATE_ACK_SENT: 6944910Swollman /* Go to closed state. */ 6954910Swollman sp->lcp.state = LCP_STATE_CLOSED; 6964910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 6974910Swollman } 69811189Sjkh break; 69912436Speter } 70012436Speter /* Send Configure-Ack packet. */ 70112436Speter sp->pp_loopcnt = 0; 70212436Speter sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, 70312436Speter h->ident, len-4, h+1); 70412436Speter /* Change the state. */ 70511189Sjkh switch (sp->lcp.state) { 70611189Sjkh case LCP_STATE_CLOSED: 70711189Sjkh sp->lcp.state = LCP_STATE_ACK_SENT; 70811189Sjkh break; 70911189Sjkh case LCP_STATE_ACK_RCVD: 71012436Speter sp->lcp.state = LCP_STATE_OPENED; 71112436Speter sppp_ipcp_open (sp); 71211189Sjkh break; 71311189Sjkh case LCP_STATE_OPENED: 71411189Sjkh /* Remote magic changed -- close session. */ 71511189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 71611189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 71711189Sjkh /* Initiate renegotiation. */ 71811189Sjkh sppp_lcp_open (sp); 71912436Speter /* An ACK has already been sent. */ 72012436Speter sp->lcp.state = LCP_STATE_ACK_SENT; 72111189Sjkh break; 7224910Swollman } 7234910Swollman break; 7244910Swollman case LCP_CONF_ACK: 72511189Sjkh if (h->ident != sp->lcp.confid) 72611189Sjkh break; 72711189Sjkh UNTIMO (sp); 72811189Sjkh if (! (ifp->if_flags & IFF_UP) && 72911189Sjkh (ifp->if_flags & IFF_RUNNING)) { 73011189Sjkh /* Coming out of loopback mode. */ 73111189Sjkh ifp->if_flags |= IFF_UP; 73211189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 73311189Sjkh } 7344910Swollman switch (sp->lcp.state) { 7354910Swollman case LCP_STATE_CLOSED: 7364910Swollman sp->lcp.state = LCP_STATE_ACK_RCVD; 73711189Sjkh TIMO (sp, 5); 7384910Swollman break; 7394910Swollman case LCP_STATE_ACK_SENT: 7404910Swollman sp->lcp.state = LCP_STATE_OPENED; 7414910Swollman sppp_ipcp_open (sp); 7424910Swollman break; 7434910Swollman } 7444910Swollman break; 7454910Swollman case LCP_CONF_NAK: 74611189Sjkh if (h->ident != sp->lcp.confid) 74711189Sjkh break; 74811189Sjkh p = (u_char*) (h+1); 7494910Swollman if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { 75011189Sjkh rmagic = (u_long)p[2] << 24 | 75111189Sjkh (u_long)p[3] << 16 | p[4] << 8 | p[5]; 75211189Sjkh if (rmagic == ~sp->lcp.magic) { 7534910Swollman if (ifp->if_flags & IFF_DEBUG) 7544910Swollman printf ("%s%d: conf nak: magic glitch\n", 7554910Swollman ifp->if_name, ifp->if_unit); 75611189Sjkh sp->lcp.magic += time.tv_sec + time.tv_usec; 75711189Sjkh } else 75811189Sjkh sp->lcp.magic = rmagic; 7594910Swollman } 76011189Sjkh if (sp->lcp.state != LCP_STATE_ACK_SENT) { 76111189Sjkh /* Go to closed state. */ 76211189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 76311189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 7644910Swollman } 76511189Sjkh /* The link will be renegotiated after timeout, 76611189Sjkh * to avoid endless req-nack loop. */ 76711189Sjkh UNTIMO (sp); 76811189Sjkh TIMO (sp, 2); 76911189Sjkh break; 7704910Swollman case LCP_CONF_REJ: 77111189Sjkh if (h->ident != sp->lcp.confid) 77211189Sjkh break; 77311189Sjkh UNTIMO (sp); 7744910Swollman /* Initiate renegotiation. */ 7754910Swollman sppp_lcp_open (sp); 7764910Swollman if (sp->lcp.state != LCP_STATE_ACK_SENT) { 7774910Swollman /* Go to closed state. */ 7784910Swollman sp->lcp.state = LCP_STATE_CLOSED; 7794910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 7804910Swollman } 7814910Swollman break; 7824910Swollman case LCP_TERM_REQ: 78311189Sjkh UNTIMO (sp); 7844910Swollman /* Send Terminate-Ack packet. */ 7854910Swollman sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); 7864910Swollman /* Go to closed state. */ 7874910Swollman sp->lcp.state = LCP_STATE_CLOSED; 7884910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 78912436Speter /* Initiate renegotiation. */ 79012436Speter sppp_lcp_open (sp); 7914910Swollman break; 79211189Sjkh case LCP_TERM_ACK: 7934910Swollman case LCP_CODE_REJ: 7944910Swollman case LCP_PROTO_REJ: 7954910Swollman /* Ignore for now. */ 7964910Swollman break; 7974910Swollman case LCP_DISC_REQ: 7984910Swollman /* Discard the packet. */ 7994910Swollman break; 8004910Swollman case LCP_ECHO_REQ: 80112436Speter if (sp->lcp.state != LCP_STATE_OPENED) 80212436Speter break; 8034910Swollman if (len < 8) { 8044910Swollman if (ifp->if_flags & IFF_DEBUG) 8054910Swollman printf ("%s%d: invalid lcp echo request packet length: %d bytes\n", 8064910Swollman ifp->if_name, ifp->if_unit, len); 80711189Sjkh break; 8084910Swollman } 8094910Swollman if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { 81011189Sjkh /* Line loopback mode detected. */ 81111189Sjkh printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); 81211189Sjkh if_down (ifp); 81311189Sjkh qflush (&sp->pp_fastq); 81411189Sjkh 81511189Sjkh /* Shut down the PPP link. */ 81611189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 81711189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 81811189Sjkh UNTIMO (sp); 81911189Sjkh /* Initiate negotiation. */ 82011189Sjkh sppp_lcp_open (sp); 82111189Sjkh break; 8224910Swollman } 8234910Swollman *(long*)(h+1) = htonl (sp->lcp.magic); 8244910Swollman sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); 8254910Swollman break; 8264910Swollman case LCP_ECHO_REPLY: 82711189Sjkh if (h->ident != sp->lcp.echoid) 82811189Sjkh break; 8294910Swollman if (len < 8) { 8304910Swollman if (ifp->if_flags & IFF_DEBUG) 8314910Swollman printf ("%s%d: invalid lcp echo reply packet length: %d bytes\n", 8324910Swollman ifp->if_name, ifp->if_unit, len); 83311189Sjkh break; 8344910Swollman } 83511189Sjkh if (ntohl (*(long*)(h+1)) != sp->lcp.magic) 8364910Swollman sp->pp_alivecnt = 0; 8374910Swollman break; 8384910Swollman } 8394910Swollman} 8404910Swollman 8414910Swollman/* 8424910Swollman * Handle incoming Cisco keepalive protocol packets. 8434910Swollman */ 84412820Sphkstatic void 84512820Sphksppp_cisco_input (struct sppp *sp, struct mbuf *m) 8464910Swollman{ 8474910Swollman struct cisco_packet *h; 8484910Swollman struct ifaddr *ifa; 8494910Swollman struct ifnet *ifp = &sp->pp_if; 8504910Swollman 8514910Swollman if (m->m_pkthdr.len != CISCO_PACKET_LEN) { 8524910Swollman if (ifp->if_flags & IFF_DEBUG) 8534910Swollman printf ("%s%d: invalid cisco packet length: %d bytes\n", 8544910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 8554910Swollman return; 8564910Swollman } 8574910Swollman h = mtod (m, struct cisco_packet*); 8584910Swollman if (ifp->if_flags & IFF_DEBUG) 85911189Sjkh printf ("%s%d: cisco input: %d bytes <%lxh %lxh %lxh %xh %xh-%xh>\n", 8604910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len, 8614910Swollman ntohl (h->type), h->par1, h->par2, h->rel, 8624910Swollman h->time0, h->time1); 8634910Swollman switch (ntohl (h->type)) { 8644910Swollman default: 8654910Swollman if (ifp->if_flags & IFF_DEBUG) 8668456Srgrimes printf ("%s%d: unknown cisco packet type: 0x%lx\n", 8674910Swollman ifp->if_name, ifp->if_unit, ntohl (h->type)); 8684910Swollman break; 8694910Swollman case CISCO_ADDR_REPLY: 8704910Swollman /* Reply on address request, ignore */ 8714910Swollman break; 8724910Swollman case CISCO_KEEPALIVE_REQ: 8734910Swollman sp->pp_alivecnt = 0; 8744910Swollman sp->pp_rseq = ntohl (h->par1); 8754910Swollman if (sp->pp_seq == sp->pp_rseq) { 8764910Swollman /* Local and remote sequence numbers are equal. 8774910Swollman * Probably, the line is in loopback mode. */ 87811189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT) { 87911189Sjkh printf ("%s%d: loopback\n", 88011189Sjkh ifp->if_name, ifp->if_unit); 88111189Sjkh sp->pp_loopcnt = 0; 88211189Sjkh if (ifp->if_flags & IFF_UP) { 88311189Sjkh if_down (ifp); 88411189Sjkh qflush (&sp->pp_fastq); 88511189Sjkh } 88611189Sjkh } 8874910Swollman ++sp->pp_loopcnt; 8884910Swollman 8894910Swollman /* Generate new local sequence number */ 8904910Swollman sp->pp_seq ^= time.tv_sec ^ time.tv_usec; 89111189Sjkh break; 89211189Sjkh } 8934910Swollman sp->pp_loopcnt = 0; 89411189Sjkh if (! (ifp->if_flags & IFF_UP) && 89511189Sjkh (ifp->if_flags & IFF_RUNNING)) { 89611189Sjkh ifp->if_flags |= IFF_UP; 89711189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 89811189Sjkh } 8994910Swollman break; 9004910Swollman case CISCO_ADDR_REQ: 9014910Swollman for (ifa=ifp->if_addrlist; ifa; ifa=ifa->ifa_next) 9024910Swollman if (ifa->ifa_addr->sa_family == AF_INET) 9034910Swollman break; 9044910Swollman if (! ifa) { 9054910Swollman if (ifp->if_flags & IFF_DEBUG) 9064910Swollman printf ("%s%d: unknown address for cisco request\n", 9074910Swollman ifp->if_name, ifp->if_unit); 9084910Swollman return; 9094910Swollman } 9104910Swollman sppp_cisco_send (sp, CISCO_ADDR_REPLY, 9114910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr), 9124910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr)); 9134910Swollman break; 9144910Swollman } 9154910Swollman} 9164910Swollman 9174910Swollman/* 9184910Swollman * Send PPP LCP packet. 9194910Swollman */ 92012820Sphkstatic void 92112820Sphksppp_cp_send (struct sppp *sp, u_short proto, u_char type, 92211189Sjkh u_char ident, u_short len, void *data) 9234910Swollman{ 9244910Swollman struct ppp_header *h; 9254910Swollman struct lcp_header *lh; 9264910Swollman struct mbuf *m; 9274910Swollman struct ifnet *ifp = &sp->pp_if; 9284910Swollman 9294910Swollman if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) 9304910Swollman len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; 9314910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9324910Swollman if (! m) 9334910Swollman return; 9344910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; 9354910Swollman m->m_pkthdr.rcvif = 0; 9364910Swollman 9374910Swollman h = mtod (m, struct ppp_header*); 9384910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 9394910Swollman h->control = PPP_UI; /* Unnumbered Info */ 9404910Swollman h->protocol = htons (proto); /* Link Control Protocol */ 9414910Swollman 9424910Swollman lh = (struct lcp_header*) (h + 1); 9434910Swollman lh->type = type; 9444910Swollman lh->ident = ident; 9454910Swollman lh->len = htons (LCP_HEADER_LEN + len); 9464910Swollman if (len) 9474910Swollman bcopy (data, lh+1, len); 9484910Swollman 9494910Swollman if (ifp->if_flags & IFF_DEBUG) { 9504910Swollman printf ("%s%d: %s output <%s id=%xh len=%xh", 9514910Swollman ifp->if_name, ifp->if_unit, 9524910Swollman proto==PPP_LCP ? "lcp" : "ipcp", 9534910Swollman proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : 9544910Swollman sppp_ipcp_type_name (lh->type), lh->ident, 9554910Swollman ntohs (lh->len)); 9564910Swollman if (len) 95711189Sjkh sppp_print_bytes ((u_char*) (lh+1), len); 9584910Swollman printf (">\n"); 9594910Swollman } 9604910Swollman if (IF_QFULL (&sp->pp_fastq)) { 9614910Swollman IF_DROP (&ifp->if_snd); 9624910Swollman m_freem (m); 9634910Swollman } else 9644910Swollman IF_ENQUEUE (&sp->pp_fastq, m); 9654910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 9664910Swollman (*ifp->if_start) (ifp); 9674910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 9684910Swollman} 9694910Swollman 9704910Swollman/* 9714910Swollman * Send Cisco keepalive packet. 9724910Swollman */ 97312820Sphkstatic void 97412820Sphksppp_cisco_send (struct sppp *sp, int type, long par1, long par2) 9754910Swollman{ 9764910Swollman struct ppp_header *h; 9774910Swollman struct cisco_packet *ch; 9784910Swollman struct mbuf *m; 9794910Swollman struct ifnet *ifp = &sp->pp_if; 98011189Sjkh u_long t = (time.tv_sec - boottime.tv_sec) * 1000; 9814910Swollman 9824910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9834910Swollman if (! m) 9844910Swollman return; 9854910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; 9864910Swollman m->m_pkthdr.rcvif = 0; 9874910Swollman 9884910Swollman h = mtod (m, struct ppp_header*); 9894910Swollman h->address = CISCO_MULTICAST; 9904910Swollman h->control = 0; 9914910Swollman h->protocol = htons (CISCO_KEEPALIVE); 9924910Swollman 9934910Swollman ch = (struct cisco_packet*) (h + 1); 9944910Swollman ch->type = htonl (type); 9954910Swollman ch->par1 = htonl (par1); 9964910Swollman ch->par2 = htonl (par2); 9974910Swollman ch->rel = -1; 99811189Sjkh ch->time0 = htons ((u_short) (t >> 16)); 99911189Sjkh ch->time1 = htons ((u_short) t); 10004910Swollman 10014910Swollman if (ifp->if_flags & IFF_DEBUG) 10028456Srgrimes printf ("%s%d: cisco output: <%lxh %lxh %lxh %xh %xh-%xh>\n", 10034910Swollman ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1, 10044910Swollman ch->par2, ch->rel, ch->time0, ch->time1); 10054910Swollman 10064910Swollman if (IF_QFULL (&sp->pp_fastq)) { 10074910Swollman IF_DROP (&ifp->if_snd); 10084910Swollman m_freem (m); 10094910Swollman } else 10104910Swollman IF_ENQUEUE (&sp->pp_fastq, m); 10114910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 10124910Swollman (*ifp->if_start) (ifp); 10134910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 10144910Swollman} 10154910Swollman 10164910Swollman/* 10174910Swollman * Process an ioctl request. Called on low priority level. 10184910Swollman */ 101912820Sphkint 102012820Sphksppp_ioctl (struct ifnet *ifp, int cmd, void *data) 10214910Swollman{ 10224910Swollman struct ifreq *ifr = (struct ifreq*) data; 102311189Sjkh struct sppp *sp = (struct sppp*) ifp; 102411189Sjkh int s, going_up, going_down; 10254910Swollman 10264910Swollman switch (cmd) { 10274910Swollman default: 10284910Swollman return (EINVAL); 10294910Swollman 10304910Swollman case SIOCAIFADDR: 10314910Swollman case SIOCSIFDSTADDR: 10324910Swollman break; 10334910Swollman 103411189Sjkh case SIOCSIFADDR: 103511189Sjkh ifp->if_flags |= IFF_UP; 103611189Sjkh /* fall through... */ 103711189Sjkh 10384910Swollman case SIOCSIFFLAGS: 10394910Swollman s = splimp (); 104011189Sjkh going_up = (ifp->if_flags & IFF_UP) && 104111189Sjkh ! (ifp->if_flags & IFF_RUNNING); 104211189Sjkh going_down = ! (ifp->if_flags & IFF_UP) && 104311189Sjkh (ifp->if_flags & IFF_RUNNING); 104411189Sjkh if (going_up || going_down) { 104511189Sjkh /* Shut down the PPP link. */ 104611189Sjkh ifp->if_flags &= ~IFF_RUNNING; 10474910Swollman sp->lcp.state = LCP_STATE_CLOSED; 10484910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 104911189Sjkh UNTIMO (sp); 105011189Sjkh } 105111189Sjkh if (going_up) { 105211189Sjkh /* Interface is starting -- initiate negotiation. */ 105311189Sjkh ifp->if_flags |= IFF_RUNNING; 105412436Speter if (!(sp->pp_flags & PP_CISCO)) 105512436Speter sppp_lcp_open (sp); 10564910Swollman } 10574910Swollman splx (s); 10584910Swollman break; 10594910Swollman 10604910Swollman#ifdef SIOCSIFMTU 10614910Swollman#ifndef ifr_mtu 10624910Swollman#define ifr_mtu ifr_metric 10634910Swollman#endif 10644910Swollman case SIOCSIFMTU: 10654910Swollman if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > PP_MTU) 10664910Swollman return (EINVAL); 10674910Swollman ifp->if_mtu = ifr->ifr_mtu; 10684910Swollman break; 10694910Swollman#endif 10704910Swollman#ifdef SLIOCSETMTU 10714910Swollman case SLIOCSETMTU: 10724910Swollman if (*(short*)data < 128 || *(short*)data > PP_MTU) 10734910Swollman return (EINVAL); 10744910Swollman ifp->if_mtu = *(short*)data; 10754910Swollman break; 10764910Swollman#endif 10774910Swollman#ifdef SIOCGIFMTU 10784910Swollman case SIOCGIFMTU: 10794910Swollman ifr->ifr_mtu = ifp->if_mtu; 10804910Swollman break; 10814910Swollman#endif 10824910Swollman#ifdef SLIOCGETMTU 10834910Swollman case SLIOCGETMTU: 10844910Swollman *(short*)data = ifp->if_mtu; 10854910Swollman break; 10864910Swollman#endif 10874910Swollman#ifdef MULTICAST 10884910Swollman case SIOCADDMULTI: 10894910Swollman case SIOCDELMULTI: 10904910Swollman break; 10914910Swollman#endif 10924910Swollman } 10934910Swollman return (0); 10944910Swollman} 10954910Swollman 109611189Sjkh/* 109711189Sjkh * Analyze the LCP Configure-Request options list 109811189Sjkh * for the presence of unknown options. 109911189Sjkh * If the request contains unknown options, build and 110011189Sjkh * send Configure-reject packet, containing only unknown options. 110111189Sjkh */ 110212820Sphkstatic int 110312820Sphksppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, 110411189Sjkh int len, u_long *magic) 11054910Swollman{ 110611189Sjkh u_char *buf, *r, *p; 110711189Sjkh int rlen; 11084910Swollman 110911189Sjkh len -= 4; 111011189Sjkh buf = r = malloc (len, M_TEMP, M_NOWAIT); 111111189Sjkh if (! buf) 111211189Sjkh return (0); 11134910Swollman 111411189Sjkh p = (void*) (h+1); 111511189Sjkh for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 111611189Sjkh switch (*p) { 111711189Sjkh case LCP_OPT_MAGIC: 111811189Sjkh /* Magic number -- extract. */ 111911189Sjkh if (len >= 6 && p[1] == 6) { 112011189Sjkh *magic = (u_long)p[2] << 24 | 112111189Sjkh (u_long)p[3] << 16 | p[4] << 8 | p[5]; 112211189Sjkh continue; 112311189Sjkh } 112411189Sjkh break; 112511189Sjkh case LCP_OPT_ASYNC_MAP: 112611189Sjkh /* Async control character map -- check to be zero. */ 112711189Sjkh if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && 112811189Sjkh ! p[4] && ! p[5]) 112911189Sjkh continue; 113011189Sjkh break; 113111189Sjkh case LCP_OPT_MRU: 113211189Sjkh /* Maximum receive unit -- always OK. */ 113311189Sjkh continue; 113411189Sjkh default: 113511189Sjkh /* Others not supported. */ 113611189Sjkh break; 113711189Sjkh } 113811189Sjkh /* Add the option to rejected list. */ 11394910Swollman bcopy (p, r, p[1]); 11404910Swollman r += p[1]; 114111189Sjkh rlen += p[1]; 114212436Speter } 114311189Sjkh if (rlen) 11444910Swollman sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); 114511189Sjkh free (buf, M_TEMP); 114611189Sjkh return (rlen == 0); 11474910Swollman} 11484910Swollman 114912820Sphkstatic void 115012820Sphksppp_ipcp_input (struct sppp *sp, struct mbuf *m) 11514910Swollman{ 11524910Swollman struct lcp_header *h; 11534910Swollman struct ifnet *ifp = &sp->pp_if; 11544910Swollman int len = m->m_pkthdr.len; 11554910Swollman 11564910Swollman if (len < 4) { 11574910Swollman /* if (ifp->if_flags & IFF_DEBUG) */ 11584910Swollman printf ("%s%d: invalid ipcp packet length: %d bytes\n", 11594910Swollman ifp->if_name, ifp->if_unit, len); 11604910Swollman return; 11614910Swollman } 11624910Swollman h = mtod (m, struct lcp_header*); 11634910Swollman if (ifp->if_flags & IFF_DEBUG) { 11644910Swollman printf ("%s%d: ipcp input: %d bytes <%s id=%xh len=%xh", 11654910Swollman ifp->if_name, ifp->if_unit, len, 11664910Swollman sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); 11674910Swollman if (len > 4) 116811189Sjkh sppp_print_bytes ((u_char*) (h+1), len-4); 11694910Swollman printf (">\n"); 11704910Swollman } 11714910Swollman if (len > ntohs (h->len)) 11724910Swollman len = ntohs (h->len); 11734910Swollman switch (h->type) { 11744910Swollman default: 11754910Swollman /* Unknown packet type -- send Code-Reject packet. */ 11764910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); 11774910Swollman break; 11784910Swollman case IPCP_CONF_REQ: 11794910Swollman if (len < 4) { 11804910Swollman if (ifp->if_flags & IFF_DEBUG) 11814910Swollman printf ("%s%d: invalid ipcp configure request packet length: %d bytes\n", 11824910Swollman ifp->if_name, ifp->if_unit, len); 11834910Swollman return; 11844910Swollman } 11854910Swollman if (len > 4) { 11864910Swollman sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, 11874910Swollman len-4, h+1); 118811189Sjkh 118911189Sjkh switch (sp->ipcp.state) { 119011189Sjkh case IPCP_STATE_OPENED: 11914910Swollman /* Initiate renegotiation. */ 11924910Swollman sppp_ipcp_open (sp); 119311189Sjkh /* fall through... */ 119411189Sjkh case IPCP_STATE_ACK_SENT: 11954910Swollman /* Go to closed state. */ 11964910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 119711189Sjkh } 11984910Swollman } else { 11994910Swollman /* Send Configure-Ack packet. */ 12004910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, 12014910Swollman 0, 0); 12024910Swollman /* Change the state. */ 120311189Sjkh if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) 120411189Sjkh sp->ipcp.state = IPCP_STATE_OPENED; 120511189Sjkh else 120611189Sjkh sp->ipcp.state = IPCP_STATE_ACK_SENT; 12074910Swollman } 12084910Swollman break; 12094910Swollman case IPCP_CONF_ACK: 121011189Sjkh if (h->ident != sp->ipcp.confid) 121111189Sjkh break; 121211189Sjkh UNTIMO (sp); 12134910Swollman switch (sp->ipcp.state) { 12144910Swollman case IPCP_STATE_CLOSED: 12154910Swollman sp->ipcp.state = IPCP_STATE_ACK_RCVD; 121611189Sjkh TIMO (sp, 5); 12174910Swollman break; 12184910Swollman case IPCP_STATE_ACK_SENT: 12194910Swollman sp->ipcp.state = IPCP_STATE_OPENED; 12204910Swollman break; 12214910Swollman } 12224910Swollman break; 12234910Swollman case IPCP_CONF_NAK: 12244910Swollman case IPCP_CONF_REJ: 122511189Sjkh if (h->ident != sp->ipcp.confid) 122611189Sjkh break; 122711189Sjkh UNTIMO (sp); 12284910Swollman /* Initiate renegotiation. */ 12294910Swollman sppp_ipcp_open (sp); 12304910Swollman if (sp->ipcp.state != IPCP_STATE_ACK_SENT) 12314910Swollman /* Go to closed state. */ 12324910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 12334910Swollman break; 12344910Swollman case IPCP_TERM_REQ: 12354910Swollman /* Send Terminate-Ack packet. */ 12364910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); 12374910Swollman /* Go to closed state. */ 12384910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 12394910Swollman /* Initiate renegotiation. */ 12404910Swollman sppp_ipcp_open (sp); 12414910Swollman break; 124211189Sjkh case IPCP_TERM_ACK: 124311189Sjkh /* Ignore for now. */ 12444910Swollman case IPCP_CODE_REJ: 12454910Swollman /* Ignore for now. */ 12464910Swollman break; 12474910Swollman } 12484910Swollman} 12494910Swollman 125012820Sphkstatic void 125112820Sphksppp_lcp_open (struct sppp *sp) 12524910Swollman{ 12534910Swollman char opt[6]; 12544910Swollman 125511189Sjkh if (! sp->lcp.magic) 12564910Swollman sp->lcp.magic = time.tv_sec + time.tv_usec; 12574910Swollman opt[0] = LCP_OPT_MAGIC; 12584910Swollman opt[1] = sizeof (opt); 12594910Swollman opt[2] = sp->lcp.magic >> 24; 12604910Swollman opt[3] = sp->lcp.magic >> 16; 12614910Swollman opt[4] = sp->lcp.magic >> 8; 12624910Swollman opt[5] = sp->lcp.magic; 126311189Sjkh sp->lcp.confid = ++sp->pp_seq; 126411189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, 12654910Swollman sizeof (opt), &opt); 126611189Sjkh TIMO (sp, 2); 12674910Swollman} 12684910Swollman 126912820Sphkstatic void 127012820Sphksppp_ipcp_open (struct sppp *sp) 12714910Swollman{ 127211189Sjkh sp->ipcp.confid = ++sp->pp_seq; 127311189Sjkh sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); 127411189Sjkh TIMO (sp, 2); 12754910Swollman} 12764910Swollman 12774910Swollman/* 12784910Swollman * Process PPP control protocol timeouts. 12794910Swollman */ 128012820Sphkstatic void 128112820Sphksppp_cp_timeout (void *arg) 12824910Swollman{ 12834910Swollman struct sppp *sp = (struct sppp*) arg; 12844910Swollman int s = splimp (); 12854910Swollman 128611189Sjkh sp->pp_flags &= ~PP_TIMO; 128711189Sjkh if (! (sp->pp_if.if_flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { 128811189Sjkh splx (s); 128911189Sjkh return; 129011189Sjkh } 12914910Swollman switch (sp->lcp.state) { 12924910Swollman case LCP_STATE_CLOSED: 12934910Swollman /* No ACK for Configure-Request, retry. */ 12944910Swollman sppp_lcp_open (sp); 12954910Swollman break; 12964910Swollman case LCP_STATE_ACK_RCVD: 12974910Swollman /* ACK got, but no Configure-Request for peer, retry. */ 12984910Swollman sppp_lcp_open (sp); 12994910Swollman sp->lcp.state = LCP_STATE_CLOSED; 13004910Swollman break; 13014910Swollman case LCP_STATE_ACK_SENT: 13024910Swollman /* ACK sent but no ACK for Configure-Request, retry. */ 13034910Swollman sppp_lcp_open (sp); 13044910Swollman break; 13054910Swollman case LCP_STATE_OPENED: 13064910Swollman /* LCP is already OK, try IPCP. */ 13074910Swollman switch (sp->ipcp.state) { 13084910Swollman case IPCP_STATE_CLOSED: 13094910Swollman /* No ACK for Configure-Request, retry. */ 13104910Swollman sppp_ipcp_open (sp); 13114910Swollman break; 13124910Swollman case IPCP_STATE_ACK_RCVD: 13134910Swollman /* ACK got, but no Configure-Request for peer, retry. */ 13144910Swollman sppp_ipcp_open (sp); 13154910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 13164910Swollman break; 13174910Swollman case IPCP_STATE_ACK_SENT: 13184910Swollman /* ACK sent but no ACK for Configure-Request, retry. */ 13194910Swollman sppp_ipcp_open (sp); 13204910Swollman break; 13214910Swollman case IPCP_STATE_OPENED: 13224910Swollman /* IPCP is OK. */ 13234910Swollman break; 13244910Swollman } 13254910Swollman break; 13264910Swollman } 13274910Swollman splx (s); 13284910Swollman} 13294910Swollman 133012820Sphkstatic char 133112820Sphk*sppp_lcp_type_name (u_char type) 13324910Swollman{ 13334910Swollman static char buf [8]; 13344910Swollman switch (type) { 13354910Swollman case LCP_CONF_REQ: return ("conf-req"); 13364910Swollman case LCP_CONF_ACK: return ("conf-ack"); 13374910Swollman case LCP_CONF_NAK: return ("conf-nack"); 13384910Swollman case LCP_CONF_REJ: return ("conf-rej"); 13394910Swollman case LCP_TERM_REQ: return ("term-req"); 13404910Swollman case LCP_TERM_ACK: return ("term-ack"); 13414910Swollman case LCP_CODE_REJ: return ("code-rej"); 13424910Swollman case LCP_PROTO_REJ: return ("proto-rej"); 13434910Swollman case LCP_ECHO_REQ: return ("echo-req"); 13444910Swollman case LCP_ECHO_REPLY: return ("echo-reply"); 13454910Swollman case LCP_DISC_REQ: return ("discard-req"); 13464910Swollman } 13474910Swollman sprintf (buf, "%xh", type); 13484910Swollman return (buf); 13494910Swollman} 13504910Swollman 135112820Sphkstatic char 135212820Sphk*sppp_ipcp_type_name (u_char type) 13534910Swollman{ 13544910Swollman static char buf [8]; 13554910Swollman switch (type) { 13564910Swollman case IPCP_CONF_REQ: return ("conf-req"); 13574910Swollman case IPCP_CONF_ACK: return ("conf-ack"); 13584910Swollman case IPCP_CONF_NAK: return ("conf-nack"); 13594910Swollman case IPCP_CONF_REJ: return ("conf-rej"); 13604910Swollman case IPCP_TERM_REQ: return ("term-req"); 13614910Swollman case IPCP_TERM_ACK: return ("term-ack"); 13624910Swollman case IPCP_CODE_REJ: return ("code-rej"); 13634910Swollman } 13644910Swollman sprintf (buf, "%xh", type); 13654910Swollman return (buf); 13664910Swollman} 13674910Swollman 136812820Sphkstatic void 136912820Sphksppp_print_bytes (u_char *p, u_short len) 13704910Swollman{ 13714910Swollman printf (" %x", *p++); 13724910Swollman while (--len > 0) 13734910Swollman printf ("-%x", *p++); 13744910Swollman} 1375