diff options
author | joerg <joerg@FreeBSD.org> | 1997-10-11 11:25:28 +0000 |
---|---|---|
committer | joerg <joerg@FreeBSD.org> | 1997-10-11 11:25:28 +0000 |
commit | dd1b2fd214aadecacef7f52a09f94f0251c710c9 (patch) | |
tree | 4f4c92fbeca4ac942087f58797022b0ac009266a /sys | |
parent | 05d08b5a3dad0def0cc0e8f8b70eea783d31d166 (diff) | |
download | FreeBSD-src-dd1b2fd214aadecacef7f52a09f94f0251c710c9.zip FreeBSD-src-dd1b2fd214aadecacef7f52a09f94f0251c710c9.tar.gz |
Jumbo patch to implement PAP and CHAP for sppp(4). Partially based on
Serge's (Cronyx's) code in the vendor branch. (FR support not yet
merged.)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_sppp.h | 55 | ||||
-rw-r--r-- | sys/net/if_spppsubr.c | 1601 |
2 files changed, 1504 insertions, 152 deletions
diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h index e0e61bb..9154eda 100644 --- a/sys/net/if_sppp.h +++ b/sys/net/if_sppp.h @@ -14,7 +14,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * From: Version 1.7, Wed Jun 7 22:12:02 MSD 1995 + * From: Version 2.0, Fri Oct 6 20:39:21 MSK 1995 * * $Id: if_sppp.h,v 1.6 1997/05/22 22:15:39 joerg Exp $ */ @@ -47,7 +47,24 @@ struct sipcp { #define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */ }; -#define IDX_COUNT (IDX_IPCP + 1) /* bump this when adding cp's! */ +#define AUTHNAMELEN 32 +#define AUTHKEYLEN 16 + +struct sauth { + u_short proto; /* authentication protocol to use */ + u_short flags; +#define AUTHFLAG_NOCALLOUT 1 /* do not require authentication on */ + /* callouts */ +#define AUTHFLAG_NORECHALLENGE 2 /* do not re-challenge CHAP */ + u_char name[AUTHNAMELEN]; /* system identification name */ + u_char secret[AUTHKEYLEN]; /* secret password */ + u_char challenge[AUTHKEYLEN]; /* random challenge */ +}; + +#define IDX_PAP 2 +#define IDX_CHAP 3 + +#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ /* * Don't change the order of this. Ordering the phases this way allows @@ -75,9 +92,12 @@ struct sppp { u_char confid[IDX_COUNT]; /* id of last configuration request */ int rst_counter[IDX_COUNT]; /* restart counter */ int fail_counter[IDX_COUNT]; /* negotiation failure counter */ - struct callout_handle ch[IDX_COUNT]; - struct slcp lcp; /* LCP params */ - struct sipcp ipcp; /* IPCP params */ + struct callout_handle ch[IDX_COUNT]; /* per-proto and if callouts */ + struct callout_handle pap_my_to_ch; /* PAP needs one more... */ + struct slcp lcp; /* LCP params */ + struct sipcp ipcp; /* IPCP params */ + struct sauth myauth; /* auth params, i'm peer */ + struct sauth hisauth; /* auth params, i'm authenticator */ /* * These functions are filled in by sppp_attach(), and are * expected to be used by the lower layer (hardware) drivers @@ -100,16 +120,41 @@ struct sppp { #define PP_KEEPALIVE 0x01 /* use keepalive protocol */ #define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ + /* 0x04 was PP_TIMO */ +#define PP_CALLIN 0x08 /* we are being called */ +#define PP_NEEDAUTH 0x10 /* remote requested authentication */ + #define PP_MTU 1500 /* default/minimal MRU */ #define PP_MAX_MRU 2048 /* maximal MRU we want to negotiate */ +/* + * Definitions to pass struct sppp data down into the kernel using the + * SIOC[SG]IFGENERIC ioctl interface. + * + * In order to use this, create a struct spppreq, fill in the cmd + * field with SPPPIOGDEFS, and put the address of this structure into + * the ifr_data portion of a struct ifreq. Pass this struct to a + * SIOCGIFGENERIC ioctl. Then replace the cmd field by SPPPIOCDEFS, + * modify the defs field as desired, and pass the struct ifreq now + * to a SIOCSIFGENERIC ioctl. + */ + +#define SPPPIOGDEFS ((caddr_t)(('S' << 24) + (1 << 16) + sizeof(struct sppp))) +#define SPPPIOSDEFS ((caddr_t)(('S' << 24) + (2 << 16) + sizeof(struct sppp))) + +struct spppreq { + int cmd; + struct sppp defs; +}; + #ifdef KERNEL void sppp_attach (struct ifnet *ifp); void sppp_detach (struct ifnet *ifp); void sppp_input (struct ifnet *ifp, struct mbuf *m); int sppp_ioctl (struct ifnet *ifp, int cmd, void *data); struct mbuf *sppp_dequeue (struct ifnet *ifp); +struct mbuf *sppp_pick(struct ifnet *ifp); int sppp_isempty (struct ifnet *ifp); void sppp_flush (struct ifnet *ifp); #endif diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index 3e1b854..29597d2 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -2,7 +2,7 @@ * Synchronous PPP/Cisco link level subroutines. * Keepalive protocol implemented in both Cisco and PPP modes. * - * Copyright (C) 1994 Cronyx Ltd. + * Copyright (C) 1994-1996 Cronyx Engineering Ltd. * Author: Serge Vakulenko, <vak@cronyx.ru> * * Heavily revamped to conform to RFC 1661. @@ -15,7 +15,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * From: Version 1.9, Wed Oct 4 18:58:15 MSK 1995 + * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997 * * $Id: if_spppsubr.c,v 1.26 1997/09/02 01:18:37 bde Exp $ */ @@ -28,11 +28,14 @@ #include <sys/syslog.h> #include <sys/malloc.h> #include <sys/mbuf.h> +#include <sys/md5.h> #include <net/if.h> #include <net/netisr.h> #include <net/if_types.h> +#include <machine/stdarg.h> + #ifdef INET #include <netinet/in.h> #include <netinet/in_systm.h> @@ -73,19 +76,30 @@ * * Setting link1 will cause the link to auto-dial only as packets * arrive to be sent. + * + * Setting IFF_DEBUG will syslog the option negotiation and state + * transitions at level kern.debug. Note: all logs consistently look + * like + * + * <if-name><unit>: <proto-name> <additional info...> + * + * with <if-name><unit> being something like "bppp0", and <proto-name> + * being one of "lcp", "ipcp", "cisco", "chap", "pap", etc. */ #define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ #define IFF_AUTO IFF_LINK1 /* auto-dial on output */ -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_IP 0x0021 /* Internet Protocol */ -#define PPP_ISO 0x0023 /* ISO OSI Protocol */ -#define PPP_XNS 0x0025 /* Xerox NS Protocol */ -#define PPP_IPX 0x002b /* Novell IPX Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_IP 0x0021 /* Internet Protocol */ +#define PPP_ISO 0x0023 /* ISO OSI Protocol */ +#define PPP_XNS 0x0025 /* Xerox NS Protocol */ +#define PPP_IPX 0x002b /* Novell IPX Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */ +#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ #define CONF_REQ 1 /* PPP configure request */ #define CONF_ACK 2 /* PPP configure acknowledge */ @@ -99,25 +113,36 @@ #define ECHO_REPLY 10 /* PPP echo reply */ #define DISC_REQ 11 /* PPP discard request */ -#define LCP_OPT_MRU 1 /* maximum receive unit */ -#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ -#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ -#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ -#define LCP_OPT_MAGIC 5 /* magic number */ -#define LCP_OPT_RESERVED 6 /* reserved */ -#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ -#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ +#define LCP_OPT_MRU 1 /* maximum receive unit */ +#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ +#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ +#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ +#define LCP_OPT_MAGIC 5 /* magic number */ +#define LCP_OPT_RESERVED 6 /* reserved */ +#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ +#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ #define IPCP_OPT_ADDRESSES 1 /* both IP addresses; deprecated */ #define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */ #define IPCP_OPT_ADDRESS 3 /* local IP address */ -#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ -#define CISCO_UNICAST 0x0f /* Cisco unicast address */ -#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ -#define CISCO_ADDR_REQ 0 /* Cisco address request */ -#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ -#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ +#define PAP_REQ 1 /* PAP name/password request */ +#define PAP_ACK 2 /* PAP acknowledge */ +#define PAP_NAK 3 /* PAP fail */ + +#define CHAP_CHALLENGE 1 /* CHAP challenge request */ +#define CHAP_RESPONSE 2 /* CHAP challenge response */ +#define CHAP_SUCCESS 3 /* CHAP response ok */ +#define CHAP_FAILURE 4 /* CHAP response failed */ + +#define CHAP_MD5 5 /* hash algorithm - MD5 */ + +#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ +#define CISCO_UNICAST 0x0f /* Cisco unicast address */ +#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ +#define CISCO_ADDR_REQ 0 /* Cisco address request */ +#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ +#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ /* states are named and numbered according to RFC 1661 */ #define STATE_INITIAL 0 @@ -188,12 +213,15 @@ struct cp { }; static struct sppp *spppq; +static struct callout_handle keepalive_ch; /* * The following disgusting hack gets around the problem that IP TOS * can't be set yet. We want to put "interactive" traffic on a high * priority queue. To decide if traffic is interactive, we check that * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. + * + * XXX is this really still necessary? - joerg - */ static u_short interactive_ports[8] = { 0, 513, 0, 0, @@ -206,7 +234,7 @@ static u_short interactive_ports[8] = { struct ifnet *ifp = &sp->pp_if; \ int debug = ifp->if_flags & IFF_DEBUG -static int sppp_output(struct ifnet *ifp, struct mbuf *m, +static int sppp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt); static void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2); @@ -219,6 +247,9 @@ static void sppp_cp_send(struct sppp *sp, u_short proto, u_char type, static void sppp_cp_timeout(void *arg); static void sppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate); +static void sppp_auth_send(const struct cp *cp, + struct sppp *sp, u_char type, u_char id, + ...); static void sppp_up_event(const struct cp *cp, struct sppp *sp); static void sppp_down_event(const struct cp *cp, struct sppp *sp); @@ -226,6 +257,8 @@ static void sppp_open_event(const struct cp *cp, struct sppp *sp); static void sppp_close_event(const struct cp *cp, struct sppp *sp); static void sppp_to_event(const struct cp *cp, struct sppp *sp); +static void sppp_null(struct sppp *sp); + static void sppp_lcp_init(struct sppp *sp); static void sppp_lcp_up(struct sppp *sp); static void sppp_lcp_down(struct sppp *sp); @@ -240,7 +273,8 @@ static void sppp_lcp_tld(struct sppp *sp); static void sppp_lcp_tls(struct sppp *sp); static void sppp_lcp_tlf(struct sppp *sp); static void sppp_lcp_scr(struct sppp *sp); -static void sppp_lcp_check(struct sppp *sp); +static void sppp_lcp_check_and_close(struct sppp *sp); +static int sppp_ncp_check(struct sppp *sp); static void sppp_ipcp_init(struct sppp *sp); static void sppp_ipcp_up(struct sppp *sp); @@ -257,22 +291,44 @@ static void sppp_ipcp_tls(struct sppp *sp); static void sppp_ipcp_tlf(struct sppp *sp); static void sppp_ipcp_scr(struct sppp *sp); +static void sppp_pap_input(struct sppp *sp, struct mbuf *m); +static void sppp_pap_init(struct sppp *sp); +static void sppp_pap_open(struct sppp *sp); +static void sppp_pap_close(struct sppp *sp); +static void sppp_pap_TO(void *sp); +static void sppp_pap_my_TO(void *sp); +static void sppp_pap_tlu(struct sppp *sp); +static void sppp_pap_tld(struct sppp *sp); +static void sppp_pap_scr(struct sppp *sp); + +static void sppp_chap_input(struct sppp *sp, struct mbuf *m); +static void sppp_chap_init(struct sppp *sp); +static void sppp_chap_open(struct sppp *sp); +static void sppp_chap_close(struct sppp *sp); +static void sppp_chap_TO(void *sp); +static void sppp_chap_tlu(struct sppp *sp); +static void sppp_chap_tld(struct sppp *sp); +static void sppp_chap_scr(struct sppp *sp); + +static const char *sppp_auth_type_name(u_short proto, u_char type); static const char *sppp_cp_type_name(u_char type); -static const char *sppp_lcp_opt_name(u_char opt); +static const char *sppp_dotted_quad(u_long addr); static const char *sppp_ipcp_opt_name(u_char opt); -static const char *sppp_state_name(int state); +static const char *sppp_lcp_opt_name(u_char opt); static const char *sppp_phase_name(enum ppp_phase phase); static const char *sppp_proto_name(u_short proto); - +static const char *sppp_state_name(int state); +static int sppp_params(struct sppp *sp, int cmd, void *data); +static int sppp_strnlen(u_char *p, int max); +static void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, + u_long *srcmask); static void sppp_keepalive(void *dummy); -static struct callout_handle keepalive_ch; +static void sppp_phase_network(struct sppp *sp); +static void sppp_print_bytes(const u_char *p, u_short len); +static void sppp_print_string(const char *p, u_short len); static void sppp_qflush(struct ifqueue *ifq); - -static void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst); static void sppp_set_ip_addr(struct sppp *sp, u_long src); -static void sppp_print_bytes(u_char *p, u_short len); - /* our control protocol descriptors */ const struct cp lcp = { PPP_LCP, IDX_LCP, CP_LCP, "lcp", @@ -290,9 +346,27 @@ const struct cp ipcp = { sppp_ipcp_scr }; +const struct cp pap = { + PPP_PAP, IDX_PAP, CP_AUTH, "pap", + sppp_null, sppp_null, sppp_pap_open, sppp_pap_close, + sppp_pap_TO, 0, 0, 0, + sppp_pap_tlu, sppp_pap_tld, sppp_null, sppp_null, + sppp_pap_scr +}; + +const struct cp chap = { + PPP_CHAP, IDX_CHAP, CP_AUTH, "chap", + sppp_null, sppp_null, sppp_chap_open, sppp_chap_close, + sppp_chap_TO, 0, 0, 0, + sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null, + sppp_chap_scr +}; + const struct cp *cps[IDX_COUNT] = { &lcp, /* IDX_LCP */ &ipcp, /* IDX_IPCP */ + &pap, /* IDX_PAP */ + &chap, /* IDX_CHAP */ }; @@ -361,13 +435,23 @@ sppp_input(struct ifnet *ifp, struct mbuf *m) ++ifp->if_noproto; goto drop; case PPP_LCP: - sppp_cp_input(&lcp, (struct sppp*)ifp, m); + sppp_cp_input(&lcp, sp, m); + m_freem (m); + return; + case PPP_PAP: + if (sp->pp_phase >= PHASE_AUTHENTICATE) + sppp_pap_input(sp, m); + m_freem (m); + return; + case PPP_CHAP: + if (sp->pp_phase >= PHASE_AUTHENTICATE) + sppp_chap_input(sp, m); m_freem (m); return; #ifdef INET case PPP_IPCP: if (sp->pp_phase == PHASE_NETWORK) - sppp_cp_input(&ipcp, (struct sppp*) ifp, m); + sppp_cp_input(&ipcp, sp, m); m_freem (m); return; case PPP_IP: @@ -628,7 +712,7 @@ sppp_attach(struct ifnet *ifp) /* Initialize keepalive handler. */ if (! spppq) - keepalive_ch = timeout (sppp_keepalive, 0, hz * 10); + keepalive_ch = timeout(sppp_keepalive, 0, hz * 10); /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; @@ -648,9 +732,11 @@ sppp_attach(struct ifnet *ifp) sppp_lcp_init(sp); sppp_ipcp_init(sp); + sppp_pap_init(sp); + sppp_chap_init(sp); } -void +void sppp_detach(struct ifnet *ifp) { struct sppp **q, *p, *sp = (struct sppp*) ifp; @@ -665,10 +751,11 @@ sppp_detach(struct ifnet *ifp) /* Stop keepalive handler. */ if (! spppq) - untimeout (sppp_keepalive, 0, keepalive_ch); + untimeout(sppp_keepalive, 0, keepalive_ch); for (i = 0; i < IDX_COUNT; i++) untimeout((cps[i])->TO, (void *)sp, sp->ch[i]); + untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); } /* @@ -712,23 +799,14 @@ sppp_dequeue(struct ifnet *ifp) s = splimp(); /* - * Process only the control protocol queue until we are in - * network phase. - * - * XXX Network phase itself is still not a sufficient test, we - * normally should keep a separate queue for each supported - * protocol family, and only serve these queues as the - * respective NCPs were opened. The simplistic logic used - * here might cause some loss of network traffic while the - * NCPs are being negotiated, in particular if the NCPs take a - * long time to negotiate. + * Process only the control protocol queue until we have at + * least one NCP open. * * Do always serve all three queues in Cisco mode. */ IF_DEQUEUE(&sp->pp_cpq, m); if (m == NULL && - (sp->pp_phase == PHASE_NETWORK || - (sp->pp_flags & PP_CISCO) != 0)) { + (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) { IF_DEQUEUE(&sp->pp_fastq, m); if (m == NULL) IF_DEQUEUE (&sp->pp_if.if_snd, m); @@ -738,6 +816,28 @@ sppp_dequeue(struct ifnet *ifp) } /* + * Pick the next packet, do not remove it from the queue. + */ +struct mbuf * +sppp_pick(struct ifnet *ifp) +{ + struct sppp *sp = (struct sppp*)ifp; + struct mbuf *m; + int s; + + s= splimp (); + + m = sp->pp_cpq.ifq_head; + if (m == NULL && + (sp->pp_phase == PHASE_NETWORK || + (sp->pp_flags & PP_CISCO) != 0)) + if ((m = sp->pp_fastq.ifq_head) == NULL) + m = sp->pp_if.if_snd.ifq_head; + splx (s); + return (m); +} + +/* * Process an ioctl request. Called on low priority level. */ int @@ -745,9 +845,10 @@ sppp_ioctl(struct ifnet *ifp, int cmd, void *data) { struct ifreq *ifr = (struct ifreq*) data; struct sppp *sp = (struct sppp*) ifp; - int s, going_up, going_down, newmode; + int s, rv, going_up, going_down, newmode; s = splimp(); + rv = 0; switch (cmd) { case SIOCAIFADDR: case SIOCSIFDSTADDR: @@ -814,12 +915,16 @@ sppp_ioctl(struct ifnet *ifp, int cmd, void *data) case SIOCDELMULTI: break; + case SIOCGIFGENERIC: + case SIOCSIFGENERIC: + rv = sppp_params(sp, cmd, data); + break; + default: - splx(s); - return (ENOTTY); + rv = ENOTTY; } splx(s); - return (0); + return rv; } @@ -830,17 +935,17 @@ sppp_ioctl(struct ifnet *ifp, int cmd, void *data) /* * Handle incoming Cisco keepalive protocol packets. */ -static void +static void sppp_cisco_input(struct sppp *sp, struct mbuf *m) { STDDCL; struct cisco_packet *h; - struct ifaddr *ifa; + u_long me, mymask; if (m->m_pkthdr.len < CISCO_PACKET_LEN) { if (debug) log(LOG_DEBUG, - "%s%d: invalid cisco packet length: %d bytes\n", + "%s%d: cisco invalid packet length: %d bytes\n", ifp->if_name, ifp->if_unit, m->m_pkthdr.len); return; } @@ -855,7 +960,7 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m) switch (ntohl (h->type)) { default: if (debug) - addlog("%s%d: unknown cisco packet type: 0x%lx\n", + addlog("%s%d: cisco unknown packet type: 0x%lx\n", ifp->if_name, ifp->if_unit, ntohl (h->type)); break; case CISCO_ADDR_REPLY: @@ -882,27 +987,17 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m) sp->pp_seq ^= time.tv_sec ^ time.tv_usec; break; } - sp->pp_loopcnt = 0; + sp->pp_loopcnt = 0; if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) { - ifp->if_flags |= IFF_UP; + if_up(ifp); printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); } break; case CISCO_ADDR_REQ: - for (ifa=ifp->if_addrhead.tqh_first; ifa; - ifa=ifa->ifa_link.tqe_next) - if (ifa->ifa_addr->sa_family == AF_INET) - break; - if (! ifa) { - if (debug) - addlog("%s%d: unknown address for cisco request\n", - ifp->if_name, ifp->if_unit); - return; - } - sppp_cisco_send (sp, CISCO_ADDR_REPLY, - ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr), - ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr)); + sppp_get_ip_addrs(sp, &me, 0, &mymask); + if (me != 0L) + sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask); break; } } @@ -1045,6 +1140,7 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) } if (len > ntohs (h->len)) len = ntohs (h->len); + p = (u_char *)(h + 1); switch (h->type) { case CONF_REQ: if (len < 4) { @@ -1055,6 +1151,16 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) ++ifp->if_ierrors; break; } + /* handle states where RCR doesn't get a SCA/SCN */ + switch (sp->state[cp->protoidx]) { + case STATE_CLOSING: + case STATE_STOPPING: + return; + case STATE_CLOSED: + sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, + 0, 0); + return; + } rv = (cp->RCR)(sp, h, len); switch (sp->state[cp->protoidx]) { case STATE_OPENED: @@ -1066,19 +1172,12 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) sppp_cp_change_state(cp, sp, rv? STATE_ACK_SENT: STATE_REQ_SENT); break; - case STATE_CLOSING: - case STATE_STOPPING: - break; case STATE_STOPPED: sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; (cp->scr)(sp); sppp_cp_change_state(cp, sp, rv? STATE_ACK_SENT: STATE_REQ_SENT); break; - case STATE_CLOSED: - sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, - 0, 0); - break; case STATE_ACK_RCVD: if (rv) { sppp_cp_change_state(cp, sp, STATE_OPENED); @@ -1130,7 +1229,7 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; sppp_cp_change_state(cp, sp, STATE_OPENED); if (debug) - addlog("%s%d: %s tlu\n", + log(LOG_DEBUG, "%s%d: %s tlu\n", ifp->if_name, ifp->if_unit, cp->name); (cp->tlu)(sp); break; @@ -1252,6 +1351,11 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) case CODE_REJ: case PROTO_REJ: /* XXX catastrophic rejects (RXJ-) aren't handled yet. */ + log(LOG_INFO, + "%s%d: %s: ignoring RXJ (%s) for proto 0x%x, " + "danger will robinson\n", + ifp->if_name, ifp->if_unit, cp->name, + sppp_cp_type_name(h->type), ntohs(*((u_short *)p))); switch (sp->state[cp->protoidx]) { case STATE_CLOSED: case STATE_STOPPED: @@ -1585,8 +1689,7 @@ sppp_lcp_init(struct sppp *sp) sp->fail_counter[IDX_LCP] = 0; sp->lcp.protos = 0; sp->lcp.mru = sp->lcp.their_mru = PP_MTU; - callout_handle_init(&sp->ch[IDX_LCP]); - + /* * Initialize counters and timeout values. Note that we don't * use the 3 seconds suggested in RFC 1661 since we are likely @@ -1598,6 +1701,7 @@ sppp_lcp_init(struct sppp *sp) sp->lcp.max_terminate = 2; sp->lcp.max_configure = 10; sp->lcp.max_failure = 10; + callout_handle_init(&sp->ch[IDX_LCP]); } static void @@ -1606,16 +1710,22 @@ sppp_lcp_up(struct sppp *sp) STDDCL; /* - * If this interface is passive or dial-on-demand, it means - * we've got in incoming call. Activate the interface. + * If this interface is passive or dial-on-demand, and we are + * still in Initial state, it means we've got an incoming + * call. Activate the interface. */ if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) { if (debug) log(LOG_DEBUG, - "%s%d: Up event (incoming call)\n", - ifp->if_name, ifp->if_unit); + "%s%d: Up event", ifp->if_name, ifp->if_unit); ifp->if_flags |= IFF_RUNNING; - lcp.Open(sp); + if (sp->state[IDX_LCP] == STATE_INITIAL) { + if (debug) + addlog("(incoming call)\n"); + sp->pp_flags |= PP_CALLIN; + lcp.Open(sp); + } else if (debug) + addlog("\n"); } sppp_up_event(&lcp, sp); @@ -1646,13 +1756,23 @@ sppp_lcp_down(struct sppp *sp) "%s%d: Down event (carrier loss)\n", ifp->if_name, ifp->if_unit); } - lcp.Close(sp); + sp->pp_flags &= ~PP_CALLIN; + if (sp->state[IDX_LCP] != STATE_INITIAL) + lcp.Close(sp); ifp->if_flags &= ~IFF_RUNNING; } static void sppp_lcp_open(struct sppp *sp) { + /* + * If we are authenticator, negotiate LCP_AUTH + */ + if (sp->hisauth.proto != 0) + sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO); + else + sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); + sp->pp_flags &= ~PP_NEEDAUTH; sppp_open_event(&lcp, sp); } @@ -1681,6 +1801,7 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) u_char *buf, *r, *p; int origlen, rlen; u_long nmagic; + u_short authproto; len -= 4; origlen = len; @@ -1715,6 +1836,31 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) if (debug) addlog("[invalid] "); break; + case LCP_OPT_AUTH_PROTO: + if (len < 4) { + if (debug) + addlog("[invalid] "); + break; + } + authproto = (p[2] << 8) + p[3]; + if (authproto == PPP_CHAP && p[1] != 5) { + if (debug) + addlog("[invalid chap len] "); + break; + } + if (sp->myauth.proto == 0) { + /* we are not configured to do auth */ + if (debug) + addlog("[not configured] "); + break; + } + /* + * Remote want us to authenticate, remember this, + * so we stay in PHASE_AUTHENTICATE after LCP got + * up. + */ + sp->pp_flags |= PP_NEEDAUTH; + continue; default: /* Others not supported. */ if (debug) @@ -1761,7 +1907,7 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) * Local and remote magics equal -- loopback? */ if (sp->pp_loopcnt >= MAXALIVECNT*5) { - printf ("\n%s%d: loopback\n", + printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); sp->pp_loopcnt = 0; if (ifp->if_flags & IFF_UP) { @@ -1809,6 +1955,26 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) if (debug) addlog("%d ", sp->lcp.their_mru); continue; + + case LCP_OPT_AUTH_PROTO: + authproto = (p[2] << 8) + p[3]; + if (sp->myauth.proto != authproto) { + /* not agreed, nak */ + if (debug) + addlog("[mine %s != his %s] ", + sppp_proto_name(sp->hisauth.proto), + sppp_proto_name(authproto)); + p[2] = sp->myauth.proto >> 8; + p[3] = sp->myauth.proto; + break; + } + if (authproto == PPP_CHAP && p[4] != CHAP_MD5) { + if (debug) + addlog("[chap not MD5] "); + p[4] == CHAP_MD5; + break; + } + continue; } /* Add the option to nak'ed list. */ bcopy (p, r, p[1]); @@ -1878,6 +2044,24 @@ sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) */ sp->lcp.opts &= ~(1 << LCP_OPT_MRU); break; + case LCP_OPT_AUTH_PROTO: + /* + * Peer doesn't want to authenticate himself, + * deny unless this is a dialout call, and + * AUTHFLAG_NOCALLOUT is set. + */ + if ((sp->pp_flags & PP_CALLIN) == 0 && + (sp->hisauth.flags & AUTHFLAG_NOCALLOUT) != 0) { + if (debug) + addlog("[don't insist on auth " + "for callout]"); + sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); + break; + } + if (debug) + addlog("[access denied]\n"); + lcp.Close(sp); + break; } } if (debug) @@ -1949,6 +2133,15 @@ sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) sp->lcp.opts |= (1 << LCP_OPT_MRU); } break; + case LCP_OPT_AUTH_PROTO: + /* + * Peer doesn't like our authentication method, + * deny. + */ + if (debug) + addlog("[access denied]\n"); + lcp.Close(sp); + break; } } if (debug) @@ -1976,7 +2169,8 @@ sppp_lcp_tlu(struct sppp *sp) if ((cps[i])->flags & CP_QUAL) (cps[i])->Open(sp); - if (/* require authentication XXX */ 0) + if ((sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0 || + (sp->pp_flags & PP_NEEDAUTH) != 0) sp->pp_phase = PHASE_AUTHENTICATE; else sp->pp_phase = PHASE_NETWORK; @@ -1984,11 +2178,18 @@ sppp_lcp_tlu(struct sppp *sp) log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, sppp_phase_name(sp->pp_phase)); - if (sp->pp_phase == PHASE_AUTHENTICATE) { - for (i = 0; i < IDX_COUNT; i++) - if ((cps[i])->flags & CP_AUTH) - (cps[i])->Open(sp); - } else { + /* + * Open all authentication protocols. This is even required + * if we already proceeded to network phase, since it might be + * that remote wants us to authenticate, so we might have to + * send a PAP request. Undesired authentication protocols + * don't do anything when they get an Open event. + */ + for (i = 0; i < IDX_COUNT; i++) + if ((cps[i])->flags & CP_AUTH) + (cps[i])->Open(sp); + + if (sp->pp_phase == PHASE_NETWORK) { /* Notify all NCPs. */ for (i = 0; i < IDX_COUNT; i++) if ((cps[i])->flags & CP_NCP) @@ -2002,7 +2203,7 @@ sppp_lcp_tlu(struct sppp *sp) if (sp->pp_phase == PHASE_NETWORK) /* if no NCP is starting, close down */ - sppp_lcp_check(sp); + sppp_lcp_check_and_close(sp); } static void @@ -2062,8 +2263,9 @@ sppp_lcp_tlf(struct sppp *sp) static void sppp_lcp_scr(struct sppp *sp) { - char opt[6 /* magicnum */ + 4 /* mru */]; + char opt[6 /* magicnum */ + 4 /* mru */ + 5 /* chap */]; int i = 0; + u_short authproto; if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) { if (! sp->lcp.magic) @@ -2083,22 +2285,49 @@ sppp_lcp_scr(struct sppp *sp) opt[i++] = sp->lcp.mru; } + if (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) { + authproto = sp->hisauth.proto; + opt[i++] = LCP_OPT_AUTH_PROTO; + opt[i++] = authproto == PPP_CHAP? 5: 4; + opt[i++] = authproto >> 8; + opt[i++] = authproto; + if (authproto == PPP_CHAP) + opt[i++] = CHAP_MD5; + } + sp->confid[IDX_LCP] = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); } /* - * Re-check the open NCPs and see if we should terminate the link. - * Called by the NCPs during their tlf action handling. + * Check the open NCPs, return true if at least one NCP is open. */ -static void -sppp_lcp_check(struct sppp *sp) +static int +sppp_ncp_check(struct sppp *sp) { int i, mask; for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP) - return; + return 1; + return 0; +} + +/* + * Re-check the open NCPs and see if we should terminate the link. + * Called by the NCPs during their tlf action handling. + */ +static void +sppp_lcp_check_and_close(struct sppp *sp) +{ + + if (sp->pp_phase < PHASE_NETWORK) + /* don't bother, we are already going down */ + return; + + if (sppp_ncp_check(sp)) + return; + lcp.Close(sp); } /* @@ -2137,7 +2366,7 @@ sppp_ipcp_open(struct sppp *sp) STDDCL; u_long myaddr, hisaddr; - sppp_get_ip_addrs(sp, &myaddr, &hisaddr); + sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0); /* * If we don't have his address, this probably means our * interface doesn't want to talk IP at all. (This could @@ -2251,9 +2480,10 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) addlog("\n"); /* pass 2: parse option values */ - sppp_get_ip_addrs(sp, 0, &hisaddr); + sppp_get_ip_addrs(sp, 0, &hisaddr, 0); if (debug) - addlog("%s%d: ipcp parse opt values: ", ifp->if_name, ifp->if_unit); + log(LOG_DEBUG, "%s%d: ipcp parse opt values: ", + ifp->if_name, ifp->if_unit); p = (void*) (h+1); len = origlen; for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { @@ -2274,7 +2504,8 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) * it. */ if (debug) - addlog("0x%x [ack] ", hisaddr); + addlog("%s [ack] ", + sppp_dotted_quad(hisaddr)); /* record that we've seen it already */ sp->ipcp.flags |= IPCP_HISADDR_SEEN; continue; @@ -2290,8 +2521,8 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) if (desiredaddr == 0) addlog("[addr requested] "); else - addlog("0x%x [not agreed] ", - desiredaddr); + addlog("%s [not agreed] ", + sppp_dotted_quad(desiredaddr)); p[2] = hisaddr >> 24; p[3] = hisaddr >> 16; @@ -2425,7 +2656,8 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) p[4] << 8 | p[5]; sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); if (debug) - addlog("[wantaddr 0x%x] ", wantaddr); + addlog("[wantaddr %s] ", + sppp_dotted_quad(wantaddr)); /* * When doing dynamic address assignment, * we accept his offer. Otherwise, we @@ -2476,7 +2708,7 @@ sppp_ipcp_tlf(struct sppp *sp) { /* we no longer need LCP */ sp->lcp.protos &= ~(1 << IDX_IPCP); - sppp_lcp_check(sp); + sppp_lcp_check_and_close(sp); } static void @@ -2498,7 +2730,7 @@ sppp_ipcp_scr(struct sppp *sp) #endif if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) { - sppp_get_ip_addrs(sp, &ouraddr, 0); + sppp_get_ip_addrs(sp, &ouraddr, 0, 0); opt[i++] = IPCP_OPT_ADDRESS; opt[i++] = 6; opt[i++] = ouraddr >> 24; @@ -2513,10 +2745,880 @@ sppp_ipcp_scr(struct sppp *sp) /* + *--------------------------------------------------------------------------* + * * + * The CHAP implementation. * + * * + *--------------------------------------------------------------------------* + */ + +/* + * The authentication protocols don't employ a full-fledged state machine as + * the control protocols do, since they do have Open and Close events, but + * not Up and Down, nor are they explicitly terminated. Also, use of the + * authentication protocols may be different in both directions (this makes + * sense, think of a machine that never accepts incoming calls but only + * calls out, it doesn't require the called party to authenticate itself). + * + * Our state machine for the local authentication protocol (we are requesting + * the peer to authenticate) looks like: + * + * RCA- + * +--------------------------------------------+ + * V scn,tld| + * +--------+ Close +---------+ RCA+ + * | |<----------------------------------| |------+ + * +--->| Closed | TO* | Opened | sca | + * | | |-----+ +-------| |<-----+ + * | +--------+ irc | | +---------+ + * | ^ | | ^ + * | | | | | + * | | | | | + * | TO-| | | | + * | |tld TO+ V | | + * | | +------->+ | | + * | | | | | | + * | +--------+ V | | + * | | |<----+<--------------------+ | + * | | Req- | scr | + * | | Sent | | + * | | | | + * | +--------+ | + * | RCA- | | RCA+ | + * +------+ +------------------------------------------+ + * scn,tld sca,irc,ict,tlu + * + * + * with: + * + * Open: LCP reached authentication phase + * Close: LCP reached terminate phase + * + * RCA+: received reply (pap-req, chap-response), acceptable + * RCN: received reply (pap-req, chap-response), not acceptable + * TO+: timeout with restart counter >= 0 + * TO-: timeout with restart counter < 0 + * TO*: reschedule timeout for CHAP + * + * scr: send request packet (none for PAP, chap-challenge) + * sca: send ack packet (pap-ack, chap-success) + * scn: send nak packet (pap-nak, chap-failure) + * ict: initialize re-challenge timer (CHAP only) + * + * tlu: this-layer-up, LCP reaches network phase + * tld: this-layer-down, LCP enters terminate phase + * + * Note that in CHAP mode, after sending a new challenge, while the state + * automaton falls back into Req-Sent state, it doesn't signal a tld + * event to LCP, so LCP remains in network phase. Only after not getting + * any response (or after getting an unacceptable response), CHAP closes, + * causing LCP to enter terminate phase. + * + * With PAP, there is no initial request that can be sent. The peer is + * expected to send one based on the successful negotiation of PAP as + * the authentication protocol during the LCP option negotiation. + * + * Incoming authentication protocol requests (remote requests + * authentication, we are peer) don't employ a state machine at all, + * they are simply answered. Some peers [Ascend P50 firmware rev + * 4.50] react allergically when sending IPCP requests while they are + * still in authentication phase (thereby violating the standard that + * demands that these NCP packets are to be discarded), so we keep + * track of the peer demanding us to authenticate, and only proceed to + * phase network once we've seen a positive acknowledge for the + * authentication. + */ + +/* + * Handle incoming CHAP packets. + */ +void +sppp_chap_input(struct sppp *sp, struct mbuf *m) +{ + STDDCL; + struct lcp_header *h; + int len, x; + u_char *value, *name, digest[AUTHKEYLEN], dsize; + int value_len, name_len; + MD5_CTX ctx; + + len = m->m_pkthdr.len; + if (len < 4) { + if (debug) + log(LOG_DEBUG, + "%s%d: chap invalid packet length: %d bytes\n", + ifp->if_name, ifp->if_unit, len); + return; + } + h = mtod (m, struct lcp_header*); + if (len > ntohs (h->len)) + len = ntohs (h->len); + + switch (h->type) { + /* challenge, failure and success are his authproto */ + case CHAP_CHALLENGE: + value = 1 + (u_char*)(h+1); + value_len = value[-1]; + name = value + value_len; + name_len = len - value_len - 5; + if (name_len < 0) { + if (debug) { + log(LOG_DEBUG, + "%s%d: chap corrupted challenge " + "<%s id=0x%x len=%d", + ifp->if_name, ifp->if_unit, + sppp_auth_type_name(PPP_CHAP, h->type), + h->ident, ntohs(h->len)); + if (len > 4) + sppp_print_bytes((u_char*) (h+1), len-4); + addlog(">\n"); + } + break; + } + if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN) + || bcmp(name, sp->hisauth.name, name_len) != 0) { + log(LOG_INFO, "%s%d: chap challenge, his name "); + sppp_print_string(name, name_len); + addlog(" != expected "); + sppp_print_string(sp->hisauth.name, + sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)); + addlog("\n"); + } + + if (debug) { + log(LOG_DEBUG, + "%s%d: chap input <%s id=0x%x len=%d name=", + ifp->if_name, ifp->if_unit, + sppp_auth_type_name(PPP_CHAP, h->type), h->ident, + ntohs(h->len)); + sppp_print_string((char*) name, name_len); + addlog(" value-size=%d value=", value_len); + sppp_print_bytes(value, value_len); + addlog(">\n"); + } + + /* Compute reply value. */ + MD5Init(&ctx); + MD5Update(&ctx, &h->ident, 1); + MD5Update(&ctx, sp->myauth.secret, + sppp_strnlen(sp->myauth.secret, AUTHKEYLEN)); + MD5Update(&ctx, value, value_len); + MD5Final(digest, &ctx); + dsize = sizeof digest; + + sppp_auth_send(&chap, sp, CHAP_RESPONSE, h->ident, + sizeof dsize, (const char *)&dsize, + sizeof digest, digest, + sppp_strnlen(sp->myauth.name, AUTHNAMELEN), + sp->myauth.name, + 0); + break; + + case CHAP_SUCCESS: + if (debug) { + log(LOG_DEBUG, "%s%d: chap success", + ifp->if_name, ifp->if_unit); + if (len > 4) { + addlog(": "); + sppp_print_string((char*)(h + 1), len - 4); + } + addlog("\n"); + } + x = splimp(); + sp->pp_flags &= ~PP_NEEDAUTH; + if (sp->myauth.proto == PPP_CHAP && + (sp->lcp.protos & (1 << IDX_CHAP)) == 0) { + /* + * We are authenticator for CHAP but didn't + * complete yet. Leave it to tlu to proceed + * to network phase. + */ + splx(x); + break; + } + splx(x); + sppp_phase_network(sp); + break; + + case CHAP_FAILURE: + if (debug) { + log(LOG_INFO, "%s%d: chap failure", + ifp->if_name, ifp->if_unit); + if (len > 4) { + addlog(": "); + sppp_print_string((char*)(h + 1), len - 4); + } + addlog("\n"); + } else + log(LOG_INFO, "%s%d: chap failure\n", + ifp->if_name, ifp->if_unit); + /* await LCP shutdown by authenticator */ + break; + + /* response is my authproto */ + case CHAP_RESPONSE: + value = 1 + (u_char*)(h+1); + value_len = value[-1]; + name = value + value_len; + name_len = len - value_len - 5; + if (name_len < 0) { + if (debug) { + log(LOG_DEBUG, + "%s%d: chap corrupted response " + "<%s id=0x%x len=%d", + ifp->if_name, ifp->if_unit, + sppp_auth_type_name(PPP_CHAP, h->type), + h->ident, ntohs(h->len)); + if (len > 4) + sppp_print_bytes((u_char*)(h+1), len-4); + addlog(">\n"); + } + break; + } + if (h->ident != sp->confid[IDX_CHAP]) { + if (debug) + log(LOG_DEBUG, + "%s%d: chap dropping response for old ID " + "(got %d, expected %d)\n", + h->ident, sp->confid[IDX_CHAP]); + break; + } + if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN) + || bcmp(name, sp->hisauth.name, name_len) != 0) { + log(LOG_INFO, "%s%d: chap response, his name ", + ifp->if_name, ifp->if_unit); + sppp_print_string(name, name_len); + addlog(" != expected "); + sppp_print_string(sp->hisauth.name, + sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)); + addlog("\n"); + } + if (debug) { + log(LOG_DEBUG, "%s%d: chap input(%s) " + "<%s id=0x%x len=%d name=", + ifp->if_name, ifp->if_unit, + sppp_state_name(sp->state[IDX_CHAP]), + sppp_auth_type_name(PPP_CHAP, h->type), + h->ident, ntohs (h->len)); + sppp_print_string((char*)name, name_len); + addlog(" value-size=%d value=", value_len); + sppp_print_bytes(value, value_len); + addlog(">\n"); + } + if (value_len != AUTHKEYLEN) { + if (debug) + log(LOG_DEBUG, + "%s%d: chap bad hash value length: " + "%d bytes, should be %d\n", + ifp->if_name, ifp->if_unit, value_len, + AUTHKEYLEN); + break; + } + + MD5Init(&ctx); + MD5Update(&ctx, &h->ident, 1); + MD5Update(&ctx, sp->hisauth.secret, + sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN)); + MD5Update(&ctx, sp->myauth.challenge, AUTHKEYLEN); + MD5Final(digest, &ctx); + +#define FAILMSG "Failed..." +#define SUCCMSG "Welcome!" + + if (value_len != sizeof digest || + bcmp(digest, value, value_len) != 0) { + /* action scn, tld */ + sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident, + sizeof(FAILMSG) - 1, (u_char *)FAILMSG, + 0); + chap.tld(sp); + break; + } + /* action sca, perhaps tlu */ + if (sp->state[IDX_CHAP] == STATE_REQ_SENT || + sp->state[IDX_CHAP] == STATE_OPENED) + sppp_auth_send(&chap, sp, CHAP_SUCCESS, h->ident, + sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, + 0); + if (sp->state[IDX_CHAP] == STATE_REQ_SENT) { + sppp_cp_change_state(&chap, sp, STATE_OPENED); + chap.tlu(sp); + } + break; + + default: + /* Unknown CHAP packet type -- ignore. */ + if (debug) { + log(LOG_DEBUG, "%s%d: chap unknown input(%s) " + "<0x%x id=0x%xh len=%d", + ifp->if_name, ifp->if_unit, + sppp_state_name(sp->state[IDX_CHAP]), + h->type, h->ident, ntohs(h->len)); + if (len > 4) + sppp_print_bytes((u_char*)(h+1), len-4); + addlog(">\n"); + } + break; + + } +} + +static void +sppp_chap_init(struct sppp *sp) +{ + /* Chap doesn't have STATE_INITIAL at all. */ + sp->state[IDX_CHAP] = STATE_CLOSED; + sp->fail_counter[IDX_CHAP] = 0; + callout_handle_init(&sp->ch[IDX_CHAP]); +} + +static void +sppp_chap_open(struct sppp *sp) +{ + if (sp->myauth.proto == PPP_CHAP && + (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { + /* we are authenticator for CHAP, start it */ + chap.scr(sp); + sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; + sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); + } + /* nothing to be done if we are peer, await a challenge */ +} + +static void +sppp_chap_close(struct sppp *sp) +{ + if (sp->state[IDX_CHAP] != STATE_CLOSED) + sppp_cp_change_state(&chap, sp, STATE_CLOSED); +} + +static void +sppp_chap_TO(void *cookie) +{ + struct sppp *sp = (struct sppp *)cookie; + STDDCL; + int s; + + s = splimp(); + if (debug) + log(LOG_DEBUG, "%s%d: chap TO(%s) rst_counter = %d\n", + ifp->if_name, ifp->if_unit, + sppp_state_name(sp->state[IDX_CHAP]), + sp->rst_counter[IDX_CHAP]); + + if (--sp->rst_counter[IDX_CHAP] < 0) + /* TO- event */ + switch (sp->state[IDX_CHAP]) { + case STATE_REQ_SENT: + chap.tld(sp); + sppp_cp_change_state(&chap, sp, STATE_CLOSED); + break; + } + else + /* TO+ (or TO*) event */ + switch (sp->state[IDX_CHAP]) { + case STATE_OPENED: + /* TO* event */ + sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; + /* fall through */ + case STATE_REQ_SENT: + chap.scr(sp); + /* sppp_cp_change_state() will restart the timer */ + sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); + break; + } + + splx(s); +} + +static void +sppp_chap_tlu(struct sppp *sp) +{ + STDDCL; + int i, x; + + sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; + + /* + * Some broken CHAP implementations (Conware CoNet, firmware + * 4.0.?) don't want to re-authenticate their CHAP once the + * initial challenge-response exchange has taken place. + * Provide for an option to avoid rechallenges. + */ + if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) { + /* + * Compute the re-challenge timeout. This will yield + * a number between 300 and 810 seconds. + */ + i = 300 + ((unsigned)(random() & 0xff00) >> 7); + + sp->ch[IDX_CHAP] = timeout(chap.TO, (void *)sp, i * hz); + } + + if (debug) { + log(LOG_DEBUG, + "%s%d: chap %s, ", + ifp->if_name, ifp->if_unit, + sp->pp_phase == PHASE_NETWORK? "reconfirmed": "tlu"); + if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) + addlog("next re-challenge in %d seconds\n", i); + else + addlog("re-challenging supressed\n"); + } + + x = splimp(); + /* indicate to LCP that we need to be closed down */ + sp->lcp.protos |= (1 << IDX_CHAP); + + if (sp->pp_flags & PP_NEEDAUTH) { + /* + * Remote is authenticator, but his auth proto didn't + * complete yet. Defer the transition to network + * phase. + */ + splx(x); + return; + } + splx(x); + + /* + * If we are already in phase network, we are done here. This + * is the case if this is a dummy tlu event after a re-challenge. + */ + if (sp->pp_phase != PHASE_NETWORK) + sppp_phase_network(sp); +} + +static void +sppp_chap_tld(struct sppp *sp) +{ + STDDCL; + + if (debug) + log(LOG_DEBUG, "%s%d: chap tld\n", ifp->if_name, ifp->if_unit); + untimeout(chap.TO, (void *)sp, sp->ch[IDX_CHAP]); + sp->lcp.protos &= ~(1 << IDX_CHAP); + + lcp.Close(sp); +} + +static void +sppp_chap_scr(struct sppp *sp) +{ + struct timeval tv; + u_long *ch, seed; + u_char clen; + + /* Compute random challenge. */ + ch = (u_long *)sp->myauth.challenge; + microtime(&tv); + seed = tv.tv_sec ^ tv.tv_usec; + ch[0] = seed ^ random(); + ch[1] = seed ^ random(); + ch[2] = seed ^ random(); + ch[3] = seed ^ random(); + clen = AUTHKEYLEN; + + sp->confid[IDX_CHAP] = ++sp->pp_seq; + + sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP], + sizeof clen, (const char *)&clen, + AUTHKEYLEN, sp->myauth.challenge, + sppp_strnlen(sp->myauth.name, AUTHNAMELEN), + sp->myauth.name, + 0); +} +/* + *--------------------------------------------------------------------------* + * * + * The PAP implementation. * + * * + *--------------------------------------------------------------------------* + */ +/* + * For PAP, we need to keep a little state also if we are the peer, not the + * authenticator. This is since we don't get a request to authenticate, but + * have to repeatedly authenticate ourself until we got a response (or the + * retry counter is expired). + */ + +/* + * Handle incoming PAP packets. */ +static void +sppp_pap_input(struct sppp *sp, struct mbuf *m) +{ + STDDCL; + struct lcp_header *h; + int len, x; + u_char *name, *passwd, mlen; + int name_len, passwd_len; + + len = m->m_pkthdr.len; + if (len < 5) { + if (debug) + log(LOG_DEBUG, + "%s%d: pap invalid packet length: %d bytes\n", + ifp->if_name, ifp->if_unit, len); + return; + } + h = mtod (m, struct lcp_header*); + if (len > ntohs (h->len)) + len = ntohs (h->len); + switch (h->type) { + /* PAP request is my authproto */ + case PAP_REQ: + name = 1 + (u_char*)(h+1); + name_len = name[-1]; + passwd = name + name_len + 1; + if (name_len > len - 6 || + (passwd_len = passwd[-1]) > len - 6 - name_len) { + if (debug) { + log(LOG_DEBUG, "%s%d: pap corrupted input " + "<%s id=0x%x len=%d", + ifp->if_name, ifp->if_unit, + sppp_auth_type_name(PPP_PAP, h->type), + h->ident, ntohs(h->len)); + if (len > 4) + sppp_print_bytes((u_char*)(h+1), len-4); + addlog(">\n"); + } + break; + } + if (debug) { + log(LOG_DEBUG, "%s%d: pap input(%s) " + "<%s id=0x%x len=%d name=", + ifp->if_name, ifp->if_unit, + sppp_state_name(sp->state[IDX_PAP]), + sppp_auth_type_name(PPP_PAP, h->type), + h->ident, ntohs(h->len)); + sppp_print_string((char*)name, name_len); + addlog(" passwd="); + sppp_print_string((char*)passwd, passwd_len); + addlog(">\n"); + } + if (name_len > AUTHNAMELEN || + passwd_len > AUTHKEYLEN || + bcmp(name, sp->hisauth.name, name_len) != 0 || + bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) { + /* action scn, tld */ + mlen = sizeof(FAILMSG) - 1; + sppp_auth_send(&pap, sp, PAP_NAK, h->ident, + sizeof mlen, (const char *)&mlen, + sizeof(FAILMSG) - 1, (u_char *)FAILMSG, + 0); + pap.tld(sp); + break; + } + /* action sca, perhaps tlu */ + if (sp->state[IDX_PAP] == STATE_REQ_SENT || + sp->state[IDX_PAP] == STATE_OPENED) { + mlen = sizeof(SUCCMSG) - 1; + sppp_auth_send(&pap, sp, PAP_ACK, h->ident, + sizeof mlen, (const char *)&mlen, + sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, + 0); + } + if (sp->state[IDX_PAP] == STATE_REQ_SENT) { + sppp_cp_change_state(&pap, sp, STATE_OPENED); + pap.tlu(sp); + } + break; + + /* ack and nak are his authproto */ + case PAP_ACK: + untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); + if (debug) { + log(LOG_DEBUG, "%s%d: pap success", + ifp->if_name, ifp->if_unit); + name_len = *((char *)h); + if (len > 5 && name_len) { + addlog(": "); + sppp_print_string((char*)(h+1), name_len); + } + addlog("\n"); + } + x = splimp(); + sp->pp_flags &= ~PP_NEEDAUTH; + if (sp->myauth.proto == PPP_PAP && + (sp->lcp.protos & (1 << IDX_PAP)) == 0) { + /* + * We are authenticator for PAP but didn't + * complete yet. Leave it to tlu to proceed + * to network phase. + */ + splx(x); + break; + } + splx(x); + sppp_phase_network(sp); + break; + + case PAP_NAK: + untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); + if (debug) { + log(LOG_INFO, "%s%d: pap failure", + ifp->if_name, ifp->if_unit); + name_len = *((char *)h); + if (len > 5 && name_len) { + addlog(": "); + sppp_print_string((char*)(h+1), name_len); + } + addlog("\n"); + } else + log(LOG_INFO, "%s%d: pap failure\n", + ifp->if_name, ifp->if_unit); + /* await LCP shutdown by authenticator */ + break; + + default: + /* Unknown PAP packet type -- ignore. */ + if (debug) { + log(LOG_DEBUG, "%s%d: pap corrupted input " + "<0x%x id=0x%x len=%d", + ifp->if_name, ifp->if_unit, + h->type, h->ident, ntohs(h->len)); + if (len > 4) + sppp_print_bytes((u_char*)(h+1), len-4); + addlog(">\n"); + } + break; + + } +} + +static void +sppp_pap_init(struct sppp *sp) +{ + /* PAP doesn't have STATE_INITIAL at all. */ + sp->state[IDX_PAP] = STATE_CLOSED; + sp->fail_counter[IDX_PAP] = 0; + callout_handle_init(&sp->ch[IDX_PAP]); + callout_handle_init(&sp->pap_my_to_ch); +} + +static void +sppp_pap_open(struct sppp *sp) +{ + if (sp->hisauth.proto == PPP_PAP && + (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { + /* we are authenticator for PAP, start our timer */ + sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; + sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); + } + if (sp->myauth.proto == PPP_PAP) { + /* we are peer, send a request, and start a timer */ + pap.scr(sp); + sp->pap_my_to_ch = timeout(sppp_pap_my_TO, (void *)sp, + sp->lcp.timeout); + } +} + +static void +sppp_pap_close(struct sppp *sp) +{ + if (sp->state[IDX_PAP] != STATE_CLOSED) + sppp_cp_change_state(&pap, sp, STATE_CLOSED); +} + +/* + * That's the timeout routine if we are authenticator. Since the + * authenticator is basically passive in PAP, we can't do much here. + */ +static void +sppp_pap_TO(void *cookie) +{ + struct sppp *sp = (struct sppp *)cookie; + STDDCL; + int s; + + s = splimp(); + if (debug) + log(LOG_DEBUG, "%s%d: pap TO(%s) rst_counter = %d\n", + ifp->if_name, ifp->if_unit, + sppp_state_name(sp->state[IDX_PAP]), + sp->rst_counter[IDX_PAP]); + + if (--sp->rst_counter[IDX_PAP] < 0) + /* TO- event */ + switch (sp->state[IDX_PAP]) { + case STATE_REQ_SENT: + pap.tld(sp); + sppp_cp_change_state(&pap, sp, STATE_CLOSED); + break; + } + else + /* TO+ event, not very much we could do */ + switch (sp->state[IDX_PAP]) { + case STATE_REQ_SENT: + /* sppp_cp_change_state() will restart the timer */ + sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); + break; + } + + splx(s); +} + +/* + * That's the timeout handler if we are peer. Since the peer is active, + * we need to retransmit our PAP request since it is apparently lost. + * XXX We should impose a max counter. + */ +static void +sppp_pap_my_TO(void *cookie) +{ + struct sppp *sp = (struct sppp *)cookie; + STDDCL; + + if (debug) + log(LOG_DEBUG, "%s%d: pap peer TO\n", + ifp->if_name, ifp->if_unit); + + pap.scr(sp); +} + +static void +sppp_pap_tlu(struct sppp *sp) +{ + STDDCL; + int x; + + sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; + + if (debug) + log(LOG_DEBUG, "%s%d: %s tlu\n", + ifp->if_name, ifp->if_unit, pap.name); + + x = splimp(); + /* indicate to LCP that we need to be closed down */ + sp->lcp.protos |= (1 << IDX_PAP); + + if (sp->pp_flags & PP_NEEDAUTH) { + /* + * Remote is authenticator, but his auth proto didn't + * complete yet. Defer the transition to network + * phase. + */ + splx(x); + return; + } + splx(x); + sppp_phase_network(sp); +} + +static void +sppp_pap_tld(struct sppp *sp) +{ + STDDCL; + + if (debug) + log(LOG_DEBUG, "%s%d: pap tld\n", ifp->if_name, ifp->if_unit); + untimeout(pap.TO, (void *)sp, sp->ch[IDX_PAP]); + untimeout(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); + sp->lcp.protos &= ~(1 << IDX_PAP); + + lcp.Close(sp); +} + +static void +sppp_pap_scr(struct sppp *sp) +{ + STDDCL; + u_char idlen, pwdlen; + + sp->confid[IDX_PAP] = ++sp->pp_seq; + pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN); + idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN); + + sppp_auth_send(&pap, sp, PAP_REQ, sp->confid[IDX_PAP], + sizeof idlen, (const char *)&idlen, + (unsigned)idlen, sp->myauth.name, + sizeof pwdlen, (const char *)&pwdlen, + (unsigned)pwdlen, sp->myauth.secret, + 0); +} +/* * Random miscellaneous functions. */ /* + * Send a PAP or CHAP proto packet. + * + * Varadic function, each of the elements for the ellipsis is of type + * ``unsigned mlen, const u_char *msg''. Processing will stop iff + * mlen == 0. + */ + +static void +sppp_auth_send(const struct cp *cp, struct sppp *sp, u_char type, u_char id, + ...) +{ + STDDCL; + struct ppp_header *h; + struct lcp_header *lh; + struct mbuf *m; + u_char *p; + int len; + unsigned mlen; + const char *msg; + va_list ap; + + MGETHDR (m, M_DONTWAIT, MT_DATA); + if (! m) + return; + m->m_pkthdr.rcvif = 0; + + h = mtod (m, struct ppp_header*); + h->address = PPP_ALLSTATIONS; /* broadcast address */ + h->control = PPP_UI; /* Unnumbered Info */ + h->protocol = htons(cp->proto); + + lh = (struct lcp_header*)(h + 1); + lh->type = type; + lh->ident = id; + p = (u_char*) (lh+1); + + va_start(ap, id); + len = 0; + + while ((mlen = va_arg(ap, unsigned)) != 0) { + msg = va_arg(ap, const char *); + len += mlen; + if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) { + va_end(ap); + m_freem(m); + return; + } + + bcopy(msg, p, mlen); + p += mlen; + } + va_end(ap); + + m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; + lh->len = htons (LCP_HEADER_LEN + len); + + if (debug) { + log(LOG_DEBUG, "%s%d: %s output <%s id=0x%x len=%d", + ifp->if_name, ifp->if_unit, cp->name, + sppp_auth_type_name(cp->proto, lh->type), + lh->ident, ntohs(lh->len)); + if (len) + sppp_print_bytes((u_char*) (lh+1), len); + addlog(">\n"); + } + if (IF_QFULL (&sp->pp_cpq)) { + IF_DROP (&sp->pp_fastq); + IF_DROP (&ifp->if_snd); + m_freem (m); + ++ifp->if_oerrors; + } else + IF_ENQUEUE (&sp->pp_cpq, m); + if (! (ifp->if_flags & IFF_OACTIVE)) + (*ifp->if_start) (ifp); + ifp->if_obytes += m->m_pkthdr.len + 3; +} + +/* * Flush interface queue. */ static void @@ -2590,11 +3692,11 @@ sppp_keepalive(void *dummy) * Get both IP addresses. */ static void -sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst) +sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask) { struct ifnet *ifp = &sp->pp_if; struct ifaddr *ifa; - struct sockaddr_in *si; + struct sockaddr_in *si, *sm; u_long ssrc, ddst; ssrc = ddst = 0L; @@ -2603,16 +3705,20 @@ sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst) * aliases don't make any sense on a p2p link anyway. */ for (ifa = ifp->if_addrhead.tqh_first, si = 0; - ifa; + ifa; ifa = ifa->ifa_link.tqe_next) if (ifa->ifa_addr->sa_family == AF_INET) { si = (struct sockaddr_in *)ifa->ifa_addr; + sm = (struct sockaddr_in *)ifa->ifa_netmask; if (si) break; } if (ifa) { - if (si && si->sin_addr.s_addr) + if (si && si->sin_addr.s_addr) { ssrc = si->sin_addr.s_addr; + if (srcmask) + *srcmask = ntohl(sm->sin_addr.s_addr); + } si = (struct sockaddr_in *)ifa->ifa_dstaddr; if (si && si->sin_addr.s_addr) @@ -2639,7 +3745,7 @@ sppp_set_ip_addr(struct sppp *sp, u_long src) * aliases don't make any sense on a p2p link anyway. */ for (ifa = ifp->if_addrhead.tqh_first, si = 0; - ifa; + ifa; ifa = ifa->ifa_link.tqe_next) if (ifa->ifa_addr->sa_family == AF_INET) { si = (struct sockaddr_in *)ifa->ifa_addr; @@ -2650,55 +3756,209 @@ sppp_set_ip_addr(struct sppp *sp, u_long src) si->sin_addr.s_addr = htonl(src); } +static int +sppp_params(struct sppp *sp, int cmd, void *data) +{ + int subcmd; + struct ifreq *ifr = (struct ifreq *)data; + struct spppreq spr; + + /* + * ifr->ifr_data is supposed to point to a struct spppreq. + * Check the cmd word first before attempting to fetch all the + * data. + */ + if ((subcmd = fuword(ifr->ifr_data)) == -1) + return EFAULT; + + if (copyin((caddr_t)ifr->ifr_data, &spr, sizeof spr) != 0) + return EFAULT; + + switch (subcmd) { + case SPPPIOGDEFS: + if (cmd != SIOCGIFGENERIC) + return EINVAL; + /* + * We copy over the entire current state, but clean + * out some of the stuff we don't wanna pass up. + * Remember, SIOCGIFGENERIC is unprotected, and can be + * called by any user. No need to ever get PAP or + * CHAP secrets back to userland anyway. + */ + bcopy(sp, &spr.defs, sizeof(struct sppp)); + bzero(spr.defs.myauth.secret, AUTHKEYLEN); + bzero(spr.defs.myauth.challenge, AUTHKEYLEN); + bzero(spr.defs.hisauth.secret, AUTHKEYLEN); + bzero(spr.defs.hisauth.challenge, AUTHKEYLEN); + return copyout(&spr, (caddr_t)ifr->ifr_data, sizeof spr); + + case SPPPIOSDEFS: + if (cmd != SIOCSIFGENERIC) + return EINVAL; + /* + * We have a very specific idea of which fields we allow + * being passed back from userland, so to not clobber our + * current state. For one, we only allow setting + * anything if LCP is in dead phase. Once the LCP + * negotiations started, the authentication settings must + * not be changed again. (The administrator can force an + * ifconfig down in order to get LCP back into dead + * phase.) + * + * Also, we only allow for authentication parameters to be + * specified. + * + * XXX Should allow to set or clear pp_flags. + * + * Finally, if the respective authentication protocol to + * be used is set differently than 0, but the secret is + * passed as all zeros, we don't trash the existing secret. + * This allows an administrator to change the system name + * only without clobbering the secret (which he didn't get + * back in a previous SPPPIOGDEFS call). However, the + * secrets are cleared if the authentication protocol is + * reset to 0. + */ + if (sp->pp_phase != PHASE_DEAD) + return EBUSY; + + if ((spr.defs.myauth.proto != 0 && spr.defs.myauth.proto != PPP_PAP && + spr.defs.myauth.proto != PPP_CHAP) || + (spr.defs.hisauth.proto != 0 && spr.defs.hisauth.proto != PPP_PAP && + spr.defs.hisauth.proto != PPP_CHAP)) + return EINVAL; + + if (spr.defs.myauth.proto == 0) + /* resetting myauth */ + bzero(&sp->myauth, sizeof sp->myauth); + else { + /* setting/changing myauth */ + sp->myauth.proto = spr.defs.myauth.proto; + bcopy(spr.defs.myauth.name, sp->myauth.name, AUTHNAMELEN); + if (spr.defs.myauth.secret[0] != '\0') + bcopy(spr.defs.myauth.secret, sp->myauth.secret, + AUTHKEYLEN); + } + if (spr.defs.hisauth.proto == 0) + /* resetting hisauth */ + bzero(&sp->hisauth, sizeof sp->hisauth); + else { + /* setting/changing hisauth */ + sp->hisauth.proto = spr.defs.hisauth.proto; + sp->hisauth.flags = spr.defs.hisauth.flags; + bcopy(spr.defs.hisauth.name, sp->hisauth.name, AUTHNAMELEN); + if (spr.defs.hisauth.secret[0] != '\0') + bcopy(spr.defs.hisauth.secret, sp->hisauth.secret, + AUTHKEYLEN); + } + break; + + default: + return EINVAL; + } + + return 0; +} + +static void +sppp_phase_network(struct sppp *sp) +{ + struct ifnet *ifp = &sp->pp_if; + int i; + u_long mask; + + sp->pp_phase = PHASE_NETWORK; + + log(LOG_INFO, "%s%d: phase %s\n", ifp->if_name, ifp->if_unit, + sppp_phase_name(sp->pp_phase)); + + /* Notify NCPs now. */ + for (i = 0; i < IDX_COUNT; i++) + if ((cps[i])->flags & CP_NCP) + (cps[i])->Open(sp); + + /* Send Up events to all NCPs. */ + for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) + if (sp->lcp.protos & mask && ((cps[i])->flags & CP_NCP)) + (cps[i])->Up(sp); + + /* if no NCP is starting, all this was in vain, close down */ + sppp_lcp_check_and_close(sp); +} + + static const char * sppp_cp_type_name(u_char type) { - static char buf [12]; + static char buf[12]; switch (type) { - case CONF_REQ: return ("conf-req"); - case CONF_ACK: return ("conf-ack"); - case CONF_NAK: return ("conf-nak"); - case CONF_REJ: return ("conf-rej"); - case TERM_REQ: return ("term-req"); - case TERM_ACK: return ("term-ack"); - case CODE_REJ: return ("code-rej"); - case PROTO_REJ: return ("proto-rej"); - case ECHO_REQ: return ("echo-req"); - case ECHO_REPLY: return ("echo-reply"); - case DISC_REQ: return ("discard-req"); + case CONF_REQ: return "conf-req"; + case CONF_ACK: return "conf-ack"; + case CONF_NAK: return "conf-nak"; + case CONF_REJ: return "conf-rej"; + case TERM_REQ: return "term-req"; + case TERM_ACK: return "term-ack"; + case CODE_REJ: return "code-rej"; + case PROTO_REJ: return "proto-rej"; + case ECHO_REQ: return "echo-req"; + case ECHO_REPLY: return "echo-reply"; + case DISC_REQ: return "discard-req"; + } + sprintf (buf, "0x%x", type); + return buf; +} + +static const char * +sppp_auth_type_name(u_short proto, u_char type) +{ + static char buf[12]; + switch (proto) { + case PPP_CHAP: + switch (type) { + case CHAP_CHALLENGE: return "challenge"; + case CHAP_RESPONSE: return "response"; + case CHAP_SUCCESS: return "success"; + case CHAP_FAILURE: return "failure"; + } + case PPP_PAP: + switch (type) { + case PAP_REQ: return "req"; + case PAP_ACK: return "ack"; + case PAP_NAK: return "nak"; + } } sprintf (buf, "0x%x", type); - return (buf); + return buf; } static const char * sppp_lcp_opt_name(u_char opt) { - static char buf [12]; + static char buf[12]; switch (opt) { - case LCP_OPT_MRU: return ("mru"); - case LCP_OPT_ASYNC_MAP: return ("async-map"); - case LCP_OPT_AUTH_PROTO: return ("auth-proto"); - case LCP_OPT_QUAL_PROTO: return ("qual-proto"); - case LCP_OPT_MAGIC: return ("magic"); - case LCP_OPT_PROTO_COMP: return ("proto-comp"); - case LCP_OPT_ADDR_COMP: return ("addr-comp"); + case LCP_OPT_MRU: return "mru"; + case LCP_OPT_ASYNC_MAP: return "async-map"; + case LCP_OPT_AUTH_PROTO: return "auth-proto"; + case LCP_OPT_QUAL_PROTO: return "qual-proto"; + case LCP_OPT_MAGIC: return "magic"; + case LCP_OPT_PROTO_COMP: return "proto-comp"; + case LCP_OPT_ADDR_COMP: return "addr-comp"; } sprintf (buf, "0x%x", opt); - return (buf); + return buf; } static const char * sppp_ipcp_opt_name(u_char opt) { - static char buf [12]; + static char buf[12]; switch (opt) { - case IPCP_OPT_ADDRESSES: return ("addresses"); - case IPCP_OPT_COMPRESSION: return ("compression"); - case IPCP_OPT_ADDRESS: return ("address"); + case IPCP_OPT_ADDRESSES: return "addresses"; + case IPCP_OPT_COMPRESSION: return "compression"; + case IPCP_OPT_ADDRESS: return "address"; } sprintf (buf, "0x%x", opt); - return (buf); + return buf; } static const char * @@ -2739,23 +3999,70 @@ sppp_proto_name(u_short proto) switch (proto) { case PPP_LCP: return "lcp"; case PPP_IPCP: return "ipcp"; + case PPP_PAP: return "pap"; + case PPP_CHAP: return "chap"; } sprintf(buf, "0x%x", (unsigned)proto); return buf; } static void -sppp_print_bytes(u_char *p, u_short len) +sppp_print_bytes(const u_char *p, u_short len) { addlog(" %x", *p++); while (--len > 0) addlog("-%x", *p++); } +static void +sppp_print_string(const char *p, u_short len) +{ + u_char c; + + while (len-- > 0) { + c = *p++; + /* + * Print only ASCII chars directly. RFC 1994 recommends + * using only them, but we don't rely on it. */ + if (c < ' ' || c > '~') + addlog("\\x%x", c); + else + addlog("%c", c); + } +} + +static const char * +sppp_dotted_quad(u_long addr) +{ + static char s[16]; + sprintf(s, "%d.%d.%d.%d", + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + addr & 0xff); + return s; +} + +static int +sppp_strnlen(u_char *p, int max) +{ + int len; + + for (len = 0; len < max && *p; ++p) + ++len; + return len; +} + +/* a dummy, used to drop uninteresting events */ +static void +sppp_null(struct sppp *unused) +{ + /* do just nothing */ +} /* * This file is large. Tell emacs to highlight it nevertheless. * * Local Variables: - * hilit-auto-highlight-maxout: 100000 + * hilit-auto-highlight-maxout: 120000 * End: */ |