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