if_spppsubr.c revision 27929
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 * 2027929Sitojun * $Id: if_spppsubr.c,v 1.22 1997/05/23 20:40:15 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 * 6825955Sjoerg * Setting link0 will make the link passive, i.e. it will be marked 6925944Sjoerg * as being administrative openable, but won't be opened to begin 7025944Sjoerg * with. Incoming calls will be answered, or subsequent calls with 7125944Sjoerg * -link1 will cause the administrative open of the LCP layer. 7225955Sjoerg * 7325955Sjoerg * Setting link1 will cause the link to auto-dial only as packets 7425955Sjoerg * arrive to be sent. 7525944Sjoerg */ 7625944Sjoerg 7725955Sjoerg#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ 7825955Sjoerg#define IFF_AUTO IFF_LINK1 /* auto-dial on output */ 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; 48625955Sjoerg int s, rv = 0; 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); 55411189Sjkh else { 55525955Sjoerg /* 55625955Sjoerg * Don't choke with an ENETDOWN early. It's 55725955Sjoerg * possible that we just started dialing out, 55825955Sjoerg * so don't drop the packet immediately. If 55925955Sjoerg * we notice that we run out of buffer space 56025955Sjoerg * below, we will however remember that we are 56125955Sjoerg * not ready to carry IP packets, and return 56225955Sjoerg * ENETDOWN, as opposed to ENOBUFS. 56325955Sjoerg */ 56425955Sjoerg h->protocol = htons(PPP_IP); 56525955Sjoerg if (sp->state[IDX_IPCP] != STATE_OPENED) 56625955Sjoerg rv = ENETDOWN; 56711189Sjkh } 5684910Swollman break; 5694910Swollman#endif 5704910Swollman#ifdef NS 5714910Swollman case AF_NS: /* Xerox NS Protocol */ 5724910Swollman h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 5734910Swollman ETHERTYPE_NS : PPP_XNS); 5744910Swollman break; 5754910Swollman#endif 57611819Sjulian#ifdef IPX 57712495Speter case AF_IPX: /* Novell IPX Protocol */ 57811819Sjulian h->protocol = htons ((sp->pp_flags & PP_CISCO) ? 57912495Speter ETHERTYPE_IPX : PPP_IPX); 58011819Sjulian break; 58111819Sjulian#endif 5824910Swollman#ifdef ISO 5834910Swollman case AF_ISO: /* ISO OSI Protocol */ 5844910Swollman if (sp->pp_flags & PP_CISCO) 5854910Swollman goto nosupport; 5864910Swollman h->protocol = htons (PPP_ISO); 5874910Swollman break; 58812820Sphknosupport: 5894910Swollman#endif 5904910Swollman default: 5914910Swollman m_freem (m); 59225944Sjoerg ++ifp->if_oerrors; 5934910Swollman splx (s); 5944910Swollman return (EAFNOSUPPORT); 5954910Swollman } 5964910Swollman 5974910Swollman /* 5984910Swollman * Queue message on interface, and start output if interface 5994910Swollman * not yet active. 6004910Swollman */ 6014910Swollman if (IF_QFULL (ifq)) { 6024910Swollman IF_DROP (&ifp->if_snd); 6034910Swollman m_freem (m); 60425944Sjoerg ++ifp->if_oerrors; 6054910Swollman splx (s); 60625955Sjoerg return (rv? rv: ENOBUFS); 6074910Swollman } 6084910Swollman IF_ENQUEUE (ifq, m); 6094910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 6104910Swollman (*ifp->if_start) (ifp); 6114910Swollman 6124910Swollman /* 6134910Swollman * Count output packets and bytes. 6144910Swollman * The packet length includes header, FCS and 1 flag, 6154910Swollman * according to RFC 1333. 6164910Swollman */ 6174910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 6184910Swollman splx (s); 6194910Swollman return (0); 6204910Swollman} 6214910Swollman 62225706Sjoergvoid 62325706Sjoergsppp_attach(struct ifnet *ifp) 6244910Swollman{ 6254910Swollman struct sppp *sp = (struct sppp*) ifp; 6264910Swollman 6274910Swollman /* Initialize keepalive handler. */ 6284910Swollman if (! spppq) 62911189Sjkh timeout (sppp_keepalive, 0, hz * 10); 6304910Swollman 6314910Swollman /* Insert new entry into the keepalive list. */ 6324910Swollman sp->pp_next = spppq; 6334910Swollman spppq = sp; 6344910Swollman 6354910Swollman sp->pp_if.if_type = IFT_PPP; 6364910Swollman sp->pp_if.if_output = sppp_output; 6374910Swollman sp->pp_fastq.ifq_maxlen = 32; 63826018Sjoerg sp->pp_cpq.ifq_maxlen = 20; 6394910Swollman sp->pp_loopcnt = 0; 6404910Swollman sp->pp_alivecnt = 0; 64111189Sjkh sp->pp_seq = 0; 6424910Swollman sp->pp_rseq = 0; 64325944Sjoerg sp->pp_phase = PHASE_DEAD; 64425944Sjoerg sp->pp_up = lcp.Up; 64525944Sjoerg sp->pp_down = lcp.Down; 64625944Sjoerg 64725944Sjoerg sppp_lcp_init(sp); 64825944Sjoerg sppp_ipcp_init(sp); 6494910Swollman} 6504910Swollman 65112820Sphkvoid 65225706Sjoergsppp_detach(struct ifnet *ifp) 6534910Swollman{ 6544910Swollman struct sppp **q, *p, *sp = (struct sppp*) ifp; 65525944Sjoerg int i; 6564910Swollman 6574910Swollman /* Remove the entry from the keepalive list. */ 6584910Swollman for (q = &spppq; (p = *q); q = &p->pp_next) 6594910Swollman if (p == sp) { 6604910Swollman *q = p->pp_next; 6614910Swollman break; 6624910Swollman } 6634910Swollman 6644910Swollman /* Stop keepalive handler. */ 6654910Swollman if (! spppq) 66611189Sjkh untimeout (sppp_keepalive, 0); 66725944Sjoerg 66825944Sjoerg for (i = 0; i < IDX_COUNT; i++) 66925944Sjoerg untimeout((cps[i])->TO, (void *)sp); 6704910Swollman} 6714910Swollman 6724910Swollman/* 6734910Swollman * Flush the interface output queue. 6744910Swollman */ 67525706Sjoergvoid 67625706Sjoergsppp_flush(struct ifnet *ifp) 6774910Swollman{ 6784910Swollman struct sppp *sp = (struct sppp*) ifp; 6794910Swollman 68025944Sjoerg sppp_qflush (&sp->pp_if.if_snd); 68125944Sjoerg sppp_qflush (&sp->pp_fastq); 68226018Sjoerg sppp_qflush (&sp->pp_cpq); 6834910Swollman} 6844910Swollman 6854910Swollman/* 68611189Sjkh * Check if the output queue is empty. 68711189Sjkh */ 68812820Sphkint 68925706Sjoergsppp_isempty(struct ifnet *ifp) 69011189Sjkh{ 69111189Sjkh struct sppp *sp = (struct sppp*) ifp; 69225944Sjoerg int empty, s; 69311189Sjkh 69425944Sjoerg s = splimp(); 69526018Sjoerg empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head && 69626018Sjoerg !sp->pp_if.if_snd.ifq_head; 69725944Sjoerg splx(s); 69811189Sjkh return (empty); 69911189Sjkh} 70011189Sjkh 70111189Sjkh/* 7024910Swollman * Get next packet to send. 7034910Swollman */ 70425706Sjoergstruct mbuf * 70525706Sjoergsppp_dequeue(struct ifnet *ifp) 7064910Swollman{ 7074910Swollman struct sppp *sp = (struct sppp*) ifp; 7084910Swollman struct mbuf *m; 70925944Sjoerg int s; 7104910Swollman 71125944Sjoerg s = splimp(); 71226018Sjoerg /* 71326018Sjoerg * Process only the control protocol queue until we are in 71426018Sjoerg * network phase. 71526018Sjoerg * 71626018Sjoerg * XXX Network phase itself is still not a sufficient test, we 71726018Sjoerg * normally should keep a separate queue for each supported 71826018Sjoerg * protocol family, and only serve these queues as the 71926018Sjoerg * respective NCPs were opened. The simplistic logic used 72026018Sjoerg * here might cause some loss of network traffic while the 72126018Sjoerg * NCPs are being negotiated, in particular if the NCPs take a 72226018Sjoerg * long time to negotiate. 72326018Sjoerg * 72426018Sjoerg * Do always serve all three queues in Cisco mode. 72526018Sjoerg */ 72626018Sjoerg IF_DEQUEUE(&sp->pp_cpq, m); 72726018Sjoerg if (m == NULL && 72826018Sjoerg (sp->pp_phase == PHASE_NETWORK || 72926018Sjoerg (sp->pp_flags & PP_CISCO) != 0)) { 73026018Sjoerg IF_DEQUEUE(&sp->pp_fastq, m); 73126018Sjoerg if (m == NULL) 73226018Sjoerg IF_DEQUEUE (&sp->pp_if.if_snd, m); 73326018Sjoerg } 73426018Sjoerg splx(s); 73526018Sjoerg return m; 7364910Swollman} 7374910Swollman 7384910Swollman/* 73925944Sjoerg * Process an ioctl request. Called on low priority level. 7404910Swollman */ 74125944Sjoergint 74225944Sjoergsppp_ioctl(struct ifnet *ifp, int cmd, void *data) 7434910Swollman{ 74425944Sjoerg struct ifreq *ifr = (struct ifreq*) data; 74525944Sjoerg struct sppp *sp = (struct sppp*) ifp; 74625944Sjoerg int s, going_up, going_down, newmode; 7474910Swollman 74825944Sjoerg s = splimp(); 74925944Sjoerg switch (cmd) { 75025944Sjoerg case SIOCAIFADDR: 75125944Sjoerg case SIOCSIFDSTADDR: 75225944Sjoerg break; 7534910Swollman 75425944Sjoerg case SIOCSIFADDR: 75525944Sjoerg if_up(ifp); 75625944Sjoerg /* fall through... */ 75711189Sjkh 75825944Sjoerg case SIOCSIFFLAGS: 75925944Sjoerg going_up = ifp->if_flags & IFF_UP && 76025944Sjoerg (ifp->if_flags & IFF_RUNNING) == 0; 76125944Sjoerg going_down = (ifp->if_flags & IFF_UP) == 0 && 76225944Sjoerg ifp->if_flags & IFF_RUNNING; 76325944Sjoerg newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE); 76425944Sjoerg if (newmode == (IFF_AUTO | IFF_PASSIVE)) { 76525944Sjoerg /* sanity */ 76625944Sjoerg newmode = IFF_PASSIVE; 76725944Sjoerg ifp->if_flags &= ~IFF_AUTO; 7684910Swollman } 7694910Swollman 77025944Sjoerg if (going_up || going_down) 77125944Sjoerg lcp.Close(sp); 77225944Sjoerg if (going_up && newmode == 0) { 77325944Sjoerg /* neither auto-dial nor passive */ 77425944Sjoerg ifp->if_flags |= IFF_RUNNING; 77525944Sjoerg if (!(sp->pp_flags & PP_CISCO)) 77625944Sjoerg lcp.Open(sp); 77726018Sjoerg } else if (going_down) { 77826018Sjoerg sppp_flush(ifp); 77925944Sjoerg ifp->if_flags &= ~IFF_RUNNING; 78026018Sjoerg } 7814910Swollman 7824910Swollman break; 78311189Sjkh 78425944Sjoerg#ifdef SIOCSIFMTU 78525944Sjoerg#ifndef ifr_mtu 78625944Sjoerg#define ifr_mtu ifr_metric 78725944Sjoerg#endif 78825944Sjoerg case SIOCSIFMTU: 78925944Sjoerg if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru) 79025944Sjoerg return (EINVAL); 79125944Sjoerg ifp->if_mtu = ifr->ifr_mtu; 7924910Swollman break; 79325944Sjoerg#endif 79425944Sjoerg#ifdef SLIOCSETMTU 79525944Sjoerg case SLIOCSETMTU: 79625944Sjoerg if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru) 79725944Sjoerg return (EINVAL); 79825944Sjoerg ifp->if_mtu = *(short*)data; 7994910Swollman break; 80025944Sjoerg#endif 80125944Sjoerg#ifdef SIOCGIFMTU 80225944Sjoerg case SIOCGIFMTU: 80325944Sjoerg ifr->ifr_mtu = ifp->if_mtu; 80411189Sjkh break; 80525944Sjoerg#endif 80625944Sjoerg#ifdef SLIOCGETMTU 80725944Sjoerg case SLIOCGETMTU: 80825944Sjoerg *(short*)data = ifp->if_mtu; 8094910Swollman break; 81025944Sjoerg#endif 81125944Sjoerg case SIOCADDMULTI: 81225944Sjoerg case SIOCDELMULTI: 8134910Swollman break; 81411189Sjkh 81525944Sjoerg default: 81625944Sjoerg splx(s); 81725944Sjoerg return (ENOTTY); 8184910Swollman } 81925944Sjoerg splx(s); 82025944Sjoerg return (0); 8214910Swollman} 8224910Swollman 82325944Sjoerg 82425944Sjoerg/* 82525944Sjoerg * Cisco framing implementation. 82625944Sjoerg */ 82725944Sjoerg 8284910Swollman/* 8294910Swollman * Handle incoming Cisco keepalive protocol packets. 8304910Swollman */ 83112820Sphkstatic void 83225706Sjoergsppp_cisco_input(struct sppp *sp, struct mbuf *m) 8334910Swollman{ 83425944Sjoerg STDDCL; 8354910Swollman struct cisco_packet *h; 8364910Swollman struct ifaddr *ifa; 8374910Swollman 83827929Sitojun if (m->m_pkthdr.len < CISCO_PACKET_LEN) { 83925706Sjoerg if (debug) 84025706Sjoerg log(LOG_DEBUG, 84125706Sjoerg "%s%d: invalid cisco packet length: %d bytes\n", 84225706Sjoerg ifp->if_name, ifp->if_unit, m->m_pkthdr.len); 8434910Swollman return; 8444910Swollman } 8454910Swollman h = mtod (m, struct cisco_packet*); 84625706Sjoerg if (debug) 84725706Sjoerg log(LOG_DEBUG, 84825706Sjoerg "%s%d: cisco input: %d bytes " 84925706Sjoerg "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", 85025706Sjoerg ifp->if_name, ifp->if_unit, m->m_pkthdr.len, 85125706Sjoerg ntohl (h->type), h->par1, h->par2, h->rel, 85225706Sjoerg h->time0, h->time1); 8534910Swollman switch (ntohl (h->type)) { 8544910Swollman default: 85525706Sjoerg if (debug) 85625706Sjoerg addlog("%s%d: unknown cisco packet type: 0x%lx\n", 85725706Sjoerg ifp->if_name, ifp->if_unit, ntohl (h->type)); 8584910Swollman break; 8594910Swollman case CISCO_ADDR_REPLY: 8604910Swollman /* Reply on address request, ignore */ 8614910Swollman break; 8624910Swollman case CISCO_KEEPALIVE_REQ: 8634910Swollman sp->pp_alivecnt = 0; 8644910Swollman sp->pp_rseq = ntohl (h->par1); 8654910Swollman if (sp->pp_seq == sp->pp_rseq) { 8664910Swollman /* Local and remote sequence numbers are equal. 8674910Swollman * Probably, the line is in loopback mode. */ 86811189Sjkh if (sp->pp_loopcnt >= MAXALIVECNT) { 86911189Sjkh printf ("%s%d: loopback\n", 87011189Sjkh ifp->if_name, ifp->if_unit); 87111189Sjkh sp->pp_loopcnt = 0; 87211189Sjkh if (ifp->if_flags & IFF_UP) { 87311189Sjkh if_down (ifp); 87426018Sjoerg sppp_qflush (&sp->pp_cpq); 87511189Sjkh } 87611189Sjkh } 8774910Swollman ++sp->pp_loopcnt; 8784910Swollman 8794910Swollman /* Generate new local sequence number */ 8804910Swollman sp->pp_seq ^= time.tv_sec ^ time.tv_usec; 88111189Sjkh break; 88211189Sjkh } 8834910Swollman sp->pp_loopcnt = 0; 88411189Sjkh if (! (ifp->if_flags & IFF_UP) && 88511189Sjkh (ifp->if_flags & IFF_RUNNING)) { 88611189Sjkh ifp->if_flags |= IFF_UP; 88711189Sjkh printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 88811189Sjkh } 8894910Swollman break; 8904910Swollman case CISCO_ADDR_REQ: 89120407Swollman for (ifa=ifp->if_addrhead.tqh_first; ifa; 89220407Swollman ifa=ifa->ifa_link.tqe_next) 8934910Swollman if (ifa->ifa_addr->sa_family == AF_INET) 8944910Swollman break; 8954910Swollman if (! ifa) { 89625706Sjoerg if (debug) 89725706Sjoerg addlog("%s%d: unknown address for cisco request\n", 89825706Sjoerg ifp->if_name, ifp->if_unit); 8994910Swollman return; 9004910Swollman } 9014910Swollman sppp_cisco_send (sp, CISCO_ADDR_REPLY, 9024910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr), 9034910Swollman ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr)); 9044910Swollman break; 9054910Swollman } 9064910Swollman} 9074910Swollman 9084910Swollman/* 90925944Sjoerg * Send Cisco keepalive packet. 9104910Swollman */ 91112820Sphkstatic void 91225944Sjoergsppp_cisco_send(struct sppp *sp, int type, long par1, long par2) 91325944Sjoerg{ 91425944Sjoerg STDDCL; 91525944Sjoerg struct ppp_header *h; 91625944Sjoerg struct cisco_packet *ch; 91725944Sjoerg struct mbuf *m; 91825944Sjoerg u_long t = (time.tv_sec - boottime.tv_sec) * 1000; 91925944Sjoerg 92025944Sjoerg MGETHDR (m, M_DONTWAIT, MT_DATA); 92125944Sjoerg if (! m) 92225944Sjoerg return; 92325944Sjoerg m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; 92425944Sjoerg m->m_pkthdr.rcvif = 0; 92525944Sjoerg 92625944Sjoerg h = mtod (m, struct ppp_header*); 92725944Sjoerg h->address = CISCO_MULTICAST; 92825944Sjoerg h->control = 0; 92925944Sjoerg h->protocol = htons (CISCO_KEEPALIVE); 93025944Sjoerg 93125944Sjoerg ch = (struct cisco_packet*) (h + 1); 93225944Sjoerg ch->type = htonl (type); 93325944Sjoerg ch->par1 = htonl (par1); 93425944Sjoerg ch->par2 = htonl (par2); 93525944Sjoerg ch->rel = -1; 93625944Sjoerg ch->time0 = htons ((u_short) (t >> 16)); 93725944Sjoerg ch->time1 = htons ((u_short) t); 93825944Sjoerg 93925944Sjoerg if (debug) 94025944Sjoerg log(LOG_DEBUG, 94125944Sjoerg "%s%d: cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", 94225944Sjoerg ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1, 94325944Sjoerg ch->par2, ch->rel, ch->time0, ch->time1); 94425944Sjoerg 94526018Sjoerg if (IF_QFULL (&sp->pp_cpq)) { 94626018Sjoerg IF_DROP (&sp->pp_fastq); 94725944Sjoerg IF_DROP (&ifp->if_snd); 94825944Sjoerg m_freem (m); 94925944Sjoerg } else 95026018Sjoerg IF_ENQUEUE (&sp->pp_cpq, m); 95125944Sjoerg if (! (ifp->if_flags & IFF_OACTIVE)) 95225944Sjoerg (*ifp->if_start) (ifp); 95325944Sjoerg ifp->if_obytes += m->m_pkthdr.len + 3; 95425944Sjoerg} 95525944Sjoerg 95625944Sjoerg/* 95725944Sjoerg * PPP protocol implementation. 95825944Sjoerg */ 95925944Sjoerg 96025944Sjoerg/* 96125944Sjoerg * Send PPP control protocol packet. 96225944Sjoerg */ 96325944Sjoergstatic void 96425706Sjoergsppp_cp_send(struct sppp *sp, u_short proto, u_char type, 96525706Sjoerg u_char ident, u_short len, void *data) 9664910Swollman{ 96725944Sjoerg STDDCL; 9684910Swollman struct ppp_header *h; 9694910Swollman struct lcp_header *lh; 9704910Swollman struct mbuf *m; 9714910Swollman 9724910Swollman if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) 9734910Swollman len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; 9744910Swollman MGETHDR (m, M_DONTWAIT, MT_DATA); 9754910Swollman if (! m) 9764910Swollman return; 9774910Swollman m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; 9784910Swollman m->m_pkthdr.rcvif = 0; 9794910Swollman 9804910Swollman h = mtod (m, struct ppp_header*); 9814910Swollman h->address = PPP_ALLSTATIONS; /* broadcast address */ 9824910Swollman h->control = PPP_UI; /* Unnumbered Info */ 9834910Swollman h->protocol = htons (proto); /* Link Control Protocol */ 9844910Swollman 9854910Swollman lh = (struct lcp_header*) (h + 1); 9864910Swollman lh->type = type; 9874910Swollman lh->ident = ident; 9884910Swollman lh->len = htons (LCP_HEADER_LEN + len); 9894910Swollman if (len) 9904910Swollman bcopy (data, lh+1, len); 9914910Swollman 99225706Sjoerg if (debug) { 99325944Sjoerg log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d", 99425944Sjoerg ifp->if_name, ifp->if_unit, 99525944Sjoerg sppp_proto_name(proto), 99625944Sjoerg sppp_cp_type_name (lh->type), lh->ident, 99725944Sjoerg ntohs (lh->len)); 9984910Swollman if (len) 99911189Sjkh sppp_print_bytes ((u_char*) (lh+1), len); 100025706Sjoerg addlog(">\n"); 10014910Swollman } 100226018Sjoerg if (IF_QFULL (&sp->pp_cpq)) { 100326018Sjoerg IF_DROP (&sp->pp_fastq); 10044910Swollman IF_DROP (&ifp->if_snd); 10054910Swollman m_freem (m); 100625944Sjoerg ++ifp->if_oerrors; 10074910Swollman } else 100826018Sjoerg IF_ENQUEUE (&sp->pp_cpq, m); 10094910Swollman if (! (ifp->if_flags & IFF_OACTIVE)) 10104910Swollman (*ifp->if_start) (ifp); 10114910Swollman ifp->if_obytes += m->m_pkthdr.len + 3; 10124910Swollman} 10134910Swollman 10144910Swollman/* 101525944Sjoerg * Handle incoming PPP control protocol packets. 10164910Swollman */ 101712820Sphkstatic void 101825944Sjoergsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) 10194910Swollman{ 102025944Sjoerg STDDCL; 102125944Sjoerg struct lcp_header *h; 102225944Sjoerg int len = m->m_pkthdr.len; 102325944Sjoerg int rv; 102425944Sjoerg u_char *p; 10254910Swollman 102625944Sjoerg if (len < 4) { 102725944Sjoerg if (debug) 102825944Sjoerg log(LOG_DEBUG, 102925944Sjoerg "%s%d: %s invalid packet length: %d bytes\n", 103025944Sjoerg ifp->if_name, ifp->if_unit, cp->name, len); 10314910Swollman return; 103225944Sjoerg } 103325944Sjoerg h = mtod (m, struct lcp_header*); 103425944Sjoerg if (debug) { 103525944Sjoerg log(LOG_DEBUG, 103625944Sjoerg "%s%d: %s input(%s): <%s id=0x%x len=%d", 103725944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 103825944Sjoerg sppp_state_name(sp->state[cp->protoidx]), 103925944Sjoerg sppp_cp_type_name (h->type), h->ident, ntohs (h->len)); 104025944Sjoerg if (len > 4) 104125944Sjoerg sppp_print_bytes ((u_char*) (h+1), len-4); 104225944Sjoerg addlog(">\n"); 104325944Sjoerg } 104425944Sjoerg if (len > ntohs (h->len)) 104525944Sjoerg len = ntohs (h->len); 104625944Sjoerg switch (h->type) { 104725944Sjoerg case CONF_REQ: 104825944Sjoerg if (len < 4) { 104925944Sjoerg if (debug) 105025944Sjoerg addlog("%s%d: %s invalid conf-req length %d\n", 105125944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 105225944Sjoerg len); 105325944Sjoerg ++ifp->if_ierrors; 105425944Sjoerg break; 105525944Sjoerg } 105625944Sjoerg rv = (cp->RCR)(sp, h, len); 105725944Sjoerg switch (sp->state[cp->protoidx]) { 105825944Sjoerg case STATE_OPENED: 105925944Sjoerg (cp->tld)(sp); 106025944Sjoerg (cp->scr)(sp); 106125944Sjoerg /* fall through... */ 106225944Sjoerg case STATE_ACK_SENT: 106325944Sjoerg case STATE_REQ_SENT: 106425944Sjoerg sppp_cp_change_state(cp, sp, rv? 106525944Sjoerg STATE_ACK_SENT: STATE_REQ_SENT); 106625944Sjoerg break; 106725944Sjoerg case STATE_CLOSING: 106825944Sjoerg case STATE_STOPPING: 106925944Sjoerg break; 107025944Sjoerg case STATE_STOPPED: 107125944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 107225944Sjoerg (cp->scr)(sp); 107325944Sjoerg sppp_cp_change_state(cp, sp, rv? 107425944Sjoerg STATE_ACK_SENT: STATE_REQ_SENT); 107525944Sjoerg break; 107625944Sjoerg case STATE_CLOSED: 107725944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 107825944Sjoerg 0, 0); 107925944Sjoerg break; 108025944Sjoerg case STATE_ACK_RCVD: 108125944Sjoerg if (rv) { 108225944Sjoerg sppp_cp_change_state(cp, sp, STATE_OPENED); 108325944Sjoerg if (debug) 108426077Sjoerg log(LOG_DEBUG, "%s%d: %s tlu\n", 108526077Sjoerg ifp->if_name, ifp->if_unit, 108626077Sjoerg cp->name); 108725944Sjoerg (cp->tlu)(sp); 108825944Sjoerg } else 108925944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); 109025944Sjoerg break; 109125944Sjoerg default: 109225944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 109325944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 109425944Sjoerg sppp_cp_type_name(h->type), 109525944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 109625944Sjoerg ++ifp->if_ierrors; 109725944Sjoerg } 109825944Sjoerg break; 109925944Sjoerg case CONF_ACK: 110025944Sjoerg if (h->ident != sp->confid[cp->protoidx]) { 110125944Sjoerg if (debug) 110225944Sjoerg addlog("%s%d: %s id mismatch 0x%x != 0x%x\n", 110325944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 110425944Sjoerg h->ident, sp->confid[cp->protoidx]); 110525944Sjoerg ++ifp->if_ierrors; 110625944Sjoerg break; 110725944Sjoerg } 110825944Sjoerg switch (sp->state[cp->protoidx]) { 110925944Sjoerg case STATE_CLOSED: 111025944Sjoerg case STATE_STOPPED: 111125944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); 111225944Sjoerg break; 111325944Sjoerg case STATE_CLOSING: 111425944Sjoerg case STATE_STOPPING: 111525944Sjoerg break; 111625944Sjoerg case STATE_REQ_SENT: 111725944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 111825944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); 111925944Sjoerg break; 112025944Sjoerg case STATE_OPENED: 112125944Sjoerg (cp->tld)(sp); 112225944Sjoerg /* fall through */ 112325944Sjoerg case STATE_ACK_RCVD: 112425944Sjoerg (cp->scr)(sp); 112525944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 112625944Sjoerg break; 112725944Sjoerg case STATE_ACK_SENT: 112825944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 112925944Sjoerg sppp_cp_change_state(cp, sp, STATE_OPENED); 113025944Sjoerg if (debug) 113125944Sjoerg addlog("%s%d: %s tlu\n", 113225944Sjoerg ifp->if_name, ifp->if_unit, cp->name); 113325944Sjoerg (cp->tlu)(sp); 113425944Sjoerg break; 113525944Sjoerg default: 113625944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 113725944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 113825944Sjoerg sppp_cp_type_name(h->type), 113925944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 114025944Sjoerg ++ifp->if_ierrors; 114125944Sjoerg } 114225944Sjoerg break; 114325944Sjoerg case CONF_NAK: 114425944Sjoerg case CONF_REJ: 114525944Sjoerg if (h->ident != sp->confid[cp->protoidx]) { 114625944Sjoerg if (debug) 114725944Sjoerg addlog("%s%d: %s id mismatch 0x%x != 0x%x\n", 114825944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 114925944Sjoerg h->ident, sp->confid[cp->protoidx]); 115025944Sjoerg ++ifp->if_ierrors; 115125944Sjoerg break; 115225944Sjoerg } 115325944Sjoerg if (h->type == CONF_NAK) 115425944Sjoerg (cp->RCN_nak)(sp, h, len); 115525944Sjoerg else /* CONF_REJ */ 115625944Sjoerg (cp->RCN_rej)(sp, h, len); 11574910Swollman 115825944Sjoerg switch (sp->state[cp->protoidx]) { 115925944Sjoerg case STATE_CLOSED: 116025944Sjoerg case STATE_STOPPED: 116125944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); 116225944Sjoerg break; 116325944Sjoerg case STATE_REQ_SENT: 116425944Sjoerg case STATE_ACK_SENT: 116525944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 116625944Sjoerg (cp->scr)(sp); 116725944Sjoerg break; 116825944Sjoerg case STATE_OPENED: 116925944Sjoerg (cp->tld)(sp); 117025944Sjoerg /* fall through */ 117125944Sjoerg case STATE_ACK_RCVD: 117225944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_SENT); 117325944Sjoerg (cp->scr)(sp); 117425944Sjoerg break; 117525944Sjoerg case STATE_CLOSING: 117625944Sjoerg case STATE_STOPPING: 117725944Sjoerg break; 117825944Sjoerg default: 117925944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 118025944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 118125944Sjoerg sppp_cp_type_name(h->type), 118225944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 118325944Sjoerg ++ifp->if_ierrors; 118425944Sjoerg } 118525944Sjoerg break; 11864910Swollman 118725944Sjoerg case TERM_REQ: 118825944Sjoerg switch (sp->state[cp->protoidx]) { 118925944Sjoerg case STATE_ACK_RCVD: 119025944Sjoerg case STATE_ACK_SENT: 119125944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 119225944Sjoerg /* fall through */ 119325944Sjoerg case STATE_CLOSED: 119425944Sjoerg case STATE_STOPPED: 119525944Sjoerg case STATE_CLOSING: 119625944Sjoerg case STATE_STOPPING: 119725944Sjoerg case STATE_REQ_SENT: 119825944Sjoerg sta: 119925944Sjoerg /* Send Terminate-Ack packet. */ 120025944Sjoerg if (debug) 120125944Sjoerg log(LOG_DEBUG, "%s%d: %s send terminate-ack\n", 120225944Sjoerg ifp->if_name, ifp->if_unit, cp->name); 120325944Sjoerg sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); 120425944Sjoerg break; 120525944Sjoerg case STATE_OPENED: 120625944Sjoerg (cp->tld)(sp); 120725944Sjoerg sp->rst_counter[cp->protoidx] = 0; 120825944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPING); 120925944Sjoerg goto sta; 121025944Sjoerg break; 121125944Sjoerg default: 121225944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 121325944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 121425944Sjoerg sppp_cp_type_name(h->type), 121525944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 121625944Sjoerg ++ifp->if_ierrors; 121725944Sjoerg } 121825944Sjoerg break; 121925944Sjoerg case TERM_ACK: 122025944Sjoerg switch (sp->state[cp->protoidx]) { 122125944Sjoerg case STATE_CLOSED: 122225944Sjoerg case STATE_STOPPED: 122325944Sjoerg case STATE_REQ_SENT: 122425944Sjoerg case STATE_ACK_SENT: 122525944Sjoerg break; 122625944Sjoerg case STATE_CLOSING: 122725944Sjoerg (cp->tlf)(sp); 122825944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 122925944Sjoerg break; 123025944Sjoerg case STATE_STOPPING: 123125944Sjoerg (cp->tlf)(sp); 123225944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPED); 123325944Sjoerg break; 123425944Sjoerg case STATE_ACK_RCVD: 123525944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 123625944Sjoerg break; 123725944Sjoerg case STATE_OPENED: 123825944Sjoerg (cp->tld)(sp); 123925944Sjoerg (cp->scr)(sp); 124025944Sjoerg sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); 124125944Sjoerg break; 124225944Sjoerg default: 124325944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 124425944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 124525944Sjoerg sppp_cp_type_name(h->type), 124625944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 124725944Sjoerg ++ifp->if_ierrors; 124825944Sjoerg } 124925944Sjoerg break; 125025944Sjoerg case CODE_REJ: 125125944Sjoerg case PROTO_REJ: 125225944Sjoerg /* XXX catastrophic rejects (RXJ-) aren't handled yet. */ 125325944Sjoerg switch (sp->state[cp->protoidx]) { 125425944Sjoerg case STATE_CLOSED: 125525944Sjoerg case STATE_STOPPED: 125625944Sjoerg case STATE_REQ_SENT: 125725944Sjoerg case STATE_ACK_SENT: 125825944Sjoerg case STATE_CLOSING: 125925944Sjoerg case STATE_STOPPING: 126025944Sjoerg case STATE_OPENED: 126125944Sjoerg break; 126225944Sjoerg case STATE_ACK_RCVD: 126325944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 126425944Sjoerg break; 126525944Sjoerg default: 126625944Sjoerg printf("%s%d: %s illegal %s in state %s\n", 126725944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 126825944Sjoerg sppp_cp_type_name(h->type), 126925944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 127025944Sjoerg ++ifp->if_ierrors; 127125944Sjoerg } 127225944Sjoerg break; 127325944Sjoerg case DISC_REQ: 127425944Sjoerg if (cp->proto != PPP_LCP) 127525944Sjoerg goto illegal; 127625944Sjoerg /* Discard the packet. */ 127725944Sjoerg break; 127825944Sjoerg case ECHO_REQ: 127925944Sjoerg if (cp->proto != PPP_LCP) 128025944Sjoerg goto illegal; 128125944Sjoerg if (sp->state[cp->protoidx] != STATE_OPENED) { 128225944Sjoerg if (debug) 128325944Sjoerg addlog("%s%d: lcp echo req but lcp closed\n", 128425944Sjoerg ifp->if_name, ifp->if_unit); 128525944Sjoerg ++ifp->if_ierrors; 128625944Sjoerg break; 128725944Sjoerg } 128825944Sjoerg if (len < 8) { 128925944Sjoerg if (debug) 129025944Sjoerg addlog("%s%d: invalid lcp echo request " 129125944Sjoerg "packet length: %d bytes\n", 129225944Sjoerg ifp->if_name, ifp->if_unit, len); 129325944Sjoerg break; 129425944Sjoerg } 129525944Sjoerg if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { 129625944Sjoerg /* Line loopback mode detected. */ 129725944Sjoerg printf("%s%d: loopback\n", ifp->if_name, ifp->if_unit); 129825944Sjoerg if_down (ifp); 129926018Sjoerg sppp_qflush (&sp->pp_cpq); 13004910Swollman 130125944Sjoerg /* Shut down the PPP link. */ 130225944Sjoerg /* XXX */ 130325944Sjoerg lcp.Down(sp); 130425944Sjoerg lcp.Up(sp); 130525944Sjoerg break; 130625944Sjoerg } 130725944Sjoerg *(long*)(h+1) = htonl (sp->lcp.magic); 130825944Sjoerg if (debug) 130925944Sjoerg addlog("%s%d: got lcp echo req, sending echo rep\n", 131025944Sjoerg ifp->if_name, ifp->if_unit); 131125944Sjoerg sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1); 131225944Sjoerg break; 131325944Sjoerg case ECHO_REPLY: 131425944Sjoerg if (cp->proto != PPP_LCP) 131525944Sjoerg goto illegal; 131625944Sjoerg if (h->ident != sp->lcp.echoid) { 131725944Sjoerg ++ifp->if_ierrors; 131825944Sjoerg break; 131925944Sjoerg } 132025944Sjoerg if (len < 8) { 132125944Sjoerg if (debug) 132225944Sjoerg addlog("%s%d: lcp invalid echo reply " 132325944Sjoerg "packet length: %d bytes\n", 132425944Sjoerg ifp->if_name, ifp->if_unit, len); 132525944Sjoerg break; 132625944Sjoerg } 132725944Sjoerg if (debug) 132825944Sjoerg addlog("%s%d: lcp got echo rep\n", 132925944Sjoerg ifp->if_name, ifp->if_unit); 133025944Sjoerg if (ntohl (*(long*)(h+1)) != sp->lcp.magic) 133125944Sjoerg sp->pp_alivecnt = 0; 133225944Sjoerg break; 133325944Sjoerg default: 133425944Sjoerg /* Unknown packet type -- send Code-Reject packet. */ 133525944Sjoerg illegal: 133625944Sjoerg if (debug) 133725944Sjoerg addlog("%s%d: %c send code-rej for 0x%x\n", 133825944Sjoerg ifp->if_name, ifp->if_unit, cp->name, h->type); 133925944Sjoerg sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq, 134025944Sjoerg m->m_pkthdr.len, h); 134125944Sjoerg ++ifp->if_ierrors; 134225944Sjoerg } 13434910Swollman} 13444910Swollman 134525944Sjoerg 13464910Swollman/* 134725944Sjoerg * The generic part of all Up/Down/Open/Close/TO event handlers. 134825944Sjoerg * Basically, the state transition handling in the automaton. 13494910Swollman */ 135025944Sjoergstatic void 135125944Sjoergsppp_up_event(const struct cp *cp, struct sppp *sp) 13524910Swollman{ 135325944Sjoerg STDDCL; 13544910Swollman 135525944Sjoerg if (debug) 135625944Sjoerg log(LOG_DEBUG, "%s%d: %s up(%s)\n", 135725944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 135825944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 135925944Sjoerg 136025944Sjoerg switch (sp->state[cp->protoidx]) { 136125944Sjoerg case STATE_INITIAL: 136225944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 136325944Sjoerg break; 136425944Sjoerg case STATE_STARTING: 136525944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 136625944Sjoerg (cp->scr)(sp); 136725944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 136825944Sjoerg break; 13694910Swollman default: 137025944Sjoerg printf("%s%d: %s illegal up in state %s\n", 137125944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 137225944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 137325944Sjoerg } 137425944Sjoerg} 13754910Swollman 137625944Sjoergstatic void 137725944Sjoergsppp_down_event(const struct cp *cp, struct sppp *sp) 137825944Sjoerg{ 137925944Sjoerg STDDCL; 138025944Sjoerg 138125944Sjoerg if (debug) 138225944Sjoerg log(LOG_DEBUG, "%s%d: %s down(%s)\n", 138325944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 138425944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 138525944Sjoerg 138625944Sjoerg switch (sp->state[cp->protoidx]) { 138725944Sjoerg case STATE_CLOSED: 138825944Sjoerg case STATE_CLOSING: 138925944Sjoerg sppp_cp_change_state(cp, sp, STATE_INITIAL); 13904910Swollman break; 139125944Sjoerg case STATE_STOPPED: 139225944Sjoerg (cp->tls)(sp); 139325944Sjoerg /* fall through */ 139425944Sjoerg case STATE_STOPPING: 139525944Sjoerg case STATE_REQ_SENT: 139625944Sjoerg case STATE_ACK_RCVD: 139725944Sjoerg case STATE_ACK_SENT: 139825944Sjoerg sppp_cp_change_state(cp, sp, STATE_STARTING); 139925944Sjoerg break; 140025944Sjoerg case STATE_OPENED: 140125944Sjoerg (cp->tld)(sp); 140225944Sjoerg sppp_cp_change_state(cp, sp, STATE_STARTING); 140325944Sjoerg break; 140425944Sjoerg default: 140525944Sjoerg printf("%s%d: %s illegal down in state %s\n", 140625944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 140725944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 140825944Sjoerg } 140925944Sjoerg} 14104910Swollman 141111189Sjkh 141225944Sjoergstatic void 141325944Sjoergsppp_open_event(const struct cp *cp, struct sppp *sp) 141425944Sjoerg{ 141525944Sjoerg STDDCL; 141625944Sjoerg 141725944Sjoerg if (debug) 141825944Sjoerg log(LOG_DEBUG, "%s%d: %s open(%s)\n", 141925944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 142025944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 142125944Sjoerg 142225944Sjoerg switch (sp->state[cp->protoidx]) { 142325944Sjoerg case STATE_INITIAL: 142425944Sjoerg (cp->tls)(sp); 142525944Sjoerg sppp_cp_change_state(cp, sp, STATE_STARTING); 14264910Swollman break; 142725944Sjoerg case STATE_STARTING: 142825944Sjoerg break; 142925944Sjoerg case STATE_CLOSED: 143025944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; 143125944Sjoerg (cp->scr)(sp); 143225944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 143325944Sjoerg break; 143425944Sjoerg case STATE_STOPPED: 143525944Sjoerg case STATE_STOPPING: 143625944Sjoerg case STATE_REQ_SENT: 143725944Sjoerg case STATE_ACK_RCVD: 143825944Sjoerg case STATE_ACK_SENT: 143925944Sjoerg case STATE_OPENED: 144025944Sjoerg break; 144125944Sjoerg case STATE_CLOSING: 144225944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPING); 144325944Sjoerg break; 144425944Sjoerg } 144525944Sjoerg} 14464910Swollman 144725944Sjoerg 144825944Sjoergstatic void 144925944Sjoergsppp_close_event(const struct cp *cp, struct sppp *sp) 145025944Sjoerg{ 145125944Sjoerg STDDCL; 145225944Sjoerg 145325944Sjoerg if (debug) 145425944Sjoerg log(LOG_DEBUG, "%s%d: %s close(%s)\n", 145525944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 145625944Sjoerg sppp_state_name(sp->state[cp->protoidx])); 145725944Sjoerg 145825944Sjoerg switch (sp->state[cp->protoidx]) { 145925944Sjoerg case STATE_INITIAL: 146025944Sjoerg case STATE_CLOSED: 146125944Sjoerg case STATE_CLOSING: 14624910Swollman break; 146325944Sjoerg case STATE_STARTING: 146425944Sjoerg (cp->tlf)(sp); 146525944Sjoerg sppp_cp_change_state(cp, sp, STATE_INITIAL); 14664910Swollman break; 146725944Sjoerg case STATE_STOPPED: 146825944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 14694910Swollman break; 147025944Sjoerg case STATE_STOPPING: 147125944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSING); 14724910Swollman break; 147325944Sjoerg case STATE_OPENED: 147425944Sjoerg (cp->tld)(sp); 147525944Sjoerg /* fall through */ 147625944Sjoerg case STATE_REQ_SENT: 147725944Sjoerg case STATE_ACK_RCVD: 147825944Sjoerg case STATE_ACK_SENT: 147925944Sjoerg sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate; 148025944Sjoerg sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); 148125944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSING); 14824910Swollman break; 14834910Swollman } 14844910Swollman} 14854910Swollman 148625944Sjoergstatic void 148725944Sjoergsppp_to_event(const struct cp *cp, struct sppp *sp) 148825944Sjoerg{ 148925944Sjoerg STDDCL; 149025944Sjoerg int s; 149125944Sjoerg 149225944Sjoerg s = splimp(); 149325944Sjoerg if (debug) 149425944Sjoerg log(LOG_DEBUG, "%s%d: %s TO(%s) rst_counter = %d\n", 149525944Sjoerg ifp->if_name, ifp->if_unit, cp->name, 149625944Sjoerg sppp_state_name(sp->state[cp->protoidx]), 149725944Sjoerg sp->rst_counter[cp->protoidx]); 149825944Sjoerg 149925944Sjoerg if (--sp->rst_counter[cp->protoidx] < 0) 150025944Sjoerg /* TO- event */ 150125944Sjoerg switch (sp->state[cp->protoidx]) { 150225944Sjoerg case STATE_CLOSING: 150325944Sjoerg (cp->tlf)(sp); 150425944Sjoerg sppp_cp_change_state(cp, sp, STATE_CLOSED); 150525944Sjoerg break; 150625944Sjoerg case STATE_STOPPING: 150725944Sjoerg (cp->tlf)(sp); 150825944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPED); 150925944Sjoerg break; 151025944Sjoerg case STATE_REQ_SENT: 151125944Sjoerg case STATE_ACK_RCVD: 151225944Sjoerg case STATE_ACK_SENT: 151325944Sjoerg (cp->tlf)(sp); 151425944Sjoerg sppp_cp_change_state(cp, sp, STATE_STOPPED); 151525944Sjoerg break; 151625944Sjoerg } 151725944Sjoerg else 151825944Sjoerg /* TO+ event */ 151925944Sjoerg switch (sp->state[cp->protoidx]) { 152025944Sjoerg case STATE_CLOSING: 152125944Sjoerg case STATE_STOPPING: 152225944Sjoerg sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 152325944Sjoerg 0, 0); 152425944Sjoerg timeout(cp->TO, (void *)sp, sp->lcp.timeout); 152525944Sjoerg break; 152625944Sjoerg case STATE_REQ_SENT: 152725944Sjoerg case STATE_ACK_RCVD: 152825944Sjoerg (cp->scr)(sp); 152925944Sjoerg /* sppp_cp_change_state() will restart the timer */ 153025944Sjoerg sppp_cp_change_state(cp, sp, STATE_REQ_SENT); 153125944Sjoerg break; 153225944Sjoerg case STATE_ACK_SENT: 153325944Sjoerg (cp->scr)(sp); 153425944Sjoerg timeout(cp->TO, (void *)sp, sp->lcp.timeout); 153525944Sjoerg break; 153625944Sjoerg } 153725944Sjoerg 153825944Sjoerg splx(s); 153925944Sjoerg} 154025944Sjoerg 154111189Sjkh/* 154225944Sjoerg * Change the state of a control protocol in the state automaton. 154325944Sjoerg * Takes care of starting/stopping the restart timer. 154411189Sjkh */ 154525944Sjoergvoid 154625944Sjoergsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate) 154725944Sjoerg{ 154825944Sjoerg sp->state[cp->protoidx] = newstate; 154925944Sjoerg 155025944Sjoerg untimeout(cp->TO, (void *)sp); 155125944Sjoerg switch (newstate) { 155225944Sjoerg case STATE_INITIAL: 155325944Sjoerg case STATE_STARTING: 155425944Sjoerg case STATE_CLOSED: 155525944Sjoerg case STATE_STOPPED: 155625944Sjoerg case STATE_OPENED: 155725944Sjoerg break; 155825944Sjoerg case STATE_CLOSING: 155925944Sjoerg case STATE_STOPPING: 156025944Sjoerg case STATE_REQ_SENT: 156125944Sjoerg case STATE_ACK_RCVD: 156225944Sjoerg case STATE_ACK_SENT: 156325944Sjoerg timeout(cp->TO, (void *)sp, sp->lcp.timeout); 156425944Sjoerg break; 156525944Sjoerg } 156625944Sjoerg} 156725944Sjoerg/* 156825944Sjoerg *--------------------------------------------------------------------------* 156925944Sjoerg * * 157025944Sjoerg * The LCP implementation. * 157125944Sjoerg * * 157225944Sjoerg *--------------------------------------------------------------------------* 157325944Sjoerg */ 157425944Sjoergstatic void 157525944Sjoergsppp_lcp_init(struct sppp *sp) 157625944Sjoerg{ 157725944Sjoerg sp->lcp.opts = (1 << LCP_OPT_MAGIC); 157825944Sjoerg sp->lcp.magic = 0; 157925944Sjoerg sp->state[IDX_LCP] = STATE_INITIAL; 158025944Sjoerg sp->fail_counter[IDX_LCP] = 0; 158125944Sjoerg sp->lcp.protos = 0; 158225944Sjoerg sp->lcp.mru = sp->lcp.their_mru = PP_MTU; 158325944Sjoerg 158425944Sjoerg /* 158525944Sjoerg * Initialize counters and timeout values. Note that we don't 158625944Sjoerg * use the 3 seconds suggested in RFC 1661 since we are likely 158725944Sjoerg * running on a fast link. XXX We should probably implement 158825944Sjoerg * the exponential backoff option. Note that these values are 158925944Sjoerg * relevant for all control protocols, not just LCP only. 159025944Sjoerg */ 159125944Sjoerg sp->lcp.timeout = 1 * hz; 159225944Sjoerg sp->lcp.max_terminate = 2; 159325944Sjoerg sp->lcp.max_configure = 10; 159425944Sjoerg sp->lcp.max_failure = 10; 159525944Sjoerg} 159625944Sjoerg 159725944Sjoergstatic void 159825944Sjoergsppp_lcp_up(struct sppp *sp) 159925944Sjoerg{ 160025944Sjoerg STDDCL; 160125944Sjoerg 160225944Sjoerg /* 160325944Sjoerg * If this interface is passive or dial-on-demand, it means 160425944Sjoerg * we've got in incoming call. Activate the interface. 160525944Sjoerg */ 160625944Sjoerg if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) { 160725944Sjoerg if (debug) 160825944Sjoerg log(LOG_DEBUG, 160925944Sjoerg "%s%d: Up event (incoming call)\n", 161025944Sjoerg ifp->if_name, ifp->if_unit); 161125944Sjoerg ifp->if_flags |= IFF_RUNNING; 161225944Sjoerg lcp.Open(sp); 161325944Sjoerg } 161425944Sjoerg 161525944Sjoerg sppp_up_event(&lcp, sp); 161625944Sjoerg} 161725944Sjoerg 161825944Sjoergstatic void 161925944Sjoergsppp_lcp_down(struct sppp *sp) 162025944Sjoerg{ 162125944Sjoerg STDDCL; 162225944Sjoerg 162325944Sjoerg sppp_down_event(&lcp, sp); 162425944Sjoerg 162525944Sjoerg /* 162625944Sjoerg * If this is neither a dial-on-demand nor a passive 162725944Sjoerg * interface, simulate an ``ifconfig down'' action, so the 162825944Sjoerg * administrator can force a redial by another ``ifconfig 162925944Sjoerg * up''. XXX For leased line operation, should we immediately 163025944Sjoerg * try to reopen the connection here? 163125944Sjoerg */ 163225944Sjoerg if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) { 163325944Sjoerg log(LOG_INFO, 163425944Sjoerg "%s%d: Down event (carrier loss), taking interface down.\n", 163525944Sjoerg ifp->if_name, ifp->if_unit); 163625944Sjoerg if_down(ifp); 163725944Sjoerg } else { 163825944Sjoerg if (debug) 163925944Sjoerg log(LOG_DEBUG, 164025944Sjoerg "%s%d: Down event (carrier loss)\n", 164125944Sjoerg ifp->if_name, ifp->if_unit); 164225944Sjoerg } 164325944Sjoerg lcp.Close(sp); 164425944Sjoerg ifp->if_flags &= ~IFF_RUNNING; 164525944Sjoerg} 164625944Sjoerg 164725944Sjoergstatic void 164825944Sjoergsppp_lcp_open(struct sppp *sp) 164925944Sjoerg{ 165025944Sjoerg sppp_open_event(&lcp, sp); 165125944Sjoerg} 165225944Sjoerg 165325944Sjoergstatic void 165425944Sjoergsppp_lcp_close(struct sppp *sp) 165525944Sjoerg{ 165625944Sjoerg sppp_close_event(&lcp, sp); 165725944Sjoerg} 165825944Sjoerg 165925944Sjoergstatic void 166025944Sjoergsppp_lcp_TO(void *cookie) 166125944Sjoerg{ 166225944Sjoerg sppp_to_event(&lcp, (struct sppp *)cookie); 166325944Sjoerg} 166425944Sjoerg 166525944Sjoerg/* 166625944Sjoerg * Analyze a configure request. Return true if it was agreeable, and 166725944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and 166825944Sjoerg * caused action scn. (The return value is used to make the state 166925944Sjoerg * transition decision in the state automaton.) 167025944Sjoerg */ 167112820Sphkstatic int 167225944Sjoergsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) 16734910Swollman{ 167425944Sjoerg STDDCL; 167511189Sjkh u_char *buf, *r, *p; 167625944Sjoerg int origlen, rlen; 167725944Sjoerg u_long nmagic; 16784910Swollman 167911189Sjkh len -= 4; 168025944Sjoerg origlen = len; 168111189Sjkh buf = r = malloc (len, M_TEMP, M_NOWAIT); 168211189Sjkh if (! buf) 168311189Sjkh return (0); 16844910Swollman 168525706Sjoerg if (debug) 168625944Sjoerg log(LOG_DEBUG, "%s%d: lcp parse opts: ", 168725944Sjoerg ifp->if_name, ifp->if_unit); 168825706Sjoerg 168925944Sjoerg /* pass 1: check for things that need to be rejected */ 169011189Sjkh p = (void*) (h+1); 169111189Sjkh for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 169225944Sjoerg if (debug) 169325944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 169411189Sjkh switch (*p) { 169511189Sjkh case LCP_OPT_MAGIC: 169625944Sjoerg /* Magic number. */ 169725944Sjoerg /* fall through, both are same length */ 169825944Sjoerg case LCP_OPT_ASYNC_MAP: 169925944Sjoerg /* Async control character map. */ 170025944Sjoerg if (len >= 6 || p[1] == 6) 170125944Sjoerg continue; 170225944Sjoerg if (debug) 170325944Sjoerg addlog("[invalid] "); 170425944Sjoerg break; 170525944Sjoerg case LCP_OPT_MRU: 170625944Sjoerg /* Maximum receive unit. */ 170725944Sjoerg if (len >= 4 && p[1] == 4) 170825944Sjoerg continue; 170925944Sjoerg if (debug) 171025944Sjoerg addlog("[invalid] "); 171125944Sjoerg break; 171225944Sjoerg default: 171325944Sjoerg /* Others not supported. */ 171425944Sjoerg if (debug) 171525944Sjoerg addlog("[rej] "); 171625944Sjoerg break; 171725944Sjoerg } 171825944Sjoerg /* Add the option to rejected list. */ 171925944Sjoerg bcopy (p, r, p[1]); 172025944Sjoerg r += p[1]; 172125944Sjoerg rlen += p[1]; 172225944Sjoerg } 172325944Sjoerg if (rlen) { 172425944Sjoerg if (debug) 172525944Sjoerg addlog(" send conf-rej\n"); 172625944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); 172725944Sjoerg return 0; 172825944Sjoerg } else if (debug) 172925944Sjoerg addlog("\n"); 173025944Sjoerg 173125944Sjoerg /* 173225944Sjoerg * pass 2: check for option values that are unacceptable and 173325944Sjoerg * thus require to be nak'ed. 173425944Sjoerg */ 173525944Sjoerg if (debug) 173626077Sjoerg log(LOG_DEBUG, "%s%d: lcp parse opt values: ", 173726077Sjoerg ifp->if_name, ifp->if_unit); 173825944Sjoerg 173925944Sjoerg p = (void*) (h+1); 174025944Sjoerg len = origlen; 174125944Sjoerg for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 174225944Sjoerg if (debug) 174325944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 174425944Sjoerg switch (*p) { 174525944Sjoerg case LCP_OPT_MAGIC: 174611189Sjkh /* Magic number -- extract. */ 174725944Sjoerg nmagic = (u_long)p[2] << 24 | 174825944Sjoerg (u_long)p[3] << 16 | p[4] << 8 | p[5]; 174925944Sjoerg if (nmagic != sp->lcp.magic) { 175025706Sjoerg if (debug) 175125944Sjoerg addlog("0x%x ", nmagic); 175211189Sjkh continue; 175311189Sjkh } 175425944Sjoerg /* 175525944Sjoerg * Local and remote magics equal -- loopback? 175625944Sjoerg */ 175725944Sjoerg if (sp->pp_loopcnt >= MAXALIVECNT*5) { 175825944Sjoerg printf ("\n%s%d: loopback\n", 175925944Sjoerg ifp->if_name, ifp->if_unit); 176025944Sjoerg sp->pp_loopcnt = 0; 176125944Sjoerg if (ifp->if_flags & IFF_UP) { 176225944Sjoerg if_down(ifp); 176326018Sjoerg sppp_qflush(&sp->pp_cpq); 176425944Sjoerg /* XXX ? */ 176525944Sjoerg lcp.Down(sp); 176625944Sjoerg lcp.Up(sp); 176725944Sjoerg } 176825944Sjoerg } else if (debug) 176925944Sjoerg addlog("[glitch] "); 177025944Sjoerg ++sp->pp_loopcnt; 177125944Sjoerg /* 177225944Sjoerg * We negate our magic here, and NAK it. If 177325944Sjoerg * we see it later in an NAK packet, we 177425944Sjoerg * suggest a new one. 177525944Sjoerg */ 177625944Sjoerg nmagic = ~sp->lcp.magic; 177725944Sjoerg /* Gonna NAK it. */ 177825944Sjoerg p[2] = nmagic >> 24; 177925944Sjoerg p[3] = nmagic >> 16; 178025944Sjoerg p[4] = nmagic >> 8; 178125944Sjoerg p[5] = nmagic; 178211189Sjkh break; 178325944Sjoerg 178411189Sjkh case LCP_OPT_ASYNC_MAP: 178511189Sjkh /* Async control character map -- check to be zero. */ 178625944Sjoerg if (! p[2] && ! p[3] && ! p[4] && ! p[5]) { 178725706Sjoerg if (debug) 178825944Sjoerg addlog("[empty] "); 178911189Sjkh continue; 179025706Sjoerg } 179125706Sjoerg if (debug) 179225944Sjoerg addlog("[non-empty] "); 179325944Sjoerg /* suggest a zero one */ 179425944Sjoerg p[2] = p[3] = p[4] = p[5] = 0; 179511189Sjkh break; 179625944Sjoerg 179711189Sjkh case LCP_OPT_MRU: 179825944Sjoerg /* 179925944Sjoerg * Maximum receive unit. Always agreeable, 180025944Sjoerg * but ignored by now. 180125944Sjoerg */ 180225944Sjoerg sp->lcp.their_mru = p[2] * 256 + p[3]; 180325706Sjoerg if (debug) 180425944Sjoerg addlog("%d ", sp->lcp.their_mru); 180511189Sjkh continue; 180611189Sjkh } 180725944Sjoerg /* Add the option to nak'ed list. */ 180825706Sjoerg bcopy (p, r, p[1]); 180925706Sjoerg r += p[1]; 181011189Sjkh rlen += p[1]; 181112436Speter } 181225706Sjoerg if (rlen) { 181325706Sjoerg if (debug) 181425944Sjoerg addlog(" send conf-nak\n"); 181525944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf); 181625944Sjoerg return 0; 181725944Sjoerg } else { 181825944Sjoerg if (debug) 181925944Sjoerg addlog(" send conf-ack\n"); 182025944Sjoerg sp->pp_loopcnt = 0; 182125944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_ACK, 182225944Sjoerg h->ident, origlen, h+1); 182325944Sjoerg } 182425944Sjoerg 182511189Sjkh free (buf, M_TEMP); 182611189Sjkh return (rlen == 0); 18274910Swollman} 18284910Swollman 182925944Sjoerg/* 183025944Sjoerg * Analyze the LCP Configure-Reject option list, and adjust our 183125944Sjoerg * negotiation. 183225944Sjoerg */ 183312820Sphkstatic void 183425944Sjoergsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) 18354910Swollman{ 183625944Sjoerg STDDCL; 183725944Sjoerg u_char *buf, *p; 18384910Swollman 183925944Sjoerg len -= 4; 184025944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 184125944Sjoerg if (!buf) 18424910Swollman return; 184325944Sjoerg 184425944Sjoerg if (debug) 184525944Sjoerg log(LOG_DEBUG, "%s%d: lcp rej opts: ", 184625944Sjoerg ifp->if_name, ifp->if_unit); 184725944Sjoerg 184825944Sjoerg p = (void*) (h+1); 184925944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 185025944Sjoerg if (debug) 185125944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 185225944Sjoerg switch (*p) { 185325944Sjoerg case LCP_OPT_MAGIC: 185425944Sjoerg /* Magic number -- can't use it, use 0 */ 185525944Sjoerg sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC); 185625944Sjoerg sp->lcp.magic = 0; 185725944Sjoerg break; 185825944Sjoerg case LCP_OPT_MRU: 185925944Sjoerg /* 186025944Sjoerg * Should not be rejected anyway, since we only 186125944Sjoerg * negotiate a MRU if explicitly requested by 186225944Sjoerg * peer. 186325944Sjoerg */ 186425944Sjoerg sp->lcp.opts &= ~(1 << LCP_OPT_MRU); 186525944Sjoerg break; 186625944Sjoerg } 18674910Swollman } 186825944Sjoerg if (debug) 186925944Sjoerg addlog("\n"); 187025944Sjoerg free (buf, M_TEMP); 187125944Sjoerg return; 187225944Sjoerg} 187325944Sjoerg 187425944Sjoerg/* 187525944Sjoerg * Analyze the LCP Configure-NAK option list, and adjust our 187625944Sjoerg * negotiation. 187725944Sjoerg */ 187825944Sjoergstatic void 187925944Sjoergsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) 188025944Sjoerg{ 188125944Sjoerg STDDCL; 188225944Sjoerg u_char *buf, *p; 188325944Sjoerg u_long magic; 188425944Sjoerg 188525944Sjoerg len -= 4; 188625944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 188725944Sjoerg if (!buf) 188825944Sjoerg return; 188925944Sjoerg 189025944Sjoerg if (debug) 189125944Sjoerg log(LOG_DEBUG, "%s%d: lcp nak opts: ", 189225944Sjoerg ifp->if_name, ifp->if_unit); 189325944Sjoerg 189425944Sjoerg p = (void*) (h+1); 189525944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 189625706Sjoerg if (debug) 189725944Sjoerg addlog(" %s ", sppp_lcp_opt_name(*p)); 189825944Sjoerg switch (*p) { 189925944Sjoerg case LCP_OPT_MAGIC: 190025944Sjoerg /* Magic number -- renegotiate */ 190125944Sjoerg if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) && 190225944Sjoerg len >= 6 && p[1] == 6) { 190325944Sjoerg magic = (u_long)p[2] << 24 | 190425944Sjoerg (u_long)p[3] << 16 | p[4] << 8 | p[5]; 190525944Sjoerg /* 190625944Sjoerg * If the remote magic is our negated one, 190725944Sjoerg * this looks like a loopback problem. 190825944Sjoerg * Suggest a new magic to make sure. 190925944Sjoerg */ 191025944Sjoerg if (magic == ~sp->lcp.magic) { 191125944Sjoerg if (debug) 191225944Sjoerg addlog("magic glitch "); 191325944Sjoerg sp->lcp.magic += time.tv_sec + time.tv_usec; 191425944Sjoerg } else { 191525944Sjoerg sp->lcp.magic = magic; 191625944Sjoerg if (debug) 191725944Sjoerg addlog("%d "); 191825944Sjoerg } 191925944Sjoerg } 192025944Sjoerg break; 192125944Sjoerg case LCP_OPT_MRU: 192225944Sjoerg /* 192325944Sjoerg * Peer wants to advise us to negotiate an MRU. 192425944Sjoerg * Agree on it if it's reasonable, or use 192525944Sjoerg * default otherwise. 192625944Sjoerg */ 192725944Sjoerg if (len >= 4 && p[1] == 4) { 192825944Sjoerg u_int mru = p[2] * 256 + p[3]; 192925944Sjoerg if (debug) 193025944Sjoerg addlog("%d ", mru); 193125944Sjoerg if (mru < PP_MTU || mru > PP_MAX_MRU) 193225944Sjoerg mru = PP_MTU; 193325944Sjoerg sp->lcp.mru = mru; 193425944Sjoerg sp->lcp.opts |= (1 << LCP_OPT_MRU); 193525944Sjoerg } 193625944Sjoerg break; 19374910Swollman } 193825944Sjoerg } 193925944Sjoerg if (debug) 194025944Sjoerg addlog("\n"); 194125944Sjoerg free (buf, M_TEMP); 194225944Sjoerg return; 194325944Sjoerg} 194411189Sjkh 194525944Sjoergstatic void 194625944Sjoergsppp_lcp_tlu(struct sppp *sp) 194725944Sjoerg{ 194825944Sjoerg STDDCL; 194925944Sjoerg int i; 195025944Sjoerg u_long mask; 195125944Sjoerg 195225944Sjoerg /* XXX ? */ 195325944Sjoerg if (! (ifp->if_flags & IFF_UP) && 195425944Sjoerg (ifp->if_flags & IFF_RUNNING)) { 195525944Sjoerg /* Coming out of loopback mode. */ 195625944Sjoerg if_up(ifp); 195725944Sjoerg printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); 195825944Sjoerg } 195925944Sjoerg 196025944Sjoerg for (i = 0; i < IDX_COUNT; i++) 196125944Sjoerg if ((cps[i])->flags & CP_QUAL) 196225944Sjoerg (cps[i])->Open(sp); 196325944Sjoerg 196425944Sjoerg if (/* require authentication XXX */ 0) 196525944Sjoerg sp->pp_phase = PHASE_AUTHENTICATE; 196625944Sjoerg else 196725944Sjoerg sp->pp_phase = PHASE_NETWORK; 196825944Sjoerg 196925944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 197025944Sjoerg sppp_phase_name(sp->pp_phase)); 197125944Sjoerg 197225944Sjoerg if (sp->pp_phase == PHASE_AUTHENTICATE) { 197325944Sjoerg for (i = 0; i < IDX_COUNT; i++) 197425944Sjoerg if ((cps[i])->flags & CP_AUTH) 197525944Sjoerg (cps[i])->Open(sp); 197625944Sjoerg } else { 197725944Sjoerg /* Notify all NCPs. */ 197825944Sjoerg for (i = 0; i < IDX_COUNT; i++) 197925944Sjoerg if ((cps[i])->flags & CP_NCP) 198025944Sjoerg (cps[i])->Open(sp); 198125944Sjoerg } 198225944Sjoerg 198325944Sjoerg /* Send Up events to all started protos. */ 198425944Sjoerg for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) 198525944Sjoerg if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) 198625944Sjoerg (cps[i])->Up(sp); 198725944Sjoerg 198825944Sjoerg if (sp->pp_phase == PHASE_NETWORK) 198925944Sjoerg /* if no NCP is starting, close down */ 199025944Sjoerg sppp_lcp_check(sp); 199125944Sjoerg} 199225944Sjoerg 199325944Sjoergstatic void 199425944Sjoergsppp_lcp_tld(struct sppp *sp) 199525944Sjoerg{ 199625944Sjoerg STDDCL; 199725944Sjoerg int i; 199825944Sjoerg u_long mask; 199925944Sjoerg 200025944Sjoerg sp->pp_phase = PHASE_TERMINATE; 200125944Sjoerg 200225944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 200325944Sjoerg sppp_phase_name(sp->pp_phase)); 200425944Sjoerg 200525944Sjoerg /* 200625944Sjoerg * Take upper layers down. We send the Down event first and 200725944Sjoerg * the Close second to prevent the upper layers from sending 200825944Sjoerg * ``a flurry of terminate-request packets'', as the RFC 200925944Sjoerg * describes it. 201025944Sjoerg */ 201125944Sjoerg for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) 201225944Sjoerg if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) { 201325944Sjoerg (cps[i])->Down(sp); 201425944Sjoerg (cps[i])->Close(sp); 201525944Sjoerg } 201625944Sjoerg} 201725944Sjoerg 201825944Sjoergstatic void 201925944Sjoergsppp_lcp_tls(struct sppp *sp) 202025944Sjoerg{ 202125944Sjoerg STDDCL; 202225944Sjoerg 202325944Sjoerg sp->pp_phase = PHASE_ESTABLISH; 202425944Sjoerg 202525944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 202625944Sjoerg sppp_phase_name(sp->pp_phase)); 202725944Sjoerg 202825944Sjoerg /* Notify lower layer if desired. */ 202925944Sjoerg if (sp->pp_tls) 203025944Sjoerg (sp->pp_tls)(sp); 203125944Sjoerg} 203225944Sjoerg 203325944Sjoergstatic void 203425944Sjoergsppp_lcp_tlf(struct sppp *sp) 203525944Sjoerg{ 203625944Sjoerg STDDCL; 203725944Sjoerg 203825944Sjoerg sp->pp_phase = PHASE_DEAD; 203925944Sjoerg log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, 204025944Sjoerg sppp_phase_name(sp->pp_phase)); 204125944Sjoerg 204225944Sjoerg /* Notify lower layer if desired. */ 204325944Sjoerg if (sp->pp_tlf) 204425944Sjoerg (sp->pp_tlf)(sp); 204525944Sjoerg} 204625944Sjoerg 204725944Sjoergstatic void 204825944Sjoergsppp_lcp_scr(struct sppp *sp) 204925944Sjoerg{ 205025944Sjoerg char opt[6 /* magicnum */ + 4 /* mru */]; 205125944Sjoerg int i = 0; 205225944Sjoerg 205325944Sjoerg if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) { 205425944Sjoerg if (! sp->lcp.magic) 205525944Sjoerg sp->lcp.magic = time.tv_sec + time.tv_usec; 205625944Sjoerg opt[i++] = LCP_OPT_MAGIC; 205725944Sjoerg opt[i++] = 6; 205825944Sjoerg opt[i++] = sp->lcp.magic >> 24; 205925944Sjoerg opt[i++] = sp->lcp.magic >> 16; 206025944Sjoerg opt[i++] = sp->lcp.magic >> 8; 206125944Sjoerg opt[i++] = sp->lcp.magic; 206225944Sjoerg } 206325944Sjoerg 206425944Sjoerg if (sp->lcp.opts & (1 << LCP_OPT_MRU)) { 206525944Sjoerg opt[i++] = LCP_OPT_MRU; 206625944Sjoerg opt[i++] = 4; 206725944Sjoerg opt[i++] = sp->lcp.mru >> 8; 206825944Sjoerg opt[i++] = sp->lcp.mru; 206925944Sjoerg } 207025944Sjoerg 207125944Sjoerg sp->confid[IDX_LCP] = ++sp->pp_seq; 207225944Sjoerg sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); 207325944Sjoerg} 207425944Sjoerg 207525944Sjoerg/* 207625944Sjoerg * Re-check the open NCPs and see if we should terminate the link. 207725944Sjoerg * Called by the NCPs during their tlf action handling. 207825944Sjoerg */ 207925944Sjoergstatic void 208025944Sjoergsppp_lcp_check(struct sppp *sp) 208125944Sjoerg{ 208225944Sjoerg int i, mask; 208325944Sjoerg 208425944Sjoerg for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) 208525944Sjoerg if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP) 208625944Sjoerg return; 208725944Sjoerg lcp.Close(sp); 208825944Sjoerg} 208925944Sjoerg/* 209025944Sjoerg *--------------------------------------------------------------------------* 209125944Sjoerg * * 209225944Sjoerg * The IPCP implementation. * 209325944Sjoerg * * 209425944Sjoerg *--------------------------------------------------------------------------* 209525944Sjoerg */ 209625944Sjoerg 209725944Sjoergstatic void 209825944Sjoergsppp_ipcp_init(struct sppp *sp) 209925944Sjoerg{ 210025944Sjoerg sp->ipcp.opts = 0; 210125944Sjoerg sp->ipcp.flags = 0; 210225944Sjoerg sp->state[IDX_IPCP] = STATE_INITIAL; 210325944Sjoerg sp->fail_counter[IDX_IPCP] = 0; 210425944Sjoerg} 210525944Sjoerg 210625944Sjoergstatic void 210725944Sjoergsppp_ipcp_up(struct sppp *sp) 210825944Sjoerg{ 210925944Sjoerg sppp_up_event(&ipcp, sp); 211025944Sjoerg} 211125944Sjoerg 211225944Sjoergstatic void 211325944Sjoergsppp_ipcp_down(struct sppp *sp) 211425944Sjoerg{ 211525944Sjoerg sppp_down_event(&ipcp, sp); 211625944Sjoerg} 211725944Sjoerg 211825944Sjoergstatic void 211925944Sjoergsppp_ipcp_open(struct sppp *sp) 212025944Sjoerg{ 212125944Sjoerg STDDCL; 212225944Sjoerg u_long myaddr, hisaddr; 212325944Sjoerg 212425944Sjoerg sppp_get_ip_addrs(sp, &myaddr, &hisaddr); 212525944Sjoerg /* 212625944Sjoerg * If we don't have his address, this probably means our 212725944Sjoerg * interface doesn't want to talk IP at all. (This could 212825944Sjoerg * be the case if somebody wants to speak only IPX, for 212925944Sjoerg * example.) Don't open IPCP in this case. 213025944Sjoerg */ 213125944Sjoerg if (hisaddr == 0L) { 213225944Sjoerg /* XXX this message should go away */ 213325944Sjoerg if (debug) 213425944Sjoerg log(LOG_DEBUG, "%s%d: ipcp_open(): no IP interface\n", 213525944Sjoerg ifp->if_name, ifp->if_unit); 213625944Sjoerg return; 213725944Sjoerg } 213825944Sjoerg 213925944Sjoerg if (myaddr == 0L) { 214025944Sjoerg /* 214125944Sjoerg * I don't have an assigned address, so i need to 214225944Sjoerg * negotiate my address. 214325944Sjoerg */ 214425944Sjoerg sp->ipcp.flags |= IPCP_MYADDR_DYN; 214525944Sjoerg sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); 214625944Sjoerg } 214725944Sjoerg sppp_open_event(&ipcp, sp); 214825944Sjoerg} 214925944Sjoerg 215025944Sjoergstatic void 215125944Sjoergsppp_ipcp_close(struct sppp *sp) 215225944Sjoerg{ 215325944Sjoerg sppp_close_event(&ipcp, sp); 215425944Sjoerg if (sp->ipcp.flags & IPCP_MYADDR_DYN) 215525944Sjoerg /* 215625944Sjoerg * My address was dynamic, clear it again. 215725944Sjoerg */ 215825944Sjoerg sppp_set_ip_addr(sp, 0L); 215925944Sjoerg} 216025944Sjoerg 216125944Sjoergstatic void 216225944Sjoergsppp_ipcp_TO(void *cookie) 216325944Sjoerg{ 216425944Sjoerg sppp_to_event(&ipcp, (struct sppp *)cookie); 216525944Sjoerg} 216625944Sjoerg 216725944Sjoerg/* 216825944Sjoerg * Analyze a configure request. Return true if it was agreeable, and 216925944Sjoerg * caused action sca, false if it has been rejected or nak'ed, and 217025944Sjoerg * caused action scn. (The return value is used to make the state 217125944Sjoerg * transition decision in the state automaton.) 217225944Sjoerg */ 217325944Sjoergstatic int 217425944Sjoergsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) 217525944Sjoerg{ 217625944Sjoerg u_char *buf, *r, *p; 217725944Sjoerg struct ifnet *ifp = &sp->pp_if; 217825944Sjoerg int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; 217925944Sjoerg u_long hisaddr, desiredaddr; 218025944Sjoerg 218125944Sjoerg len -= 4; 218225944Sjoerg origlen = len; 218325944Sjoerg /* 218425944Sjoerg * Make sure to allocate a buf that can at least hold a 218525944Sjoerg * conf-nak with an `address' option. We might need it below. 218625944Sjoerg */ 218725944Sjoerg buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT); 218825944Sjoerg if (! buf) 218925944Sjoerg return (0); 219025944Sjoerg 219125944Sjoerg /* pass 1: see if we can recognize them */ 219225944Sjoerg if (debug) 219325944Sjoerg log(LOG_DEBUG, "%s%d: ipcp parse opts: ", 219425944Sjoerg ifp->if_name, ifp->if_unit); 219525944Sjoerg p = (void*) (h+1); 219625944Sjoerg for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 219725944Sjoerg if (debug) 219825944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 219925944Sjoerg switch (*p) { 220025944Sjoerg#ifdef notyet 220125944Sjoerg case IPCP_OPT_COMPRESSION: 220225944Sjoerg if (len >= 6 && p[1] >= 6) { 220325944Sjoerg /* correctly formed compress option */ 220425944Sjoerg continue; 220511189Sjkh } 220625706Sjoerg if (debug) 220725944Sjoerg addlog("[invalid] "); 220825944Sjoerg break; 220925944Sjoerg#endif 221025944Sjoerg case IPCP_OPT_ADDRESS: 221125944Sjoerg if (len >= 6 && p[1] == 6) { 221225944Sjoerg /* correctly formed address option */ 221325944Sjoerg continue; 221425944Sjoerg } 221525706Sjoerg if (debug) 221625944Sjoerg addlog("[invalid] "); 221711189Sjkh break; 221825944Sjoerg default: 221925944Sjoerg /* Others not supported. */ 222025944Sjoerg if (debug) 222125944Sjoerg addlog("[rej] "); 22224910Swollman break; 22234910Swollman } 222425944Sjoerg /* Add the option to rejected list. */ 222525944Sjoerg bcopy (p, r, p[1]); 222625944Sjoerg r += p[1]; 222725944Sjoerg rlen += p[1]; 222825944Sjoerg } 222925944Sjoerg if (rlen) { 223025944Sjoerg if (debug) 223125944Sjoerg addlog(" send conf-rej\n"); 223225944Sjoerg sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf); 223325944Sjoerg return 0; 223425944Sjoerg } else if (debug) 223525944Sjoerg addlog("\n"); 223625944Sjoerg 223725944Sjoerg /* pass 2: parse option values */ 223825944Sjoerg sppp_get_ip_addrs(sp, 0, &hisaddr); 223925944Sjoerg if (debug) 224025944Sjoerg addlog("%s%d: ipcp parse opt values: ", ifp->if_name, ifp->if_unit); 224125944Sjoerg p = (void*) (h+1); 224225944Sjoerg len = origlen; 224325944Sjoerg for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { 224425944Sjoerg if (debug) 224525944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 224625944Sjoerg switch (*p) { 224725944Sjoerg#ifdef notyet 224825944Sjoerg case IPCP_OPT_COMPRESSION: 224925944Sjoerg continue; 225025944Sjoerg#endif 225125944Sjoerg case IPCP_OPT_ADDRESS: 225225944Sjoerg desiredaddr = p[2] << 24 | p[3] << 16 | 225325944Sjoerg p[4] << 8 | p[5]; 225425944Sjoerg if (desiredaddr == hisaddr) { 225525944Sjoerg /* 225625944Sjoerg * Peer's address is same as our value, 225725944Sjoerg * this is agreeable. Gonna conf-ack 225825944Sjoerg * it. 225925944Sjoerg */ 226025944Sjoerg if (debug) 226125944Sjoerg addlog("0x%x [ack] ", hisaddr); 226225944Sjoerg /* record that we've seen it already */ 226325944Sjoerg sp->ipcp.flags |= IPCP_HISADDR_SEEN; 226425944Sjoerg continue; 226525944Sjoerg } 226625944Sjoerg /* 226725944Sjoerg * The address wasn't agreeable. This is either 226825944Sjoerg * he sent us 0.0.0.0, asking to assign him an 226925944Sjoerg * address, or he send us another address not 227025944Sjoerg * matching our value. Either case, we gonna 227125944Sjoerg * conf-nak it with our value. 227225944Sjoerg */ 227325944Sjoerg if (debug) { 227425944Sjoerg if (desiredaddr == 0) 227525944Sjoerg addlog("[addr requested] "); 227625944Sjoerg else 227725944Sjoerg addlog("0x%x [not agreed] ", 227825944Sjoerg desiredaddr); 227925944Sjoerg 228025944Sjoerg p[2] = hisaddr >> 24; 228125944Sjoerg p[3] = hisaddr >> 16; 228225944Sjoerg p[4] = hisaddr >> 8; 228325944Sjoerg p[5] = hisaddr; 228425944Sjoerg } 228511189Sjkh break; 228625706Sjoerg } 228725944Sjoerg /* Add the option to nak'ed list. */ 228825944Sjoerg bcopy (p, r, p[1]); 228925944Sjoerg r += p[1]; 229025944Sjoerg rlen += p[1]; 229125944Sjoerg } 229225944Sjoerg 229325944Sjoerg /* 229425944Sjoerg * If we are about to conf-ack the request, but haven't seen 229525944Sjoerg * his address so far, gonna conf-nak it instead, with the 229625944Sjoerg * `address' option present and our idea of his address being 229725944Sjoerg * filled in there, to request negotiation of both addresses. 229825944Sjoerg * 229925944Sjoerg * XXX This can result in an endless req - nak loop if peer 230025944Sjoerg * doesn't want to send us his address. Q: What should we do 230125944Sjoerg * about it? XXX A: implement the max-failure counter. 230225944Sjoerg */ 230325944Sjoerg if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) { 230425944Sjoerg buf[0] = IPCP_OPT_ADDRESS; 230525944Sjoerg buf[1] = 6; 230625944Sjoerg buf[2] = hisaddr >> 24; 230725944Sjoerg buf[3] = hisaddr >> 16; 230825944Sjoerg buf[4] = hisaddr >> 8; 230925944Sjoerg buf[5] = hisaddr; 231025944Sjoerg rlen = 6; 231125706Sjoerg if (debug) 231225944Sjoerg addlog("still need hisaddr "); 231325944Sjoerg } 231425944Sjoerg 231525944Sjoerg if (rlen) { 231625706Sjoerg if (debug) 231725944Sjoerg addlog(" send conf-nak\n"); 231825944Sjoerg sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf); 231925944Sjoerg } else { 232025706Sjoerg if (debug) 232125944Sjoerg addlog(" send conf-ack\n"); 232225944Sjoerg sppp_cp_send (sp, PPP_IPCP, CONF_ACK, 232325944Sjoerg h->ident, origlen, h+1); 232425944Sjoerg } 232525944Sjoerg 232625944Sjoerg free (buf, M_TEMP); 232725944Sjoerg return (rlen == 0); 232825944Sjoerg} 232925944Sjoerg 233025944Sjoerg/* 233125944Sjoerg * Analyze the IPCP Configure-Reject option list, and adjust our 233225944Sjoerg * negotiation. 233325944Sjoerg */ 233425944Sjoergstatic void 233525944Sjoergsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) 233625944Sjoerg{ 233725944Sjoerg u_char *buf, *p; 233825944Sjoerg struct ifnet *ifp = &sp->pp_if; 233925944Sjoerg int debug = ifp->if_flags & IFF_DEBUG; 234025944Sjoerg 234125944Sjoerg len -= 4; 234225944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 234325944Sjoerg if (!buf) 234425944Sjoerg return; 234525944Sjoerg 234625944Sjoerg if (debug) 234725944Sjoerg log(LOG_DEBUG, "%s%d: ipcp rej opts: ", 234825944Sjoerg ifp->if_name, ifp->if_unit); 234925944Sjoerg 235025944Sjoerg p = (void*) (h+1); 235125944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 235225706Sjoerg if (debug) 235325944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 235425944Sjoerg switch (*p) { 235525944Sjoerg case IPCP_OPT_ADDRESS: 235625944Sjoerg /* 235725944Sjoerg * Peer doesn't grok address option. This is 235825944Sjoerg * bad. XXX Should we better give up here? 235925944Sjoerg */ 236025944Sjoerg sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS); 236125944Sjoerg break; 236225944Sjoerg#ifdef notyet 236325944Sjoerg case IPCP_OPT_COMPRESS: 236425944Sjoerg sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS); 236525944Sjoerg break; 236625944Sjoerg#endif 236725944Sjoerg } 23684910Swollman } 236925944Sjoerg if (debug) 237025944Sjoerg addlog("\n"); 237125944Sjoerg free (buf, M_TEMP); 237225944Sjoerg return; 23734910Swollman} 23744910Swollman 237525944Sjoerg/* 237625944Sjoerg * Analyze the IPCP Configure-NAK option list, and adjust our 237725944Sjoerg * negotiation. 237825944Sjoerg */ 237912820Sphkstatic void 238025944Sjoergsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) 23814910Swollman{ 238225944Sjoerg u_char *buf, *p; 238325944Sjoerg struct ifnet *ifp = &sp->pp_if; 238425944Sjoerg int debug = ifp->if_flags & IFF_DEBUG; 238525944Sjoerg u_long wantaddr; 23864910Swollman 238725944Sjoerg len -= 4; 238825944Sjoerg buf = malloc (len, M_TEMP, M_NOWAIT); 238925944Sjoerg if (!buf) 239025944Sjoerg return; 239125944Sjoerg 239225944Sjoerg if (debug) 239325944Sjoerg log(LOG_DEBUG, "%s%d: ipcp nak opts: ", 239425944Sjoerg ifp->if_name, ifp->if_unit); 239525944Sjoerg 239625944Sjoerg p = (void*) (h+1); 239725944Sjoerg for (; len > 1 && p[1]; len -= p[1], p += p[1]) { 239825944Sjoerg if (debug) 239925944Sjoerg addlog(" %s ", sppp_ipcp_opt_name(*p)); 240025944Sjoerg switch (*p) { 240125944Sjoerg case IPCP_OPT_ADDRESS: 240225944Sjoerg /* 240325944Sjoerg * Peer doesn't like our local IP address. See 240425944Sjoerg * if we can do something for him. We'll drop 240525944Sjoerg * him our address then. 240625944Sjoerg */ 240725944Sjoerg if (len >= 6 && p[1] == 6) { 240825944Sjoerg wantaddr = p[2] << 24 | p[3] << 16 | 240925944Sjoerg p[4] << 8 | p[5]; 241025944Sjoerg sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); 241125944Sjoerg if (debug) 241225944Sjoerg addlog("[wantaddr 0x%x] ", wantaddr); 241325944Sjoerg /* 241425944Sjoerg * When doing dynamic address assignment, 241525944Sjoerg * we accept his offer. Otherwise, we 241625944Sjoerg * ignore it and thus continue to negotiate 241725944Sjoerg * our already existing value. 241825944Sjoerg */ 241925944Sjoerg if (sp->ipcp.flags & IPCP_MYADDR_DYN) { 242025944Sjoerg sppp_set_ip_addr(sp, wantaddr); 242125944Sjoerg if (debug) 242225944Sjoerg addlog("[agree] "); 242325944Sjoerg } 242425944Sjoerg } 242525944Sjoerg break; 242625944Sjoerg#ifdef notyet 242725944Sjoerg case IPCP_OPT_COMPRESS: 242825944Sjoerg /* 242925944Sjoerg * Peer wants different compression parameters. 243025944Sjoerg */ 243125944Sjoerg break; 243225944Sjoerg#endif 243325944Sjoerg } 243425944Sjoerg } 243525944Sjoerg if (debug) 243625944Sjoerg addlog("\n"); 243725944Sjoerg free (buf, M_TEMP); 243825944Sjoerg return; 24394910Swollman} 24404910Swollman 244112820Sphkstatic void 244225944Sjoergsppp_ipcp_tlu(struct sppp *sp) 24434910Swollman{ 24444910Swollman} 24454910Swollman 244625944Sjoergstatic void 244725944Sjoergsppp_ipcp_tld(struct sppp *sp) 244825944Sjoerg{ 244925944Sjoerg} 245025944Sjoerg 245125944Sjoergstatic void 245225944Sjoergsppp_ipcp_tls(struct sppp *sp) 245325944Sjoerg{ 245425944Sjoerg /* indicate to LCP that it must stay alive */ 245525944Sjoerg sp->lcp.protos |= (1 << IDX_IPCP); 245625944Sjoerg} 245725944Sjoerg 245825944Sjoergstatic void 245925944Sjoergsppp_ipcp_tlf(struct sppp *sp) 246025944Sjoerg{ 246125944Sjoerg /* we no longer need LCP */ 246225944Sjoerg sp->lcp.protos &= ~(1 << IDX_IPCP); 246325944Sjoerg sppp_lcp_check(sp); 246425944Sjoerg} 246525944Sjoerg 246625944Sjoergstatic void 246725944Sjoergsppp_ipcp_scr(struct sppp *sp) 246825944Sjoerg{ 246925944Sjoerg char opt[6 /* compression */ + 6 /* address */]; 247025944Sjoerg u_long ouraddr; 247125944Sjoerg int i = 0; 247225944Sjoerg 247325944Sjoerg#ifdef notyet 247425944Sjoerg if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) { 247525944Sjoerg opt[i++] = IPCP_OPT_COMPRESSION; 247625944Sjoerg opt[i++] = 6; 247725944Sjoerg opt[i++] = 0; /* VJ header compression */ 247825944Sjoerg opt[i++] = 0x2d; /* VJ header compression */ 247925944Sjoerg opt[i++] = max_slot_id; 248025944Sjoerg opt[i++] = comp_slot_id; 248125944Sjoerg } 248225944Sjoerg#endif 248325944Sjoerg 248425944Sjoerg if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) { 248525944Sjoerg sppp_get_ip_addrs(sp, &ouraddr, 0); 248625944Sjoerg opt[i++] = IPCP_OPT_ADDRESS; 248725944Sjoerg opt[i++] = 6; 248825944Sjoerg opt[i++] = ouraddr >> 24; 248925944Sjoerg opt[i++] = ouraddr >> 16; 249025944Sjoerg opt[i++] = ouraddr >> 8; 249125944Sjoerg opt[i++] = ouraddr; 249225944Sjoerg } 249325944Sjoerg 249425944Sjoerg sp->confid[IDX_IPCP] = ++sp->pp_seq; 249525944Sjoerg sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt); 249625944Sjoerg} 249725944Sjoerg 249825944Sjoerg 249925944Sjoerg/* 250025944Sjoerg * Random miscellaneous functions. 250125944Sjoerg */ 250225944Sjoerg 25034910Swollman/* 250425944Sjoerg * Flush interface queue. 25054910Swollman */ 250612820Sphkstatic void 250725944Sjoergsppp_qflush(struct ifqueue *ifq) 25084910Swollman{ 250925944Sjoerg struct mbuf *m, *n; 25104910Swollman 251125944Sjoerg n = ifq->ifq_head; 251225944Sjoerg while ((m = n)) { 251325944Sjoerg n = m->m_act; 251425944Sjoerg m_freem (m); 251511189Sjkh } 251625944Sjoerg ifq->ifq_head = 0; 251725944Sjoerg ifq->ifq_tail = 0; 251825944Sjoerg ifq->ifq_len = 0; 251925944Sjoerg} 252025944Sjoerg 252125944Sjoerg/* 252225944Sjoerg * Send keepalive packets, every 10 seconds. 252325944Sjoerg */ 252425944Sjoergstatic void 252525944Sjoergsppp_keepalive(void *dummy) 252625944Sjoerg{ 252725944Sjoerg struct sppp *sp; 252825944Sjoerg int s; 252925944Sjoerg 253025944Sjoerg s = splimp(); 253125944Sjoerg for (sp=spppq; sp; sp=sp->pp_next) { 253225944Sjoerg struct ifnet *ifp = &sp->pp_if; 253325944Sjoerg 253425944Sjoerg /* Keepalive mode disabled or channel down? */ 253525944Sjoerg if (! (sp->pp_flags & PP_KEEPALIVE) || 253625944Sjoerg ! (ifp->if_flags & IFF_RUNNING)) 253725944Sjoerg continue; 253825944Sjoerg 253925944Sjoerg /* No keepalive in PPP mode if LCP not opened yet. */ 254025944Sjoerg if (! (sp->pp_flags & PP_CISCO) && 254125944Sjoerg sp->pp_phase < PHASE_AUTHENTICATE) 254225944Sjoerg continue; 254325944Sjoerg 254425944Sjoerg if (sp->pp_alivecnt == MAXALIVECNT) { 254525944Sjoerg /* No keepalive packets got. Stop the interface. */ 254625944Sjoerg printf ("%s%d: down\n", ifp->if_name, ifp->if_unit); 254725944Sjoerg if_down (ifp); 254826018Sjoerg sppp_qflush (&sp->pp_cpq); 254925944Sjoerg if (! (sp->pp_flags & PP_CISCO)) { 255025944Sjoerg /* XXX */ 255125944Sjoerg /* Shut down the PPP link. */ 255225944Sjoerg lcp.Down(sp); 255325944Sjoerg /* Initiate negotiation. XXX */ 255425944Sjoerg lcp.Up(sp); 255525944Sjoerg } 25564910Swollman } 255725944Sjoerg if (sp->pp_alivecnt <= MAXALIVECNT) 255825944Sjoerg ++sp->pp_alivecnt; 255925944Sjoerg if (sp->pp_flags & PP_CISCO) 256025944Sjoerg sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, 256125944Sjoerg sp->pp_rseq); 256225944Sjoerg else if (sp->pp_phase >= PHASE_AUTHENTICATE) { 256325944Sjoerg long nmagic = htonl (sp->lcp.magic); 256425944Sjoerg sp->lcp.echoid = ++sp->pp_seq; 256525944Sjoerg sppp_cp_send (sp, PPP_LCP, ECHO_REQ, 256625944Sjoerg sp->lcp.echoid, 4, &nmagic); 256725944Sjoerg } 25684910Swollman } 256925944Sjoerg splx(s); 257025944Sjoerg timeout(sppp_keepalive, 0, hz * 10); 25714910Swollman} 25724910Swollman 257325944Sjoerg/* 257425944Sjoerg * Get both IP addresses. 257525944Sjoerg */ 257625944Sjoergstatic void 257725944Sjoergsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst) 257825944Sjoerg{ 257925944Sjoerg struct ifnet *ifp = &sp->pp_if; 258025944Sjoerg struct ifaddr *ifa; 258125944Sjoerg struct sockaddr_in *si; 258225944Sjoerg u_long ssrc, ddst; 258325944Sjoerg 258425944Sjoerg ssrc = ddst = 0L; 258525944Sjoerg /* 258625944Sjoerg * Pick the first AF_INET address from the list, 258725944Sjoerg * aliases don't make any sense on a p2p link anyway. 258825944Sjoerg */ 258925944Sjoerg for (ifa = ifp->if_addrhead.tqh_first, si = 0; 259025944Sjoerg ifa; 259125944Sjoerg ifa = ifa->ifa_link.tqe_next) 259225944Sjoerg if (ifa->ifa_addr->sa_family == AF_INET) { 259325944Sjoerg si = (struct sockaddr_in *)ifa->ifa_addr; 259425944Sjoerg if (si) 259525944Sjoerg break; 259625944Sjoerg } 259725944Sjoerg if (ifa) { 259825944Sjoerg if (si && si->sin_addr.s_addr) 259925944Sjoerg ssrc = si->sin_addr.s_addr; 260025944Sjoerg 260125944Sjoerg si = (struct sockaddr_in *)ifa->ifa_dstaddr; 260225944Sjoerg if (si && si->sin_addr.s_addr) 260325944Sjoerg ddst = si->sin_addr.s_addr; 260425944Sjoerg } 260525944Sjoerg 260625944Sjoerg if (dst) *dst = ntohl(ddst); 260725944Sjoerg if (src) *src = ntohl(ssrc); 260825944Sjoerg} 260925944Sjoerg 261025944Sjoerg/* 261125944Sjoerg * Set my IP address. Must be called at splimp. 261225944Sjoerg */ 261325944Sjoergstatic void 261425944Sjoergsppp_set_ip_addr(struct sppp *sp, u_long src) 261525944Sjoerg{ 261625944Sjoerg struct ifnet *ifp = &sp->pp_if; 261725944Sjoerg struct ifaddr *ifa; 261825944Sjoerg struct sockaddr_in *si; 261925944Sjoerg u_long ssrc, ddst; 262025944Sjoerg 262125944Sjoerg /* 262225944Sjoerg * Pick the first AF_INET address from the list, 262325944Sjoerg * aliases don't make any sense on a p2p link anyway. 262425944Sjoerg */ 262525944Sjoerg for (ifa = ifp->if_addrhead.tqh_first, si = 0; 262625944Sjoerg ifa; 262725944Sjoerg ifa = ifa->ifa_link.tqe_next) 262825944Sjoerg if (ifa->ifa_addr->sa_family == AF_INET) { 262925944Sjoerg si = (struct sockaddr_in *)ifa->ifa_addr; 263025944Sjoerg if (si) 263125944Sjoerg break; 263225944Sjoerg } 263325944Sjoerg if (ifa && si) 263425944Sjoerg si->sin_addr.s_addr = htonl(src); 263525944Sjoerg} 263625944Sjoerg 263725706Sjoergstatic const char * 263825944Sjoergsppp_cp_type_name(u_char type) 26394910Swollman{ 264025706Sjoerg static char buf [12]; 26414910Swollman switch (type) { 264225944Sjoerg case CONF_REQ: return ("conf-req"); 264325944Sjoerg case CONF_ACK: return ("conf-ack"); 264425944Sjoerg case CONF_NAK: return ("conf-nak"); 264525944Sjoerg case CONF_REJ: return ("conf-rej"); 264625944Sjoerg case TERM_REQ: return ("term-req"); 264725944Sjoerg case TERM_ACK: return ("term-ack"); 264825944Sjoerg case CODE_REJ: return ("code-rej"); 264925944Sjoerg case PROTO_REJ: return ("proto-rej"); 265025944Sjoerg case ECHO_REQ: return ("echo-req"); 265125944Sjoerg case ECHO_REPLY: return ("echo-reply"); 265225944Sjoerg case DISC_REQ: return ("discard-req"); 26534910Swollman } 265425706Sjoerg sprintf (buf, "0x%x", type); 26554910Swollman return (buf); 26564910Swollman} 26574910Swollman 265825706Sjoergstatic const char * 265925944Sjoergsppp_lcp_opt_name(u_char opt) 26604910Swollman{ 266125706Sjoerg static char buf [12]; 266225944Sjoerg switch (opt) { 266325944Sjoerg case LCP_OPT_MRU: return ("mru"); 266425944Sjoerg case LCP_OPT_ASYNC_MAP: return ("async-map"); 266525944Sjoerg case LCP_OPT_AUTH_PROTO: return ("auth-proto"); 266625944Sjoerg case LCP_OPT_QUAL_PROTO: return ("qual-proto"); 266725944Sjoerg case LCP_OPT_MAGIC: return ("magic"); 266825944Sjoerg case LCP_OPT_PROTO_COMP: return ("proto-comp"); 266925944Sjoerg case LCP_OPT_ADDR_COMP: return ("addr-comp"); 26704910Swollman } 267125944Sjoerg sprintf (buf, "0x%x", opt); 26724910Swollman return (buf); 26734910Swollman} 26744910Swollman 267525944Sjoergstatic const char * 267625944Sjoergsppp_ipcp_opt_name(u_char opt) 267725944Sjoerg{ 267825944Sjoerg static char buf [12]; 267925944Sjoerg switch (opt) { 268025944Sjoerg case IPCP_OPT_ADDRESSES: return ("addresses"); 268125944Sjoerg case IPCP_OPT_COMPRESSION: return ("compression"); 268225944Sjoerg case IPCP_OPT_ADDRESS: return ("address"); 268325944Sjoerg } 268425944Sjoerg sprintf (buf, "0x%x", opt); 268525944Sjoerg return (buf); 268625944Sjoerg} 268725944Sjoerg 268825944Sjoergstatic const char * 268925944Sjoergsppp_state_name(int state) 269025944Sjoerg{ 269125944Sjoerg switch (state) { 269225944Sjoerg case STATE_INITIAL: return "initial"; 269325944Sjoerg case STATE_STARTING: return "starting"; 269425944Sjoerg case STATE_CLOSED: return "closed"; 269525944Sjoerg case STATE_STOPPED: return "stopped"; 269625944Sjoerg case STATE_CLOSING: return "closing"; 269725944Sjoerg case STATE_STOPPING: return "stopping"; 269825944Sjoerg case STATE_REQ_SENT: return "req-sent"; 269925944Sjoerg case STATE_ACK_RCVD: return "ack-rcvd"; 270025944Sjoerg case STATE_ACK_SENT: return "ack-sent"; 270125944Sjoerg case STATE_OPENED: return "opened"; 270225944Sjoerg } 270325944Sjoerg return "illegal"; 270425944Sjoerg} 270525944Sjoerg 270625944Sjoergstatic const char * 270725944Sjoergsppp_phase_name(enum ppp_phase phase) 270825944Sjoerg{ 270925944Sjoerg switch (phase) { 271025944Sjoerg case PHASE_DEAD: return "dead"; 271125944Sjoerg case PHASE_ESTABLISH: return "establish"; 271225944Sjoerg case PHASE_TERMINATE: return "terminate"; 271325944Sjoerg case PHASE_AUTHENTICATE: return "authenticate"; 271425944Sjoerg case PHASE_NETWORK: return "network"; 271525944Sjoerg } 271625944Sjoerg return "illegal"; 271725944Sjoerg} 271825944Sjoerg 271925944Sjoergstatic const char * 272025944Sjoergsppp_proto_name(u_short proto) 272125944Sjoerg{ 272225944Sjoerg static char buf[12]; 272325944Sjoerg switch (proto) { 272425944Sjoerg case PPP_LCP: return "lcp"; 272525944Sjoerg case PPP_IPCP: return "ipcp"; 272625944Sjoerg } 272725944Sjoerg sprintf(buf, "0x%x", (unsigned)proto); 272825944Sjoerg return buf; 272925944Sjoerg} 273025944Sjoerg 273112820Sphkstatic void 273225706Sjoergsppp_print_bytes(u_char *p, u_short len) 27334910Swollman{ 273425706Sjoerg addlog(" %x", *p++); 27354910Swollman while (--len > 0) 273625706Sjoerg addlog("-%x", *p++); 27374910Swollman} 273825944Sjoerg 273925944Sjoerg/* 274025944Sjoerg * This file is large. Tell emacs to highlight it nevertheless. 274125944Sjoerg * 274225944Sjoerg * Local Variables: 274325944Sjoerg * hilit-auto-highlight-maxout: 100000 274425944Sjoerg * End: 274525944Sjoerg */ 2746