if_spppsubr.c revision 12436
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 */ 714910Swollman#define PPP_LCP 0xc021 /* Link Control Protocol */ 724910Swollman#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ 734910Swollman 744910Swollman#define LCP_CONF_REQ 1 /* PPP LCP configure request */ 754910Swollman#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ 764910Swollman#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ 774910Swollman#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ 784910Swollman#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ 794910Swollman#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ 804910Swollman#define LCP_CODE_REJ 7 /* PPP LCP code reject */ 814910Swollman#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ 824910Swollman#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ 834910Swollman#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ 844910Swollman#define LCP_DISC_REQ 11 /* PPP LCP discard request */ 854910Swollman 864910Swollman#define LCP_OPT_MRU 1 /* maximum receive unit */ 874910Swollman#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ 884910Swollman#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ 894910Swollman#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ 904910Swollman#define LCP_OPT_MAGIC 5 /* magic number */ 914910Swollman#define LCP_OPT_RESERVED 6 /* reserved */ 924910Swollman#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ 934910Swollman#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ 944910Swollman 954910Swollman#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ 964910Swollman#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ 974910Swollman#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ 984910Swollman#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ 994910Swollman#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ 1004910Swollman#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ 1014910Swollman#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ 1024910Swollman 1034910Swollman#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ 1044910Swollman#define CISCO_UNICAST 0x0f /* Cisco unicast address */ 1054910Swollman#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ 1064910Swollman#define CISCO_ADDR_REQ 0 /* Cisco address request */ 1074910Swollman#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ 1084910Swollman#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ 1094910Swollman 1104910Swollmanstruct ppp_header { 11111189Sjkh u_char address; 11211189Sjkh u_char control; 11311189Sjkh u_short protocol; 1144910Swollman}; 1154910Swollman#define PPP_HEADER_LEN sizeof (struct ppp_header) 1164910Swollman 1174910Swollmanstruct lcp_header { 11811189Sjkh u_char type; 11911189Sjkh u_char ident; 12011189Sjkh u_short len; 1214910Swollman}; 1224910Swollman#define LCP_HEADER_LEN sizeof (struct lcp_header) 1234910Swollman 1244910Swollmanstruct cisco_packet { 12511189Sjkh u_long type; 12611189Sjkh u_long par1; 12711189Sjkh u_long par2; 12811189Sjkh u_short rel; 12911189Sjkh u_short time0; 13011189Sjkh u_short time1; 1314910Swollman}; 1324910Swollman#define CISCO_PACKET_LEN 18 1334910Swollman 1344910Swollmanstruct sppp *spppq; 1354910Swollman 1364910Swollman/* 1374910Swollman * The following disgusting hack gets around the problem that IP TOS 1384910Swollman * can't be set yet. We want to put "interactive" traffic on a high 1394910Swollman * priority queue. To decide if traffic is interactive, we check that 1404910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 1414910Swollman */ 14211189Sjkhstatic u_short interactive_ports[8] = { 1434910Swollman 0, 513, 0, 0, 1444910Swollman 0, 21, 0, 23, 1454910Swollman}; 1464910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 1474910Swollman 14811189Sjkh/* 14911189Sjkh * Timeout routine activation macros. 15011189Sjkh */ 15111189Sjkh#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \ 15211189Sjkh timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \ 15311189Sjkh (p)->pp_flags |= PP_TIMO; } 15411189Sjkh#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \ 15511189Sjkh untimeout (sppp_cp_timeout, (void*) (p)); \ 15611189Sjkh (p)->pp_flags &= ~PP_TIMO; } 15711189Sjkh 15811189Sjkhvoid sppp_keepalive (void *dummy); 15911189Sjkhvoid sppp_cp_send (struct sppp *sp, u_short proto, u_char type, 16011189Sjkh u_char ident, u_short len, void *data); 1614910Swollmanvoid sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); 1624910Swollmanvoid sppp_lcp_input (struct sppp *sp, struct mbuf *m); 1634910Swollmanvoid sppp_cisco_input (struct sppp *sp, struct mbuf *m); 1644910Swollmanvoid sppp_ipcp_input (struct sppp *sp, struct mbuf *m); 1654910Swollmanvoid sppp_lcp_open (struct sppp *sp); 1664910Swollmanvoid sppp_ipcp_open (struct sppp *sp); 16711189Sjkhint sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, 16811189Sjkh int len, u_long *magic); 1696429Sjkhvoid sppp_cp_timeout (void *arg); 17011189Sjkhchar *sppp_lcp_type_name (u_char type); 17111189Sjkhchar *sppp_ipcp_type_name (u_char type); 17211189Sjkhvoid sppp_print_bytes (u_char *p, u_short len); 1734910Swollman 1744910Swollman/* 1754910Swollman * Flush interface queue. 1764910Swollman */ 1774910Swollmanstatic void qflush (struct ifqueue *ifq) 1784910Swollman{ 1794910Swollman struct mbuf *m, *n; 1804910Swollman 1814910Swollman n = ifq->ifq_head; 1824910Swollman while ((m = n)) { 1834910Swollman n = m->m_act; 1844910Swollman m_freem (m); 1854910Swollman } 1864910Swollman ifq->ifq_head = 0; 1874910Swollman ifq->ifq_tail = 0; 1884910Swollman ifq->ifq_len = 0; 1894910Swollman} 1904910Swollman 1914910Swollman/* 1924910Swollman * Process the received packet. 1934910Swollman */ 1944910Swollmanvoid sppp_input (struct ifnet *ifp, struct mbuf *m) 1954910Swollman{ 1964910Swollman struct ppp_header *h; 19711189Sjkh struct sppp *sp = (struct sppp*) ifp; 1984910Swollman struct ifqueue *inq = 0; 19911189Sjkh int s; 2004910Swollman 2014910Swollman ifp->if_lastchange = time; 2024910Swollman if (ifp->if_flags & IFF_UP) 2034910Swollman /* Count received bytes, add FCS and one flag */ 2044910Swollman ifp->if_ibytes += m->m_pkthdr.len + 3; 2054910Swollman 2064910Swollman if (m->m_pkthdr.len <= PPP_HEADER_LEN) { 2074910Swollman /* Too small packet, drop it. */ 2084910Swollman if (ifp->if_flags & IFF_DEBUG) 2094910Swollman printf ("%s%d: input packet is too small, %d bytes\n", 2104910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 2114910Swollmandrop: ++ifp->if_iqdrops; 2124910Swollman m_freem (m); 2134910Swollman return; 2144910Swollman } 2154910Swollman 2164910Swollman /* Get PPP header. */ 2174910Swollman h = mtod (m, struct ppp_header*); 2184910Swollman m_adj (m, PPP_HEADER_LEN); 2194910Swollman 2204910Swollman switch (h->address) { 2214910Swollman default: /* Invalid PPP packet. */ 2224910Swollmaninvalid: if (ifp->if_flags & IFF_DEBUG) 2234910Swollman printf ("%s%d: invalid input packet <0x%x 0x%x 0x%x>\n", 2244910Swollman ifp->if_name, ifp->if_unit, 2254910Swollman h->address, h->control, ntohs (h->protocol)); 2264910Swollman goto drop; 2274910Swollman case PPP_ALLSTATIONS: 2284910Swollman if (h->control != PPP_UI) 2294910Swollman goto invalid; 23011189Sjkh if (sp->pp_flags & PP_CISCO) { 23111189Sjkh if (ifp->if_flags & IFF_DEBUG) 23211189Sjkh printf ("%s%d: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", 23311189Sjkh ifp->if_name, ifp->if_unit, 23411189Sjkh h->address, h->control, ntohs (h->protocol)); 23511189Sjkh goto drop; 23611189Sjkh } 2374910Swollman switch (ntohs (h->protocol)) { 2384910Swollman default: 2394910Swollman if (sp->lcp.state == LCP_STATE_OPENED) 2404910Swollman sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, 24111189Sjkh ++sp->pp_seq, m->m_pkthdr.len + 2, 2424910Swollman &h->protocol); 2434910Swollman if (ifp->if_flags & IFF_DEBUG) 2444910Swollman printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n", 2454910Swollman ifp->if_name, ifp->if_unit, 2464910Swollman h->address, h->control, ntohs (h->protocol)); 2474910Swollman ++ifp->if_noproto; 2484910Swollman goto drop; 2494910Swollman case PPP_LCP: 2504910Swollman sppp_lcp_input ((struct sppp*) ifp, m); 2514910Swollman m_freem (m); 2524910Swollman return; 2534910Swollman#ifdef INET 2544910Swollman case PPP_IPCP: 2554910Swollman if (sp->lcp.state == LCP_STATE_OPENED) 2564910Swollman sppp_ipcp_input ((struct sppp*) ifp, m); 2574910Swollman m_freem (m); 2584910Swollman return; 2594910Swollman case PPP_IP: 2604910Swollman if (sp->ipcp.state == IPCP_STATE_OPENED) { 2614910Swollman schednetisr (NETISR_IP); 2624910Swollman inq = &ipintrq; 2634910Swollman } 2644910Swollman break; 2654910Swollman#endif 2664910Swollman#ifdef NS 2674910Swollman case PPP_XNS: 2684910Swollman /* XNS IDPCP not implemented yet */ 2694910Swollman if (sp->lcp.state == LCP_STATE_OPENED) { 2704910Swollman schednetisr (NETISR_NS); 2714910Swollman inq = &nsintrq; 2724910Swollman } 2734910Swollman break; 2744910Swollman#endif 2754910Swollman#ifdef ISO 2764910Swollman case PPP_ISO: 2774910Swollman /* OSI NLCP not implemented yet */ 2784910Swollman if (sp->lcp.state == LCP_STATE_OPENED) { 2794910Swollman schednetisr (NETISR_ISO); 2804910Swollman inq = &clnlintrq; 2814910Swollman } 2824910Swollman break; 2834910Swollman#endif 2844910Swollman } 2854910Swollman break; 2864910Swollman case CISCO_MULTICAST: 2874910Swollman case CISCO_UNICAST: 2884910Swollman /* Don't check the control field here (RFC 1547). */ 28911189Sjkh if (! (sp->pp_flags & PP_CISCO)) { 29011189Sjkh if (ifp->if_flags & IFF_DEBUG) 29111189Sjkh printf ("%s%d: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", 29211189Sjkh ifp->if_name, ifp->if_unit, 29311189Sjkh h->address, h->control, ntohs (h->protocol)); 29411189Sjkh goto drop; 29511189Sjkh } 2964910Swollman switch (ntohs (h->protocol)) { 2974910Swollman default: 2984910Swollman ++ifp->if_noproto; 2994910Swollman goto invalid; 3004910Swollman case CISCO_KEEPALIVE: 3014910Swollman sppp_cisco_input ((struct sppp*) ifp, m); 3024910Swollman m_freem (m); 3034910Swollman return; 3044910Swollman#ifdef INET 3054910Swollman case ETHERTYPE_IP: 3064910Swollman schednetisr (NETISR_IP); 3074910Swollman inq = &ipintrq; 3084910Swollman break; 3094910Swollman#endif 3104910Swollman#ifdef NS 3114910Swollman case ETHERTYPE_NS: 3124910Swollman schednetisr (NETISR_NS); 3134910Swollman inq = &nsintrq; 3144910Swollman break; 3154910Swollman#endif 3164910Swollman } 3174910Swollman break; 3184910Swollman } 3194910Swollman 3204910Swollman if (! (ifp->if_flags & IFF_UP) || ! inq) 3214910Swollman goto drop; 3224910Swollman 3234910Swollman /* Check queue. */ 32411189Sjkh s = splimp (); 3254910Swollman if (IF_QFULL (inq)) { 3264910Swollman /* Queue overflow. */ 32711189Sjkh IF_DROP (inq); 32811189Sjkh splx (s); 3294910Swollman if (ifp->if_flags & IFF_DEBUG) 3304910Swollman printf ("%s%d: protocol queue overflow\n", 3314910Swollman ifp->if_name, ifp->if_unit); 3324910Swollman goto drop; 3334910Swollman } 3344910Swollman IF_ENQUEUE (inq, m); 33511189Sjkh splx (s); 3364910Swollman} 3374910Swollman 3384910Swollman/* 3394910Swollman * Enqueue transmit packet. 3404910Swollman */ 3414910Swollmanint sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) 3424910Swollman{ 3434910Swollman struct sppp *sp = (struct sppp*) ifp; 3444910Swollman struct ppp_header *h; 3454910Swollman struct ifqueue *ifq; 3464910Swollman int s = splimp (); 3474910Swollman 3484910Swollman if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) { 3494910Swollman m_freem (m); 3504910Swollman splx (s); 3514910Swollman return (ENETDOWN); 3524910Swollman } 3534910Swollman 3544910Swollman ifq = &ifp->if_snd; 3554910Swollman#ifdef INET 3564910Swollman /* 3574910Swollman * Put low delay, telnet, rlogin and ftp control packets 3584910Swollman * in front of the queue. 3594910Swollman */ 36012436Speter if (dst->sa_family == AF_INET) { 36112436Speter struct ip *ip = mtod (m, struct ip*); 36212436Speter struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); 3634910Swollman 36412436Speter if (! IF_QFULL (&sp->pp_fastq) && 36512436Speter ((ip->ip_tos & IPTOS_LOWDELAY) || 36612436Speter ip->ip_p == IPPROTO_TCP && 36712436Speter m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) && 36812436Speter (INTERACTIVE (ntohs (tcp->th_sport)) || 36912436Speter INTERACTIVE (ntohs (tcp->th_dport))))) 37012436Speter ifq = &sp->pp_fastq; 3714910Swollman } 3724910Swollman#endif 3734910Swollman 3744910Swollman /* 3754910Swollman * Prepend general data packet PPP header. For now, IP only. 3764910Swollman */ 3774910Swollman M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); 3784910Swollman if (! m) { 3794910Swollman if (ifp->if_flags & IFF_DEBUG) 3804910Swollman printf ("%s%d: no memory for transmit header\n", 3814910Swollman ifp->if_name, ifp->if_unit); 3824910Swollman splx (s); 3834910Swollman return (ENOBUFS); 3844910Swollman } 3854910Swollman h = mtod (m, struct ppp_header*); 3864910Swollman if (sp->pp_flags & PP_CISCO) { 3874910Swollman h->address = CISCO_MULTICAST; /* broadcast address */ 3884910Swollman h->control = 0; 3894910Swollman } else { 3904910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 3914910Swollman h->control = PPP_UI; /* Unnumbered Info */ 3924910Swollman } 3934910Swollman 3944910Swollman switch (dst->sa_family) { 3954910Swollman#ifdef INET 3964910Swollman case AF_INET: /* Internet Protocol */ 39711189Sjkh if (sp->pp_flags & PP_CISCO) 39811189Sjkh h->protocol = htons (ETHERTYPE_IP); 39911189Sjkh else if (sp->ipcp.state == IPCP_STATE_OPENED) 40011189Sjkh h->protocol = htons (PPP_IP); 40111189Sjkh else { 40211189Sjkh m_freem (m); 40311189Sjkh splx (s); 40411189Sjkh return (ENETDOWN); 40511189Sjkh } 4064910Swollman break; 4074910Swollman#endif 4084910Swollman#ifdef NS 4094910Swollman case AF_NS: /* Xerox NS Protocol */ 4104910Swollman h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 4114910Swollman ETHERTYPE_NS : PPP_XNS); 4124910Swollman break; 4134910Swollman#endif 41411819Sjulian#ifdef IPX 41511819Sjulian case AF_IPX: /* Xerox NS Protocol */ 41611819Sjulian h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 41711819Sjulian ETHERTYPE_IPX : PPP_XNS); 41811819Sjulian break; 41911819Sjulian#endif 4204910Swollman#ifdef ISO 4214910Swollman case AF_ISO: /* ISO OSI Protocol */ 4224910Swollman if (sp->pp_flags & PP_CISCO) 4234910Swollman goto nosupport; 4244910Swollman h->protocol = htons (PPP_ISO); 4254910Swollman break; 4264910Swollman#endif 4275099Swollmannosupport: 4284910Swollman default: 4294910Swollman m_freem (m); 4304910Swollman splx (s); 4314910Swollman return (EAFNOSUPPORT); 4324910Swollman } 4334910Swollman 4344910Swollman /* 4354910Swollman * Queue message on interface, and start output if interface 4364910Swollman * not yet active. 4374910Swollman */ 4384910Swollman if (IF_QFULL (ifq)) { 4394910Swollman IF_DROP (&ifp->if_snd); 4404910Swollman m_freem (m); 4414910Swollman splx (s); 4424910Swollman return (ENOBUFS); 4434910Swollman } 4444910Swollman IF_ENQUEUE (ifq, m); 4454910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 4464910Swollman (*ifp->if_start) (ifp); 4474910Swollman 4484910Swollman /* 4494910Swollman * Count output packets and bytes. 4504910Swollman * The packet length includes header, FCS and 1 flag, 4514910Swollman * according to RFC 1333. 4524910Swollman */ 4534910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 4544910Swollman ifp->if_lastchange = time; 4554910Swollman splx (s); 4564910Swollman return (0); 4574910Swollman} 4584910Swollman 4594910Swollmanvoid sppp_attach (struct ifnet *ifp) 4604910Swollman{ 4614910Swollman struct sppp *sp = (struct sppp*) ifp; 4624910Swollman 4634910Swollman /* Initialize keepalive handler. */ 4644910Swollman if (! spppq) 46511189Sjkh timeout (sppp_keepalive, 0, hz * 10); 4664910Swollman 4674910Swollman /* Insert new entry into the keepalive list. */ 4684910Swollman sp->pp_next = spppq; 4694910Swollman spppq = sp; 4704910Swollman 4714910Swollman sp->pp_if.if_type = IFT_PPP; 4724910Swollman sp->pp_if.if_output = sppp_output; 4734910Swollman sp->pp_fastq.ifq_maxlen = 32; 4744910Swollman sp->pp_loopcnt = 0; 4754910Swollman sp->pp_alivecnt = 0; 47611189Sjkh sp->pp_seq = 0; 4774910Swollman sp->pp_rseq = 0; 47811189Sjkh sp->lcp.magic = 0; 47911189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 48011189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 4814910Swollman} 4824910Swollman 4834910Swollmanvoid sppp_detach (struct ifnet *ifp) 4844910Swollman{ 4854910Swollman struct sppp **q, *p, *sp = (struct sppp*) ifp; 4864910Swollman 4874910Swollman /* Remove the entry from the keepalive list. */ 4884910Swollman for (q = &spppq; (p = *q); q = &p->pp_next) 4894910Swollman if (p == sp) { 4904910Swollman *q = p->pp_next; 4914910Swollman break; 4924910Swollman } 4934910Swollman 4944910Swollman /* Stop keepalive handler. */ 4954910Swollman if (! spppq) 49611189Sjkh untimeout (sppp_keepalive, 0); 49711189Sjkh UNTIMO (sp); 4984910Swollman} 4994910Swollman 5004910Swollman/* 5014910Swollman * Flush the interface output queue. 5024910Swollman */ 5034910Swollmanvoid sppp_flush (struct ifnet *ifp) 5044910Swollman{ 5054910Swollman struct sppp *sp = (struct sppp*) ifp; 5064910Swollman 5074910Swollman qflush (&sp->pp_if.if_snd); 5084910Swollman qflush (&sp->pp_fastq); 5094910Swollman} 5104910Swollman 5114910Swollman/* 51211189Sjkh * Check if the output queue is empty. 51311189Sjkh */ 51411189Sjkhint sppp_isempty (struct ifnet *ifp) 51511189Sjkh{ 51611189Sjkh struct sppp *sp = (struct sppp*) ifp; 51711189Sjkh int empty, s = splimp (); 51811189Sjkh 51911189Sjkh empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head; 52011189Sjkh splx (s); 52111189Sjkh return (empty); 52211189Sjkh} 52311189Sjkh 52411189Sjkh/* 5254910Swollman * Get next packet to send. 5264910Swollman */ 5274910Swollmanstruct mbuf *sppp_dequeue (struct ifnet *ifp) 5284910Swollman{ 5294910Swollman struct sppp *sp = (struct sppp*) ifp; 5304910Swollman struct mbuf *m; 5314910Swollman int s = splimp (); 5324910Swollman 5334910Swollman IF_DEQUEUE (&sp->pp_fastq, m); 5344910Swollman if (! m) 5354910Swollman IF_DEQUEUE (&sp->pp_if.if_snd, m); 5364910Swollman splx (s); 5374910Swollman return (m); 5384910Swollman} 5394910Swollman 5404910Swollman/* 5414910Swollman * Send keepalive packets, every 10 seconds. 5424910Swollman */ 54311189Sjkhvoid sppp_keepalive (void *dummy) 5444910Swollman{ 5454910Swollman struct sppp *sp; 5464910Swollman int s = splimp (); 5474910Swollman 5484910Swollman for (sp=spppq; sp; sp=sp->pp_next) { 5494910Swollman struct ifnet *ifp = &sp->pp_if; 5504910Swollman 55111189Sjkh /* Keepalive mode disabled or channel down? */ 5524910Swollman if (! (sp->pp_flags & PP_KEEPALIVE) || 55311189Sjkh ! (ifp->if_flags & IFF_RUNNING)) 55411189Sjkh continue; 55511189Sjkh 55611189Sjkh /* No keepalive in PPP mode if LCP not opened yet. */ 55711189Sjkh if (! (sp->pp_flags & PP_CISCO) && 5584910Swollman sp->lcp.state != LCP_STATE_OPENED) 5594910Swollman continue; 5604910Swollman 5614910Swollman if (sp->pp_alivecnt == MAXALIVECNT) { 5624910Swollman /* No keepalive packets got. Stop the interface. */ 5634910Swollman printf ("%s%d: down\n", ifp->if_name, ifp->if_unit); 5644910Swollman if_down (ifp); 5654910Swollman qflush (&sp->pp_fastq); 56611189Sjkh if (! (sp->pp_flags & PP_CISCO)) { 56711189Sjkh /* Shut down the PPP link. */ 56811189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 56911189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 57011189Sjkh UNTIMO (sp); 57111189Sjkh /* Initiate negotiation. */ 57211189Sjkh sppp_lcp_open (sp); 57311189Sjkh } 5744910Swollman } 5754910Swollman if (sp->pp_alivecnt <= MAXALIVECNT) 5764910Swollman ++sp->pp_alivecnt; 5774910Swollman if (sp->pp_flags & PP_CISCO) 5784910Swollman sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, 5794910Swollman sp->pp_rseq); 5804910Swollman else if (sp->lcp.state == LCP_STATE_OPENED) { 5814910Swollman long nmagic = htonl (sp->lcp.magic); 58211189Sjkh sp->lcp.echoid = ++sp->pp_seq; 5834910Swollman sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, 58411189Sjkh sp->lcp.echoid, 4, &nmagic); 5854910Swollman } 5864910Swollman } 5874910Swollman splx (s); 58811189Sjkh timeout (sppp_keepalive, 0, hz * 10); 5894910Swollman} 5904910Swollman 5914910Swollman/* 5924910Swollman * Handle incoming PPP Link Control Protocol packets. 5934910Swollman */ 5944910Swollmanvoid sppp_lcp_input (struct sppp *sp, struct mbuf *m) 5954910Swollman{ 5964910Swollman struct lcp_header *h; 5974910Swollman struct ifnet *ifp = &sp->pp_if; 5984910Swollman int len = m->m_pkthdr.len; 59911189Sjkh u_char *p, opt[6]; 60011189Sjkh u_long rmagic; 6014910Swollman 6024910Swollman if (len < 4) { 6034910Swollman if (ifp->if_flags & IFF_DEBUG) 6044910Swollman printf ("%s%d: invalid lcp packet length: %d bytes\n", 6054910Swollman ifp->if_name, ifp->if_unit, len); 6064910Swollman return; 6074910Swollman } 6084910Swollman h = mtod (m, struct lcp_header*); 6094910Swollman if (ifp->if_flags & IFF_DEBUG) { 61011189Sjkh char state = '?'; 61111189Sjkh switch (sp->lcp.state) { 61211189Sjkh case LCP_STATE_CLOSED: state = 'C'; break; 61311189Sjkh case LCP_STATE_ACK_RCVD: state = 'R'; break; 61411189Sjkh case LCP_STATE_ACK_SENT: state = 'S'; break; 61511189Sjkh case LCP_STATE_OPENED: state = 'O'; break; 61611189Sjkh } 61711189Sjkh printf ("%s%d: lcp input(%c): %d bytes <%s id=%xh len=%xh", 61811189Sjkh ifp->if_name, ifp->if_unit, state, len, 6194910Swollman sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); 6204910Swollman if (len > 4) 62111189Sjkh sppp_print_bytes ((u_char*) (h+1), len-4); 6224910Swollman printf (">\n"); 6234910Swollman } 6244910Swollman if (len > ntohs (h->len)) 6254910Swollman len = ntohs (h->len); 6264910Swollman switch (h->type) { 6274910Swollman default: 6284910Swollman /* Unknown packet type -- send Code-Reject packet. */ 62911189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, 63011189Sjkh m->m_pkthdr.len, h); 6314910Swollman break; 6324910Swollman case LCP_CONF_REQ: 6334910Swollman if (len < 4) { 6344910Swollman if (ifp->if_flags & IFF_DEBUG) 6354910Swollman printf ("%s%d: invalid lcp configure request packet length: %d bytes\n", 6364910Swollman ifp->if_name, ifp->if_unit, len); 63711189Sjkh break; 6384910Swollman } 63911189Sjkh if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) 64011189Sjkh goto badreq; 64111189Sjkh if (rmagic == sp->lcp.magic) { 64211189Sjkh /* Local and remote magics equal -- loopback? */ 64311189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT*5) { 64411189Sjkh printf ("%s%d: loopback\n", 64511189Sjkh ifp->if_name, ifp->if_unit); 64611189Sjkh sp->pp_loopcnt = 0; 64711189Sjkh if (ifp->if_flags & IFF_UP) { 64811189Sjkh if_down (ifp); 64911189Sjkh qflush (&sp->pp_fastq); 65011189Sjkh } 65111189Sjkh } else if (ifp->if_flags & IFF_DEBUG) 65211189Sjkh printf ("%s%d: conf req: magic glitch\n", 65311189Sjkh ifp->if_name, ifp->if_unit); 65411189Sjkh ++sp->pp_loopcnt; 65511189Sjkh 65611189Sjkh /* MUST send Conf-Nack packet. */ 65711189Sjkh rmagic = ~sp->lcp.magic; 65811189Sjkh opt[0] = LCP_OPT_MAGIC; 65911189Sjkh opt[1] = sizeof (opt); 66011189Sjkh opt[2] = rmagic >> 24; 66111189Sjkh opt[3] = rmagic >> 16; 66211189Sjkh opt[4] = rmagic >> 8; 66311189Sjkh opt[5] = rmagic; 66411189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, 66511189Sjkh h->ident, sizeof (opt), &opt); 66611189Sjkhbadreq: 66711189Sjkh switch (sp->lcp.state) { 66811189Sjkh case LCP_STATE_OPENED: 6694910Swollman /* Initiate renegotiation. */ 6704910Swollman sppp_lcp_open (sp); 67111189Sjkh /* fall through... */ 67211189Sjkh case LCP_STATE_ACK_SENT: 6734910Swollman /* Go to closed state. */ 6744910Swollman sp->lcp.state = LCP_STATE_CLOSED; 6754910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 6764910Swollman } 67711189Sjkh break; 67812436Speter } 67912436Speter /* Send Configure-Ack packet. */ 68012436Speter sp->pp_loopcnt = 0; 68112436Speter sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, 68212436Speter h->ident, len-4, h+1); 68312436Speter /* Change the state. */ 68411189Sjkh switch (sp->lcp.state) { 68511189Sjkh case LCP_STATE_CLOSED: 68611189Sjkh sp->lcp.state = LCP_STATE_ACK_SENT; 68711189Sjkh break; 68811189Sjkh case LCP_STATE_ACK_RCVD: 68912436Speter sp->lcp.state = LCP_STATE_OPENED; 69012436Speter sppp_ipcp_open (sp); 69111189Sjkh break; 69211189Sjkh case LCP_STATE_OPENED: 69311189Sjkh /* Remote magic changed -- close session. */ 69411189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 69511189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 69611189Sjkh /* Initiate renegotiation. */ 69711189Sjkh sppp_lcp_open (sp); 69812436Speter /* An ACK has already been sent. */ 69912436Speter sp->lcp.state = LCP_STATE_ACK_SENT; 70011189Sjkh break; 7014910Swollman } 7024910Swollman break; 7034910Swollman case LCP_CONF_ACK: 70411189Sjkh if (h->ident != sp->lcp.confid) 70511189Sjkh break; 70611189Sjkh UNTIMO (sp); 70711189Sjkh if (! (ifp->if_flags & IFF_UP) && 70811189Sjkh (ifp->if_flags & IFF_RUNNING)) { 70911189Sjkh /* Coming out of loopback mode. */ 71011189Sjkh ifp->if_flags |= IFF_UP; 71111189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 71211189Sjkh } 7134910Swollman switch (sp->lcp.state) { 7144910Swollman case LCP_STATE_CLOSED: 7154910Swollman sp->lcp.state = LCP_STATE_ACK_RCVD; 71611189Sjkh TIMO (sp, 5); 7174910Swollman break; 7184910Swollman case LCP_STATE_ACK_SENT: 7194910Swollman sp->lcp.state = LCP_STATE_OPENED; 7204910Swollman sppp_ipcp_open (sp); 7214910Swollman break; 7224910Swollman } 7234910Swollman break; 7244910Swollman case LCP_CONF_NAK: 72511189Sjkh if (h->ident != sp->lcp.confid) 72611189Sjkh break; 72711189Sjkh p = (u_char*) (h+1); 7284910Swollman if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { 72911189Sjkh rmagic = (u_long)p[2] << 24 | 73011189Sjkh (u_long)p[3] << 16 | p[4] << 8 | p[5]; 73111189Sjkh if (rmagic == ~sp->lcp.magic) { 7324910Swollman if (ifp->if_flags & IFF_DEBUG) 7334910Swollman printf ("%s%d: conf nak: magic glitch\n", 7344910Swollman ifp->if_name, ifp->if_unit); 73511189Sjkh sp->lcp.magic += time.tv_sec + time.tv_usec; 73611189Sjkh } else 73711189Sjkh sp->lcp.magic = rmagic; 7384910Swollman } 73911189Sjkh if (sp->lcp.state != LCP_STATE_ACK_SENT) { 74011189Sjkh /* Go to closed state. */ 74111189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 74211189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 7434910Swollman } 74411189Sjkh /* The link will be renegotiated after timeout, 74511189Sjkh * to avoid endless req-nack loop. */ 74611189Sjkh UNTIMO (sp); 74711189Sjkh TIMO (sp, 2); 74811189Sjkh break; 7494910Swollman case LCP_CONF_REJ: 75011189Sjkh if (h->ident != sp->lcp.confid) 75111189Sjkh break; 75211189Sjkh UNTIMO (sp); 7534910Swollman /* Initiate renegotiation. */ 7544910Swollman sppp_lcp_open (sp); 7554910Swollman if (sp->lcp.state != LCP_STATE_ACK_SENT) { 7564910Swollman /* Go to closed state. */ 7574910Swollman sp->lcp.state = LCP_STATE_CLOSED; 7584910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 7594910Swollman } 7604910Swollman break; 7614910Swollman case LCP_TERM_REQ: 76211189Sjkh UNTIMO (sp); 7634910Swollman /* Send Terminate-Ack packet. */ 7644910Swollman sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); 7654910Swollman /* Go to closed state. */ 7664910Swollman sp->lcp.state = LCP_STATE_CLOSED; 7674910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 76812436Speter /* Initiate renegotiation. */ 76912436Speter sppp_lcp_open (sp); 7704910Swollman break; 77111189Sjkh case LCP_TERM_ACK: 7724910Swollman case LCP_CODE_REJ: 7734910Swollman case LCP_PROTO_REJ: 7744910Swollman /* Ignore for now. */ 7754910Swollman break; 7764910Swollman case LCP_DISC_REQ: 7774910Swollman /* Discard the packet. */ 7784910Swollman break; 7794910Swollman case LCP_ECHO_REQ: 78012436Speter if (sp->lcp.state != LCP_STATE_OPENED) 78112436Speter break; 7824910Swollman if (len < 8) { 7834910Swollman if (ifp->if_flags & IFF_DEBUG) 7844910Swollman printf ("%s%d: invalid lcp echo request packet length: %d bytes\n", 7854910Swollman ifp->if_name, ifp->if_unit, len); 78611189Sjkh break; 7874910Swollman } 7884910Swollman if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { 78911189Sjkh /* Line loopback mode detected. */ 79011189Sjkh printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); 79111189Sjkh if_down (ifp); 79211189Sjkh qflush (&sp->pp_fastq); 79311189Sjkh 79411189Sjkh /* Shut down the PPP link. */ 79511189Sjkh sp->lcp.state = LCP_STATE_CLOSED; 79611189Sjkh sp->ipcp.state = IPCP_STATE_CLOSED; 79711189Sjkh UNTIMO (sp); 79811189Sjkh /* Initiate negotiation. */ 79911189Sjkh sppp_lcp_open (sp); 80011189Sjkh break; 8014910Swollman } 8024910Swollman *(long*)(h+1) = htonl (sp->lcp.magic); 8034910Swollman sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); 8044910Swollman break; 8054910Swollman case LCP_ECHO_REPLY: 80611189Sjkh if (h->ident != sp->lcp.echoid) 80711189Sjkh break; 8084910Swollman if (len < 8) { 8094910Swollman if (ifp->if_flags & IFF_DEBUG) 8104910Swollman printf ("%s%d: invalid lcp echo reply packet length: %d bytes\n", 8114910Swollman ifp->if_name, ifp->if_unit, len); 81211189Sjkh break; 8134910Swollman } 81411189Sjkh if (ntohl (*(long*)(h+1)) != sp->lcp.magic) 8154910Swollman sp->pp_alivecnt = 0; 8164910Swollman break; 8174910Swollman } 8184910Swollman} 8194910Swollman 8204910Swollman/* 8214910Swollman * Handle incoming Cisco keepalive protocol packets. 8224910Swollman */ 8234910Swollmanvoid sppp_cisco_input (struct sppp *sp, struct mbuf *m) 8244910Swollman{ 8254910Swollman struct cisco_packet *h; 8264910Swollman struct ifaddr *ifa; 8274910Swollman struct ifnet *ifp = &sp->pp_if; 8284910Swollman 8294910Swollman if (m->m_pkthdr.len != CISCO_PACKET_LEN) { 8304910Swollman if (ifp->if_flags & IFF_DEBUG) 8314910Swollman printf ("%s%d: invalid cisco packet length: %d bytes\n", 8324910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 8334910Swollman return; 8344910Swollman } 8354910Swollman h = mtod (m, struct cisco_packet*); 8364910Swollman if (ifp->if_flags & IFF_DEBUG) 83711189Sjkh printf ("%s%d: cisco input: %d bytes <%lxh %lxh %lxh %xh %xh-%xh>\n", 8384910Swollman ifp->if_name, ifp->if_unit, m->m_pkthdr.len, 8394910Swollman ntohl (h->type), h->par1, h->par2, h->rel, 8404910Swollman h->time0, h->time1); 8414910Swollman switch (ntohl (h->type)) { 8424910Swollman default: 8434910Swollman if (ifp->if_flags & IFF_DEBUG) 8448456Srgrimes printf ("%s%d: unknown cisco packet type: 0x%lx\n", 8454910Swollman ifp->if_name, ifp->if_unit, ntohl (h->type)); 8464910Swollman break; 8474910Swollman case CISCO_ADDR_REPLY: 8484910Swollman /* Reply on address request, ignore */ 8494910Swollman break; 8504910Swollman case CISCO_KEEPALIVE_REQ: 8514910Swollman sp->pp_alivecnt = 0; 8524910Swollman sp->pp_rseq = ntohl (h->par1); 8534910Swollman if (sp->pp_seq == sp->pp_rseq) { 8544910Swollman /* Local and remote sequence numbers are equal. 8554910Swollman * Probably, the line is in loopback mode. */ 85611189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT) { 85711189Sjkh printf ("%s%d: loopback\n", 85811189Sjkh ifp->if_name, ifp->if_unit); 85911189Sjkh sp->pp_loopcnt = 0; 86011189Sjkh if (ifp->if_flags & IFF_UP) { 86111189Sjkh if_down (ifp); 86211189Sjkh qflush (&sp->pp_fastq); 86311189Sjkh } 86411189Sjkh } 8654910Swollman ++sp->pp_loopcnt; 8664910Swollman 8674910Swollman /* Generate new local sequence number */ 8684910Swollman sp->pp_seq ^= time.tv_sec ^ time.tv_usec; 86911189Sjkh break; 87011189Sjkh } 8714910Swollman sp->pp_loopcnt = 0; 87211189Sjkh if (! (ifp->if_flags & IFF_UP) && 87311189Sjkh (ifp->if_flags & IFF_RUNNING)) { 87411189Sjkh ifp->if_flags |= IFF_UP; 87511189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 87611189Sjkh } 8774910Swollman break; 8784910Swollman case CISCO_ADDR_REQ: 8794910Swollman for (ifa=ifp->if_addrlist; ifa; ifa=ifa->ifa_next) 8804910Swollman if (ifa->ifa_addr->sa_family == AF_INET) 8814910Swollman break; 8824910Swollman if (! ifa) { 8834910Swollman if (ifp->if_flags & IFF_DEBUG) 8844910Swollman printf ("%s%d: unknown address for cisco request\n", 8854910Swollman ifp->if_name, ifp->if_unit); 8864910Swollman return; 8874910Swollman } 8884910Swollman sppp_cisco_send (sp, CISCO_ADDR_REPLY, 8894910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr), 8904910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr)); 8914910Swollman break; 8924910Swollman } 8934910Swollman} 8944910Swollman 8954910Swollman/* 8964910Swollman * Send PPP LCP packet. 8974910Swollman */ 89811189Sjkhvoid sppp_cp_send (struct sppp *sp, u_short proto, u_char type, 89911189Sjkh u_char ident, u_short len, void *data) 9004910Swollman{ 9014910Swollman struct ppp_header *h; 9024910Swollman struct lcp_header *lh; 9034910Swollman struct mbuf *m; 9044910Swollman struct ifnet *ifp = &sp->pp_if; 9054910Swollman 9064910Swollman if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) 9074910Swollman len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; 9084910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9094910Swollman if (! m) 9104910Swollman return; 9114910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; 9124910Swollman m->m_pkthdr.rcvif = 0; 9134910Swollman 9144910Swollman h = mtod (m, struct ppp_header*); 9154910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 9164910Swollman h->control = PPP_UI; /* Unnumbered Info */ 9174910Swollman h->protocol = htons (proto); /* Link Control Protocol */ 9184910Swollman 9194910Swollman lh = (struct lcp_header*) (h + 1); 9204910Swollman lh->type = type; 9214910Swollman lh->ident = ident; 9224910Swollman lh->len = htons (LCP_HEADER_LEN + len); 9234910Swollman if (len) 9244910Swollman bcopy (data, lh+1, len); 9254910Swollman 9264910Swollman if (ifp->if_flags & IFF_DEBUG) { 9274910Swollman printf ("%s%d: %s output <%s id=%xh len=%xh", 9284910Swollman ifp->if_name, ifp->if_unit, 9294910Swollman proto==PPP_LCP ? "lcp" : "ipcp", 9304910Swollman proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : 9314910Swollman sppp_ipcp_type_name (lh->type), lh->ident, 9324910Swollman ntohs (lh->len)); 9334910Swollman if (len) 93411189Sjkh sppp_print_bytes ((u_char*) (lh+1), len); 9354910Swollman printf (">\n"); 9364910Swollman } 9374910Swollman if (IF_QFULL (&sp->pp_fastq)) { 9384910Swollman IF_DROP (&ifp->if_snd); 9394910Swollman m_freem (m); 9404910Swollman } else 9414910Swollman IF_ENQUEUE (&sp->pp_fastq, m); 9424910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 9434910Swollman (*ifp->if_start) (ifp); 9444910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 9454910Swollman} 9464910Swollman 9474910Swollman/* 9484910Swollman * Send Cisco keepalive packet. 9494910Swollman */ 9504910Swollmanvoid sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) 9514910Swollman{ 9524910Swollman struct ppp_header *h; 9534910Swollman struct cisco_packet *ch; 9544910Swollman struct mbuf *m; 9554910Swollman struct ifnet *ifp = &sp->pp_if; 95611189Sjkh u_long t = (time.tv_sec - boottime.tv_sec) * 1000; 9574910Swollman 9584910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9594910Swollman if (! m) 9604910Swollman return; 9614910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; 9624910Swollman m->m_pkthdr.rcvif = 0; 9634910Swollman 9644910Swollman h = mtod (m, struct ppp_header*); 9654910Swollman h->address = CISCO_MULTICAST; 9664910Swollman h->control = 0; 9674910Swollman h->protocol = htons (CISCO_KEEPALIVE); 9684910Swollman 9694910Swollman ch = (struct cisco_packet*) (h + 1); 9704910Swollman ch->type = htonl (type); 9714910Swollman ch->par1 = htonl (par1); 9724910Swollman ch->par2 = htonl (par2); 9734910Swollman ch->rel = -1; 97411189Sjkh ch->time0 = htons ((u_short) (t >> 16)); 97511189Sjkh ch->time1 = htons ((u_short) t); 9764910Swollman 9774910Swollman if (ifp->if_flags & IFF_DEBUG) 9788456Srgrimes printf ("%s%d: cisco output: <%lxh %lxh %lxh %xh %xh-%xh>\n", 9794910Swollman ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1, 9804910Swollman ch->par2, ch->rel, ch->time0, ch->time1); 9814910Swollman 9824910Swollman if (IF_QFULL (&sp->pp_fastq)) { 9834910Swollman IF_DROP (&ifp->if_snd); 9844910Swollman m_freem (m); 9854910Swollman } else 9864910Swollman IF_ENQUEUE (&sp->pp_fastq, m); 9874910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 9884910Swollman (*ifp->if_start) (ifp); 9894910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 9904910Swollman} 9914910Swollman 9924910Swollman/* 9934910Swollman * Process an ioctl request. Called on low priority level. 9944910Swollman */ 99511189Sjkhint sppp_ioctl (struct ifnet *ifp, int cmd, void *data) 9964910Swollman{ 9974910Swollman struct ifreq *ifr = (struct ifreq*) data; 99811189Sjkh struct sppp *sp = (struct sppp*) ifp; 99911189Sjkh int s, going_up, going_down; 10004910Swollman 10014910Swollman switch (cmd) { 10024910Swollman default: 10034910Swollman return (EINVAL); 10044910Swollman 10054910Swollman case SIOCAIFADDR: 10064910Swollman case SIOCSIFDSTADDR: 10074910Swollman break; 10084910Swollman 100911189Sjkh case SIOCSIFADDR: 101011189Sjkh ifp->if_flags |= IFF_UP; 101111189Sjkh /* fall through... */ 101211189Sjkh 10134910Swollman case SIOCSIFFLAGS: 10144910Swollman s = splimp (); 101511189Sjkh going_up = (ifp->if_flags & IFF_UP) && 101611189Sjkh ! (ifp->if_flags & IFF_RUNNING); 101711189Sjkh going_down = ! (ifp->if_flags & IFF_UP) && 101811189Sjkh (ifp->if_flags & IFF_RUNNING); 101911189Sjkh if (going_up || going_down) { 102011189Sjkh /* Shut down the PPP link. */ 102111189Sjkh ifp->if_flags &= ~IFF_RUNNING; 10224910Swollman sp->lcp.state = LCP_STATE_CLOSED; 10234910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 102411189Sjkh UNTIMO (sp); 102511189Sjkh } 102611189Sjkh if (going_up) { 102711189Sjkh /* Interface is starting -- initiate negotiation. */ 102811189Sjkh ifp->if_flags |= IFF_RUNNING; 102912436Speter if (!(sp->pp_flags & PP_CISCO)) 103012436Speter sppp_lcp_open (sp); 10314910Swollman } 10324910Swollman splx (s); 10334910Swollman break; 10344910Swollman 10354910Swollman#ifdef SIOCSIFMTU 10364910Swollman#ifndef ifr_mtu 10374910Swollman#define ifr_mtu ifr_metric 10384910Swollman#endif 10394910Swollman case SIOCSIFMTU: 10404910Swollman if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > PP_MTU) 10414910Swollman return (EINVAL); 10424910Swollman ifp->if_mtu = ifr->ifr_mtu; 10434910Swollman break; 10444910Swollman#endif 10454910Swollman#ifdef SLIOCSETMTU 10464910Swollman case SLIOCSETMTU: 10474910Swollman if (*(short*)data < 128 || *(short*)data > PP_MTU) 10484910Swollman return (EINVAL); 10494910Swollman ifp->if_mtu = *(short*)data; 10504910Swollman break; 10514910Swollman#endif 10524910Swollman#ifdef SIOCGIFMTU 10534910Swollman case SIOCGIFMTU: 10544910Swollman ifr->ifr_mtu = ifp->if_mtu; 10554910Swollman break; 10564910Swollman#endif 10574910Swollman#ifdef SLIOCGETMTU 10584910Swollman case SLIOCGETMTU: 10594910Swollman *(short*)data = ifp->if_mtu; 10604910Swollman break; 10614910Swollman#endif 10624910Swollman#ifdef MULTICAST 10634910Swollman case SIOCADDMULTI: 10644910Swollman case SIOCDELMULTI: 10654910Swollman break; 10664910Swollman#endif 10674910Swollman } 10684910Swollman return (0); 10694910Swollman} 10704910Swollman 107111189Sjkh/* 107211189Sjkh * Analyze the LCP Configure-Request options list 107311189Sjkh * for the presence of unknown options. 107411189Sjkh * If the request contains unknown options, build and 107511189Sjkh * send Configure-reject packet, containing only unknown options. 107611189Sjkh */ 107711189Sjkhint sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, 107811189Sjkh int len, u_long *magic) 10794910Swollman{ 108011189Sjkh u_char *buf, *r, *p; 108111189Sjkh int rlen; 10824910Swollman 108311189Sjkh len -= 4; 108411189Sjkh buf = r = malloc (len, M_TEMP, M_NOWAIT); 108511189Sjkh if (! buf) 108611189Sjkh return (0); 10874910Swollman 108811189Sjkh p = (void*) (h+1); 108911189Sjkh for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 109011189Sjkh switch (*p) { 109111189Sjkh case LCP_OPT_MAGIC: 109211189Sjkh /* Magic number -- extract. */ 109311189Sjkh if (len >= 6 && p[1] == 6) { 109411189Sjkh *magic = (u_long)p[2] << 24 | 109511189Sjkh (u_long)p[3] << 16 | p[4] << 8 | p[5]; 109611189Sjkh continue; 109711189Sjkh } 109811189Sjkh break; 109911189Sjkh case LCP_OPT_ASYNC_MAP: 110011189Sjkh /* Async control character map -- check to be zero. */ 110111189Sjkh if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && 110211189Sjkh ! p[4] && ! p[5]) 110311189Sjkh continue; 110411189Sjkh break; 110511189Sjkh case LCP_OPT_MRU: 110611189Sjkh /* Maximum receive unit -- always OK. */ 110711189Sjkh continue; 110811189Sjkh default: 110911189Sjkh /* Others not supported. */ 111011189Sjkh break; 111111189Sjkh } 111211189Sjkh /* Add the option to rejected list. */ 11134910Swollman bcopy (p, r, p[1]); 11144910Swollman r += p[1]; 111511189Sjkh rlen += p[1]; 111612436Speter } 111711189Sjkh if (rlen) 11184910Swollman sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); 111911189Sjkh free (buf, M_TEMP); 112011189Sjkh return (rlen == 0); 11214910Swollman} 11224910Swollman 11234910Swollmanvoid sppp_ipcp_input (struct sppp *sp, struct mbuf *m) 11244910Swollman{ 11254910Swollman struct lcp_header *h; 11264910Swollman struct ifnet *ifp = &sp->pp_if; 11274910Swollman int len = m->m_pkthdr.len; 11284910Swollman 11294910Swollman if (len < 4) { 11304910Swollman /* if (ifp->if_flags & IFF_DEBUG) */ 11314910Swollman printf ("%s%d: invalid ipcp packet length: %d bytes\n", 11324910Swollman ifp->if_name, ifp->if_unit, len); 11334910Swollman return; 11344910Swollman } 11354910Swollman h = mtod (m, struct lcp_header*); 11364910Swollman if (ifp->if_flags & IFF_DEBUG) { 11374910Swollman printf ("%s%d: ipcp input: %d bytes <%s id=%xh len=%xh", 11384910Swollman ifp->if_name, ifp->if_unit, len, 11394910Swollman sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); 11404910Swollman if (len > 4) 114111189Sjkh sppp_print_bytes ((u_char*) (h+1), len-4); 11424910Swollman printf (">\n"); 11434910Swollman } 11444910Swollman if (len > ntohs (h->len)) 11454910Swollman len = ntohs (h->len); 11464910Swollman switch (h->type) { 11474910Swollman default: 11484910Swollman /* Unknown packet type -- send Code-Reject packet. */ 11494910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); 11504910Swollman break; 11514910Swollman case IPCP_CONF_REQ: 11524910Swollman if (len < 4) { 11534910Swollman if (ifp->if_flags & IFF_DEBUG) 11544910Swollman printf ("%s%d: invalid ipcp configure request packet length: %d bytes\n", 11554910Swollman ifp->if_name, ifp->if_unit, len); 11564910Swollman return; 11574910Swollman } 11584910Swollman if (len > 4) { 11594910Swollman sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, 11604910Swollman len-4, h+1); 116111189Sjkh 116211189Sjkh switch (sp->ipcp.state) { 116311189Sjkh case IPCP_STATE_OPENED: 11644910Swollman /* Initiate renegotiation. */ 11654910Swollman sppp_ipcp_open (sp); 116611189Sjkh /* fall through... */ 116711189Sjkh case IPCP_STATE_ACK_SENT: 11684910Swollman /* Go to closed state. */ 11694910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 117011189Sjkh } 11714910Swollman } else { 11724910Swollman /* Send Configure-Ack packet. */ 11734910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, 11744910Swollman 0, 0); 11754910Swollman /* Change the state. */ 117611189Sjkh if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) 117711189Sjkh sp->ipcp.state = IPCP_STATE_OPENED; 117811189Sjkh else 117911189Sjkh sp->ipcp.state = IPCP_STATE_ACK_SENT; 11804910Swollman } 11814910Swollman break; 11824910Swollman case IPCP_CONF_ACK: 118311189Sjkh if (h->ident != sp->ipcp.confid) 118411189Sjkh break; 118511189Sjkh UNTIMO (sp); 11864910Swollman switch (sp->ipcp.state) { 11874910Swollman case IPCP_STATE_CLOSED: 11884910Swollman sp->ipcp.state = IPCP_STATE_ACK_RCVD; 118911189Sjkh TIMO (sp, 5); 11904910Swollman break; 11914910Swollman case IPCP_STATE_ACK_SENT: 11924910Swollman sp->ipcp.state = IPCP_STATE_OPENED; 11934910Swollman break; 11944910Swollman } 11954910Swollman break; 11964910Swollman case IPCP_CONF_NAK: 11974910Swollman case IPCP_CONF_REJ: 119811189Sjkh if (h->ident != sp->ipcp.confid) 119911189Sjkh break; 120011189Sjkh UNTIMO (sp); 12014910Swollman /* Initiate renegotiation. */ 12024910Swollman sppp_ipcp_open (sp); 12034910Swollman if (sp->ipcp.state != IPCP_STATE_ACK_SENT) 12044910Swollman /* Go to closed state. */ 12054910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 12064910Swollman break; 12074910Swollman case IPCP_TERM_REQ: 12084910Swollman /* Send Terminate-Ack packet. */ 12094910Swollman sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); 12104910Swollman /* Go to closed state. */ 12114910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 12124910Swollman /* Initiate renegotiation. */ 12134910Swollman sppp_ipcp_open (sp); 12144910Swollman break; 121511189Sjkh case IPCP_TERM_ACK: 121611189Sjkh /* Ignore for now. */ 12174910Swollman case IPCP_CODE_REJ: 12184910Swollman /* Ignore for now. */ 12194910Swollman break; 12204910Swollman } 12214910Swollman} 12224910Swollman 12234910Swollmanvoid sppp_lcp_open (struct sppp *sp) 12244910Swollman{ 12254910Swollman char opt[6]; 12264910Swollman 122711189Sjkh if (! sp->lcp.magic) 12284910Swollman sp->lcp.magic = time.tv_sec + time.tv_usec; 12294910Swollman opt[0] = LCP_OPT_MAGIC; 12304910Swollman opt[1] = sizeof (opt); 12314910Swollman opt[2] = sp->lcp.magic >> 24; 12324910Swollman opt[3] = sp->lcp.magic >> 16; 12334910Swollman opt[4] = sp->lcp.magic >> 8; 12344910Swollman opt[5] = sp->lcp.magic; 123511189Sjkh sp->lcp.confid = ++sp->pp_seq; 123611189Sjkh sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, 12374910Swollman sizeof (opt), &opt); 123811189Sjkh TIMO (sp, 2); 12394910Swollman} 12404910Swollman 12414910Swollmanvoid sppp_ipcp_open (struct sppp *sp) 12424910Swollman{ 124311189Sjkh sp->ipcp.confid = ++sp->pp_seq; 124411189Sjkh sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); 124511189Sjkh TIMO (sp, 2); 12464910Swollman} 12474910Swollman 12484910Swollman/* 12494910Swollman * Process PPP control protocol timeouts. 12504910Swollman */ 125111189Sjkhvoid sppp_cp_timeout (void *arg) 12524910Swollman{ 12534910Swollman struct sppp *sp = (struct sppp*) arg; 12544910Swollman int s = splimp (); 12554910Swollman 125611189Sjkh sp->pp_flags &= ~PP_TIMO; 125711189Sjkh if (! (sp->pp_if.if_flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { 125811189Sjkh splx (s); 125911189Sjkh return; 126011189Sjkh } 12614910Swollman switch (sp->lcp.state) { 12624910Swollman case LCP_STATE_CLOSED: 12634910Swollman /* No ACK for Configure-Request, retry. */ 12644910Swollman sppp_lcp_open (sp); 12654910Swollman break; 12664910Swollman case LCP_STATE_ACK_RCVD: 12674910Swollman /* ACK got, but no Configure-Request for peer, retry. */ 12684910Swollman sppp_lcp_open (sp); 12694910Swollman sp->lcp.state = LCP_STATE_CLOSED; 12704910Swollman break; 12714910Swollman case LCP_STATE_ACK_SENT: 12724910Swollman /* ACK sent but no ACK for Configure-Request, retry. */ 12734910Swollman sppp_lcp_open (sp); 12744910Swollman break; 12754910Swollman case LCP_STATE_OPENED: 12764910Swollman /* LCP is already OK, try IPCP. */ 12774910Swollman switch (sp->ipcp.state) { 12784910Swollman case IPCP_STATE_CLOSED: 12794910Swollman /* No ACK for Configure-Request, retry. */ 12804910Swollman sppp_ipcp_open (sp); 12814910Swollman break; 12824910Swollman case IPCP_STATE_ACK_RCVD: 12834910Swollman /* ACK got, but no Configure-Request for peer, retry. */ 12844910Swollman sppp_ipcp_open (sp); 12854910Swollman sp->ipcp.state = IPCP_STATE_CLOSED; 12864910Swollman break; 12874910Swollman case IPCP_STATE_ACK_SENT: 12884910Swollman /* ACK sent but no ACK for Configure-Request, retry. */ 12894910Swollman sppp_ipcp_open (sp); 12904910Swollman break; 12914910Swollman case IPCP_STATE_OPENED: 12924910Swollman /* IPCP is OK. */ 12934910Swollman break; 12944910Swollman } 12954910Swollman break; 12964910Swollman } 12974910Swollman splx (s); 12984910Swollman} 12994910Swollman 130011189Sjkhchar *sppp_lcp_type_name (u_char type) 13014910Swollman{ 13024910Swollman static char buf [8]; 13034910Swollman switch (type) { 13044910Swollman case LCP_CONF_REQ: return ("conf-req"); 13054910Swollman case LCP_CONF_ACK: return ("conf-ack"); 13064910Swollman case LCP_CONF_NAK: return ("conf-nack"); 13074910Swollman case LCP_CONF_REJ: return ("conf-rej"); 13084910Swollman case LCP_TERM_REQ: return ("term-req"); 13094910Swollman case LCP_TERM_ACK: return ("term-ack"); 13104910Swollman case LCP_CODE_REJ: return ("code-rej"); 13114910Swollman case LCP_PROTO_REJ: return ("proto-rej"); 13124910Swollman case LCP_ECHO_REQ: return ("echo-req"); 13134910Swollman case LCP_ECHO_REPLY: return ("echo-reply"); 13144910Swollman case LCP_DISC_REQ: return ("discard-req"); 13154910Swollman } 13164910Swollman sprintf (buf, "%xh", type); 13174910Swollman return (buf); 13184910Swollman} 13194910Swollman 132011189Sjkhchar *sppp_ipcp_type_name (u_char type) 13214910Swollman{ 13224910Swollman static char buf [8]; 13234910Swollman switch (type) { 13244910Swollman case IPCP_CONF_REQ: return ("conf-req"); 13254910Swollman case IPCP_CONF_ACK: return ("conf-ack"); 13264910Swollman case IPCP_CONF_NAK: return ("conf-nack"); 13274910Swollman case IPCP_CONF_REJ: return ("conf-rej"); 13284910Swollman case IPCP_TERM_REQ: return ("term-req"); 13294910Swollman case IPCP_TERM_ACK: return ("term-ack"); 13304910Swollman case IPCP_CODE_REJ: return ("code-rej"); 13314910Swollman } 13324910Swollman sprintf (buf, "%xh", type); 13334910Swollman return (buf); 13344910Swollman} 13354910Swollman 133611189Sjkhvoid sppp_print_bytes (u_char *p, u_short len) 13374910Swollman{ 13384910Swollman printf (" %x", *p++); 13394910Swollman while (--len > 0) 13404910Swollman printf ("-%x", *p++); 13414910Swollman} 1342