if_spppsubr.c revision 12495
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 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 3911819Sjulian#ifdef IPX 4011819Sjulian#include <netipx/ipx.h> 4111819Sjulian#include <netipx/ipx_if.h> 4211819Sjulian#endif 4311819Sjulian 444910Swollman#ifdef NS 454910Swollman#include <netns/ns.h> 464910Swollman#include <netns/ns_if.h> 474910Swollman#endif 484910Swollman 494910Swollman#ifdef ISO 504910Swollman#include <netiso/argo_debug.h> 514910Swollman#include <netiso/iso.h> 524910Swollman#include <netiso/iso_var.h> 534910Swollman#include <netiso/iso_snpac.h> 544910Swollman#endif 554910Swollman 564910Swollman#include <net/if_sppp.h> 574910Swollman 584910Swollman#ifdef DEBUG 594910Swollman#define print(s) printf s 604910Swollman#else 6111189Sjkh#define print(s) {/*void*/} 624910Swollman#endif 634910Swollman 644910Swollman#define MAXALIVECNT 3 /* max. alive packets */ 654910Swollman 664910Swollman#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ 674910Swollman#define PPP_UI 0x03 /* Unnumbered Information */ 684910Swollman#define PPP_IP 0x0021 /* Internet Protocol */ 694910Swollman#define PPP_ISO 0x0023 /* ISO OSI Protocol */ 704910Swollman#define PPP_XNS 0x0025 /* Xerox NS Protocol */ 7112495Speter#define PPP_IPX 0x002b /* Novell IPX Protocol */ 724910Swollman#define PPP_LCP 0xc021 /* Link Control Protocol */ 734910Swollman#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ 744910Swollman 754910Swollman#define LCP_CONF_REQ 1 /* PPP LCP configure request */ 764910Swollman#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ 774910Swollman#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ 784910Swollman#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ 794910Swollman#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ 804910Swollman#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ 814910Swollman#define LCP_CODE_REJ 7 /* PPP LCP code reject */ 824910Swollman#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ 834910Swollman#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ 844910Swollman#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ 854910Swollman#define LCP_DISC_REQ 11 /* PPP LCP discard request */ 864910Swollman 874910Swollman#define LCP_OPT_MRU 1 /* maximum receive unit */ 884910Swollman#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ 894910Swollman#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ 904910Swollman#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ 914910Swollman#define LCP_OPT_MAGIC 5 /* magic number */ 924910Swollman#define LCP_OPT_RESERVED 6 /* reserved */ 934910Swollman#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ 944910Swollman#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ 954910Swollman 964910Swollman#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ 974910Swollman#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ 984910Swollman#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ 994910Swollman#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ 1004910Swollman#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ 1014910Swollman#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ 1024910Swollman#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ 1034910Swollman 1044910Swollman#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ 1054910Swollman#define CISCO_UNICAST 0x0f /* Cisco unicast address */ 1064910Swollman#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ 1074910Swollman#define CISCO_ADDR_REQ 0 /* Cisco address request */ 1084910Swollman#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ 1094910Swollman#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ 1104910Swollman 1114910Swollmanstruct ppp_header { 11211189Sjkh u_char address; 11311189Sjkh u_char control; 11411189Sjkh u_short protocol; 1154910Swollman}; 1164910Swollman#define PPP_HEADER_LEN sizeof (struct ppp_header) 1174910Swollman 1184910Swollmanstruct lcp_header { 11911189Sjkh u_char type; 12011189Sjkh u_char ident; 12111189Sjkh u_short len; 1224910Swollman}; 1234910Swollman#define LCP_HEADER_LEN sizeof (struct lcp_header) 1244910Swollman 1254910Swollmanstruct cisco_packet { 12611189Sjkh u_long type; 12711189Sjkh u_long par1; 12811189Sjkh u_long par2; 12911189Sjkh u_short rel; 13011189Sjkh u_short time0; 13111189Sjkh u_short time1; 1324910Swollman}; 1334910Swollman#define CISCO_PACKET_LEN 18 1344910Swollman 1354910Swollmanstruct sppp *spppq; 1364910Swollman 1374910Swollman/* 1384910Swollman * The following disgusting hack gets around the problem that IP TOS 1394910Swollman * can't be set yet. We want to put "interactive" traffic on a high 1404910Swollman * priority queue. To decide if traffic is interactive, we check that 1414910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 1424910Swollman */ 14311189Sjkhstatic u_short interactive_ports[8] = { 1444910Swollman 0, 513, 0, 0, 1454910Swollman 0, 21, 0, 23, 1464910Swollman}; 1474910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 1484910Swollman 14911189Sjkh/* 15011189Sjkh * Timeout routine activation macros. 15111189Sjkh */ 15211189Sjkh#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \ 15311189Sjkh timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \ 15411189Sjkh (p)->pp_flags |= PP_TIMO; } 15511189Sjkh#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \ 15611189Sjkh untimeout (sppp_cp_timeout, (void*) (p)); \ 15711189Sjkh (p)->pp_flags &= ~PP_TIMO; } 15811189Sjkh 15911189Sjkhvoid sppp_keepalive (void *dummy); 16011189Sjkhvoid sppp_cp_send (struct sppp *sp, u_short proto, u_char type, 16111189Sjkh u_char ident, u_short len, void *data); 1624910Swollmanvoid sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); 1634910Swollmanvoid sppp_lcp_input (struct sppp *sp, struct mbuf *m); 1644910Swollmanvoid sppp_cisco_input (struct sppp *sp, struct mbuf *m); 1654910Swollmanvoid sppp_ipcp_input (struct sppp *sp, struct mbuf *m); 1664910Swollmanvoid sppp_lcp_open (struct sppp *sp); 1674910Swollmanvoid sppp_ipcp_open (struct sppp *sp); 16811189Sjkhint sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, 16911189Sjkh int len, u_long *magic); 1706429Sjkhvoid sppp_cp_timeout (void *arg); 17111189Sjkhchar *sppp_lcp_type_name (u_char type); 17211189Sjkhchar *sppp_ipcp_type_name (u_char type); 17311189Sjkhvoid sppp_print_bytes (u_char *p, u_short len); 1744910Swollman 1754910Swollman/* 1764910Swollman * Flush interface queue. 1774910Swollman */ 1784910Swollmanstatic void qflush (struct ifqueue *ifq) 1794910Swollman{ 1804910Swollman struct mbuf *m, *n; 1814910Swollman 1824910Swollman n = ifq->ifq_head; 1834910Swollman while ((m = n)) { 1844910Swollman n = m->m_act; 1854910Swollman m_freem (m); 1864910Swollman } 1874910Swollman ifq->ifq_head = 0; 1884910Swollman ifq->ifq_tail = 0; 1894910Swollman ifq->ifq_len = 0; 1904910Swollman} 1914910Swollman 1924910Swollman/* 1934910Swollman * Process the received packet. 1944910Swollman */ 1954910Swollmanvoid sppp_input (struct ifnet *ifp, struct mbuf *m) 1964910Swollman{ 1974910Swollman struct ppp_header *h; 19811189Sjkh struct sppp *sp = (struct sppp*) ifp; 1994910Swollman struct ifqueue *inq = 0; 20011189Sjkh int s; 2014910Swollman 2024910Swollman ifp->if_lastchange = time; 2034910Swollman if (ifp->if_flags & IFF_UP) 2044910Swollman /* Count received bytes, add FCS and one flag */ 2054910Swollman ifp->if_ibytes += m->m_pkthdr.len + 3; 2064910Swollman 2074910Swollman if (m->m_pkthdr.len <= PPP_HEADER_LEN) { 2084910Swollman /* Too small packet, drop it. */ 2094910Swollman if (ifp->if_flags & IFF_DEBUG) 2104910Swollman printf ("%s%d: input packet is too small, %d bytes\n", 2114910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 2124910Swollmandrop: ++ifp->if_iqdrops; 2134910Swollman m_freem (m); 2144910Swollman return; 2154910Swollman } 2164910Swollman 2174910Swollman /* Get PPP header. */ 2184910Swollman h = mtod (m, struct ppp_header*); 2194910Swollman m_adj (m, PPP_HEADER_LEN); 2204910Swollman 2214910Swollman switch (h->address) { 2224910Swollman default: /* Invalid PPP packet. */ 2234910Swollmaninvalid: if (ifp->if_flags & IFF_DEBUG) 2244910Swollman printf ("%s%d: invalid input packet <0x%x 0x%x 0x%x>\n", 2254910Swollman ifp->if_name, ifp->if_unit, 2264910Swollman h->address, h->control, ntohs (h->protocol)); 2274910Swollman goto drop; 2284910Swollman case PPP_ALLSTATIONS: 2294910Swollman if (h->control != PPP_UI) 2304910Swollman goto invalid; 23111189Sjkh if (sp->pp_flags & PP_CISCO) { 23211189Sjkh if (ifp->if_flags & IFF_DEBUG) 23311189Sjkh printf ("%s%d: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", 23411189Sjkh ifp->if_name, ifp->if_unit, 23511189Sjkh h->address, h->control, ntohs (h->protocol)); 23611189Sjkh goto drop; 23711189Sjkh } 2384910Swollman switch (ntohs (h->protocol)) { 2394910Swollman default: 2404910Swollman if (sp->lcp.state == LCP_STATE_OPENED) 2414910Swollman sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, 24211189Sjkh ++sp->pp_seq, m->m_pkthdr.len + 2, 2434910Swollman &h->protocol); 2444910Swollman if (ifp->if_flags & IFF_DEBUG) 2454910Swollman printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n", 2464910Swollman ifp->if_name, ifp->if_unit, 2474910Swollman h->address, h->control, ntohs (h->protocol)); 2484910Swollman ++ifp->if_noproto; 2494910Swollman goto drop; 2504910Swollman case PPP_LCP: 2514910Swollman sppp_lcp_input ((struct sppp*) ifp, m); 2524910Swollman m_freem (m); 2534910Swollman return; 2544910Swollman#ifdef INET 2554910Swollman case PPP_IPCP: 2564910Swollman if (sp->lcp.state == LCP_STATE_OPENED) 2574910Swollman sppp_ipcp_input ((struct sppp*) ifp, m); 2584910Swollman m_freem (m); 2594910Swollman return; 2604910Swollman case PPP_IP: 2614910Swollman if (sp->ipcp.state == IPCP_STATE_OPENED) { 2624910Swollman schednetisr (NETISR_IP); 2634910Swollman inq = &ipintrq; 2644910Swollman } 2654910Swollman break; 2664910Swollman#endif 26712495Speter#ifdef IPX 26812495Speter case PPP_IPX: 26912495Speter /* IPX IPXCP not implemented yet */ 27012495Speter if (sp->lcp.state == LCP_STATE_OPENED) { 27112495Speter schednetisr (NETISR_IPX); 27212495Speter inq = &ipxintrq; 27312495Speter } 27412495Speter break; 27512495Speter#endif 2764910Swollman#ifdef NS 2774910Swollman case PPP_XNS: 2784910Swollman /* XNS IDPCP not implemented yet */ 2794910Swollman if (sp->lcp.state == LCP_STATE_OPENED) { 2804910Swollman schednetisr (NETISR_NS); 2814910Swollman inq = &nsintrq; 2824910Swollman } 2834910Swollman break; 2844910Swollman#endif 2854910Swollman#ifdef ISO 2864910Swollman case PPP_ISO: 2874910Swollman /* OSI NLCP not implemented yet */ 2884910Swollman if (sp->lcp.state == LCP_STATE_OPENED) { 2894910Swollman schednetisr (NETISR_ISO); 2904910Swollman inq = &clnlintrq; 2914910Swollman } 2924910Swollman break; 2934910Swollman#endif 2944910Swollman } 2954910Swollman break; 2964910Swollman case CISCO_MULTICAST: 2974910Swollman case CISCO_UNICAST: 2984910Swollman /* Don't check the control field here (RFC 1547). */ 29911189Sjkh if (! (sp->pp_flags & PP_CISCO)) { 30011189Sjkh if (ifp->if_flags & IFF_DEBUG) 30111189Sjkh printf ("%s%d: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", 30211189Sjkh ifp->if_name, ifp->if_unit, 30311189Sjkh h->address, h->control, ntohs (h->protocol)); 30411189Sjkh goto drop; 30511189Sjkh } 3064910Swollman switch (ntohs (h->protocol)) { 3074910Swollman default: 3084910Swollman ++ifp->if_noproto; 3094910Swollman goto invalid; 3104910Swollman case CISCO_KEEPALIVE: 3114910Swollman sppp_cisco_input ((struct sppp*) ifp, m); 3124910Swollman m_freem (m); 3134910Swollman return; 3144910Swollman#ifdef INET 3154910Swollman case ETHERTYPE_IP: 3164910Swollman schednetisr (NETISR_IP); 3174910Swollman inq = &ipintrq; 3184910Swollman break; 3194910Swollman#endif 32012495Speter#ifdef IPX 32112495Speter case ETHERTYPE_IPX: 32212495Speter schednetisr (NETISR_IPX); 32312495Speter inq = &ipxintrq; 32412495Speter break; 32512495Speter#endif 3264910Swollman#ifdef NS 3274910Swollman case ETHERTYPE_NS: 3284910Swollman schednetisr (NETISR_NS); 3294910Swollman inq = &nsintrq; 3304910Swollman break; 3314910Swollman#endif 3324910Swollman } 3334910Swollman break; 3344910Swollman } 3354910Swollman 3364910Swollman if (! (ifp->if_flags & IFF_UP) || ! inq) 3374910Swollman goto drop; 3384910Swollman 3394910Swollman /* Check queue. */ 34011189Sjkh s = splimp (); 3414910Swollman if (IF_QFULL (inq)) { 3424910Swollman /* Queue overflow. */ 34311189Sjkh IF_DROP (inq); 34411189Sjkh splx (s); 3454910Swollman if (ifp->if_flags & IFF_DEBUG) 3464910Swollman printf ("%s%d: protocol queue overflow\n", 3474910Swollman ifp->if_name, ifp->if_unit); 3484910Swollman goto drop; 3494910Swollman } 3504910Swollman IF_ENQUEUE (inq, m); 35111189Sjkh splx (s); 3524910Swollman} 3534910Swollman 3544910Swollman/* 3554910Swollman * Enqueue transmit packet. 3564910Swollman */ 3574910Swollmanint sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) 3584910Swollman{ 3594910Swollman struct sppp *sp = (struct sppp*) ifp; 3604910Swollman struct ppp_header *h; 3614910Swollman struct ifqueue *ifq; 3624910Swollman int s = splimp (); 3634910Swollman 3644910Swollman if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) { 3654910Swollman m_freem (m); 3664910Swollman splx (s); 3674910Swollman return (ENETDOWN); 3684910Swollman } 3694910Swollman 3704910Swollman ifq = &ifp->if_snd; 3714910Swollman#ifdef INET 3724910Swollman /* 3734910Swollman * Put low delay, telnet, rlogin and ftp control packets 3744910Swollman * in front of the queue. 3754910Swollman */ 37612436Speter if (dst->sa_family == AF_INET) { 37712436Speter struct ip *ip = mtod (m, struct ip*); 37812436Speter struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); 3794910Swollman 38012436Speter if (! IF_QFULL (&sp->pp_fastq) && 38112436Speter ((ip->ip_tos & IPTOS_LOWDELAY) || 38212436Speter ip->ip_p == IPPROTO_TCP && 38312436Speter m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) && 38412436Speter (INTERACTIVE (ntohs (tcp->th_sport)) || 38512436Speter INTERACTIVE (ntohs (tcp->th_dport))))) 38612436Speter ifq = &sp->pp_fastq; 3874910Swollman } 3884910Swollman#endif 3894910Swollman 3904910Swollman /* 3914910Swollman * Prepend general data packet PPP header. For now, IP only. 3924910Swollman */ 3934910Swollman M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); 3944910Swollman if (! m) { 3954910Swollman if (ifp->if_flags & IFF_DEBUG) 3964910Swollman printf ("%s%d: no memory for transmit header\n", 3974910Swollman ifp->if_name, ifp->if_unit); 3984910Swollman splx (s); 3994910Swollman return (ENOBUFS); 4004910Swollman } 4014910Swollman h = mtod (m, struct ppp_header*); 4024910Swollman if (sp->pp_flags & PP_CISCO) { 4034910Swollman h->address = CISCO_MULTICAST; /* broadcast address */ 4044910Swollman h->control = 0; 4054910Swollman } else { 4064910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 4074910Swollman h->control = PPP_UI; /* Unnumbered Info */ 4084910Swollman } 4094910Swollman 4104910Swollman switch (dst->sa_family) { 4114910Swollman#ifdef INET 4124910Swollman case AF_INET: /* Internet Protocol */ 41311189Sjkh if (sp->pp_flags & PP_CISCO) 41411189Sjkh h->protocol = htons (ETHERTYPE_IP); 41511189Sjkh else if (sp->ipcp.state == IPCP_STATE_OPENED) 41611189Sjkh h->protocol = htons (PPP_IP); 41711189Sjkh else { 41811189Sjkh m_freem (m); 41911189Sjkh splx (s); 42011189Sjkh return (ENETDOWN); 42111189Sjkh } 4224910Swollman break; 4234910Swollman#endif 4244910Swollman#ifdef NS 4254910Swollman case AF_NS: /* Xerox NS Protocol */ 4264910Swollman h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 4274910Swollman ETHERTYPE_NS : PPP_XNS); 4284910Swollman break; 4294910Swollman#endif 43011819Sjulian#ifdef IPX 43112495Speter case AF_IPX: /* Novell IPX Protocol */ 43211819Sjulian h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 43312495Speter ETHERTYPE_IPX : PPP_IPX); 43411819Sjulian break; 43511819Sjulian#endif 4364910Swollman#ifdef ISO 4374910Swollman case AF_ISO: /* ISO OSI Protocol */ 4384910Swollman if (sp->pp_flags & PP_CISCO) 4394910Swollman goto nosupport; 4404910Swollman h->protocol = htons (PPP_ISO); 4414910Swollman break; 4424910Swollman#endif 4435099Swollmannosupport: 4444910Swollman default: 4454910Swollman m_freem (m); 4464910Swollman splx (s); 4474910Swollman return (EAFNOSUPPORT); 4484910Swollman } 4494910Swollman 4504910Swollman /* 4514910Swollman * Queue message on interface, and start output if interface 4524910Swollman * not yet active. 4534910Swollman */ 4544910Swollman if (IF_QFULL (ifq)) { 4554910Swollman IF_DROP (&ifp->if_snd); 4564910Swollman m_freem (m); 4574910Swollman splx (s); 4584910Swollman return (ENOBUFS); 4594910Swollman } 4604910Swollman IF_ENQUEUE (ifq, m); 4614910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 4624910Swollman (*ifp->if_start) (ifp); 4634910Swollman 4644910Swollman /* 4654910Swollman * Count output packets and bytes. 4664910Swollman * The packet length includes header, FCS and 1 flag, 4674910Swollman * according to RFC 1333. 4684910Swollman */ 4694910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 4704910Swollman ifp->if_lastchange = time; 4714910Swollman splx (s); 4724910Swollman return (0); 4734910Swollman} 4744910Swollman 4754910Swollmanvoid sppp_attach (struct ifnet *ifp) 4764910Swollman{ 4774910Swollman struct sppp *sp = (struct sppp*) ifp; 4784910Swollman 4794910Swollman /* Initialize keepalive handler. */ 4804910Swollman if (! spppq) 48111189Sjkh timeout (sppp_keepalive, 0, hz * 10); 4824910Swollman 4834910Swollman /* Insert new entry into the keepalive list. */ 4844910Swollman sp->pp_next = spppq; 4854910Swollman spppq = sp; 4864910Swollman 4874910Swollman sp->pp_if.if_type = IFT_PPP; 4884910Swollman sp->pp_if.if_output = sppp_output; 4894910Swollman sp->pp_fastq.ifq_maxlen = 32; 4904910Swollman sp->pp_loopcnt = 0; 4914910Swollman sp->pp_alivecnt = 0; 49211189Sjkh sp->pp_seq = 0; 4934910Swollman sp->pp_rseq = 0; 49411189Sjkh sp->lcp.magic = 0; 49511189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 49611189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 4974910Swollman} 4984910Swollman 4994910Swollmanvoid sppp_detach (struct ifnet *ifp) 5004910Swollman{ 5014910Swollman struct sppp **q, *p, *sp = (struct sppp*) ifp; 5024910Swollman 5034910Swollman /* Remove the entry from the keepalive list. */ 5044910Swollman for (q = &spppq; (p = *q); q = &p->pp_next) 5054910Swollman if (p == sp) { 5064910Swollman *q = p->pp_next; 5074910Swollman break; 5084910Swollman } 5094910Swollman 5104910Swollman /* Stop keepalive handler. */ 5114910Swollman if (! spppq) 51211189Sjkh untimeout (sppp_keepalive, 0); 51311189Sjkh UNTIMO (sp); 5144910Swollman} 5154910Swollman 5164910Swollman/* 5174910Swollman * Flush the interface output queue. 5184910Swollman */ 5194910Swollmanvoid sppp_flush (struct ifnet *ifp) 5204910Swollman{ 5214910Swollman struct sppp *sp = (struct sppp*) ifp; 5224910Swollman 5234910Swollman qflush (&sp->pp_if.if_snd); 5244910Swollman qflush (&sp->pp_fastq); 5254910Swollman} 5264910Swollman 5274910Swollman/* 52811189Sjkh * Check if the output queue is empty. 52911189Sjkh */ 53011189Sjkhint sppp_isempty (struct ifnet *ifp) 53111189Sjkh{ 53211189Sjkh struct sppp *sp = (struct sppp*) ifp; 53311189Sjkh int empty, s = splimp (); 53411189Sjkh 53511189Sjkh empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head; 53611189Sjkh splx (s); 53711189Sjkh return (empty); 53811189Sjkh} 53911189Sjkh 54011189Sjkh/* 5414910Swollman * Get next packet to send. 5424910Swollman */ 5434910Swollmanstruct mbuf *sppp_dequeue (struct ifnet *ifp) 5444910Swollman{ 5454910Swollman struct sppp *sp = (struct sppp*) ifp; 5464910Swollman struct mbuf *m; 5474910Swollman int s = splimp (); 5484910Swollman 5494910Swollman IF_DEQUEUE (&sp->pp_fastq, m); 5504910Swollman if (! m) 5514910Swollman IF_DEQUEUE (&sp->pp_if.if_snd, m); 5524910Swollman splx (s); 5534910Swollman return (m); 5544910Swollman} 5554910Swollman 5564910Swollman/* 5574910Swollman * Send keepalive packets, every 10 seconds. 5584910Swollman */ 55911189Sjkhvoid sppp_keepalive (void *dummy) 5604910Swollman{ 5614910Swollman struct sppp *sp; 5624910Swollman int s = splimp (); 5634910Swollman 5644910Swollman for (sp=spppq; sp; sp=sp->pp_next) { 5654910Swollman struct ifnet *ifp = &sp->pp_if; 5664910Swollman 56711189Sjkh /* Keepalive mode disabled or channel down? */ 5684910Swollman if (! (sp->pp_flags & PP_KEEPALIVE) || 56911189Sjkh ! (ifp->if_flags & IFF_RUNNING)) 57011189Sjkh continue; 57111189Sjkh 57211189Sjkh /* No keepalive in PPP mode if LCP not opened yet. */ 57311189Sjkh if (! (sp->pp_flags & PP_CISCO) && 5744910Swollman sp->lcp.state != LCP_STATE_OPENED) 5754910Swollman continue; 5764910Swollman 5774910Swollman if (sp->pp_alivecnt == MAXALIVECNT) { 5784910Swollman /* No keepalive packets got. Stop the interface. */ 5794910Swollman printf ("%s%d: down\n", ifp->if_name, ifp->if_unit); 5804910Swollman if_down (ifp); 5814910Swollman qflush (&sp->pp_fastq); 58211189Sjkh if (! (sp->pp_flags & PP_CISCO)) { 58311189Sjkh /* Shut down the PPP link. */ 58411189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 58511189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 58611189Sjkh UNTIMO (sp); 58711189Sjkh /* Initiate negotiation. */ 58811189Sjkh sppp_lcp_open (sp); 58911189Sjkh } 5904910Swollman } 5914910Swollman if (sp->pp_alivecnt <= MAXALIVECNT) 5924910Swollman ++sp->pp_alivecnt; 5934910Swollman if (sp->pp_flags & PP_CISCO) 5944910Swollman sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, 5954910Swollman sp->pp_rseq); 5964910Swollman else if (sp->lcp.state == LCP_STATE_OPENED) { 5974910Swollman long nmagic = htonl (sp->lcp.magic); 59811189Sjkh sp->lcp.echoid = ++sp->pp_seq; 5994910Swollman sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, 60011189Sjkh sp->lcp.echoid, 4, &nmagic); 6014910Swollman } 6024910Swollman } 6034910Swollman splx (s); 60411189Sjkh timeout (sppp_keepalive, 0, hz * 10); 6054910Swollman} 6064910Swollman 6074910Swollman/* 6084910Swollman * Handle incoming PPP Link Control Protocol packets. 6094910Swollman */ 6104910Swollmanvoid sppp_lcp_input (struct sppp *sp, struct mbuf *m) 6114910Swollman{ 6124910Swollman struct lcp_header *h; 6134910Swollman struct ifnet *ifp = &sp->pp_if; 6144910Swollman int len = m->m_pkthdr.len; 61511189Sjkh u_char *p, opt[6]; 61611189Sjkh u_long rmagic; 6174910Swollman 6184910Swollman if (len < 4) { 6194910Swollman if (ifp->if_flags & IFF_DEBUG) 6204910Swollman printf ("%s%d: invalid lcp packet length: %d bytes\n", 6214910Swollman ifp->if_name, ifp->if_unit, len); 6224910Swollman return; 6234910Swollman } 6244910Swollman h = mtod (m, struct lcp_header*); 6254910Swollman if (ifp->if_flags & IFF_DEBUG) { 62611189Sjkh char state = '?'; 62711189Sjkh switch (sp->lcp.state) { 62811189Sjkh case LCP_STATE_CLOSED: state = 'C'; break; 62911189Sjkh case LCP_STATE_ACK_RCVD: state = 'R'; break; 63011189Sjkh case LCP_STATE_ACK_SENT: state = 'S'; break; 63111189Sjkh case LCP_STATE_OPENED: state = 'O'; break; 63211189Sjkh } 63311189Sjkh printf ("%s%d: lcp input(%c): %d bytes <%s id=%xh len=%xh", 63411189Sjkh ifp->if_name, ifp->if_unit, state, len, 6354910Swollman sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); 6364910Swollman if (len > 4) 63711189Sjkh sppp_print_bytes ((u_char*) (h+1), len-4); 6384910Swollman printf (">\n"); 6394910Swollman } 6404910Swollman if (len > ntohs (h->len)) 6414910Swollman len = ntohs (h->len); 6424910Swollman switch (h->type) { 6434910Swollman default: 6444910Swollman /* Unknown packet type -- send Code-Reject packet. */ 64511189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, 64611189Sjkh m->m_pkthdr.len, h); 6474910Swollman break; 6484910Swollman case LCP_CONF_REQ: 6494910Swollman if (len < 4) { 6504910Swollman if (ifp->if_flags & IFF_DEBUG) 6514910Swollman printf ("%s%d: invalid lcp configure request packet length: %d bytes\n", 6524910Swollman ifp->if_name, ifp->if_unit, len); 65311189Sjkh break; 6544910Swollman } 65511189Sjkh if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) 65611189Sjkh goto badreq; 65711189Sjkh if (rmagic == sp->lcp.magic) { 65811189Sjkh /* Local and remote magics equal -- loopback? */ 65911189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT*5) { 66011189Sjkh printf ("%s%d: loopback\n", 66111189Sjkh ifp->if_name, ifp->if_unit); 66211189Sjkh sp->pp_loopcnt = 0; 66311189Sjkh if (ifp->if_flags & IFF_UP) { 66411189Sjkh if_down (ifp); 66511189Sjkh qflush (&sp->pp_fastq); 66611189Sjkh } 66711189Sjkh } else if (ifp->if_flags & IFF_DEBUG) 66811189Sjkh printf ("%s%d: conf req: magic glitch\n", 66911189Sjkh ifp->if_name, ifp->if_unit); 67011189Sjkh ++sp->pp_loopcnt; 67111189Sjkh 67211189Sjkh /* MUST send Conf-Nack packet. */ 67311189Sjkh rmagic = ~sp->lcp.magic; 67411189Sjkh opt[0] = LCP_OPT_MAGIC; 67511189Sjkh opt[1] = sizeof (opt); 67611189Sjkh opt[2] = rmagic >> 24; 67711189Sjkh opt[3] = rmagic >> 16; 67811189Sjkh opt[4] = rmagic >> 8; 67911189Sjkh opt[5] = rmagic; 68011189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, 68111189Sjkh h->ident, sizeof (opt), &opt); 68211189Sjkhbadreq: 68311189Sjkh switch (sp->lcp.state) { 68411189Sjkh case LCP_STATE_OPENED: 6854910Swollman /* Initiate renegotiation. */ 6864910Swollman sppp_lcp_open (sp); 68711189Sjkh /* fall through... */ 68811189Sjkh case LCP_STATE_ACK_SENT: 6894910Swollman /* Go to closed state. */ 6904910Swollman sp->lcp.state = LCP_STATE_CLOSED; 6914910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 6924910Swollman } 69311189Sjkh break; 69412436Speter } 69512436Speter /* Send Configure-Ack packet. */ 69612436Speter sp->pp_loopcnt = 0; 69712436Speter sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, 69812436Speter h->ident, len-4, h+1); 69912436Speter /* Change the state. */ 70011189Sjkh switch (sp->lcp.state) { 70111189Sjkh case LCP_STATE_CLOSED: 70211189Sjkh sp->lcp.state = LCP_STATE_ACK_SENT; 70311189Sjkh break; 70411189Sjkh case LCP_STATE_ACK_RCVD: 70512436Speter sp->lcp.state = LCP_STATE_OPENED; 70612436Speter sppp_ipcp_open (sp); 70711189Sjkh break; 70811189Sjkh case LCP_STATE_OPENED: 70911189Sjkh /* Remote magic changed -- close session. */ 71011189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 71111189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 71211189Sjkh /* Initiate renegotiation. */ 71311189Sjkh sppp_lcp_open (sp); 71412436Speter /* An ACK has already been sent. */ 71512436Speter sp->lcp.state = LCP_STATE_ACK_SENT; 71611189Sjkh break; 7174910Swollman } 7184910Swollman break; 7194910Swollman case LCP_CONF_ACK: 72011189Sjkh if (h->ident != sp->lcp.confid) 72111189Sjkh break; 72211189Sjkh UNTIMO (sp); 72311189Sjkh if (! (ifp->if_flags & IFF_UP) && 72411189Sjkh (ifp->if_flags & IFF_RUNNING)) { 72511189Sjkh /* Coming out of loopback mode. */ 72611189Sjkh ifp->if_flags |= IFF_UP; 72711189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 72811189Sjkh } 7294910Swollman switch (sp->lcp.state) { 7304910Swollman case LCP_STATE_CLOSED: 7314910Swollman sp->lcp.state = LCP_STATE_ACK_RCVD; 73211189Sjkh TIMO (sp, 5); 7334910Swollman break; 7344910Swollman case LCP_STATE_ACK_SENT: 7354910Swollman sp->lcp.state = LCP_STATE_OPENED; 7364910Swollman sppp_ipcp_open (sp); 7374910Swollman break; 7384910Swollman } 7394910Swollman break; 7404910Swollman case LCP_CONF_NAK: 74111189Sjkh if (h->ident != sp->lcp.confid) 74211189Sjkh break; 74311189Sjkh p = (u_char*) (h+1); 7444910Swollman if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { 74511189Sjkh rmagic = (u_long)p[2] << 24 | 74611189Sjkh (u_long)p[3] << 16 | p[4] << 8 | p[5]; 74711189Sjkh if (rmagic == ~sp->lcp.magic) { 7484910Swollman if (ifp->if_flags & IFF_DEBUG) 7494910Swollman printf ("%s%d: conf nak: magic glitch\n", 7504910Swollman ifp->if_name, ifp->if_unit); 75111189Sjkh sp->lcp.magic += time.tv_sec + time.tv_usec; 75211189Sjkh } else 75311189Sjkh sp->lcp.magic = rmagic; 7544910Swollman } 75511189Sjkh if (sp->lcp.state != LCP_STATE_ACK_SENT) { 75611189Sjkh /* Go to closed state. */ 75711189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 75811189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 7594910Swollman } 76011189Sjkh /* The link will be renegotiated after timeout, 76111189Sjkh * to avoid endless req-nack loop. */ 76211189Sjkh UNTIMO (sp); 76311189Sjkh TIMO (sp, 2); 76411189Sjkh break; 7654910Swollman case LCP_CONF_REJ: 76611189Sjkh if (h->ident != sp->lcp.confid) 76711189Sjkh break; 76811189Sjkh UNTIMO (sp); 7694910Swollman /* Initiate renegotiation. */ 7704910Swollman sppp_lcp_open (sp); 7714910Swollman if (sp->lcp.state != LCP_STATE_ACK_SENT) { 7724910Swollman /* Go to closed state. */ 7734910Swollman sp->lcp.state = LCP_STATE_CLOSED; 7744910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 7754910Swollman } 7764910Swollman break; 7774910Swollman case LCP_TERM_REQ: 77811189Sjkh UNTIMO (sp); 7794910Swollman /* Send Terminate-Ack packet. */ 7804910Swollman sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); 7814910Swollman /* Go to closed state. */ 7824910Swollman sp->lcp.state = LCP_STATE_CLOSED; 7834910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 78412436Speter /* Initiate renegotiation. */ 78512436Speter sppp_lcp_open (sp); 7864910Swollman break; 78711189Sjkh case LCP_TERM_ACK: 7884910Swollman case LCP_CODE_REJ: 7894910Swollman case LCP_PROTO_REJ: 7904910Swollman /* Ignore for now. */ 7914910Swollman break; 7924910Swollman case LCP_DISC_REQ: 7934910Swollman /* Discard the packet. */ 7944910Swollman break; 7954910Swollman case LCP_ECHO_REQ: 79612436Speter if (sp->lcp.state != LCP_STATE_OPENED) 79712436Speter break; 7984910Swollman if (len < 8) { 7994910Swollman if (ifp->if_flags & IFF_DEBUG) 8004910Swollman printf ("%s%d: invalid lcp echo request packet length: %d bytes\n", 8014910Swollman ifp->if_name, ifp->if_unit, len); 80211189Sjkh break; 8034910Swollman } 8044910Swollman if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { 80511189Sjkh /* Line loopback mode detected. */ 80611189Sjkh printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); 80711189Sjkh if_down (ifp); 80811189Sjkh qflush (&sp->pp_fastq); 80911189Sjkh 81011189Sjkh /* Shut down the PPP link. */ 81111189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 81211189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 81311189Sjkh UNTIMO (sp); 81411189Sjkh /* Initiate negotiation. */ 81511189Sjkh sppp_lcp_open (sp); 81611189Sjkh break; 8174910Swollman } 8184910Swollman *(long*)(h+1) = htonl (sp->lcp.magic); 8194910Swollman sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); 8204910Swollman break; 8214910Swollman case LCP_ECHO_REPLY: 82211189Sjkh if (h->ident != sp->lcp.echoid) 82311189Sjkh break; 8244910Swollman if (len < 8) { 8254910Swollman if (ifp->if_flags & IFF_DEBUG) 8264910Swollman printf ("%s%d: invalid lcp echo reply packet length: %d bytes\n", 8274910Swollman ifp->if_name, ifp->if_unit, len); 82811189Sjkh break; 8294910Swollman } 83011189Sjkh if (ntohl (*(long*)(h+1)) != sp->lcp.magic) 8314910Swollman sp->pp_alivecnt = 0; 8324910Swollman break; 8334910Swollman } 8344910Swollman} 8354910Swollman 8364910Swollman/* 8374910Swollman * Handle incoming Cisco keepalive protocol packets. 8384910Swollman */ 8394910Swollmanvoid sppp_cisco_input (struct sppp *sp, struct mbuf *m) 8404910Swollman{ 8414910Swollman struct cisco_packet *h; 8424910Swollman struct ifaddr *ifa; 8434910Swollman struct ifnet *ifp = &sp->pp_if; 8444910Swollman 8454910Swollman if (m->m_pkthdr.len != CISCO_PACKET_LEN) { 8464910Swollman if (ifp->if_flags & IFF_DEBUG) 8474910Swollman printf ("%s%d: invalid cisco packet length: %d bytes\n", 8484910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 8494910Swollman return; 8504910Swollman } 8514910Swollman h = mtod (m, struct cisco_packet*); 8524910Swollman if (ifp->if_flags & IFF_DEBUG) 85311189Sjkh printf ("%s%d: cisco input: %d bytes <%lxh %lxh %lxh %xh %xh-%xh>\n", 8544910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len, 8554910Swollman ntohl (h->type), h->par1, h->par2, h->rel, 8564910Swollman h->time0, h->time1); 8574910Swollman switch (ntohl (h->type)) { 8584910Swollman default: 8594910Swollman if (ifp->if_flags & IFF_DEBUG) 8608456Srgrimes printf ("%s%d: unknown cisco packet type: 0x%lx\n", 8614910Swollman ifp->if_name, ifp->if_unit, ntohl (h->type)); 8624910Swollman break; 8634910Swollman case CISCO_ADDR_REPLY: 8644910Swollman /* Reply on address request, ignore */ 8654910Swollman break; 8664910Swollman case CISCO_KEEPALIVE_REQ: 8674910Swollman sp->pp_alivecnt = 0; 8684910Swollman sp->pp_rseq = ntohl (h->par1); 8694910Swollman if (sp->pp_seq == sp->pp_rseq) { 8704910Swollman /* Local and remote sequence numbers are equal. 8714910Swollman * Probably, the line is in loopback mode. */ 87211189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT) { 87311189Sjkh printf ("%s%d: loopback\n", 87411189Sjkh ifp->if_name, ifp->if_unit); 87511189Sjkh sp->pp_loopcnt = 0; 87611189Sjkh if (ifp->if_flags & IFF_UP) { 87711189Sjkh if_down (ifp); 87811189Sjkh qflush (&sp->pp_fastq); 87911189Sjkh } 88011189Sjkh } 8814910Swollman ++sp->pp_loopcnt; 8824910Swollman 8834910Swollman /* Generate new local sequence number */ 8844910Swollman sp->pp_seq ^= time.tv_sec ^ time.tv_usec; 88511189Sjkh break; 88611189Sjkh } 8874910Swollman sp->pp_loopcnt = 0; 88811189Sjkh if (! (ifp->if_flags & IFF_UP) && 88911189Sjkh (ifp->if_flags & IFF_RUNNING)) { 89011189Sjkh ifp->if_flags |= IFF_UP; 89111189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 89211189Sjkh } 8934910Swollman break; 8944910Swollman case CISCO_ADDR_REQ: 8954910Swollman for (ifa=ifp->if_addrlist; ifa; ifa=ifa->ifa_next) 8964910Swollman if (ifa->ifa_addr->sa_family == AF_INET) 8974910Swollman break; 8984910Swollman if (! ifa) { 8994910Swollman if (ifp->if_flags & IFF_DEBUG) 9004910Swollman printf ("%s%d: unknown address for cisco request\n", 9014910Swollman ifp->if_name, ifp->if_unit); 9024910Swollman return; 9034910Swollman } 9044910Swollman sppp_cisco_send (sp, CISCO_ADDR_REPLY, 9054910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr), 9064910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr)); 9074910Swollman break; 9084910Swollman } 9094910Swollman} 9104910Swollman 9114910Swollman/* 9124910Swollman * Send PPP LCP packet. 9134910Swollman */ 91411189Sjkhvoid sppp_cp_send (struct sppp *sp, u_short proto, u_char type, 91511189Sjkh u_char ident, u_short len, void *data) 9164910Swollman{ 9174910Swollman struct ppp_header *h; 9184910Swollman struct lcp_header *lh; 9194910Swollman struct mbuf *m; 9204910Swollman struct ifnet *ifp = &sp->pp_if; 9214910Swollman 9224910Swollman if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) 9234910Swollman len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; 9244910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9254910Swollman if (! m) 9264910Swollman return; 9274910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; 9284910Swollman m->m_pkthdr.rcvif = 0; 9294910Swollman 9304910Swollman h = mtod (m, struct ppp_header*); 9314910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 9324910Swollman h->control = PPP_UI; /* Unnumbered Info */ 9334910Swollman h->protocol = htons (proto); /* Link Control Protocol */ 9344910Swollman 9354910Swollman lh = (struct lcp_header*) (h + 1); 9364910Swollman lh->type = type; 9374910Swollman lh->ident = ident; 9384910Swollman lh->len = htons (LCP_HEADER_LEN + len); 9394910Swollman if (len) 9404910Swollman bcopy (data, lh+1, len); 9414910Swollman 9424910Swollman if (ifp->if_flags & IFF_DEBUG) { 9434910Swollman printf ("%s%d: %s output <%s id=%xh len=%xh", 9444910Swollman ifp->if_name, ifp->if_unit, 9454910Swollman proto==PPP_LCP ? "lcp" : "ipcp", 9464910Swollman proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : 9474910Swollman sppp_ipcp_type_name (lh->type), lh->ident, 9484910Swollman ntohs (lh->len)); 9494910Swollman if (len) 95011189Sjkh sppp_print_bytes ((u_char*) (lh+1), len); 9514910Swollman printf (">\n"); 9524910Swollman } 9534910Swollman if (IF_QFULL (&sp->pp_fastq)) { 9544910Swollman IF_DROP (&ifp->if_snd); 9554910Swollman m_freem (m); 9564910Swollman } else 9574910Swollman IF_ENQUEUE (&sp->pp_fastq, m); 9584910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 9594910Swollman (*ifp->if_start) (ifp); 9604910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 9614910Swollman} 9624910Swollman 9634910Swollman/* 9644910Swollman * Send Cisco keepalive packet. 9654910Swollman */ 9664910Swollmanvoid sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) 9674910Swollman{ 9684910Swollman struct ppp_header *h; 9694910Swollman struct cisco_packet *ch; 9704910Swollman struct mbuf *m; 9714910Swollman struct ifnet *ifp = &sp->pp_if; 97211189Sjkh u_long t = (time.tv_sec - boottime.tv_sec) * 1000; 9734910Swollman 9744910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9754910Swollman if (! m) 9764910Swollman return; 9774910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; 9784910Swollman m->m_pkthdr.rcvif = 0; 9794910Swollman 9804910Swollman h = mtod (m, struct ppp_header*); 9814910Swollman h->address = CISCO_MULTICAST; 9824910Swollman h->control = 0; 9834910Swollman h->protocol = htons (CISCO_KEEPALIVE); 9844910Swollman 9854910Swollman ch = (struct cisco_packet*) (h + 1); 9864910Swollman ch->type = htonl (type); 9874910Swollman ch->par1 = htonl (par1); 9884910Swollman ch->par2 = htonl (par2); 9894910Swollman ch->rel = -1; 99011189Sjkh ch->time0 = htons ((u_short) (t >> 16)); 99111189Sjkh ch->time1 = htons ((u_short) t); 9924910Swollman 9934910Swollman if (ifp->if_flags & IFF_DEBUG) 9948456Srgrimes printf ("%s%d: cisco output: <%lxh %lxh %lxh %xh %xh-%xh>\n", 9954910Swollman ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1, 9964910Swollman ch->par2, ch->rel, ch->time0, ch->time1); 9974910Swollman 9984910Swollman if (IF_QFULL (&sp->pp_fastq)) { 9994910Swollman IF_DROP (&ifp->if_snd); 10004910Swollman m_freem (m); 10014910Swollman } else 10024910Swollman IF_ENQUEUE (&sp->pp_fastq, m); 10034910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 10044910Swollman (*ifp->if_start) (ifp); 10054910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 10064910Swollman} 10074910Swollman 10084910Swollman/* 10094910Swollman * Process an ioctl request. Called on low priority level. 10104910Swollman */ 101111189Sjkhint sppp_ioctl (struct ifnet *ifp, int cmd, void *data) 10124910Swollman{ 10134910Swollman struct ifreq *ifr = (struct ifreq*) data; 101411189Sjkh struct sppp *sp = (struct sppp*) ifp; 101511189Sjkh int s, going_up, going_down; 10164910Swollman 10174910Swollman switch (cmd) { 10184910Swollman default: 10194910Swollman return (EINVAL); 10204910Swollman 10214910Swollman case SIOCAIFADDR: 10224910Swollman case SIOCSIFDSTADDR: 10234910Swollman break; 10244910Swollman 102511189Sjkh case SIOCSIFADDR: 102611189Sjkh ifp->if_flags |= IFF_UP; 102711189Sjkh /* fall through... */ 102811189Sjkh 10294910Swollman case SIOCSIFFLAGS: 10304910Swollman s = splimp (); 103111189Sjkh going_up = (ifp->if_flags & IFF_UP) && 103211189Sjkh ! (ifp->if_flags & IFF_RUNNING); 103311189Sjkh going_down = ! (ifp->if_flags & IFF_UP) && 103411189Sjkh (ifp->if_flags & IFF_RUNNING); 103511189Sjkh if (going_up || going_down) { 103611189Sjkh /* Shut down the PPP link. */ 103711189Sjkh ifp->if_flags &= ~IFF_RUNNING; 10384910Swollman sp->lcp.state = LCP_STATE_CLOSED; 10394910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 104011189Sjkh UNTIMO (sp); 104111189Sjkh } 104211189Sjkh if (going_up) { 104311189Sjkh /* Interface is starting -- initiate negotiation. */ 104411189Sjkh ifp->if_flags |= IFF_RUNNING; 104512436Speter if (!(sp->pp_flags & PP_CISCO)) 104612436Speter sppp_lcp_open (sp); 10474910Swollman } 10484910Swollman splx (s); 10494910Swollman break; 10504910Swollman 10514910Swollman#ifdef SIOCSIFMTU 10524910Swollman#ifndef ifr_mtu 10534910Swollman#define ifr_mtu ifr_metric 10544910Swollman#endif 10554910Swollman case SIOCSIFMTU: 10564910Swollman if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > PP_MTU) 10574910Swollman return (EINVAL); 10584910Swollman ifp->if_mtu = ifr->ifr_mtu; 10594910Swollman break; 10604910Swollman#endif 10614910Swollman#ifdef SLIOCSETMTU 10624910Swollman case SLIOCSETMTU: 10634910Swollman if (*(short*)data < 128 || *(short*)data > PP_MTU) 10644910Swollman return (EINVAL); 10654910Swollman ifp->if_mtu = *(short*)data; 10664910Swollman break; 10674910Swollman#endif 10684910Swollman#ifdef SIOCGIFMTU 10694910Swollman case SIOCGIFMTU: 10704910Swollman ifr->ifr_mtu = ifp->if_mtu; 10714910Swollman break; 10724910Swollman#endif 10734910Swollman#ifdef SLIOCGETMTU 10744910Swollman case SLIOCGETMTU: 10754910Swollman *(short*)data = ifp->if_mtu; 10764910Swollman break; 10774910Swollman#endif 10784910Swollman#ifdef MULTICAST 10794910Swollman case SIOCADDMULTI: 10804910Swollman case SIOCDELMULTI: 10814910Swollman break; 10824910Swollman#endif 10834910Swollman } 10844910Swollman return (0); 10854910Swollman} 10864910Swollman 108711189Sjkh/* 108811189Sjkh * Analyze the LCP Configure-Request options list 108911189Sjkh * for the presence of unknown options. 109011189Sjkh * If the request contains unknown options, build and 109111189Sjkh * send Configure-reject packet, containing only unknown options. 109211189Sjkh */ 109311189Sjkhint sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, 109411189Sjkh int len, u_long *magic) 10954910Swollman{ 109611189Sjkh u_char *buf, *r, *p; 109711189Sjkh int rlen; 10984910Swollman 109911189Sjkh len -= 4; 110011189Sjkh buf = r = malloc (len, M_TEMP, M_NOWAIT); 110111189Sjkh if (! buf) 110211189Sjkh return (0); 11034910Swollman 110411189Sjkh p = (void*) (h+1); 110511189Sjkh for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 110611189Sjkh switch (*p) { 110711189Sjkh case LCP_OPT_MAGIC: 110811189Sjkh /* Magic number -- extract. */ 110911189Sjkh if (len >= 6 && p[1] == 6) { 111011189Sjkh *magic = (u_long)p[2] << 24 | 111111189Sjkh (u_long)p[3] << 16 | p[4] << 8 | p[5]; 111211189Sjkh continue; 111311189Sjkh } 111411189Sjkh break; 111511189Sjkh case LCP_OPT_ASYNC_MAP: 111611189Sjkh /* Async control character map -- check to be zero. */ 111711189Sjkh if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && 111811189Sjkh ! p[4] && ! p[5]) 111911189Sjkh continue; 112011189Sjkh break; 112111189Sjkh case LCP_OPT_MRU: 112211189Sjkh /* Maximum receive unit -- always OK. */ 112311189Sjkh continue; 112411189Sjkh default: 112511189Sjkh /* Others not supported. */ 112611189Sjkh break; 112711189Sjkh } 112811189Sjkh /* Add the option to rejected list. */ 11294910Swollman bcopy (p, r, p[1]); 11304910Swollman r += p[1]; 113111189Sjkh rlen += p[1]; 113212436Speter } 113311189Sjkh if (rlen) 11344910Swollman sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); 113511189Sjkh free (buf, M_TEMP); 113611189Sjkh return (rlen == 0); 11374910Swollman} 11384910Swollman 11394910Swollmanvoid sppp_ipcp_input (struct sppp *sp, struct mbuf *m) 11404910Swollman{ 11414910Swollman struct lcp_header *h; 11424910Swollman struct ifnet *ifp = &sp->pp_if; 11434910Swollman int len = m->m_pkthdr.len; 11444910Swollman 11454910Swollman if (len < 4) { 11464910Swollman /* if (ifp->if_flags & IFF_DEBUG) */ 11474910Swollman printf ("%s%d: invalid ipcp packet length: %d bytes\n", 11484910Swollman ifp->if_name, ifp->if_unit, len); 11494910Swollman return; 11504910Swollman } 11514910Swollman h = mtod (m, struct lcp_header*); 11524910Swollman if (ifp->if_flags & IFF_DEBUG) { 11534910Swollman printf ("%s%d: ipcp input: %d bytes <%s id=%xh len=%xh", 11544910Swollman ifp->if_name, ifp->if_unit, len, 11554910Swollman sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); 11564910Swollman if (len > 4) 115711189Sjkh sppp_print_bytes ((u_char*) (h+1), len-4); 11584910Swollman printf (">\n"); 11594910Swollman } 11604910Swollman if (len > ntohs (h->len)) 11614910Swollman len = ntohs (h->len); 11624910Swollman switch (h->type) { 11634910Swollman default: 11644910Swollman /* Unknown packet type -- send Code-Reject packet. */ 11654910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); 11664910Swollman break; 11674910Swollman case IPCP_CONF_REQ: 11684910Swollman if (len < 4) { 11694910Swollman if (ifp->if_flags & IFF_DEBUG) 11704910Swollman printf ("%s%d: invalid ipcp configure request packet length: %d bytes\n", 11714910Swollman ifp->if_name, ifp->if_unit, len); 11724910Swollman return; 11734910Swollman } 11744910Swollman if (len > 4) { 11754910Swollman sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, 11764910Swollman len-4, h+1); 117711189Sjkh 117811189Sjkh switch (sp->ipcp.state) { 117911189Sjkh case IPCP_STATE_OPENED: 11804910Swollman /* Initiate renegotiation. */ 11814910Swollman sppp_ipcp_open (sp); 118211189Sjkh /* fall through... */ 118311189Sjkh case IPCP_STATE_ACK_SENT: 11844910Swollman /* Go to closed state. */ 11854910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 118611189Sjkh } 11874910Swollman } else { 11884910Swollman /* Send Configure-Ack packet. */ 11894910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, 11904910Swollman 0, 0); 11914910Swollman /* Change the state. */ 119211189Sjkh if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) 119311189Sjkh sp->ipcp.state = IPCP_STATE_OPENED; 119411189Sjkh else 119511189Sjkh sp->ipcp.state = IPCP_STATE_ACK_SENT; 11964910Swollman } 11974910Swollman break; 11984910Swollman case IPCP_CONF_ACK: 119911189Sjkh if (h->ident != sp->ipcp.confid) 120011189Sjkh break; 120111189Sjkh UNTIMO (sp); 12024910Swollman switch (sp->ipcp.state) { 12034910Swollman case IPCP_STATE_CLOSED: 12044910Swollman sp->ipcp.state = IPCP_STATE_ACK_RCVD; 120511189Sjkh TIMO (sp, 5); 12064910Swollman break; 12074910Swollman case IPCP_STATE_ACK_SENT: 12084910Swollman sp->ipcp.state = IPCP_STATE_OPENED; 12094910Swollman break; 12104910Swollman } 12114910Swollman break; 12124910Swollman case IPCP_CONF_NAK: 12134910Swollman case IPCP_CONF_REJ: 121411189Sjkh if (h->ident != sp->ipcp.confid) 121511189Sjkh break; 121611189Sjkh UNTIMO (sp); 12174910Swollman /* Initiate renegotiation. */ 12184910Swollman sppp_ipcp_open (sp); 12194910Swollman if (sp->ipcp.state != IPCP_STATE_ACK_SENT) 12204910Swollman /* Go to closed state. */ 12214910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 12224910Swollman break; 12234910Swollman case IPCP_TERM_REQ: 12244910Swollman /* Send Terminate-Ack packet. */ 12254910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); 12264910Swollman /* Go to closed state. */ 12274910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 12284910Swollman /* Initiate renegotiation. */ 12294910Swollman sppp_ipcp_open (sp); 12304910Swollman break; 123111189Sjkh case IPCP_TERM_ACK: 123211189Sjkh /* Ignore for now. */ 12334910Swollman case IPCP_CODE_REJ: 12344910Swollman /* Ignore for now. */ 12354910Swollman break; 12364910Swollman } 12374910Swollman} 12384910Swollman 12394910Swollmanvoid sppp_lcp_open (struct sppp *sp) 12404910Swollman{ 12414910Swollman char opt[6]; 12424910Swollman 124311189Sjkh if (! sp->lcp.magic) 12444910Swollman sp->lcp.magic = time.tv_sec + time.tv_usec; 12454910Swollman opt[0] = LCP_OPT_MAGIC; 12464910Swollman opt[1] = sizeof (opt); 12474910Swollman opt[2] = sp->lcp.magic >> 24; 12484910Swollman opt[3] = sp->lcp.magic >> 16; 12494910Swollman opt[4] = sp->lcp.magic >> 8; 12504910Swollman opt[5] = sp->lcp.magic; 125111189Sjkh sp->lcp.confid = ++sp->pp_seq; 125211189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, 12534910Swollman sizeof (opt), &opt); 125411189Sjkh TIMO (sp, 2); 12554910Swollman} 12564910Swollman 12574910Swollmanvoid sppp_ipcp_open (struct sppp *sp) 12584910Swollman{ 125911189Sjkh sp->ipcp.confid = ++sp->pp_seq; 126011189Sjkh sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); 126111189Sjkh TIMO (sp, 2); 12624910Swollman} 12634910Swollman 12644910Swollman/* 12654910Swollman * Process PPP control protocol timeouts. 12664910Swollman */ 126711189Sjkhvoid sppp_cp_timeout (void *arg) 12684910Swollman{ 12694910Swollman struct sppp *sp = (struct sppp*) arg; 12704910Swollman int s = splimp (); 12714910Swollman 127211189Sjkh sp->pp_flags &= ~PP_TIMO; 127311189Sjkh if (! (sp->pp_if.if_flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { 127411189Sjkh splx (s); 127511189Sjkh return; 127611189Sjkh } 12774910Swollman switch (sp->lcp.state) { 12784910Swollman case LCP_STATE_CLOSED: 12794910Swollman /* No ACK for Configure-Request, retry. */ 12804910Swollman sppp_lcp_open (sp); 12814910Swollman break; 12824910Swollman case LCP_STATE_ACK_RCVD: 12834910Swollman /* ACK got, but no Configure-Request for peer, retry. */ 12844910Swollman sppp_lcp_open (sp); 12854910Swollman sp->lcp.state = LCP_STATE_CLOSED; 12864910Swollman break; 12874910Swollman case LCP_STATE_ACK_SENT: 12884910Swollman /* ACK sent but no ACK for Configure-Request, retry. */ 12894910Swollman sppp_lcp_open (sp); 12904910Swollman break; 12914910Swollman case LCP_STATE_OPENED: 12924910Swollman /* LCP is already OK, try IPCP. */ 12934910Swollman switch (sp->ipcp.state) { 12944910Swollman case IPCP_STATE_CLOSED: 12954910Swollman /* No ACK for Configure-Request, retry. */ 12964910Swollman sppp_ipcp_open (sp); 12974910Swollman break; 12984910Swollman case IPCP_STATE_ACK_RCVD: 12994910Swollman /* ACK got, but no Configure-Request for peer, retry. */ 13004910Swollman sppp_ipcp_open (sp); 13014910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 13024910Swollman break; 13034910Swollman case IPCP_STATE_ACK_SENT: 13044910Swollman /* ACK sent but no ACK for Configure-Request, retry. */ 13054910Swollman sppp_ipcp_open (sp); 13064910Swollman break; 13074910Swollman case IPCP_STATE_OPENED: 13084910Swollman /* IPCP is OK. */ 13094910Swollman break; 13104910Swollman } 13114910Swollman break; 13124910Swollman } 13134910Swollman splx (s); 13144910Swollman} 13154910Swollman 131611189Sjkhchar *sppp_lcp_type_name (u_char type) 13174910Swollman{ 13184910Swollman static char buf [8]; 13194910Swollman switch (type) { 13204910Swollman case LCP_CONF_REQ: return ("conf-req"); 13214910Swollman case LCP_CONF_ACK: return ("conf-ack"); 13224910Swollman case LCP_CONF_NAK: return ("conf-nack"); 13234910Swollman case LCP_CONF_REJ: return ("conf-rej"); 13244910Swollman case LCP_TERM_REQ: return ("term-req"); 13254910Swollman case LCP_TERM_ACK: return ("term-ack"); 13264910Swollman case LCP_CODE_REJ: return ("code-rej"); 13274910Swollman case LCP_PROTO_REJ: return ("proto-rej"); 13284910Swollman case LCP_ECHO_REQ: return ("echo-req"); 13294910Swollman case LCP_ECHO_REPLY: return ("echo-reply"); 13304910Swollman case LCP_DISC_REQ: return ("discard-req"); 13314910Swollman } 13324910Swollman sprintf (buf, "%xh", type); 13334910Swollman return (buf); 13344910Swollman} 13354910Swollman 133611189Sjkhchar *sppp_ipcp_type_name (u_char type) 13374910Swollman{ 13384910Swollman static char buf [8]; 13394910Swollman switch (type) { 13404910Swollman case IPCP_CONF_REQ: return ("conf-req"); 13414910Swollman case IPCP_CONF_ACK: return ("conf-ack"); 13424910Swollman case IPCP_CONF_NAK: return ("conf-nack"); 13434910Swollman case IPCP_CONF_REJ: return ("conf-rej"); 13444910Swollman case IPCP_TERM_REQ: return ("term-req"); 13454910Swollman case IPCP_TERM_ACK: return ("term-ack"); 13464910Swollman case IPCP_CODE_REJ: return ("code-rej"); 13474910Swollman } 13484910Swollman sprintf (buf, "%xh", type); 13494910Swollman return (buf); 13504910Swollman} 13514910Swollman 135211189Sjkhvoid sppp_print_bytes (u_char *p, u_short len) 13534910Swollman{ 13544910Swollman printf (" %x", *p++); 13554910Swollman while (--len > 0) 13564910Swollman printf ("-%x", *p++); 13574910Swollman} 1358