if_spppsubr.c revision 25944
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. 625944Sjoerg * Author: Serge Vakulenko, <vak@cronyx.ru> 74910Swollman * 825944Sjoerg * Heavily revamped to conform to RFC 1661. 925944Sjoerg * Copyright (C) 1997, Joerg Wunsch. 1025944Sjoerg * 114910Swollman * This software is distributed with NO WARRANTIES, not even the implied 124910Swollman * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 134910Swollman * 144910Swollman * Authors grant any other persons or organisations permission to use 154910Swollman * or modify this software as long as this message is kept with the software, 164910Swollman * all derivative works or modified versions. 174910Swollman * 1825944Sjoerg * From: Version 1.9, Wed Oct 4 18:58:15 MSK 1995 1916288Sgpalmer * 2025944Sjoerg * $Id: if_spppsubr.c,v 1.18 1997/05/11 10:04:24 joerg Exp $ 214910Swollman */ 224910Swollman 234910Swollman#include <sys/param.h> 244952Sbde#include <sys/systm.h> 254952Sbde#include <sys/kernel.h> 2624204Sbde#include <sys/sockio.h> 274910Swollman#include <sys/socket.h> 2825706Sjoerg#include <sys/syslog.h> 294910Swollman#include <sys/mbuf.h> 304910Swollman 314910Swollman#include <net/if.h> 324910Swollman#include <net/netisr.h> 334910Swollman#include <net/if_types.h> 344910Swollman 354910Swollman#ifdef INET 364910Swollman#include <netinet/in.h> 374910Swollman#include <netinet/in_systm.h> 384910Swollman#include <netinet/in_var.h> 394910Swollman#include <netinet/ip.h> 404910Swollman#include <netinet/tcp.h> 414910Swollman#include <netinet/if_ether.h> 424910Swollman#endif 434910Swollman 4411819Sjulian#ifdef IPX 4511819Sjulian#include <netipx/ipx.h> 4611819Sjulian#include <netipx/ipx_if.h> 4711819Sjulian#endif 4811819Sjulian 494910Swollman#ifdef NS 504910Swollman#include <netns/ns.h> 514910Swollman#include <netns/ns_if.h> 524910Swollman#endif 534910Swollman 544910Swollman#ifdef ISO 554910Swollman#include <netiso/argo_debug.h> 564910Swollman#include <netiso/iso.h> 574910Swollman#include <netiso/iso_var.h> 584910Swollman#include <netiso/iso_snpac.h> 594910Swollman#endif 604910Swollman 614910Swollman#include <net/if_sppp.h> 624910Swollman 634910Swollman#define MAXALIVECNT 3 /* max. alive packets */ 644910Swollman 6525944Sjoerg/* 6625944Sjoerg * Interface flags that can be set in an ifconfig command. 6725944Sjoerg * 6825944Sjoerg * Setting link0 will cause the link to auto-dial only as packets 6925944Sjoerg * arrive to be sent. 7025944Sjoerg * 7125944Sjoerg * Setting link1 will make the link passive, i.e. it will be marked 7225944Sjoerg * as being administrative openable, but won't be opened to begin 7325944Sjoerg * with. Incoming calls will be answered, or subsequent calls with 7425944Sjoerg * -link1 will cause the administrative open of the LCP layer. 7525944Sjoerg */ 7625944Sjoerg 7725944Sjoerg#define IFF_AUTO IFF_LINK0 /* auto-dial on output */ 7825944Sjoerg#define IFF_PASSIVE IFF_LINK1 /* wait passively for connection */ 7925944Sjoerg 804910Swollman#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ 814910Swollman#define PPP_UI 0x03 /* Unnumbered Information */ 824910Swollman#define PPP_IP 0x0021 /* Internet Protocol */ 834910Swollman#define PPP_ISO 0x0023 /* ISO OSI Protocol */ 844910Swollman#define PPP_XNS 0x0025 /* Xerox NS Protocol */ 8512495Speter#define PPP_IPX 0x002b /* Novell IPX Protocol */ 864910Swollman#define PPP_LCP 0xc021 /* Link Control Protocol */ 874910Swollman#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ 884910Swollman 8925944Sjoerg#define CONF_REQ 1 /* PPP configure request */ 9025944Sjoerg#define CONF_ACK 2 /* PPP configure acknowledge */ 9125944Sjoerg#define CONF_NAK 3 /* PPP configure negative ack */ 9225944Sjoerg#define CONF_REJ 4 /* PPP configure reject */ 9325944Sjoerg#define TERM_REQ 5 /* PPP terminate request */ 9425944Sjoerg#define TERM_ACK 6 /* PPP terminate acknowledge */ 9525944Sjoerg#define CODE_REJ 7 /* PPP code reject */ 9625944Sjoerg#define PROTO_REJ 8 /* PPP protocol reject */ 9725944Sjoerg#define ECHO_REQ 9 /* PPP echo request */ 9825944Sjoerg#define ECHO_REPLY 10 /* PPP echo reply */ 9925944Sjoerg#define DISC_REQ 11 /* PPP discard request */ 1004910Swollman 1014910Swollman#define LCP_OPT_MRU 1 /* maximum receive unit */ 1024910Swollman#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ 1034910Swollman#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ 1044910Swollman#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ 1054910Swollman#define LCP_OPT_MAGIC 5 /* magic number */ 1064910Swollman#define LCP_OPT_RESERVED 6 /* reserved */ 1074910Swollman#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ 1084910Swollman#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ 1094910Swollman 11025944Sjoerg#define IPCP_OPT_ADDRESSES 1 /* both IP addresses; deprecated */ 11125944Sjoerg#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */ 11225944Sjoerg#define IPCP_OPT_ADDRESS 3 /* local IP address */ 1134910Swollman 1144910Swollman#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ 1154910Swollman#define CISCO_UNICAST 0x0f /* Cisco unicast address */ 1164910Swollman#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ 1174910Swollman#define CISCO_ADDR_REQ 0 /* Cisco address request */ 1184910Swollman#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ 1194910Swollman#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ 1204910Swollman 12125944Sjoerg/* states are named and numbered according to RFC 1661 */ 12225944Sjoerg#define STATE_INITIAL 0 12325944Sjoerg#define STATE_STARTING 1 12425944Sjoerg#define STATE_CLOSED 2 12525944Sjoerg#define STATE_STOPPED 3 12625944Sjoerg#define STATE_CLOSING 4 12725944Sjoerg#define STATE_STOPPING 5 12825944Sjoerg#define STATE_REQ_SENT 6 12925944Sjoerg#define STATE_ACK_RCVD 7 13025944Sjoerg#define STATE_ACK_SENT 8 13125944Sjoerg#define STATE_OPENED 9 13225944Sjoerg 1334910Swollmanstruct ppp_header { 13411189Sjkh u_char address; 13511189Sjkh u_char control; 13611189Sjkh u_short protocol; 1374910Swollman}; 1384910Swollman#define PPP_HEADER_LEN sizeof (struct ppp_header) 1394910Swollman 1404910Swollmanstruct lcp_header { 14111189Sjkh u_char type; 14211189Sjkh u_char ident; 14311189Sjkh u_short len; 1444910Swollman}; 1454910Swollman#define LCP_HEADER_LEN sizeof (struct lcp_header) 1464910Swollman 1474910Swollmanstruct cisco_packet { 14811189Sjkh u_long type; 14911189Sjkh u_long par1; 15011189Sjkh u_long par2; 15111189Sjkh u_short rel; 15211189Sjkh u_short time0; 15311189Sjkh u_short time1; 1544910Swollman}; 1554910Swollman#define CISCO_PACKET_LEN 18 1564910Swollman 15725944Sjoerg/* 15825944Sjoerg * We follow the spelling and capitalization of RFC 1661 here, to make 15925944Sjoerg * it easier comparing with the standard. Please refer to this RFC in 16025944Sjoerg * case you can't make sense out of these abbreviation; it will also 16125944Sjoerg * explain the semantics related to the various events and actions. 16225944Sjoerg */ 16325944Sjoergstruct cp { 16425944Sjoerg u_short proto; /* PPP control protocol number */ 16525944Sjoerg u_char protoidx; /* index into state table in struct sppp */ 16625944Sjoerg u_char flags; 16725944Sjoerg#define CP_LCP 0x01 /* this is the LCP */ 16825944Sjoerg#define CP_AUTH 0x02 /* this is an authentication protocol */ 16925944Sjoerg#define CP_NCP 0x04 /* this is a NCP */ 17025944Sjoerg#define CP_QUAL 0x08 /* this is a quality reporting protocol */ 17125944Sjoerg const char *name; /* name of this control protocol */ 17225944Sjoerg /* event handlers */ 17325944Sjoerg void (*Up)(struct sppp *sp); 17425944Sjoerg void (*Down)(struct sppp *sp); 17525944Sjoerg void (*Open)(struct sppp *sp); 17625944Sjoerg void (*Close)(struct sppp *sp); 17725944Sjoerg void (*TO)(void *sp); 17825944Sjoerg int (*RCR)(struct sppp *sp, struct lcp_header *h, int len); 17925944Sjoerg void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len); 18025944Sjoerg void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len); 18125944Sjoerg /* actions */ 18225944Sjoerg void (*tlu)(struct sppp *sp); 18325944Sjoerg void (*tld)(struct sppp *sp); 18425944Sjoerg void (*tls)(struct sppp *sp); 18525944Sjoerg void (*tlf)(struct sppp *sp); 18625944Sjoerg void (*scr)(struct sppp *sp); 18725944Sjoerg}; 18825944Sjoerg 18912820Sphkstatic struct sppp *spppq; 1904910Swollman 1914910Swollman/* 1924910Swollman * The following disgusting hack gets around the problem that IP TOS 1934910Swollman * can't be set yet. We want to put "interactive" traffic on a high 1944910Swollman * priority queue. To decide if traffic is interactive, we check that 1954910Swollman * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 1964910Swollman */ 19711189Sjkhstatic u_short interactive_ports[8] = { 1984910Swollman 0, 513, 0, 0, 1994910Swollman 0, 21, 0, 23, 2004910Swollman}; 2014910Swollman#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 2024910Swollman 20325944Sjoerg/* almost every function needs these */ 20425944Sjoerg#define STDDCL \ 20525944Sjoerg struct ifnet *ifp = &sp->pp_if; \ 20625944Sjoerg int debug = ifp->if_flags & IFF_DEBUG 20711189Sjkh 20825944Sjoergstatic int sppp_output(struct ifnet *ifp, struct mbuf *m, 20925944Sjoerg struct sockaddr *dst, struct rtentry *rt); 2104910Swollman 21125944Sjoergstatic void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2); 21225944Sjoergstatic void sppp_cisco_input(struct sppp *sp, struct mbuf *m); 21325944Sjoerg 21425944Sjoergstatic void sppp_cp_input(const struct cp *cp, struct sppp *sp, 21525944Sjoerg struct mbuf *m); 21625944Sjoergstatic void sppp_cp_send(struct sppp *sp, u_short proto, u_char type, 21725944Sjoerg u_char ident, u_short len, void *data); 21825944Sjoergstatic void sppp_cp_timeout(void *arg); 21925944Sjoergstatic void sppp_cp_change_state(const struct cp *cp, struct sppp *sp, 22025944Sjoerg int newstate); 22125944Sjoerg 22225944Sjoergstatic void sppp_up_event(const struct cp *cp, struct sppp *sp); 22325944Sjoergstatic void sppp_down_event(const struct cp *cp, struct sppp *sp); 22425944Sjoergstatic void sppp_open_event(const struct cp *cp, struct sppp *sp); 22525944Sjoergstatic void sppp_close_event(const struct cp *cp, struct sppp *sp); 22625944Sjoergstatic void sppp_to_event(const struct cp *cp, struct sppp *sp); 22725944Sjoerg 22825944Sjoergstatic void sppp_lcp_init(struct sppp *sp); 22925944Sjoergstatic void sppp_lcp_up(struct sppp *sp); 23025944Sjoergstatic void sppp_lcp_down(struct sppp *sp); 23125944Sjoergstatic void sppp_lcp_open(struct sppp *sp); 23225944Sjoergstatic void sppp_lcp_close(struct sppp *sp); 23325944Sjoergstatic void sppp_lcp_TO(void *sp); 23425944Sjoergstatic int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len); 23525944Sjoergstatic void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); 23625944Sjoergstatic void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); 23725944Sjoergstatic void sppp_lcp_tlu(struct sppp *sp); 23825944Sjoergstatic void sppp_lcp_tld(struct sppp *sp); 23925944Sjoergstatic void sppp_lcp_tls(struct sppp *sp); 24025944Sjoergstatic void sppp_lcp_tlf(struct sppp *sp); 24125944Sjoergstatic void sppp_lcp_scr(struct sppp *sp); 24225944Sjoergstatic void sppp_lcp_check(struct sppp *sp); 24325944Sjoerg 24425944Sjoergstatic void sppp_ipcp_init(struct sppp *sp); 24525944Sjoergstatic void sppp_ipcp_up(struct sppp *sp); 24625944Sjoergstatic void sppp_ipcp_down(struct sppp *sp); 24725944Sjoergstatic void sppp_ipcp_open(struct sppp *sp); 24825944Sjoergstatic void sppp_ipcp_close(struct sppp *sp); 24925944Sjoergstatic void sppp_ipcp_TO(void *sp); 25025944Sjoergstatic int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len); 25125944Sjoergstatic void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); 25225944Sjoergstatic void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); 25325944Sjoergstatic void sppp_ipcp_tlu(struct sppp *sp); 25425944Sjoergstatic void sppp_ipcp_tld(struct sppp *sp); 25525944Sjoergstatic void sppp_ipcp_tls(struct sppp *sp); 25625944Sjoergstatic void sppp_ipcp_tlf(struct sppp *sp); 25725944Sjoergstatic void sppp_ipcp_scr(struct sppp *sp); 25825944Sjoerg 25925944Sjoergstatic const char *sppp_cp_type_name(u_char type); 26025944Sjoergstatic const char *sppp_lcp_opt_name(u_char opt); 26125944Sjoergstatic const char *sppp_ipcp_opt_name(u_char opt); 26225944Sjoergstatic const char *sppp_state_name(int state); 26325944Sjoergstatic const char *sppp_phase_name(enum ppp_phase phase); 26425944Sjoergstatic const char *sppp_proto_name(u_short proto); 26525944Sjoerg 26625944Sjoergstatic void sppp_keepalive(void *dummy); 26725944Sjoergstatic void sppp_qflush(struct ifqueue *ifq); 26825944Sjoerg 26925944Sjoergstatic void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst); 27025944Sjoergstatic void sppp_set_ip_addr(struct sppp *sp, u_long src); 27125944Sjoerg 27225944Sjoergstatic void sppp_print_bytes(u_char *p, u_short len); 27325944Sjoerg 27425944Sjoerg/* our control protocol descriptors */ 27525944Sjoergconst struct cp lcp = { 27625944Sjoerg PPP_LCP, IDX_LCP, CP_LCP, "lcp", 27725944Sjoerg sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close, 27825944Sjoerg sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak, 27925944Sjoerg sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf, 28025944Sjoerg sppp_lcp_scr 28125944Sjoerg}; 28225944Sjoerg 28325944Sjoergconst struct cp ipcp = { 28425944Sjoerg PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp", 28525944Sjoerg sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close, 28625944Sjoerg sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak, 28725944Sjoerg sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf, 28825944Sjoerg sppp_ipcp_scr 28925944Sjoerg}; 29025944Sjoerg 29125944Sjoergconst struct cp *cps[IDX_COUNT] = { 29225944Sjoerg &lcp, /* IDX_LCP */ 29325944Sjoerg &ipcp, /* IDX_IPCP */ 29425944Sjoerg}; 29525944Sjoerg 29625944Sjoerg 29725944Sjoerg/* 29825944Sjoerg * Exported functions, comprising our interface to the lower layer. 2994910Swollman */ 3004910Swollman 3014910Swollman/* 3024910Swollman * Process the received packet. 3034910Swollman */ 30425706Sjoergvoid 30525706Sjoergsppp_input(struct ifnet *ifp, struct mbuf *m) 3064910Swollman{ 3074910Swollman struct ppp_header *h; 3084910Swollman struct ifqueue *inq = 0; 30911189Sjkh int s; 31025944Sjoerg struct sppp *sp = (struct sppp *)ifp; 31125944Sjoerg int debug = ifp->if_flags & IFF_DEBUG; 3124910Swollman 3134910Swollman if (ifp->if_flags & IFF_UP) 3144910Swollman /* Count received bytes, add FCS and one flag */ 3154910Swollman ifp->if_ibytes += m->m_pkthdr.len + 3; 3164910Swollman 3174910Swollman if (m->m_pkthdr.len <= PPP_HEADER_LEN) { 3184910Swollman /* Too small packet, drop it. */ 31925944Sjoerg if (debug) 32025706Sjoerg log(LOG_DEBUG, 32125706Sjoerg "%s%d: input packet is too small, %d bytes\n", 32225706Sjoerg ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 32325944Sjoerg drop: 32425944Sjoerg ++ifp->if_ierrors; 32525944Sjoerg ++ifp->if_iqdrops; 3264910Swollman m_freem (m); 3274910Swollman return; 3284910Swollman } 3294910Swollman 3304910Swollman /* Get PPP header. */ 3314910Swollman h = mtod (m, struct ppp_header*); 3324910Swollman m_adj (m, PPP_HEADER_LEN); 3334910Swollman 3344910Swollman switch (h->address) { 3354910Swollman case PPP_ALLSTATIONS: 3364910Swollman if (h->control != PPP_UI) 3374910Swollman goto invalid; 33811189Sjkh if (sp->pp_flags & PP_CISCO) { 33925944Sjoerg if (debug) 34025706Sjoerg log(LOG_DEBUG, 34125706Sjoerg "%s%d: PPP packet in Cisco mode " 34225706Sjoerg "<addr=0x%x ctrl=0x%x proto=0x%x>\n", 34325706Sjoerg ifp->if_name, ifp->if_unit, 34425706Sjoerg h->address, h->control, ntohs(h->protocol)); 34511189Sjkh goto drop; 34611189Sjkh } 3474910Swollman switch (ntohs (h->protocol)) { 3484910Swollman default: 34925944Sjoerg if (sp->state[IDX_LCP] == STATE_OPENED) 35025944Sjoerg sppp_cp_send (sp, PPP_LCP, PROTO_REJ, 35111189Sjkh ++sp->pp_seq, m->m_pkthdr.len + 2, 3524910Swollman &h->protocol); 35325944Sjoerg if (debug) 35425706Sjoerg log(LOG_DEBUG, 35525706Sjoerg "%s%d: invalid input protocol " 35625706Sjoerg "<addr=0x%x ctrl=0x%x proto=0x%x>\n", 35725706Sjoerg ifp->if_name, ifp->if_unit, 35825706Sjoerg h->address, h->control, ntohs(h->protocol)); 3594910Swollman ++ifp->if_noproto; 3604910Swollman goto drop; 3614910Swollman case PPP_LCP: 36225944Sjoerg sppp_cp_input(&lcp, (struct sppp*)ifp, m); 3634910Swollman m_freem (m); 3644910Swollman return; 3654910Swollman#ifdef INET 3664910Swollman case PPP_IPCP: 36725944Sjoerg if (sp->pp_phase == PHASE_NETWORK) 36825944Sjoerg sppp_cp_input(&ipcp, (struct sppp*) ifp, m); 3694910Swollman m_freem (m); 3704910Swollman return; 3714910Swollman case PPP_IP: 37225944Sjoerg if (sp->state[IDX_IPCP] == STATE_OPENED) { 3734910Swollman schednetisr (NETISR_IP); 3744910Swollman inq = &ipintrq; 3754910Swollman } 3764910Swollman break; 3774910Swollman#endif 37812495Speter#ifdef IPX 37912495Speter case PPP_IPX: 38012495Speter /* IPX IPXCP not implemented yet */ 38125944Sjoerg if (sp->pp_phase == PHASE_NETWORK) { 38212495Speter schednetisr (NETISR_IPX); 38312495Speter inq = &ipxintrq; 38412495Speter } 38512495Speter break; 38612495Speter#endif 3874910Swollman#ifdef NS 3884910Swollman case PPP_XNS: 3894910Swollman /* XNS IDPCP not implemented yet */ 39025944Sjoerg if (sp->pp_phase == PHASE_NETWORK) { 3914910Swollman schednetisr (NETISR_NS); 3924910Swollman inq = &nsintrq; 3934910Swollman } 3944910Swollman break; 3954910Swollman#endif 3964910Swollman#ifdef ISO 3974910Swollman case PPP_ISO: 3984910Swollman /* OSI NLCP not implemented yet */ 39925944Sjoerg if (sp->pp_phase == PHASE_NETWORK) { 4004910Swollman schednetisr (NETISR_ISO); 4014910Swollman inq = &clnlintrq; 4024910Swollman } 4034910Swollman break; 4044910Swollman#endif 4054910Swollman } 4064910Swollman break; 4074910Swollman case CISCO_MULTICAST: 4084910Swollman case CISCO_UNICAST: 4094910Swollman /* Don't check the control field here (RFC 1547). */ 41011189Sjkh if (! (sp->pp_flags & PP_CISCO)) { 41125944Sjoerg if (debug) 41225706Sjoerg log(LOG_DEBUG, 41325706Sjoerg "%s%d: Cisco packet in PPP mode " 41425706Sjoerg "<addr=0x%x ctrl=0x%x proto=0x%x>\n", 41525706Sjoerg ifp->if_name, ifp->if_unit, 41625706Sjoerg h->address, h->control, ntohs(h->protocol)); 41711189Sjkh goto drop; 41811189Sjkh } 4194910Swollman switch (ntohs (h->protocol)) { 4204910Swollman default: 4214910Swollman ++ifp->if_noproto; 4224910Swollman goto invalid; 4234910Swollman case CISCO_KEEPALIVE: 4244910Swollman sppp_cisco_input ((struct sppp*) ifp, m); 4254910Swollman m_freem (m); 4264910Swollman return; 4274910Swollman#ifdef INET 4284910Swollman case ETHERTYPE_IP: 4294910Swollman schednetisr (NETISR_IP); 4304910Swollman inq = &ipintrq; 4314910Swollman break; 4324910Swollman#endif 43312495Speter#ifdef IPX 43412495Speter case ETHERTYPE_IPX: 43512495Speter schednetisr (NETISR_IPX); 43612495Speter inq = &ipxintrq; 43712495Speter break; 43812495Speter#endif 4394910Swollman#ifdef NS 4404910Swollman case ETHERTYPE_NS: 4414910Swollman schednetisr (NETISR_NS); 4424910Swollman inq = &nsintrq; 4434910Swollman break; 4444910Swollman#endif 4454910Swollman } 4464910Swollman break; 44725944Sjoerg default: /* Invalid PPP packet. */ 44825944Sjoerg invalid: 44925944Sjoerg if (debug) 45025944Sjoerg log(LOG_DEBUG, 45125944Sjoerg "%s%d: invalid input packet " 45225944Sjoerg "<addr=0x%x ctrl=0x%x proto=0x%x>\n", 45325944Sjoerg ifp->if_name, ifp->if_unit, 45425944Sjoerg h->address, h->control, ntohs(h->protocol)); 45525944Sjoerg goto drop; 4564910Swollman } 4574910Swollman 4584910Swollman if (! (ifp->if_flags & IFF_UP) || ! inq) 4594910Swollman goto drop; 4604910Swollman 4614910Swollman /* Check queue. */ 46225944Sjoerg s = splimp(); 4634910Swollman if (IF_QFULL (inq)) { 4644910Swollman /* Queue overflow. */ 46525944Sjoerg IF_DROP(inq); 46625944Sjoerg splx(s); 46725944Sjoerg if (debug) 46825706Sjoerg log(LOG_DEBUG, "%s%d: protocol queue overflow\n", 4694910Swollman ifp->if_name, ifp->if_unit); 4704910Swollman goto drop; 4714910Swollman } 47225944Sjoerg IF_ENQUEUE(inq, m); 47325944Sjoerg splx(s); 4744910Swollman} 4754910Swollman 4764910Swollman/* 4774910Swollman * Enqueue transmit packet. 4784910Swollman */ 47912820Sphkstatic int 48025706Sjoergsppp_output(struct ifnet *ifp, struct mbuf *m, 48125706Sjoerg struct sockaddr *dst, struct rtentry *rt) 4824910Swollman{ 4834910Swollman struct sppp *sp = (struct sppp*) ifp; 4844910Swollman struct ppp_header *h; 4854910Swollman struct ifqueue *ifq; 48625944Sjoerg int s; 4874910Swollman 48825944Sjoerg s = splimp(); 48925944Sjoerg 49025944Sjoerg if ((ifp->if_flags & IFF_UP) == 0 || 49125944Sjoerg (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) { 4924910Swollman m_freem (m); 4934910Swollman splx (s); 4944910Swollman return (ENETDOWN); 4954910Swollman } 4964910Swollman 49725944Sjoerg if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) { 49825944Sjoerg /* 49925944Sjoerg * Interface is not yet running, but auto-dial. Need 50025944Sjoerg * to start LCP for it. 50125944Sjoerg */ 50225944Sjoerg ifp->if_flags |= IFF_RUNNING; 50325944Sjoerg splx(s); 50425944Sjoerg lcp.Open(sp); 50525944Sjoerg s = splimp(); 50625944Sjoerg } 50725944Sjoerg 5084910Swollman ifq = &ifp->if_snd; 5094910Swollman#ifdef INET 5104910Swollman /* 5114910Swollman * Put low delay, telnet, rlogin and ftp control packets 5124910Swollman * in front of the queue. 5134910Swollman */ 51412436Speter if (dst->sa_family == AF_INET) { 51512436Speter struct ip *ip = mtod (m, struct ip*); 51612436Speter struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); 5174910Swollman 51812436Speter if (! IF_QFULL (&sp->pp_fastq) && 51912436Speter ((ip->ip_tos & IPTOS_LOWDELAY) || 52012436Speter ip->ip_p == IPPROTO_TCP && 52112436Speter m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) && 52212436Speter (INTERACTIVE (ntohs (tcp->th_sport)) || 52312436Speter INTERACTIVE (ntohs (tcp->th_dport))))) 52412436Speter ifq = &sp->pp_fastq; 5254910Swollman } 5264910Swollman#endif 5274910Swollman 5284910Swollman /* 5294910Swollman * Prepend general data packet PPP header. For now, IP only. 5304910Swollman */ 5314910Swollman M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); 5324910Swollman if (! m) { 5334910Swollman if (ifp->if_flags & IFF_DEBUG) 53425706Sjoerg log(LOG_DEBUG, "%s%d: no memory for transmit header\n", 5354910Swollman ifp->if_name, ifp->if_unit); 53625944Sjoerg ++ifp->if_oerrors; 5374910Swollman splx (s); 5384910Swollman return (ENOBUFS); 5394910Swollman } 5404910Swollman h = mtod (m, struct ppp_header*); 5414910Swollman if (sp->pp_flags & PP_CISCO) { 5424910Swollman h->address = CISCO_MULTICAST; /* broadcast address */ 5434910Swollman h->control = 0; 5444910Swollman } else { 5454910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 5464910Swollman h->control = PPP_UI; /* Unnumbered Info */ 5474910Swollman } 5484910Swollman 5494910Swollman switch (dst->sa_family) { 5504910Swollman#ifdef INET 5514910Swollman case AF_INET: /* Internet Protocol */ 55211189Sjkh if (sp->pp_flags & PP_CISCO) 55311189Sjkh h->protocol = htons (ETHERTYPE_IP); 55425944Sjoerg else if (sp->state[IDX_IPCP] == STATE_OPENED) 55511189Sjkh h->protocol = htons (PPP_IP); 55611189Sjkh else { 55711189Sjkh m_freem (m); 55825944Sjoerg ++ifp->if_oerrors; 55911189Sjkh splx (s); 56011189Sjkh return (ENETDOWN); 56111189Sjkh } 5624910Swollman break; 5634910Swollman#endif 5644910Swollman#ifdef NS 5654910Swollman case AF_NS: /* Xerox NS Protocol */ 5664910Swollman h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 5674910Swollman ETHERTYPE_NS : PPP_XNS); 5684910Swollman break; 5694910Swollman#endif 57011819Sjulian#ifdef IPX 57112495Speter case AF_IPX: /* Novell IPX Protocol */ 57211819Sjulian h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 57312495Speter ETHERTYPE_IPX : PPP_IPX); 57411819Sjulian break; 57511819Sjulian#endif 5764910Swollman#ifdef ISO 5774910Swollman case AF_ISO: /* ISO OSI Protocol */ 5784910Swollman if (sp->pp_flags & PP_CISCO) 5794910Swollman goto nosupport; 5804910Swollman h->protocol = htons (PPP_ISO); 5814910Swollman break; 58212820Sphknosupport: 5834910Swollman#endif 5844910Swollman default: 5854910Swollman m_freem (m); 58625944Sjoerg ++ifp->if_oerrors; 5874910Swollman splx (s); 5884910Swollman return (EAFNOSUPPORT); 5894910Swollman } 5904910Swollman 5914910Swollman /* 5924910Swollman * Queue message on interface, and start output if interface 5934910Swollman * not yet active. 5944910Swollman */ 5954910Swollman if (IF_QFULL (ifq)) { 5964910Swollman IF_DROP (&ifp->if_snd); 5974910Swollman m_freem (m); 59825944Sjoerg ++ifp->if_oerrors; 5994910Swollman splx (s); 6004910Swollman return (ENOBUFS); 6014910Swollman } 6024910Swollman IF_ENQUEUE (ifq, m); 6034910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 6044910Swollman (*ifp->if_start) (ifp); 6054910Swollman 6064910Swollman /* 6074910Swollman * Count output packets and bytes. 6084910Swollman * The packet length includes header, FCS and 1 flag, 6094910Swollman * according to RFC 1333. 6104910Swollman */ 6114910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 6124910Swollman splx (s); 6134910Swollman return (0); 6144910Swollman} 6154910Swollman 61625706Sjoergvoid 61725706Sjoergsppp_attach(struct ifnet *ifp) 6184910Swollman{ 6194910Swollman struct sppp *sp = (struct sppp*) ifp; 6204910Swollman 6214910Swollman /* Initialize keepalive handler. */ 6224910Swollman if (! spppq) 62311189Sjkh timeout (sppp_keepalive, 0, hz * 10); 6244910Swollman 6254910Swollman /* Insert new entry into the keepalive list. */ 6264910Swollman sp->pp_next = spppq; 6274910Swollman spppq = sp; 6284910Swollman 6294910Swollman sp->pp_if.if_type = IFT_PPP; 6304910Swollman sp->pp_if.if_output = sppp_output; 6314910Swollman sp->pp_fastq.ifq_maxlen = 32; 6324910Swollman sp->pp_loopcnt = 0; 6334910Swollman sp->pp_alivecnt = 0; 63411189Sjkh sp->pp_seq = 0; 6354910Swollman sp->pp_rseq = 0; 63625944Sjoerg sp->pp_phase = PHASE_DEAD; 63725944Sjoerg sp->pp_up = lcp.Up; 63825944Sjoerg sp->pp_down = lcp.Down; 63925944Sjoerg 64025944Sjoerg sppp_lcp_init(sp); 64125944Sjoerg sppp_ipcp_init(sp); 6424910Swollman} 6434910Swollman 64412820Sphkvoid 64525706Sjoergsppp_detach(struct ifnet *ifp) 6464910Swollman{ 6474910Swollman struct sppp **q, *p, *sp = (struct sppp*) ifp; 64825944Sjoerg int i; 6494910Swollman 6504910Swollman /* Remove the entry from the keepalive list. */ 6514910Swollman for (q = &spppq; (p = *q); q = &p->pp_next) 6524910Swollman if (p == sp) { 6534910Swollman *q = p->pp_next; 6544910Swollman break; 6554910Swollman } 6564910Swollman 6574910Swollman /* Stop keepalive handler. */ 6584910Swollman if (! spppq) 65911189Sjkh untimeout (sppp_keepalive, 0); 66025944Sjoerg 66125944Sjoerg for (i = 0; i < IDX_COUNT; i++) 66225944Sjoerg untimeout((cps[i])->TO, (void *)sp); 6634910Swollman} 6644910Swollman 6654910Swollman/* 6664910Swollman * Flush the interface output queue. 6674910Swollman */ 66825706Sjoergvoid 66925706Sjoergsppp_flush(struct ifnet *ifp) 6704910Swollman{ 6714910Swollman struct sppp *sp = (struct sppp*) ifp; 6724910Swollman 67325944Sjoerg sppp_qflush (&sp->pp_if.if_snd); 67425944Sjoerg sppp_qflush (&sp->pp_fastq); 6754910Swollman} 6764910Swollman 6774910Swollman/* 67811189Sjkh * Check if the output queue is empty. 67911189Sjkh */ 68012820Sphkint 68125706Sjoergsppp_isempty(struct ifnet *ifp) 68211189Sjkh{ 68311189Sjkh struct sppp *sp = (struct sppp*) ifp; 68425944Sjoerg int empty, s; 68511189Sjkh 68625944Sjoerg s = splimp(); 68711189Sjkh empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head; 68825944Sjoerg splx(s); 68911189Sjkh return (empty); 69011189Sjkh} 69111189Sjkh 69211189Sjkh/* 6934910Swollman * Get next packet to send. 6944910Swollman */ 69525706Sjoergstruct mbuf * 69625706Sjoergsppp_dequeue(struct ifnet *ifp) 6974910Swollman{ 6984910Swollman struct sppp *sp = (struct sppp*) ifp; 6994910Swollman struct mbuf *m; 70025944Sjoerg int s; 7014910Swollman 70225944Sjoerg s = splimp(); 7034910Swollman IF_DEQUEUE (&sp->pp_fastq, m); 7044910Swollman if (! m) 7054910Swollman IF_DEQUEUE (&sp->pp_if.if_snd, m); 7064910Swollman splx (s); 7074910Swollman return (m); 7084910Swollman} 7094910Swollman 7104910Swollman/* 71125944Sjoerg * Process an ioctl request. Called on low priority level. 7124910Swollman */ 71325944Sjoergint 71425944Sjoergsppp_ioctl(struct ifnet *ifp, int cmd, void *data) 7154910Swollman{ 71625944Sjoerg struct ifreq *ifr = (struct ifreq*) data; 71725944Sjoerg struct sppp *sp = (struct sppp*) ifp; 71825944Sjoerg int s, going_up, going_down, newmode; 7194910Swollman 72025944Sjoerg s = splimp(); 72125944Sjoerg switch (cmd) { 72225944Sjoerg case SIOCAIFADDR: 72325944Sjoerg case SIOCSIFDSTADDR: 72425944Sjoerg break; 7254910Swollman 72625944Sjoerg case SIOCSIFADDR: 72725944Sjoerg if_up(ifp); 72825944Sjoerg /* fall through... */ 72911189Sjkh 73025944Sjoerg case SIOCSIFFLAGS: 73125944Sjoerg going_up = ifp->if_flags & IFF_UP && 73225944Sjoerg (ifp->if_flags & IFF_RUNNING) == 0; 73325944Sjoerg going_down = (ifp->if_flags & IFF_UP) == 0 && 73425944Sjoerg ifp->if_flags & IFF_RUNNING; 73525944Sjoerg newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE); 73625944Sjoerg if (newmode == (IFF_AUTO | IFF_PASSIVE)) { 73725944Sjoerg /* sanity */ 73825944Sjoerg newmode = IFF_PASSIVE; 73925944Sjoerg ifp->if_flags &= ~IFF_AUTO; 7404910Swollman } 7414910Swollman 74225944Sjoerg if (going_up || going_down) 74325944Sjoerg lcp.Close(sp); 74425944Sjoerg if (going_up && newmode == 0) { 74525944Sjoerg /* neither auto-dial nor passive */ 74625944Sjoerg ifp->if_flags |= IFF_RUNNING; 74725944Sjoerg if (!(sp->pp_flags & PP_CISCO)) 74825944Sjoerg lcp.Open(sp); 74925944Sjoerg } else if (going_down) 75025944Sjoerg ifp->if_flags &= ~IFF_RUNNING; 7514910Swollman 7524910Swollman break; 75311189Sjkh 75425944Sjoerg#ifdef SIOCSIFMTU 75525944Sjoerg#ifndef ifr_mtu 75625944Sjoerg#define ifr_mtu ifr_metric 75725944Sjoerg#endif 75825944Sjoerg case SIOCSIFMTU: 75925944Sjoerg if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru) 76025944Sjoerg return (EINVAL); 76125944Sjoerg ifp->if_mtu = ifr->ifr_mtu; 7624910Swollman break; 76325944Sjoerg#endif 76425944Sjoerg#ifdef SLIOCSETMTU 76525944Sjoerg case SLIOCSETMTU: 76625944Sjoerg if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru) 76725944Sjoerg return (EINVAL); 76825944Sjoerg ifp->if_mtu = *(short*)data; 7694910Swollman break; 77025944Sjoerg#endif 77125944Sjoerg#ifdef SIOCGIFMTU 77225944Sjoerg case SIOCGIFMTU: 77325944Sjoerg ifr->ifr_mtu = ifp->if_mtu; 77411189Sjkh break; 77525944Sjoerg#endif 77625944Sjoerg#ifdef SLIOCGETMTU 77725944Sjoerg case SLIOCGETMTU: 77825944Sjoerg *(short*)data = ifp->if_mtu; 7794910Swollman break; 78025944Sjoerg#endif 78125944Sjoerg case SIOCADDMULTI: 78225944Sjoerg case SIOCDELMULTI: 7834910Swollman break; 78411189Sjkh 78525944Sjoerg default: 78625944Sjoerg splx(s); 78725944Sjoerg return (ENOTTY); 7884910Swollman } 78925944Sjoerg splx(s); 79025944Sjoerg return (0); 7914910Swollman} 7924910Swollman 79325944Sjoerg 79425944Sjoerg/* 79525944Sjoerg * Cisco framing implementation. 79625944Sjoerg */ 79725944Sjoerg 7984910Swollman/* 7994910Swollman * Handle incoming Cisco keepalive protocol packets. 8004910Swollman */ 80112820Sphkstatic void 80225706Sjoergsppp_cisco_input(struct sppp *sp, struct mbuf *m) 8034910Swollman{ 80425944Sjoerg STDDCL; 8054910Swollman struct cisco_packet *h; 8064910Swollman struct ifaddr *ifa; 8074910Swollman 8084910Swollman if (m->m_pkthdr.len != CISCO_PACKET_LEN) { 80925706Sjoerg if (debug) 81025706Sjoerg log(LOG_DEBUG, 81125706Sjoerg "%s%d: invalid cisco packet length: %d bytes\n", 81225706Sjoerg ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 8134910Swollman return; 8144910Swollman } 8154910Swollman h = mtod (m, struct cisco_packet*); 81625706Sjoerg if (debug) 81725706Sjoerg log(LOG_DEBUG, 81825706Sjoerg "%s%d: cisco input: %d bytes " 81925706Sjoerg "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", 82025706Sjoerg ifp->if_name, ifp->if_unit, m->m_pkthdr.len, 82125706Sjoerg ntohl (h->type), h->par1, h->par2, h->rel, 82225706Sjoerg h->time0, h->time1); 8234910Swollman switch (ntohl (h->type)) { 8244910Swollman default: 82525706Sjoerg if (debug) 82625706Sjoerg addlog("%s%d: unknown cisco packet type: 0x%lx\n", 82725706Sjoerg ifp->if_name, ifp->if_unit, ntohl (h->type)); 8284910Swollman break; 8294910Swollman case CISCO_ADDR_REPLY: 8304910Swollman /* Reply on address request, ignore */ 8314910Swollman break; 8324910Swollman case CISCO_KEEPALIVE_REQ: 8334910Swollman sp->pp_alivecnt = 0; 8344910Swollman sp->pp_rseq = ntohl (h->par1); 8354910Swollman if (sp->pp_seq == sp->pp_rseq) { 8364910Swollman /* Local and remote sequence numbers are equal. 8374910Swollman * Probably, the line is in loopback mode. */ 83811189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT) { 83911189Sjkh printf ("%s%d: loopback\n", 84011189Sjkh ifp->if_name, ifp->if_unit); 84111189Sjkh sp->pp_loopcnt = 0; 84211189Sjkh if (ifp->if_flags & IFF_UP) { 84311189Sjkh if_down (ifp); 84425944Sjoerg sppp_qflush (&sp->pp_fastq); 84511189Sjkh } 84611189Sjkh } 8474910Swollman ++sp->pp_loopcnt; 8484910Swollman 8494910Swollman /* Generate new local sequence number */ 8504910Swollman sp->pp_seq ^= time.tv_sec ^ time.tv_usec; 85111189Sjkh break; 85211189Sjkh } 8534910Swollman sp->pp_loopcnt = 0; 85411189Sjkh if (! (ifp->if_flags & IFF_UP) && 85511189Sjkh (ifp->if_flags & IFF_RUNNING)) { 85611189Sjkh ifp->if_flags |= IFF_UP; 85711189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 85811189Sjkh } 8594910Swollman break; 8604910Swollman case CISCO_ADDR_REQ: 86120407Swollman for (ifa=ifp->if_addrhead.tqh_first; ifa; 86220407Swollman ifa=ifa->ifa_link.tqe_next) 8634910Swollman if (ifa->ifa_addr->sa_family == AF_INET) 8644910Swollman break; 8654910Swollman if (! ifa) { 86625706Sjoerg if (debug) 86725706Sjoerg addlog("%s%d: unknown address for cisco request\n", 86825706Sjoerg ifp->if_name, ifp->if_unit); 8694910Swollman return; 8704910Swollman } 8714910Swollman sppp_cisco_send (sp, CISCO_ADDR_REPLY, 8724910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr), 8734910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr)); 8744910Swollman break; 8754910Swollman } 8764910Swollman} 8774910Swollman 8784910Swollman/* 87925944Sjoerg * Send Cisco keepalive packet. 8804910Swollman */ 88112820Sphkstatic void 88225944Sjoergsppp_cisco_send(struct sppp *sp, int type, long par1, long par2) 88325944Sjoerg{ 88425944Sjoerg STDDCL; 88525944Sjoerg struct ppp_header *h; 88625944Sjoerg struct cisco_packet *ch; 88725944Sjoerg struct mbuf *m; 88825944Sjoerg u_long t = (time.tv_sec - boottime.tv_sec) * 1000; 88925944Sjoerg 89025944Sjoerg MGETHDR (m, M_DONTWAIT, MT_DATA); 89125944Sjoerg if (! m) 89225944Sjoerg return; 89325944Sjoerg m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; 89425944Sjoerg m->m_pkthdr.rcvif = 0; 89525944Sjoerg 89625944Sjoerg h = mtod (m, struct ppp_header*); 89725944Sjoerg h->address = CISCO_MULTICAST; 89825944Sjoerg h->control = 0; 89925944Sjoerg h->protocol = htons (CISCO_KEEPALIVE); 90025944Sjoerg 90125944Sjoerg ch = (struct cisco_packet*) (h + 1); 90225944Sjoerg ch->type = htonl (type); 90325944Sjoerg ch->par1 = htonl (par1); 90425944Sjoerg ch->par2 = htonl (par2); 90525944Sjoerg ch->rel = -1; 90625944Sjoerg ch->time0 = htons ((u_short) (t >> 16)); 90725944Sjoerg ch->time1 = htons ((u_short) t); 90825944Sjoerg 90925944Sjoerg if (debug) 91025944Sjoerg log(LOG_DEBUG, 91125944Sjoerg "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", 91225944Sjoerg ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1, 91325944Sjoerg ch->par2, ch->rel, ch->time0, ch->time1); 91425944Sjoerg 91525944Sjoerg if (IF_QFULL (&sp->pp_fastq)) { 91625944Sjoerg IF_DROP (&ifp->if_snd); 91725944Sjoerg m_freem (m); 91825944Sjoerg } else 91925944Sjoerg IF_ENQUEUE (&sp->pp_fastq, m); 92025944Sjoerg if (! (ifp->if_flags & IFF_OACTIVE)) 92125944Sjoerg (*ifp->if_start) (ifp); 92225944Sjoerg ifp->if_obytes += m->m_pkthdr.len + 3; 92325944Sjoerg} 92425944Sjoerg 92525944Sjoerg/* 92625944Sjoerg * PPP protocol implementation. 92725944Sjoerg */ 92825944Sjoerg 92925944Sjoerg/* 93025944Sjoerg * Send PPP control protocol packet. 93125944Sjoerg */ 93225944Sjoergstatic void 93325706Sjoergsppp_cp_send(struct sppp *sp, u_short proto, u_char type, 93425706Sjoerg u_char ident, u_short len, void *data) 9354910Swollman{ 93625944Sjoerg STDDCL; 9374910Swollman struct ppp_header *h; 9384910Swollman struct lcp_header *lh; 9394910Swollman struct mbuf *m; 9404910Swollman 9414910Swollman if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) 9424910Swollman len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; 9434910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9444910Swollman if (! m) 9454910Swollman return; 9464910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; 9474910Swollman m->m_pkthdr.rcvif = 0; 9484910Swollman 9494910Swollman h = mtod (m, struct ppp_header*); 9504910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 9514910Swollman h->control = PPP_UI; /* Unnumbered Info */ 9524910Swollman h->protocol = htons (proto); /* Link Control Protocol */ 9534910Swollman 9544910Swollman lh = (struct lcp_header*) (h + 1); 9554910Swollman lh->type = type; 9564910Swollman lh->ident = ident; 9574910Swollman lh->len = htons (LCP_HEADER_LEN + len); 9584910Swollman if (len) 9594910Swollman bcopy (data, lh+1, len); 9604910Swollman 96125706Sjoerg if (debug) { 96225944Sjoerg log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d", 96325944Sjoerg ifp->if_name, ifp->if_unit, 96425944Sjoerg sppp_proto_name(proto), 96525944Sjoerg sppp_cp_type_name (lh->type), lh->ident, 96625944Sjoerg ntohs (lh->len)); 9674910Swollman if (len) 96811189Sjkh sppp_print_bytes ((u_char*) (lh+1), len); 96925706Sjoerg addlog(">\n"); 9704910Swollman } 9714910Swollman if (IF_QFULL (&sp->pp_fastq)) { 9724910Swollman IF_DROP (&ifp->if_snd); 9734910Swollman m_freem (m); 97425944Sjoerg ++ifp->if_oerrors; 9754910Swollman } else 9764910Swollman IF_ENQUEUE (&sp->pp_fastq, m); 9774910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 9784910Swollman (*ifp->if_start) (ifp); 9794910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 9804910Swollman} 9814910Swollman 9824910Swollman/* 98325944Sjoerg * Handle incoming PPP control protocol packets. 9844910Swollman */ 98512820Sphkstatic void 98625944Sjoergsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) 9874910Swollman{ 98825944Sjoerg STDDCL; 98925944Sjoerg struct lcp_header *h; 99025944Sjoerg int len = m->m_pkthdr.len; 99125944Sjoerg int rv; 99225944Sjoerg u_char *p; 9934910Swollman 99425944Sjoerg if (len < 4) { 99525944Sjoerg if (debug) 99625944Sjoerg log(LOG_DEBUG, 99725944Sjoerg "%s%d: %s invalid packet length: %d bytes\n", 99825944Sjoerg ifp->if_name, ifp->if_unit, cp->name, len); 9994910Swollman return; 100025944Sjoerg } 100125944Sjoerg h = mtod (m, struct lcp_header*); 100225944Sjoerg if (debug) { 100325944Sjoerg log(LOG_DEBUG, 100425944Sjoerg "%s%d: %s input(%s): <%s id=0x%x len=%d", 100525944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 100625944Sjoerg sppp_state_name(sp->state[cp->protoidx]), 100725944Sjoerg sppp_cp_type_name (h->type), h->ident, ntohs (h->len)); 100825944Sjoerg if (len > 4) 100925944Sjoerg sppp_print_bytes ((u_char*) (h+1), len-4); 101025944Sjoerg addlog(">\n"); 101125944Sjoerg } 101225944Sjoerg if (len > ntohs (h->len)) 101325944Sjoerg len = ntohs (h->len); 101425944Sjoerg switch (h->type) { 101525944Sjoerg case CONF_REQ: 101625944Sjoerg if (len < 4) { 101725944Sjoerg if (debug) 101825944Sjoerg addlog("%s%d: %s invalid conf-req length %d\n", 101925944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 102025944Sjoerg len); 102125944Sjoerg ++ifp->if_ierrors; 102225944Sjoerg break; 102325944Sjoerg } 102425944Sjoerg rv = (cp->RCR)(sp, h, len); 102525944Sjoerg switch (sp->state[cp->protoidx]) { 102625944Sjoerg case STATE_OPENED: 102725944Sjoerg (cp->tld)(sp); 102825944Sjoerg (cp->scr)(sp); 102925944Sjoerg /* fall through... */ 103025944Sjoerg case STATE_ACK_SENT: 103125944Sjoerg case STATE_REQ_SENT: 103225944Sjoerg sppp_cp_change_state(cp, sp, rv? 103325944Sjoerg STATE_ACK_SENT: STATE_REQ_SENT); 103425944Sjoerg break; 103525944Sjoerg case STATE_CLOSING: 103625944Sjoerg case STATE_STOPPING: 103725944Sjoerg break; 103825944Sjoerg case STATE_STOPPED: 103925944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 104025944Sjoerg (cp->scr)(sp); 104125944Sjoerg sppp_cp_change_state(cp, sp, rv? 104225944Sjoerg STATE_ACK_SENT: STATE_REQ_SENT); 104325944Sjoerg break; 104425944Sjoerg case STATE_CLOSED: 104525944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 104625944Sjoerg 0, 0); 104725944Sjoerg break; 104825944Sjoerg case STATE_ACK_RCVD: 104925944Sjoerg if (rv) { 105025944Sjoerg sppp_cp_change_state(cp, sp, STATE_OPENED); 105125944Sjoerg if (debug) 105225944Sjoerg addlog("%s%d: %s tlu\n", 105325944Sjoerg ifp->if_name, ifp->if_unit, 105425944Sjoerg cp->name); 105525944Sjoerg (cp->tlu)(sp); 105625944Sjoerg } else 105725944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); 105825944Sjoerg break; 105925944Sjoerg default: 106025944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 106125944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 106225944Sjoerg sppp_cp_type_name(h->type), 106325944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 106425944Sjoerg ++ifp->if_ierrors; 106525944Sjoerg } 106625944Sjoerg break; 106725944Sjoerg case CONF_ACK: 106825944Sjoerg if (h->ident != sp->confid[cp->protoidx]) { 106925944Sjoerg if (debug) 107025944Sjoerg addlog("%s%d: %s id mismatch 0x%x != 0x%x\n", 107125944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 107225944Sjoerg h->ident, sp->confid[cp->protoidx]); 107325944Sjoerg ++ifp->if_ierrors; 107425944Sjoerg break; 107525944Sjoerg } 107625944Sjoerg switch (sp->state[cp->protoidx]) { 107725944Sjoerg case STATE_CLOSED: 107825944Sjoerg case STATE_STOPPED: 107925944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); 108025944Sjoerg break; 108125944Sjoerg case STATE_CLOSING: 108225944Sjoerg case STATE_STOPPING: 108325944Sjoerg break; 108425944Sjoerg case STATE_REQ_SENT: 108525944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 108625944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); 108725944Sjoerg break; 108825944Sjoerg case STATE_OPENED: 108925944Sjoerg (cp->tld)(sp); 109025944Sjoerg /* fall through */ 109125944Sjoerg case STATE_ACK_RCVD: 109225944Sjoerg (cp->scr)(sp); 109325944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 109425944Sjoerg break; 109525944Sjoerg case STATE_ACK_SENT: 109625944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 109725944Sjoerg sppp_cp_change_state(cp, sp, STATE_OPENED); 109825944Sjoerg if (debug) 109925944Sjoerg addlog("%s%d: %s tlu\n", 110025944Sjoerg ifp->if_name, ifp->if_unit, cp->name); 110125944Sjoerg (cp->tlu)(sp); 110225944Sjoerg break; 110325944Sjoerg default: 110425944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 110525944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 110625944Sjoerg sppp_cp_type_name(h->type), 110725944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 110825944Sjoerg ++ifp->if_ierrors; 110925944Sjoerg } 111025944Sjoerg break; 111125944Sjoerg case CONF_NAK: 111225944Sjoerg case CONF_REJ: 111325944Sjoerg if (h->ident != sp->confid[cp->protoidx]) { 111425944Sjoerg if (debug) 111525944Sjoerg addlog("%s%d: %s id mismatch 0x%x != 0x%x\n", 111625944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 111725944Sjoerg h->ident, sp->confid[cp->protoidx]); 111825944Sjoerg ++ifp->if_ierrors; 111925944Sjoerg break; 112025944Sjoerg } 112125944Sjoerg if (h->type == CONF_NAK) 112225944Sjoerg (cp->RCN_nak)(sp, h, len); 112325944Sjoerg else /* CONF_REJ */ 112425944Sjoerg (cp->RCN_rej)(sp, h, len); 11254910Swollman 112625944Sjoerg switch (sp->state[cp->protoidx]) { 112725944Sjoerg case STATE_CLOSED: 112825944Sjoerg case STATE_STOPPED: 112925944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); 113025944Sjoerg break; 113125944Sjoerg case STATE_REQ_SENT: 113225944Sjoerg case STATE_ACK_SENT: 113325944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 113425944Sjoerg (cp->scr)(sp); 113525944Sjoerg break; 113625944Sjoerg case STATE_OPENED: 113725944Sjoerg (cp->tld)(sp); 113825944Sjoerg /* fall through */ 113925944Sjoerg case STATE_ACK_RCVD: 114025944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_SENT); 114125944Sjoerg (cp->scr)(sp); 114225944Sjoerg break; 114325944Sjoerg case STATE_CLOSING: 114425944Sjoerg case STATE_STOPPING: 114525944Sjoerg break; 114625944Sjoerg default: 114725944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 114825944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 114925944Sjoerg sppp_cp_type_name(h->type), 115025944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 115125944Sjoerg ++ifp->if_ierrors; 115225944Sjoerg } 115325944Sjoerg break; 11544910Swollman 115525944Sjoerg case TERM_REQ: 115625944Sjoerg switch (sp->state[cp->protoidx]) { 115725944Sjoerg case STATE_ACK_RCVD: 115825944Sjoerg case STATE_ACK_SENT: 115925944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 116025944Sjoerg /* fall through */ 116125944Sjoerg case STATE_CLOSED: 116225944Sjoerg case STATE_STOPPED: 116325944Sjoerg case STATE_CLOSING: 116425944Sjoerg case STATE_STOPPING: 116525944Sjoerg case STATE_REQ_SENT: 116625944Sjoerg sta: 116725944Sjoerg /* Send Terminate-Ack packet. */ 116825944Sjoerg if (debug) 116925944Sjoerg log(LOG_DEBUG, "%s%d: %s send terminate-ack\n", 117025944Sjoerg ifp->if_name, ifp->if_unit, cp->name); 117125944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); 117225944Sjoerg break; 117325944Sjoerg case STATE_OPENED: 117425944Sjoerg (cp->tld)(sp); 117525944Sjoerg sp->rst_counter[cp->protoidx] = 0; 117625944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPING); 117725944Sjoerg goto sta; 117825944Sjoerg break; 117925944Sjoerg default: 118025944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 118125944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 118225944Sjoerg sppp_cp_type_name(h->type), 118325944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 118425944Sjoerg ++ifp->if_ierrors; 118525944Sjoerg } 118625944Sjoerg break; 118725944Sjoerg case TERM_ACK: 118825944Sjoerg switch (sp->state[cp->protoidx]) { 118925944Sjoerg case STATE_CLOSED: 119025944Sjoerg case STATE_STOPPED: 119125944Sjoerg case STATE_REQ_SENT: 119225944Sjoerg case STATE_ACK_SENT: 119325944Sjoerg break; 119425944Sjoerg case STATE_CLOSING: 119525944Sjoerg (cp->tlf)(sp); 119625944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 119725944Sjoerg break; 119825944Sjoerg case STATE_STOPPING: 119925944Sjoerg (cp->tlf)(sp); 120025944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPED); 120125944Sjoerg break; 120225944Sjoerg case STATE_ACK_RCVD: 120325944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 120425944Sjoerg break; 120525944Sjoerg case STATE_OPENED: 120625944Sjoerg (cp->tld)(sp); 120725944Sjoerg (cp->scr)(sp); 120825944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); 120925944Sjoerg break; 121025944Sjoerg default: 121125944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 121225944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 121325944Sjoerg sppp_cp_type_name(h->type), 121425944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 121525944Sjoerg ++ifp->if_ierrors; 121625944Sjoerg } 121725944Sjoerg break; 121825944Sjoerg case CODE_REJ: 121925944Sjoerg case PROTO_REJ: 122025944Sjoerg /* XXX catastrophic rejects (RXJ-) aren't handled yet. */ 122125944Sjoerg switch (sp->state[cp->protoidx]) { 122225944Sjoerg case STATE_CLOSED: 122325944Sjoerg case STATE_STOPPED: 122425944Sjoerg case STATE_REQ_SENT: 122525944Sjoerg case STATE_ACK_SENT: 122625944Sjoerg case STATE_CLOSING: 122725944Sjoerg case STATE_STOPPING: 122825944Sjoerg case STATE_OPENED: 122925944Sjoerg break; 123025944Sjoerg case STATE_ACK_RCVD: 123125944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 123225944Sjoerg break; 123325944Sjoerg default: 123425944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 123525944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 123625944Sjoerg sppp_cp_type_name(h->type), 123725944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 123825944Sjoerg ++ifp->if_ierrors; 123925944Sjoerg } 124025944Sjoerg break; 124125944Sjoerg case DISC_REQ: 124225944Sjoerg if (cp->proto != PPP_LCP) 124325944Sjoerg goto illegal; 124425944Sjoerg /* Discard the packet. */ 124525944Sjoerg break; 124625944Sjoerg case ECHO_REQ: 124725944Sjoerg if (cp->proto != PPP_LCP) 124825944Sjoerg goto illegal; 124925944Sjoerg if (sp->state[cp->protoidx] != STATE_OPENED) { 125025944Sjoerg if (debug) 125125944Sjoerg addlog("%s%d: lcp echo req but lcp closed\n", 125225944Sjoerg ifp->if_name, ifp->if_unit); 125325944Sjoerg ++ifp->if_ierrors; 125425944Sjoerg break; 125525944Sjoerg } 125625944Sjoerg if (len < 8) { 125725944Sjoerg if (debug) 125825944Sjoerg addlog("%s%d: invalid lcp echo request " 125925944Sjoerg "packet length: %d bytes\n", 126025944Sjoerg ifp->if_name, ifp->if_unit, len); 126125944Sjoerg break; 126225944Sjoerg } 126325944Sjoerg if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { 126425944Sjoerg /* Line loopback mode detected. */ 126525944Sjoerg printf("%s%d: loopback\n", ifp->if_name, ifp->if_unit); 126625944Sjoerg if_down (ifp); 126725944Sjoerg sppp_qflush (&sp->pp_fastq); 12684910Swollman 126925944Sjoerg /* Shut down the PPP link. */ 127025944Sjoerg /* XXX */ 127125944Sjoerg lcp.Down(sp); 127225944Sjoerg lcp.Up(sp); 127325944Sjoerg break; 127425944Sjoerg } 127525944Sjoerg *(long*)(h+1) = htonl (sp->lcp.magic); 127625944Sjoerg if (debug) 127725944Sjoerg addlog("%s%d: got lcp echo req, sending echo rep\n", 127825944Sjoerg ifp->if_name, ifp->if_unit); 127925944Sjoerg sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1); 128025944Sjoerg break; 128125944Sjoerg case ECHO_REPLY: 128225944Sjoerg if (cp->proto != PPP_LCP) 128325944Sjoerg goto illegal; 128425944Sjoerg if (h->ident != sp->lcp.echoid) { 128525944Sjoerg ++ifp->if_ierrors; 128625944Sjoerg break; 128725944Sjoerg } 128825944Sjoerg if (len < 8) { 128925944Sjoerg if (debug) 129025944Sjoerg addlog("%s%d: lcp invalid echo reply " 129125944Sjoerg "packet length: %d bytes\n", 129225944Sjoerg ifp->if_name, ifp->if_unit, len); 129325944Sjoerg break; 129425944Sjoerg } 129525944Sjoerg if (debug) 129625944Sjoerg addlog("%s%d: lcp got echo rep\n", 129725944Sjoerg ifp->if_name, ifp->if_unit); 129825944Sjoerg if (ntohl (*(long*)(h+1)) != sp->lcp.magic) 129925944Sjoerg sp->pp_alivecnt = 0; 130025944Sjoerg break; 130125944Sjoerg default: 130225944Sjoerg /* Unknown packet type -- send Code-Reject packet. */ 130325944Sjoerg illegal: 130425944Sjoerg if (debug) 130525944Sjoerg addlog("%s%d: %c send code-rej for 0x%x\n", 130625944Sjoerg ifp->if_name, ifp->if_unit, cp->name, h->type); 130725944Sjoerg sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq, 130825944Sjoerg m->m_pkthdr.len, h); 130925944Sjoerg ++ifp->if_ierrors; 131025944Sjoerg } 13114910Swollman} 13124910Swollman 131325944Sjoerg 13144910Swollman/* 131525944Sjoerg * The generic part of all Up/Down/Open/Close/TO event handlers. 131625944Sjoerg * Basically, the state transition handling in the automaton. 13174910Swollman */ 131825944Sjoergstatic void 131925944Sjoergsppp_up_event(const struct cp *cp, struct sppp *sp) 13204910Swollman{ 132125944Sjoerg STDDCL; 13224910Swollman 132325944Sjoerg if (debug) 132425944Sjoerg log(LOG_DEBUG, "%s%d: %s up(%s)\n", 132525944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 132625944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 132725944Sjoerg 132825944Sjoerg switch (sp->state[cp->protoidx]) { 132925944Sjoerg case STATE_INITIAL: 133025944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 133125944Sjoerg break; 133225944Sjoerg case STATE_STARTING: 133325944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 133425944Sjoerg (cp->scr)(sp); 133525944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 133625944Sjoerg break; 13374910Swollman default: 133825944Sjoerg printf("%s%d: %s illegal up in state %s\n", 133925944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 134025944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 134125944Sjoerg } 134225944Sjoerg} 13434910Swollman 134425944Sjoergstatic void 134525944Sjoergsppp_down_event(const struct cp *cp, struct sppp *sp) 134625944Sjoerg{ 134725944Sjoerg STDDCL; 134825944Sjoerg 134925944Sjoerg if (debug) 135025944Sjoerg log(LOG_DEBUG, "%s%d: %s down(%s)\n", 135125944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 135225944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 135325944Sjoerg 135425944Sjoerg switch (sp->state[cp->protoidx]) { 135525944Sjoerg case STATE_CLOSED: 135625944Sjoerg case STATE_CLOSING: 135725944Sjoerg sppp_cp_change_state(cp, sp, STATE_INITIAL); 13584910Swollman break; 135925944Sjoerg case STATE_STOPPED: 136025944Sjoerg (cp->tls)(sp); 136125944Sjoerg /* fall through */ 136225944Sjoerg case STATE_STOPPING: 136325944Sjoerg case STATE_REQ_SENT: 136425944Sjoerg case STATE_ACK_RCVD: 136525944Sjoerg case STATE_ACK_SENT: 136625944Sjoerg sppp_cp_change_state(cp, sp, STATE_STARTING); 136725944Sjoerg break; 136825944Sjoerg case STATE_OPENED: 136925944Sjoerg (cp->tld)(sp); 137025944Sjoerg sppp_cp_change_state(cp, sp, STATE_STARTING); 137125944Sjoerg break; 137225944Sjoerg default: 137325944Sjoerg printf("%s%d: %s illegal down in state %s\n", 137425944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 137525944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 137625944Sjoerg } 137725944Sjoerg} 13784910Swollman 137911189Sjkh 138025944Sjoergstatic void 138125944Sjoergsppp_open_event(const struct cp *cp, struct sppp *sp) 138225944Sjoerg{ 138325944Sjoerg STDDCL; 138425944Sjoerg 138525944Sjoerg if (debug) 138625944Sjoerg log(LOG_DEBUG, "%s%d: %s open(%s)\n", 138725944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 138825944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 138925944Sjoerg 139025944Sjoerg switch (sp->state[cp->protoidx]) { 139125944Sjoerg case STATE_INITIAL: 139225944Sjoerg (cp->tls)(sp); 139325944Sjoerg sppp_cp_change_state(cp, sp, STATE_STARTING); 13944910Swollman break; 139525944Sjoerg case STATE_STARTING: 139625944Sjoerg break; 139725944Sjoerg case STATE_CLOSED: 139825944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 139925944Sjoerg (cp->scr)(sp); 140025944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 140125944Sjoerg break; 140225944Sjoerg case STATE_STOPPED: 140325944Sjoerg case STATE_STOPPING: 140425944Sjoerg case STATE_REQ_SENT: 140525944Sjoerg case STATE_ACK_RCVD: 140625944Sjoerg case STATE_ACK_SENT: 140725944Sjoerg case STATE_OPENED: 140825944Sjoerg break; 140925944Sjoerg case STATE_CLOSING: 141025944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPING); 141125944Sjoerg break; 141225944Sjoerg } 141325944Sjoerg} 14144910Swollman 141525944Sjoerg 141625944Sjoergstatic void 141725944Sjoergsppp_close_event(const struct cp *cp, struct sppp *sp) 141825944Sjoerg{ 141925944Sjoerg STDDCL; 142025944Sjoerg 142125944Sjoerg if (debug) 142225944Sjoerg log(LOG_DEBUG, "%s%d: %s close(%s)\n", 142325944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 142425944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 142525944Sjoerg 142625944Sjoerg switch (sp->state[cp->protoidx]) { 142725944Sjoerg case STATE_INITIAL: 142825944Sjoerg case STATE_CLOSED: 142925944Sjoerg case STATE_CLOSING: 14304910Swollman break; 143125944Sjoerg case STATE_STARTING: 143225944Sjoerg (cp->tlf)(sp); 143325944Sjoerg sppp_cp_change_state(cp, sp, STATE_INITIAL); 14344910Swollman break; 143525944Sjoerg case STATE_STOPPED: 143625944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 14374910Swollman break; 143825944Sjoerg case STATE_STOPPING: 143925944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSING); 14404910Swollman break; 144125944Sjoerg case STATE_OPENED: 144225944Sjoerg (cp->tld)(sp); 144325944Sjoerg /* fall through */ 144425944Sjoerg case STATE_REQ_SENT: 144525944Sjoerg case STATE_ACK_RCVD: 144625944Sjoerg case STATE_ACK_SENT: 144725944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate; 144825944Sjoerg sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); 144925944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSING); 14504910Swollman break; 14514910Swollman } 14524910Swollman} 14534910Swollman 145425944Sjoergstatic void 145525944Sjoergsppp_to_event(const struct cp *cp, struct sppp *sp) 145625944Sjoerg{ 145725944Sjoerg STDDCL; 145825944Sjoerg int s; 145925944Sjoerg 146025944Sjoerg s = splimp(); 146125944Sjoerg if (debug) 146225944Sjoerg log(LOG_DEBUG, "%s%d: %s TO(%s) rst_counter = %d\n", 146325944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 146425944Sjoerg sppp_state_name(sp->state[cp->protoidx]), 146525944Sjoerg sp->rst_counter[cp->protoidx]); 146625944Sjoerg 146725944Sjoerg if (--sp->rst_counter[cp->protoidx] < 0) 146825944Sjoerg /* TO- event */ 146925944Sjoerg switch (sp->state[cp->protoidx]) { 147025944Sjoerg case STATE_CLOSING: 147125944Sjoerg (cp->tlf)(sp); 147225944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 147325944Sjoerg break; 147425944Sjoerg case STATE_STOPPING: 147525944Sjoerg (cp->tlf)(sp); 147625944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPED); 147725944Sjoerg break; 147825944Sjoerg case STATE_REQ_SENT: 147925944Sjoerg case STATE_ACK_RCVD: 148025944Sjoerg case STATE_ACK_SENT: 148125944Sjoerg (cp->tlf)(sp); 148225944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPED); 148325944Sjoerg break; 148425944Sjoerg } 148525944Sjoerg else 148625944Sjoerg /* TO+ event */ 148725944Sjoerg switch (sp->state[cp->protoidx]) { 148825944Sjoerg case STATE_CLOSING: 148925944Sjoerg case STATE_STOPPING: 149025944Sjoerg sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 149125944Sjoerg 0, 0); 149225944Sjoerg timeout(cp->TO, (void *)sp, sp->lcp.timeout); 149325944Sjoerg break; 149425944Sjoerg case STATE_REQ_SENT: 149525944Sjoerg case STATE_ACK_RCVD: 149625944Sjoerg (cp->scr)(sp); 149725944Sjoerg /* sppp_cp_change_state() will restart the timer */ 149825944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 149925944Sjoerg break; 150025944Sjoerg case STATE_ACK_SENT: 150125944Sjoerg (cp->scr)(sp); 150225944Sjoerg timeout(cp->TO, (void *)sp, sp->lcp.timeout); 150325944Sjoerg break; 150425944Sjoerg } 150525944Sjoerg 150625944Sjoerg splx(s); 150725944Sjoerg} 150825944Sjoerg 150911189Sjkh/* 151025944Sjoerg * Change the state of a control protocol in the state automaton. 151125944Sjoerg * Takes care of starting/stopping the restart timer. 151211189Sjkh */ 151325944Sjoergvoid 151425944Sjoergsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate) 151525944Sjoerg{ 151625944Sjoerg sp->state[cp->protoidx] = newstate; 151725944Sjoerg 151825944Sjoerg untimeout(cp->TO, (void *)sp); 151925944Sjoerg switch (newstate) { 152025944Sjoerg case STATE_INITIAL: 152125944Sjoerg case STATE_STARTING: 152225944Sjoerg case STATE_CLOSED: 152325944Sjoerg case STATE_STOPPED: 152425944Sjoerg case STATE_OPENED: 152525944Sjoerg break; 152625944Sjoerg case STATE_CLOSING: 152725944Sjoerg case STATE_STOPPING: 152825944Sjoerg case STATE_REQ_SENT: 152925944Sjoerg case STATE_ACK_RCVD: 153025944Sjoerg case STATE_ACK_SENT: 153125944Sjoerg timeout(cp->TO, (void *)sp, sp->lcp.timeout); 153225944Sjoerg break; 153325944Sjoerg } 153425944Sjoerg} 153525944Sjoerg/* 153625944Sjoerg *--------------------------------------------------------------------------* 153725944Sjoerg * * 153825944Sjoerg * The LCP implementation. * 153925944Sjoerg * * 154025944Sjoerg *--------------------------------------------------------------------------* 154125944Sjoerg */ 154225944Sjoergstatic void 154325944Sjoergsppp_lcp_init(struct sppp *sp) 154425944Sjoerg{ 154525944Sjoerg sp->lcp.opts = (1 << LCP_OPT_MAGIC); 154625944Sjoerg sp->lcp.magic = 0; 154725944Sjoerg sp->state[IDX_LCP] = STATE_INITIAL; 154825944Sjoerg sp->fail_counter[IDX_LCP] = 0; 154925944Sjoerg sp->lcp.protos = 0; 155025944Sjoerg sp->lcp.mru = sp->lcp.their_mru = PP_MTU; 155125944Sjoerg 155225944Sjoerg /* 155325944Sjoerg * Initialize counters and timeout values. Note that we don't 155425944Sjoerg * use the 3 seconds suggested in RFC 1661 since we are likely 155525944Sjoerg * running on a fast link. XXX We should probably implement 155625944Sjoerg * the exponential backoff option. Note that these values are 155725944Sjoerg * relevant for all control protocols, not just LCP only. 155825944Sjoerg */ 155925944Sjoerg sp->lcp.timeout = 1 * hz; 156025944Sjoerg sp->lcp.max_terminate = 2; 156125944Sjoerg sp->lcp.max_configure = 10; 156225944Sjoerg sp->lcp.max_failure = 10; 156325944Sjoerg} 156425944Sjoerg 156525944Sjoergstatic void 156625944Sjoergsppp_lcp_up(struct sppp *sp) 156725944Sjoerg{ 156825944Sjoerg STDDCL; 156925944Sjoerg 157025944Sjoerg /* 157125944Sjoerg * If this interface is passive or dial-on-demand, it means 157225944Sjoerg * we've got in incoming call. Activate the interface. 157325944Sjoerg */ 157425944Sjoerg if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) { 157525944Sjoerg if (debug) 157625944Sjoerg log(LOG_DEBUG, 157725944Sjoerg "%s%d: Up event (incoming call)\n", 157825944Sjoerg ifp->if_name, ifp->if_unit); 157925944Sjoerg ifp->if_flags |= IFF_RUNNING; 158025944Sjoerg lcp.Open(sp); 158125944Sjoerg } 158225944Sjoerg 158325944Sjoerg sppp_up_event(&lcp, sp); 158425944Sjoerg} 158525944Sjoerg 158625944Sjoergstatic void 158725944Sjoergsppp_lcp_down(struct sppp *sp) 158825944Sjoerg{ 158925944Sjoerg STDDCL; 159025944Sjoerg 159125944Sjoerg sppp_down_event(&lcp, sp); 159225944Sjoerg 159325944Sjoerg /* 159425944Sjoerg * If this is neither a dial-on-demand nor a passive 159525944Sjoerg * interface, simulate an ``ifconfig down'' action, so the 159625944Sjoerg * administrator can force a redial by another ``ifconfig 159725944Sjoerg * up''. XXX For leased line operation, should we immediately 159825944Sjoerg * try to reopen the connection here? 159925944Sjoerg */ 160025944Sjoerg if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) { 160125944Sjoerg log(LOG_INFO, 160225944Sjoerg "%s%d: Down event (carrier loss), taking interface down.\n", 160325944Sjoerg ifp->if_name, ifp->if_unit); 160425944Sjoerg if_down(ifp); 160525944Sjoerg } else { 160625944Sjoerg if (debug) 160725944Sjoerg log(LOG_DEBUG, 160825944Sjoerg "%s%d: Down event (carrier loss)\n", 160925944Sjoerg ifp->if_name, ifp->if_unit); 161025944Sjoerg } 161125944Sjoerg lcp.Close(sp); 161225944Sjoerg ifp->if_flags &= ~IFF_RUNNING; 161325944Sjoerg} 161425944Sjoerg 161525944Sjoergstatic void 161625944Sjoergsppp_lcp_open(struct sppp *sp) 161725944Sjoerg{ 161825944Sjoerg sppp_open_event(&lcp, sp); 161925944Sjoerg} 162025944Sjoerg 162125944Sjoergstatic void 162225944Sjoergsppp_lcp_close(struct sppp *sp) 162325944Sjoerg{ 162425944Sjoerg sppp_close_event(&lcp, sp); 162525944Sjoerg} 162625944Sjoerg 162725944Sjoergstatic void 162825944Sjoergsppp_lcp_TO(void *cookie) 162925944Sjoerg{ 163025944Sjoerg sppp_to_event(&lcp, (struct sppp *)cookie); 163125944Sjoerg} 163225944Sjoerg 163325944Sjoerg/* 163425944Sjoerg * Analyze a configure request. Return true if it was agreeable, and 163525944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and 163625944Sjoerg * caused action scn. (The return value is used to make the state 163725944Sjoerg * transition decision in the state automaton.) 163825944Sjoerg */ 163912820Sphkstatic int 164025944Sjoergsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) 16414910Swollman{ 164225944Sjoerg STDDCL; 164311189Sjkh u_char *buf, *r, *p; 164425944Sjoerg int origlen, rlen; 164525944Sjoerg u_long nmagic; 16464910Swollman 164711189Sjkh len -= 4; 164825944Sjoerg origlen = len; 164911189Sjkh buf = r = malloc (len, M_TEMP, M_NOWAIT); 165011189Sjkh if (! buf) 165111189Sjkh return (0); 16524910Swollman 165325706Sjoerg if (debug) 165425944Sjoerg log(LOG_DEBUG, "%s%d: lcp parse opts: ", 165525944Sjoerg ifp->if_name, ifp->if_unit); 165625706Sjoerg 165725944Sjoerg /* pass 1: check for things that need to be rejected */ 165811189Sjkh p = (void*) (h+1); 165911189Sjkh for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 166025944Sjoerg if (debug) 166125944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 166211189Sjkh switch (*p) { 166311189Sjkh case LCP_OPT_MAGIC: 166425944Sjoerg /* Magic number. */ 166525944Sjoerg /* fall through, both are same length */ 166625944Sjoerg case LCP_OPT_ASYNC_MAP: 166725944Sjoerg /* Async control character map. */ 166825944Sjoerg if (len >= 6 || p[1] == 6) 166925944Sjoerg continue; 167025944Sjoerg if (debug) 167125944Sjoerg addlog("[invalid] "); 167225944Sjoerg break; 167325944Sjoerg case LCP_OPT_MRU: 167425944Sjoerg /* Maximum receive unit. */ 167525944Sjoerg if (len >= 4 && p[1] == 4) 167625944Sjoerg continue; 167725944Sjoerg if (debug) 167825944Sjoerg addlog("[invalid] "); 167925944Sjoerg break; 168025944Sjoerg default: 168125944Sjoerg /* Others not supported. */ 168225944Sjoerg if (debug) 168325944Sjoerg addlog("[rej] "); 168425944Sjoerg break; 168525944Sjoerg } 168625944Sjoerg /* Add the option to rejected list. */ 168725944Sjoerg bcopy (p, r, p[1]); 168825944Sjoerg r += p[1]; 168925944Sjoerg rlen += p[1]; 169025944Sjoerg } 169125944Sjoerg if (rlen) { 169225944Sjoerg if (debug) 169325944Sjoerg addlog(" send conf-rej\n"); 169425944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); 169525944Sjoerg return 0; 169625944Sjoerg } else if (debug) 169725944Sjoerg addlog("\n"); 169825944Sjoerg 169925944Sjoerg /* 170025944Sjoerg * pass 2: check for option values that are unacceptable and 170125944Sjoerg * thus require to be nak'ed. 170225944Sjoerg */ 170325944Sjoerg if (debug) 170425944Sjoerg addlog("%s%d: lcp parse opt values: ", 170525944Sjoerg ifp->if_name, ifp->if_unit); 170625944Sjoerg 170725944Sjoerg p = (void*) (h+1); 170825944Sjoerg len = origlen; 170925944Sjoerg for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 171025944Sjoerg if (debug) 171125944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 171225944Sjoerg switch (*p) { 171325944Sjoerg case LCP_OPT_MAGIC: 171411189Sjkh /* Magic number -- extract. */ 171525944Sjoerg nmagic = (u_long)p[2] << 24 | 171625944Sjoerg (u_long)p[3] << 16 | p[4] << 8 | p[5]; 171725944Sjoerg if (nmagic != sp->lcp.magic) { 171825706Sjoerg if (debug) 171925944Sjoerg addlog("0x%x ", nmagic); 172011189Sjkh continue; 172111189Sjkh } 172225944Sjoerg /* 172325944Sjoerg * Local and remote magics equal -- loopback? 172425944Sjoerg */ 172525944Sjoerg if (sp->pp_loopcnt >= MAXALIVECNT*5) { 172625944Sjoerg printf ("\n%s%d: loopback\n", 172725944Sjoerg ifp->if_name, ifp->if_unit); 172825944Sjoerg sp->pp_loopcnt = 0; 172925944Sjoerg if (ifp->if_flags & IFF_UP) { 173025944Sjoerg if_down(ifp); 173125944Sjoerg sppp_qflush(&sp->pp_fastq); 173225944Sjoerg /* XXX ? */ 173325944Sjoerg lcp.Down(sp); 173425944Sjoerg lcp.Up(sp); 173525944Sjoerg } 173625944Sjoerg } else if (debug) 173725944Sjoerg addlog("[glitch] "); 173825944Sjoerg ++sp->pp_loopcnt; 173925944Sjoerg /* 174025944Sjoerg * We negate our magic here, and NAK it. If 174125944Sjoerg * we see it later in an NAK packet, we 174225944Sjoerg * suggest a new one. 174325944Sjoerg */ 174425944Sjoerg nmagic = ~sp->lcp.magic; 174525944Sjoerg /* Gonna NAK it. */ 174625944Sjoerg p[2] = nmagic >> 24; 174725944Sjoerg p[3] = nmagic >> 16; 174825944Sjoerg p[4] = nmagic >> 8; 174925944Sjoerg p[5] = nmagic; 175011189Sjkh break; 175125944Sjoerg 175211189Sjkh case LCP_OPT_ASYNC_MAP: 175311189Sjkh /* Async control character map -- check to be zero. */ 175425944Sjoerg if (! p[2] && ! p[3] && ! p[4] && ! p[5]) { 175525706Sjoerg if (debug) 175625944Sjoerg addlog("[empty] "); 175711189Sjkh continue; 175825706Sjoerg } 175925706Sjoerg if (debug) 176025944Sjoerg addlog("[non-empty] "); 176125944Sjoerg /* suggest a zero one */ 176225944Sjoerg p[2] = p[3] = p[4] = p[5] = 0; 176311189Sjkh break; 176425944Sjoerg 176511189Sjkh case LCP_OPT_MRU: 176625944Sjoerg /* 176725944Sjoerg * Maximum receive unit. Always agreeable, 176825944Sjoerg * but ignored by now. 176925944Sjoerg */ 177025944Sjoerg sp->lcp.their_mru = p[2] * 256 + p[3]; 177125706Sjoerg if (debug) 177225944Sjoerg addlog("%d ", sp->lcp.their_mru); 177311189Sjkh continue; 177411189Sjkh } 177525944Sjoerg /* Add the option to nak'ed list. */ 177625706Sjoerg bcopy (p, r, p[1]); 177725706Sjoerg r += p[1]; 177811189Sjkh rlen += p[1]; 177912436Speter } 178025706Sjoerg if (rlen) { 178125706Sjoerg if (debug) 178225944Sjoerg addlog(" send conf-nak\n"); 178325944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf); 178425944Sjoerg return 0; 178525944Sjoerg } else { 178625944Sjoerg if (debug) 178725944Sjoerg addlog(" send conf-ack\n"); 178825944Sjoerg sp->pp_loopcnt = 0; 178925944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_ACK, 179025944Sjoerg h->ident, origlen, h+1); 179125944Sjoerg } 179225944Sjoerg 179311189Sjkh free (buf, M_TEMP); 179411189Sjkh return (rlen == 0); 17954910Swollman} 17964910Swollman 179725944Sjoerg/* 179825944Sjoerg * Analyze the LCP Configure-Reject option list, and adjust our 179925944Sjoerg * negotiation. 180025944Sjoerg */ 180112820Sphkstatic void 180225944Sjoergsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) 18034910Swollman{ 180425944Sjoerg STDDCL; 180525944Sjoerg u_char *buf, *p; 18064910Swollman 180725944Sjoerg len -= 4; 180825944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 180925944Sjoerg if (!buf) 18104910Swollman return; 181125944Sjoerg 181225944Sjoerg if (debug) 181325944Sjoerg log(LOG_DEBUG, "%s%d: lcp rej opts: ", 181425944Sjoerg ifp->if_name, ifp->if_unit); 181525944Sjoerg 181625944Sjoerg p = (void*) (h+1); 181725944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 181825944Sjoerg if (debug) 181925944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 182025944Sjoerg switch (*p) { 182125944Sjoerg case LCP_OPT_MAGIC: 182225944Sjoerg /* Magic number -- can't use it, use 0 */ 182325944Sjoerg sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC); 182425944Sjoerg sp->lcp.magic = 0; 182525944Sjoerg break; 182625944Sjoerg case LCP_OPT_MRU: 182725944Sjoerg /* 182825944Sjoerg * Should not be rejected anyway, since we only 182925944Sjoerg * negotiate a MRU if explicitly requested by 183025944Sjoerg * peer. 183125944Sjoerg */ 183225944Sjoerg sp->lcp.opts &= ~(1 << LCP_OPT_MRU); 183325944Sjoerg break; 183425944Sjoerg } 18354910Swollman } 183625944Sjoerg if (debug) 183725944Sjoerg addlog("\n"); 183825944Sjoerg free (buf, M_TEMP); 183925944Sjoerg return; 184025944Sjoerg} 184125944Sjoerg 184225944Sjoerg/* 184325944Sjoerg * Analyze the LCP Configure-NAK option list, and adjust our 184425944Sjoerg * negotiation. 184525944Sjoerg */ 184625944Sjoergstatic void 184725944Sjoergsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) 184825944Sjoerg{ 184925944Sjoerg STDDCL; 185025944Sjoerg u_char *buf, *p; 185125944Sjoerg u_long magic; 185225944Sjoerg 185325944Sjoerg len -= 4; 185425944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 185525944Sjoerg if (!buf) 185625944Sjoerg return; 185725944Sjoerg 185825944Sjoerg if (debug) 185925944Sjoerg log(LOG_DEBUG, "%s%d: lcp nak opts: ", 186025944Sjoerg ifp->if_name, ifp->if_unit); 186125944Sjoerg 186225944Sjoerg p = (void*) (h+1); 186325944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 186425706Sjoerg if (debug) 186525944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 186625944Sjoerg switch (*p) { 186725944Sjoerg case LCP_OPT_MAGIC: 186825944Sjoerg /* Magic number -- renegotiate */ 186925944Sjoerg if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) && 187025944Sjoerg len >= 6 && p[1] == 6) { 187125944Sjoerg magic = (u_long)p[2] << 24 | 187225944Sjoerg (u_long)p[3] << 16 | p[4] << 8 | p[5]; 187325944Sjoerg /* 187425944Sjoerg * If the remote magic is our negated one, 187525944Sjoerg * this looks like a loopback problem. 187625944Sjoerg * Suggest a new magic to make sure. 187725944Sjoerg */ 187825944Sjoerg if (magic == ~sp->lcp.magic) { 187925944Sjoerg if (debug) 188025944Sjoerg addlog("magic glitch "); 188125944Sjoerg sp->lcp.magic += time.tv_sec + time.tv_usec; 188225944Sjoerg } else { 188325944Sjoerg sp->lcp.magic = magic; 188425944Sjoerg if (debug) 188525944Sjoerg addlog("%d "); 188625944Sjoerg } 188725944Sjoerg } 188825944Sjoerg break; 188925944Sjoerg case LCP_OPT_MRU: 189025944Sjoerg /* 189125944Sjoerg * Peer wants to advise us to negotiate an MRU. 189225944Sjoerg * Agree on it if it's reasonable, or use 189325944Sjoerg * default otherwise. 189425944Sjoerg */ 189525944Sjoerg if (len >= 4 && p[1] == 4) { 189625944Sjoerg u_int mru = p[2] * 256 + p[3]; 189725944Sjoerg if (debug) 189825944Sjoerg addlog("%d ", mru); 189925944Sjoerg if (mru < PP_MTU || mru > PP_MAX_MRU) 190025944Sjoerg mru = PP_MTU; 190125944Sjoerg sp->lcp.mru = mru; 190225944Sjoerg sp->lcp.opts |= (1 << LCP_OPT_MRU); 190325944Sjoerg } 190425944Sjoerg break; 19054910Swollman } 190625944Sjoerg } 190725944Sjoerg if (debug) 190825944Sjoerg addlog("\n"); 190925944Sjoerg free (buf, M_TEMP); 191025944Sjoerg return; 191125944Sjoerg} 191211189Sjkh 191325944Sjoergstatic void 191425944Sjoergsppp_lcp_tlu(struct sppp *sp) 191525944Sjoerg{ 191625944Sjoerg STDDCL; 191725944Sjoerg int i; 191825944Sjoerg u_long mask; 191925944Sjoerg 192025944Sjoerg /* XXX ? */ 192125944Sjoerg if (! (ifp->if_flags & IFF_UP) && 192225944Sjoerg (ifp->if_flags & IFF_RUNNING)) { 192325944Sjoerg /* Coming out of loopback mode. */ 192425944Sjoerg if_up(ifp); 192525944Sjoerg printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 192625944Sjoerg } 192725944Sjoerg 192825944Sjoerg for (i = 0; i < IDX_COUNT; i++) 192925944Sjoerg if ((cps[i])->flags & CP_QUAL) 193025944Sjoerg (cps[i])->Open(sp); 193125944Sjoerg 193225944Sjoerg if (/* require authentication XXX */ 0) 193325944Sjoerg sp->pp_phase = PHASE_AUTHENTICATE; 193425944Sjoerg else 193525944Sjoerg sp->pp_phase = PHASE_NETWORK; 193625944Sjoerg 193725944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 193825944Sjoerg sppp_phase_name(sp->pp_phase)); 193925944Sjoerg 194025944Sjoerg if (sp->pp_phase == PHASE_AUTHENTICATE) { 194125944Sjoerg for (i = 0; i < IDX_COUNT; i++) 194225944Sjoerg if ((cps[i])->flags & CP_AUTH) 194325944Sjoerg (cps[i])->Open(sp); 194425944Sjoerg } else { 194525944Sjoerg /* Notify all NCPs. */ 194625944Sjoerg for (i = 0; i < IDX_COUNT; i++) 194725944Sjoerg if ((cps[i])->flags & CP_NCP) 194825944Sjoerg (cps[i])->Open(sp); 194925944Sjoerg } 195025944Sjoerg 195125944Sjoerg /* Send Up events to all started protos. */ 195225944Sjoerg for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) 195325944Sjoerg if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) 195425944Sjoerg (cps[i])->Up(sp); 195525944Sjoerg 195625944Sjoerg if (sp->pp_phase == PHASE_NETWORK) 195725944Sjoerg /* if no NCP is starting, close down */ 195825944Sjoerg sppp_lcp_check(sp); 195925944Sjoerg} 196025944Sjoerg 196125944Sjoergstatic void 196225944Sjoergsppp_lcp_tld(struct sppp *sp) 196325944Sjoerg{ 196425944Sjoerg STDDCL; 196525944Sjoerg int i; 196625944Sjoerg u_long mask; 196725944Sjoerg 196825944Sjoerg sp->pp_phase = PHASE_TERMINATE; 196925944Sjoerg 197025944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 197125944Sjoerg sppp_phase_name(sp->pp_phase)); 197225944Sjoerg 197325944Sjoerg /* 197425944Sjoerg * Take upper layers down. We send the Down event first and 197525944Sjoerg * the Close second to prevent the upper layers from sending 197625944Sjoerg * ``a flurry of terminate-request packets'', as the RFC 197725944Sjoerg * describes it. 197825944Sjoerg */ 197925944Sjoerg for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) 198025944Sjoerg if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) { 198125944Sjoerg (cps[i])->Down(sp); 198225944Sjoerg (cps[i])->Close(sp); 198325944Sjoerg } 198425944Sjoerg} 198525944Sjoerg 198625944Sjoergstatic void 198725944Sjoergsppp_lcp_tls(struct sppp *sp) 198825944Sjoerg{ 198925944Sjoerg STDDCL; 199025944Sjoerg 199125944Sjoerg sp->pp_phase = PHASE_ESTABLISH; 199225944Sjoerg 199325944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 199425944Sjoerg sppp_phase_name(sp->pp_phase)); 199525944Sjoerg 199625944Sjoerg /* Notify lower layer if desired. */ 199725944Sjoerg if (sp->pp_tls) 199825944Sjoerg (sp->pp_tls)(sp); 199925944Sjoerg} 200025944Sjoerg 200125944Sjoergstatic void 200225944Sjoergsppp_lcp_tlf(struct sppp *sp) 200325944Sjoerg{ 200425944Sjoerg STDDCL; 200525944Sjoerg 200625944Sjoerg sp->pp_phase = PHASE_DEAD; 200725944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 200825944Sjoerg sppp_phase_name(sp->pp_phase)); 200925944Sjoerg 201025944Sjoerg /* Notify lower layer if desired. */ 201125944Sjoerg if (sp->pp_tlf) 201225944Sjoerg (sp->pp_tlf)(sp); 201325944Sjoerg} 201425944Sjoerg 201525944Sjoergstatic void 201625944Sjoergsppp_lcp_scr(struct sppp *sp) 201725944Sjoerg{ 201825944Sjoerg char opt[6 /* magicnum */ + 4 /* mru */]; 201925944Sjoerg int i = 0; 202025944Sjoerg 202125944Sjoerg if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) { 202225944Sjoerg if (! sp->lcp.magic) 202325944Sjoerg sp->lcp.magic = time.tv_sec + time.tv_usec; 202425944Sjoerg opt[i++] = LCP_OPT_MAGIC; 202525944Sjoerg opt[i++] = 6; 202625944Sjoerg opt[i++] = sp->lcp.magic >> 24; 202725944Sjoerg opt[i++] = sp->lcp.magic >> 16; 202825944Sjoerg opt[i++] = sp->lcp.magic >> 8; 202925944Sjoerg opt[i++] = sp->lcp.magic; 203025944Sjoerg } 203125944Sjoerg 203225944Sjoerg if (sp->lcp.opts & (1 << LCP_OPT_MRU)) { 203325944Sjoerg opt[i++] = LCP_OPT_MRU; 203425944Sjoerg opt[i++] = 4; 203525944Sjoerg opt[i++] = sp->lcp.mru >> 8; 203625944Sjoerg opt[i++] = sp->lcp.mru; 203725944Sjoerg } 203825944Sjoerg 203925944Sjoerg sp->confid[IDX_LCP] = ++sp->pp_seq; 204025944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); 204125944Sjoerg} 204225944Sjoerg 204325944Sjoerg/* 204425944Sjoerg * Re-check the open NCPs and see if we should terminate the link. 204525944Sjoerg * Called by the NCPs during their tlf action handling. 204625944Sjoerg */ 204725944Sjoergstatic void 204825944Sjoergsppp_lcp_check(struct sppp *sp) 204925944Sjoerg{ 205025944Sjoerg int i, mask; 205125944Sjoerg 205225944Sjoerg for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) 205325944Sjoerg if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP) 205425944Sjoerg return; 205525944Sjoerg lcp.Close(sp); 205625944Sjoerg} 205725944Sjoerg/* 205825944Sjoerg *--------------------------------------------------------------------------* 205925944Sjoerg * * 206025944Sjoerg * The IPCP implementation. * 206125944Sjoerg * * 206225944Sjoerg *--------------------------------------------------------------------------* 206325944Sjoerg */ 206425944Sjoerg 206525944Sjoergstatic void 206625944Sjoergsppp_ipcp_init(struct sppp *sp) 206725944Sjoerg{ 206825944Sjoerg sp->ipcp.opts = 0; 206925944Sjoerg sp->ipcp.flags = 0; 207025944Sjoerg sp->state[IDX_IPCP] = STATE_INITIAL; 207125944Sjoerg sp->fail_counter[IDX_IPCP] = 0; 207225944Sjoerg} 207325944Sjoerg 207425944Sjoergstatic void 207525944Sjoergsppp_ipcp_up(struct sppp *sp) 207625944Sjoerg{ 207725944Sjoerg sppp_up_event(&ipcp, sp); 207825944Sjoerg} 207925944Sjoerg 208025944Sjoergstatic void 208125944Sjoergsppp_ipcp_down(struct sppp *sp) 208225944Sjoerg{ 208325944Sjoerg sppp_down_event(&ipcp, sp); 208425944Sjoerg} 208525944Sjoerg 208625944Sjoergstatic void 208725944Sjoergsppp_ipcp_open(struct sppp *sp) 208825944Sjoerg{ 208925944Sjoerg STDDCL; 209025944Sjoerg u_long myaddr, hisaddr; 209125944Sjoerg 209225944Sjoerg sppp_get_ip_addrs(sp, &myaddr, &hisaddr); 209325944Sjoerg /* 209425944Sjoerg * If we don't have his address, this probably means our 209525944Sjoerg * interface doesn't want to talk IP at all. (This could 209625944Sjoerg * be the case if somebody wants to speak only IPX, for 209725944Sjoerg * example.) Don't open IPCP in this case. 209825944Sjoerg */ 209925944Sjoerg if (hisaddr == 0L) { 210025944Sjoerg /* XXX this message should go away */ 210125944Sjoerg if (debug) 210225944Sjoerg log(LOG_DEBUG, "%s%d: ipcp_open(): no IP interface\n", 210325944Sjoerg ifp->if_name, ifp->if_unit); 210425944Sjoerg return; 210525944Sjoerg } 210625944Sjoerg 210725944Sjoerg if (myaddr == 0L) { 210825944Sjoerg /* 210925944Sjoerg * I don't have an assigned address, so i need to 211025944Sjoerg * negotiate my address. 211125944Sjoerg */ 211225944Sjoerg sp->ipcp.flags |= IPCP_MYADDR_DYN; 211325944Sjoerg sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); 211425944Sjoerg } 211525944Sjoerg sppp_open_event(&ipcp, sp); 211625944Sjoerg} 211725944Sjoerg 211825944Sjoergstatic void 211925944Sjoergsppp_ipcp_close(struct sppp *sp) 212025944Sjoerg{ 212125944Sjoerg sppp_close_event(&ipcp, sp); 212225944Sjoerg if (sp->ipcp.flags & IPCP_MYADDR_DYN) 212325944Sjoerg /* 212425944Sjoerg * My address was dynamic, clear it again. 212525944Sjoerg */ 212625944Sjoerg sppp_set_ip_addr(sp, 0L); 212725944Sjoerg} 212825944Sjoerg 212925944Sjoergstatic void 213025944Sjoergsppp_ipcp_TO(void *cookie) 213125944Sjoerg{ 213225944Sjoerg sppp_to_event(&ipcp, (struct sppp *)cookie); 213325944Sjoerg} 213425944Sjoerg 213525944Sjoerg/* 213625944Sjoerg * Analyze a configure request. Return true if it was agreeable, and 213725944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and 213825944Sjoerg * caused action scn. (The return value is used to make the state 213925944Sjoerg * transition decision in the state automaton.) 214025944Sjoerg */ 214125944Sjoergstatic int 214225944Sjoergsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) 214325944Sjoerg{ 214425944Sjoerg u_char *buf, *r, *p; 214525944Sjoerg struct ifnet *ifp = &sp->pp_if; 214625944Sjoerg int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; 214725944Sjoerg u_long hisaddr, desiredaddr; 214825944Sjoerg 214925944Sjoerg len -= 4; 215025944Sjoerg origlen = len; 215125944Sjoerg /* 215225944Sjoerg * Make sure to allocate a buf that can at least hold a 215325944Sjoerg * conf-nak with an `address' option. We might need it below. 215425944Sjoerg */ 215525944Sjoerg buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT); 215625944Sjoerg if (! buf) 215725944Sjoerg return (0); 215825944Sjoerg 215925944Sjoerg /* pass 1: see if we can recognize them */ 216025944Sjoerg if (debug) 216125944Sjoerg log(LOG_DEBUG, "%s%d: ipcp parse opts: ", 216225944Sjoerg ifp->if_name, ifp->if_unit); 216325944Sjoerg p = (void*) (h+1); 216425944Sjoerg for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 216525944Sjoerg if (debug) 216625944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 216725944Sjoerg switch (*p) { 216825944Sjoerg#ifdef notyet 216925944Sjoerg case IPCP_OPT_COMPRESSION: 217025944Sjoerg if (len >= 6 && p[1] >= 6) { 217125944Sjoerg /* correctly formed compress option */ 217225944Sjoerg continue; 217311189Sjkh } 217425706Sjoerg if (debug) 217525944Sjoerg addlog("[invalid] "); 217625944Sjoerg break; 217725944Sjoerg#endif 217825944Sjoerg case IPCP_OPT_ADDRESS: 217925944Sjoerg if (len >= 6 && p[1] == 6) { 218025944Sjoerg /* correctly formed address option */ 218125944Sjoerg continue; 218225944Sjoerg } 218325706Sjoerg if (debug) 218425944Sjoerg addlog("[invalid] "); 218511189Sjkh break; 218625944Sjoerg default: 218725944Sjoerg /* Others not supported. */ 218825944Sjoerg if (debug) 218925944Sjoerg addlog("[rej] "); 21904910Swollman break; 21914910Swollman } 219225944Sjoerg /* Add the option to rejected list. */ 219325944Sjoerg bcopy (p, r, p[1]); 219425944Sjoerg r += p[1]; 219525944Sjoerg rlen += p[1]; 219625944Sjoerg } 219725944Sjoerg if (rlen) { 219825944Sjoerg if (debug) 219925944Sjoerg addlog(" send conf-rej\n"); 220025944Sjoerg sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf); 220125944Sjoerg return 0; 220225944Sjoerg } else if (debug) 220325944Sjoerg addlog("\n"); 220425944Sjoerg 220525944Sjoerg /* pass 2: parse option values */ 220625944Sjoerg sppp_get_ip_addrs(sp, 0, &hisaddr); 220725944Sjoerg if (debug) 220825944Sjoerg addlog("%s%d: ipcp parse opt values: ", ifp->if_name, ifp->if_unit); 220925944Sjoerg p = (void*) (h+1); 221025944Sjoerg len = origlen; 221125944Sjoerg for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 221225944Sjoerg if (debug) 221325944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 221425944Sjoerg switch (*p) { 221525944Sjoerg#ifdef notyet 221625944Sjoerg case IPCP_OPT_COMPRESSION: 221725944Sjoerg continue; 221825944Sjoerg#endif 221925944Sjoerg case IPCP_OPT_ADDRESS: 222025944Sjoerg desiredaddr = p[2] << 24 | p[3] << 16 | 222125944Sjoerg p[4] << 8 | p[5]; 222225944Sjoerg if (desiredaddr == hisaddr) { 222325944Sjoerg /* 222425944Sjoerg * Peer's address is same as our value, 222525944Sjoerg * this is agreeable. Gonna conf-ack 222625944Sjoerg * it. 222725944Sjoerg */ 222825944Sjoerg if (debug) 222925944Sjoerg addlog("0x%x [ack] ", hisaddr); 223025944Sjoerg /* record that we've seen it already */ 223125944Sjoerg sp->ipcp.flags |= IPCP_HISADDR_SEEN; 223225944Sjoerg continue; 223325944Sjoerg } 223425944Sjoerg /* 223525944Sjoerg * The address wasn't agreeable. This is either 223625944Sjoerg * he sent us 0.0.0.0, asking to assign him an 223725944Sjoerg * address, or he send us another address not 223825944Sjoerg * matching our value. Either case, we gonna 223925944Sjoerg * conf-nak it with our value. 224025944Sjoerg */ 224125944Sjoerg if (debug) { 224225944Sjoerg if (desiredaddr == 0) 224325944Sjoerg addlog("[addr requested] "); 224425944Sjoerg else 224525944Sjoerg addlog("0x%x [not agreed] ", 224625944Sjoerg desiredaddr); 224725944Sjoerg 224825944Sjoerg p[2] = hisaddr >> 24; 224925944Sjoerg p[3] = hisaddr >> 16; 225025944Sjoerg p[4] = hisaddr >> 8; 225125944Sjoerg p[5] = hisaddr; 225225944Sjoerg } 225311189Sjkh break; 225425706Sjoerg } 225525944Sjoerg /* Add the option to nak'ed list. */ 225625944Sjoerg bcopy (p, r, p[1]); 225725944Sjoerg r += p[1]; 225825944Sjoerg rlen += p[1]; 225925944Sjoerg } 226025944Sjoerg 226125944Sjoerg /* 226225944Sjoerg * If we are about to conf-ack the request, but haven't seen 226325944Sjoerg * his address so far, gonna conf-nak it instead, with the 226425944Sjoerg * `address' option present and our idea of his address being 226525944Sjoerg * filled in there, to request negotiation of both addresses. 226625944Sjoerg * 226725944Sjoerg * XXX This can result in an endless req - nak loop if peer 226825944Sjoerg * doesn't want to send us his address. Q: What should we do 226925944Sjoerg * about it? XXX A: implement the max-failure counter. 227025944Sjoerg */ 227125944Sjoerg if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) { 227225944Sjoerg buf[0] = IPCP_OPT_ADDRESS; 227325944Sjoerg buf[1] = 6; 227425944Sjoerg buf[2] = hisaddr >> 24; 227525944Sjoerg buf[3] = hisaddr >> 16; 227625944Sjoerg buf[4] = hisaddr >> 8; 227725944Sjoerg buf[5] = hisaddr; 227825944Sjoerg rlen = 6; 227925706Sjoerg if (debug) 228025944Sjoerg addlog("still need hisaddr "); 228125944Sjoerg } 228225944Sjoerg 228325944Sjoerg if (rlen) { 228425706Sjoerg if (debug) 228525944Sjoerg addlog(" send conf-nak\n"); 228625944Sjoerg sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf); 228725944Sjoerg } else { 228825706Sjoerg if (debug) 228925944Sjoerg addlog(" send conf-ack\n"); 229025944Sjoerg sppp_cp_send (sp, PPP_IPCP, CONF_ACK, 229125944Sjoerg h->ident, origlen, h+1); 229225944Sjoerg } 229325944Sjoerg 229425944Sjoerg free (buf, M_TEMP); 229525944Sjoerg return (rlen == 0); 229625944Sjoerg} 229725944Sjoerg 229825944Sjoerg/* 229925944Sjoerg * Analyze the IPCP Configure-Reject option list, and adjust our 230025944Sjoerg * negotiation. 230125944Sjoerg */ 230225944Sjoergstatic void 230325944Sjoergsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) 230425944Sjoerg{ 230525944Sjoerg u_char *buf, *p; 230625944Sjoerg struct ifnet *ifp = &sp->pp_if; 230725944Sjoerg int debug = ifp->if_flags & IFF_DEBUG; 230825944Sjoerg 230925944Sjoerg len -= 4; 231025944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 231125944Sjoerg if (!buf) 231225944Sjoerg return; 231325944Sjoerg 231425944Sjoerg if (debug) 231525944Sjoerg log(LOG_DEBUG, "%s%d: ipcp rej opts: ", 231625944Sjoerg ifp->if_name, ifp->if_unit); 231725944Sjoerg 231825944Sjoerg p = (void*) (h+1); 231925944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 232025706Sjoerg if (debug) 232125944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 232225944Sjoerg switch (*p) { 232325944Sjoerg case IPCP_OPT_ADDRESS: 232425944Sjoerg /* 232525944Sjoerg * Peer doesn't grok address option. This is 232625944Sjoerg * bad. XXX Should we better give up here? 232725944Sjoerg */ 232825944Sjoerg sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS); 232925944Sjoerg break; 233025944Sjoerg#ifdef notyet 233125944Sjoerg case IPCP_OPT_COMPRESS: 233225944Sjoerg sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS); 233325944Sjoerg break; 233425944Sjoerg#endif 233525944Sjoerg } 23364910Swollman } 233725944Sjoerg if (debug) 233825944Sjoerg addlog("\n"); 233925944Sjoerg free (buf, M_TEMP); 234025944Sjoerg return; 23414910Swollman} 23424910Swollman 234325944Sjoerg/* 234425944Sjoerg * Analyze the IPCP Configure-NAK option list, and adjust our 234525944Sjoerg * negotiation. 234625944Sjoerg */ 234712820Sphkstatic void 234825944Sjoergsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) 23494910Swollman{ 235025944Sjoerg u_char *buf, *p; 235125944Sjoerg struct ifnet *ifp = &sp->pp_if; 235225944Sjoerg int debug = ifp->if_flags & IFF_DEBUG; 235325944Sjoerg u_long wantaddr; 23544910Swollman 235525944Sjoerg len -= 4; 235625944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 235725944Sjoerg if (!buf) 235825944Sjoerg return; 235925944Sjoerg 236025944Sjoerg if (debug) 236125944Sjoerg log(LOG_DEBUG, "%s%d: ipcp nak opts: ", 236225944Sjoerg ifp->if_name, ifp->if_unit); 236325944Sjoerg 236425944Sjoerg p = (void*) (h+1); 236525944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 236625944Sjoerg if (debug) 236725944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 236825944Sjoerg switch (*p) { 236925944Sjoerg case IPCP_OPT_ADDRESS: 237025944Sjoerg /* 237125944Sjoerg * Peer doesn't like our local IP address. See 237225944Sjoerg * if we can do something for him. We'll drop 237325944Sjoerg * him our address then. 237425944Sjoerg */ 237525944Sjoerg if (len >= 6 && p[1] == 6) { 237625944Sjoerg wantaddr = p[2] << 24 | p[3] << 16 | 237725944Sjoerg p[4] << 8 | p[5]; 237825944Sjoerg sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); 237925944Sjoerg if (debug) 238025944Sjoerg addlog("[wantaddr 0x%x] ", wantaddr); 238125944Sjoerg /* 238225944Sjoerg * When doing dynamic address assignment, 238325944Sjoerg * we accept his offer. Otherwise, we 238425944Sjoerg * ignore it and thus continue to negotiate 238525944Sjoerg * our already existing value. 238625944Sjoerg */ 238725944Sjoerg if (sp->ipcp.flags & IPCP_MYADDR_DYN) { 238825944Sjoerg sppp_set_ip_addr(sp, wantaddr); 238925944Sjoerg if (debug) 239025944Sjoerg addlog("[agree] "); 239125944Sjoerg } 239225944Sjoerg } 239325944Sjoerg break; 239425944Sjoerg#ifdef notyet 239525944Sjoerg case IPCP_OPT_COMPRESS: 239625944Sjoerg /* 239725944Sjoerg * Peer wants different compression parameters. 239825944Sjoerg */ 239925944Sjoerg break; 240025944Sjoerg#endif 240125944Sjoerg } 240225944Sjoerg } 240325944Sjoerg if (debug) 240425944Sjoerg addlog("\n"); 240525944Sjoerg free (buf, M_TEMP); 240625944Sjoerg return; 24074910Swollman} 24084910Swollman 240912820Sphkstatic void 241025944Sjoergsppp_ipcp_tlu(struct sppp *sp) 24114910Swollman{ 24124910Swollman} 24134910Swollman 241425944Sjoergstatic void 241525944Sjoergsppp_ipcp_tld(struct sppp *sp) 241625944Sjoerg{ 241725944Sjoerg} 241825944Sjoerg 241925944Sjoergstatic void 242025944Sjoergsppp_ipcp_tls(struct sppp *sp) 242125944Sjoerg{ 242225944Sjoerg /* indicate to LCP that it must stay alive */ 242325944Sjoerg sp->lcp.protos |= (1 << IDX_IPCP); 242425944Sjoerg} 242525944Sjoerg 242625944Sjoergstatic void 242725944Sjoergsppp_ipcp_tlf(struct sppp *sp) 242825944Sjoerg{ 242925944Sjoerg /* we no longer need LCP */ 243025944Sjoerg sp->lcp.protos &= ~(1 << IDX_IPCP); 243125944Sjoerg sppp_lcp_check(sp); 243225944Sjoerg} 243325944Sjoerg 243425944Sjoergstatic void 243525944Sjoergsppp_ipcp_scr(struct sppp *sp) 243625944Sjoerg{ 243725944Sjoerg char opt[6 /* compression */ + 6 /* address */]; 243825944Sjoerg u_long ouraddr; 243925944Sjoerg int i = 0; 244025944Sjoerg 244125944Sjoerg#ifdef notyet 244225944Sjoerg if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) { 244325944Sjoerg opt[i++] = IPCP_OPT_COMPRESSION; 244425944Sjoerg opt[i++] = 6; 244525944Sjoerg opt[i++] = 0; /* VJ header compression */ 244625944Sjoerg opt[i++] = 0x2d; /* VJ header compression */ 244725944Sjoerg opt[i++] = max_slot_id; 244825944Sjoerg opt[i++] = comp_slot_id; 244925944Sjoerg } 245025944Sjoerg#endif 245125944Sjoerg 245225944Sjoerg if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) { 245325944Sjoerg sppp_get_ip_addrs(sp, &ouraddr, 0); 245425944Sjoerg opt[i++] = IPCP_OPT_ADDRESS; 245525944Sjoerg opt[i++] = 6; 245625944Sjoerg opt[i++] = ouraddr >> 24; 245725944Sjoerg opt[i++] = ouraddr >> 16; 245825944Sjoerg opt[i++] = ouraddr >> 8; 245925944Sjoerg opt[i++] = ouraddr; 246025944Sjoerg } 246125944Sjoerg 246225944Sjoerg sp->confid[IDX_IPCP] = ++sp->pp_seq; 246325944Sjoerg sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt); 246425944Sjoerg} 246525944Sjoerg 246625944Sjoerg 246725944Sjoerg/* 246825944Sjoerg * Random miscellaneous functions. 246925944Sjoerg */ 247025944Sjoerg 24714910Swollman/* 247225944Sjoerg * Flush interface queue. 24734910Swollman */ 247412820Sphkstatic void 247525944Sjoergsppp_qflush(struct ifqueue *ifq) 24764910Swollman{ 247725944Sjoerg struct mbuf *m, *n; 24784910Swollman 247925944Sjoerg n = ifq->ifq_head; 248025944Sjoerg while ((m = n)) { 248125944Sjoerg n = m->m_act; 248225944Sjoerg m_freem (m); 248311189Sjkh } 248425944Sjoerg ifq->ifq_head = 0; 248525944Sjoerg ifq->ifq_tail = 0; 248625944Sjoerg ifq->ifq_len = 0; 248725944Sjoerg} 248825944Sjoerg 248925944Sjoerg/* 249025944Sjoerg * Send keepalive packets, every 10 seconds. 249125944Sjoerg */ 249225944Sjoergstatic void 249325944Sjoergsppp_keepalive(void *dummy) 249425944Sjoerg{ 249525944Sjoerg struct sppp *sp; 249625944Sjoerg int s; 249725944Sjoerg 249825944Sjoerg s = splimp(); 249925944Sjoerg for (sp=spppq; sp; sp=sp->pp_next) { 250025944Sjoerg struct ifnet *ifp = &sp->pp_if; 250125944Sjoerg 250225944Sjoerg /* Keepalive mode disabled or channel down? */ 250325944Sjoerg if (! (sp->pp_flags & PP_KEEPALIVE) || 250425944Sjoerg ! (ifp->if_flags & IFF_RUNNING)) 250525944Sjoerg continue; 250625944Sjoerg 250725944Sjoerg /* No keepalive in PPP mode if LCP not opened yet. */ 250825944Sjoerg if (! (sp->pp_flags & PP_CISCO) && 250925944Sjoerg sp->pp_phase < PHASE_AUTHENTICATE) 251025944Sjoerg continue; 251125944Sjoerg 251225944Sjoerg if (sp->pp_alivecnt == MAXALIVECNT) { 251325944Sjoerg /* No keepalive packets got. Stop the interface. */ 251425944Sjoerg printf ("%s%d: down\n", ifp->if_name, ifp->if_unit); 251525944Sjoerg if_down (ifp); 251625944Sjoerg sppp_qflush (&sp->pp_fastq); 251725944Sjoerg if (! (sp->pp_flags & PP_CISCO)) { 251825944Sjoerg /* XXX */ 251925944Sjoerg /* Shut down the PPP link. */ 252025944Sjoerg lcp.Down(sp); 252125944Sjoerg /* Initiate negotiation. XXX */ 252225944Sjoerg lcp.Up(sp); 252325944Sjoerg } 25244910Swollman } 252525944Sjoerg if (sp->pp_alivecnt <= MAXALIVECNT) 252625944Sjoerg ++sp->pp_alivecnt; 252725944Sjoerg if (sp->pp_flags & PP_CISCO) 252825944Sjoerg sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, 252925944Sjoerg sp->pp_rseq); 253025944Sjoerg else if (sp->pp_phase >= PHASE_AUTHENTICATE) { 253125944Sjoerg long nmagic = htonl (sp->lcp.magic); 253225944Sjoerg sp->lcp.echoid = ++sp->pp_seq; 253325944Sjoerg sppp_cp_send (sp, PPP_LCP, ECHO_REQ, 253425944Sjoerg sp->lcp.echoid, 4, &nmagic); 253525944Sjoerg } 25364910Swollman } 253725944Sjoerg splx(s); 253825944Sjoerg timeout(sppp_keepalive, 0, hz * 10); 25394910Swollman} 25404910Swollman 254125944Sjoerg/* 254225944Sjoerg * Get both IP addresses. 254325944Sjoerg */ 254425944Sjoergstatic void 254525944Sjoergsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst) 254625944Sjoerg{ 254725944Sjoerg struct ifnet *ifp = &sp->pp_if; 254825944Sjoerg struct ifaddr *ifa; 254925944Sjoerg struct sockaddr_in *si; 255025944Sjoerg u_long ssrc, ddst; 255125944Sjoerg 255225944Sjoerg ssrc = ddst = 0L; 255325944Sjoerg /* 255425944Sjoerg * Pick the first AF_INET address from the list, 255525944Sjoerg * aliases don't make any sense on a p2p link anyway. 255625944Sjoerg */ 255725944Sjoerg for (ifa = ifp->if_addrhead.tqh_first, si = 0; 255825944Sjoerg ifa; 255925944Sjoerg ifa = ifa->ifa_link.tqe_next) 256025944Sjoerg if (ifa->ifa_addr->sa_family == AF_INET) { 256125944Sjoerg si = (struct sockaddr_in *)ifa->ifa_addr; 256225944Sjoerg if (si) 256325944Sjoerg break; 256425944Sjoerg } 256525944Sjoerg if (ifa) { 256625944Sjoerg if (si && si->sin_addr.s_addr) 256725944Sjoerg ssrc = si->sin_addr.s_addr; 256825944Sjoerg 256925944Sjoerg si = (struct sockaddr_in *)ifa->ifa_dstaddr; 257025944Sjoerg if (si && si->sin_addr.s_addr) 257125944Sjoerg ddst = si->sin_addr.s_addr; 257225944Sjoerg } 257325944Sjoerg 257425944Sjoerg if (dst) *dst = ntohl(ddst); 257525944Sjoerg if (src) *src = ntohl(ssrc); 257625944Sjoerg} 257725944Sjoerg 257825944Sjoerg/* 257925944Sjoerg * Set my IP address. Must be called at splimp. 258025944Sjoerg */ 258125944Sjoergstatic void 258225944Sjoergsppp_set_ip_addr(struct sppp *sp, u_long src) 258325944Sjoerg{ 258425944Sjoerg struct ifnet *ifp = &sp->pp_if; 258525944Sjoerg struct ifaddr *ifa; 258625944Sjoerg struct sockaddr_in *si; 258725944Sjoerg u_long ssrc, ddst; 258825944Sjoerg 258925944Sjoerg /* 259025944Sjoerg * Pick the first AF_INET address from the list, 259125944Sjoerg * aliases don't make any sense on a p2p link anyway. 259225944Sjoerg */ 259325944Sjoerg for (ifa = ifp->if_addrhead.tqh_first, si = 0; 259425944Sjoerg ifa; 259525944Sjoerg ifa = ifa->ifa_link.tqe_next) 259625944Sjoerg if (ifa->ifa_addr->sa_family == AF_INET) { 259725944Sjoerg si = (struct sockaddr_in *)ifa->ifa_addr; 259825944Sjoerg if (si) 259925944Sjoerg break; 260025944Sjoerg } 260125944Sjoerg if (ifa && si) 260225944Sjoerg si->sin_addr.s_addr = htonl(src); 260325944Sjoerg} 260425944Sjoerg 260525706Sjoergstatic const char * 260625944Sjoergsppp_cp_type_name(u_char type) 26074910Swollman{ 260825706Sjoerg static char buf [12]; 26094910Swollman switch (type) { 261025944Sjoerg case CONF_REQ: return ("conf-req"); 261125944Sjoerg case CONF_ACK: return ("conf-ack"); 261225944Sjoerg case CONF_NAK: return ("conf-nak"); 261325944Sjoerg case CONF_REJ: return ("conf-rej"); 261425944Sjoerg case TERM_REQ: return ("term-req"); 261525944Sjoerg case TERM_ACK: return ("term-ack"); 261625944Sjoerg case CODE_REJ: return ("code-rej"); 261725944Sjoerg case PROTO_REJ: return ("proto-rej"); 261825944Sjoerg case ECHO_REQ: return ("echo-req"); 261925944Sjoerg case ECHO_REPLY: return ("echo-reply"); 262025944Sjoerg case DISC_REQ: return ("discard-req"); 26214910Swollman } 262225706Sjoerg sprintf (buf, "0x%x", type); 26234910Swollman return (buf); 26244910Swollman} 26254910Swollman 262625706Sjoergstatic const char * 262725944Sjoergsppp_lcp_opt_name(u_char opt) 26284910Swollman{ 262925706Sjoerg static char buf [12]; 263025944Sjoerg switch (opt) { 263125944Sjoerg case LCP_OPT_MRU: return ("mru"); 263225944Sjoerg case LCP_OPT_ASYNC_MAP: return ("async-map"); 263325944Sjoerg case LCP_OPT_AUTH_PROTO: return ("auth-proto"); 263425944Sjoerg case LCP_OPT_QUAL_PROTO: return ("qual-proto"); 263525944Sjoerg case LCP_OPT_MAGIC: return ("magic"); 263625944Sjoerg case LCP_OPT_PROTO_COMP: return ("proto-comp"); 263725944Sjoerg case LCP_OPT_ADDR_COMP: return ("addr-comp"); 26384910Swollman } 263925944Sjoerg sprintf (buf, "0x%x", opt); 26404910Swollman return (buf); 26414910Swollman} 26424910Swollman 264325944Sjoergstatic const char * 264425944Sjoergsppp_ipcp_opt_name(u_char opt) 264525944Sjoerg{ 264625944Sjoerg static char buf [12]; 264725944Sjoerg switch (opt) { 264825944Sjoerg case IPCP_OPT_ADDRESSES: return ("addresses"); 264925944Sjoerg case IPCP_OPT_COMPRESSION: return ("compression"); 265025944Sjoerg case IPCP_OPT_ADDRESS: return ("address"); 265125944Sjoerg } 265225944Sjoerg sprintf (buf, "0x%x", opt); 265325944Sjoerg return (buf); 265425944Sjoerg} 265525944Sjoerg 265625944Sjoergstatic const char * 265725944Sjoergsppp_state_name(int state) 265825944Sjoerg{ 265925944Sjoerg switch (state) { 266025944Sjoerg case STATE_INITIAL: return "initial"; 266125944Sjoerg case STATE_STARTING: return "starting"; 266225944Sjoerg case STATE_CLOSED: return "closed"; 266325944Sjoerg case STATE_STOPPED: return "stopped"; 266425944Sjoerg case STATE_CLOSING: return "closing"; 266525944Sjoerg case STATE_STOPPING: return "stopping"; 266625944Sjoerg case STATE_REQ_SENT: return "req-sent"; 266725944Sjoerg case STATE_ACK_RCVD: return "ack-rcvd"; 266825944Sjoerg case STATE_ACK_SENT: return "ack-sent"; 266925944Sjoerg case STATE_OPENED: return "opened"; 267025944Sjoerg } 267125944Sjoerg return "illegal"; 267225944Sjoerg} 267325944Sjoerg 267425944Sjoergstatic const char * 267525944Sjoergsppp_phase_name(enum ppp_phase phase) 267625944Sjoerg{ 267725944Sjoerg switch (phase) { 267825944Sjoerg case PHASE_DEAD: return "dead"; 267925944Sjoerg case PHASE_ESTABLISH: return "establish"; 268025944Sjoerg case PHASE_TERMINATE: return "terminate"; 268125944Sjoerg case PHASE_AUTHENTICATE: return "authenticate"; 268225944Sjoerg case PHASE_NETWORK: return "network"; 268325944Sjoerg } 268425944Sjoerg return "illegal"; 268525944Sjoerg} 268625944Sjoerg 268725944Sjoergstatic const char * 268825944Sjoergsppp_proto_name(u_short proto) 268925944Sjoerg{ 269025944Sjoerg static char buf[12]; 269125944Sjoerg switch (proto) { 269225944Sjoerg case PPP_LCP: return "lcp"; 269325944Sjoerg case PPP_IPCP: return "ipcp"; 269425944Sjoerg } 269525944Sjoerg sprintf(buf, "0x%x", (unsigned)proto); 269625944Sjoerg return buf; 269725944Sjoerg} 269825944Sjoerg 269912820Sphkstatic void 270025706Sjoergsppp_print_bytes(u_char *p, u_short len) 27014910Swollman{ 270225706Sjoerg addlog(" %x", *p++); 27034910Swollman while (--len > 0) 270425706Sjoerg addlog("-%x", *p++); 27054910Swollman} 270625944Sjoerg 270725944Sjoerg/* 270825944Sjoerg * This file is large. Tell emacs to highlight it nevertheless. 270925944Sjoerg * 271025944Sjoerg * Local Variables: 271125944Sjoerg * hilit-auto-highlight-maxout: 100000 271225944Sjoerg * End: 271325944Sjoerg */ 2714