📄 if_spppsubr.c
字号:
/* * Synchronous PPP/Cisco link level subroutines. * Keepalive protocol implemented in both Cisco and PPP modes. * * Copyright (C) 1994-1996 Cronyx Engineering Ltd. * Author: Serge Vakulenko, <vak@cronyx.ru> * * Heavily revamped to conform to RFC 1661. * Copyright (C) 1997, Joerg Wunsch. * * This software is distributed with NO WARRANTIES, not even the implied * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Authors grant any other persons or organisations permission to use * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997 * * $Id: if_spppsubr.c,v 1.52 1998/12/27 21:30:44 phk Exp $ */#include <sys/param.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include "opt_inet.h"#include "opt_ipx.h"#endif#ifdef NetBSD1_3# if NetBSD1_3 > 6# include "opt_inet.h"# include "opt_iso.h"# endif#endif#include <sys/systm.h>#include <sys/kernel.h>#include <sys/sockio.h>#include <sys/socket.h>#include <sys/syslog.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <machine/random.h>#endif#include <sys/malloc.h>#include <sys/mbuf.h>#if defined (__OpenBSD__)#include <sys/md5k.h>#else#include <sys/md5.h>#endif#include <net/if.h>#include <net/netisr.h>#include <net/if_types.h>#include <net/route.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <machine/random.h>#endif#if defined (__NetBSD__) || defined (__OpenBSD__)#include <machine/cpu.h> /* XXX for softnet */#endif#include <machine/stdarg.h>#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/tcp.h># if defined (__FreeBSD__) || defined (__OpenBSD__)# include <netinet/if_ether.h># else# include <net/ethertypes.h># endif#else# error Huh? sppp without INET?#endif#ifdef IPX#include <netipx/ipx.h>#include <netipx/ipx_if.h>#endif#ifdef NS#include <netns/ns.h>#include <netns/ns_if.h>#endif#ifdef ISO#include <netiso/argo_debug.h>#include <netiso/iso.h>#include <netiso/iso_var.h>#include <netiso/iso_snpac.h>#endif#include <net/if_sppp.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg, handle)# define TIMEOUT(fun, arg1, arg2, handle) handle = timeout(fun, arg1, arg2)# define IOCTL_CMD_T u_long#else# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg)# define TIMEOUT(fun, arg1, arg2, handle) timeout(fun, arg1, arg2)# define IOCTL_CMD_T int#endif#define MAXALIVECNT 3 /* max. alive packets *//* * Interface flags that can be set in an ifconfig command. * * Setting link0 will make the link passive, i.e. it will be marked * as being administrative openable, but won't be opened to begin * with. Incoming calls will be answered, or subsequent calls with * -link1 will cause the administrative open of the LCP layer. * * 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_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 */#define CONF_NAK 3 /* PPP configure negative ack */#define CONF_REJ 4 /* PPP configure reject */#define TERM_REQ 5 /* PPP terminate request */#define TERM_ACK 6 /* PPP terminate acknowledge */#define CODE_REJ 7 /* PPP code reject */#define PROTO_REJ 8 /* PPP protocol reject */#define ECHO_REQ 9 /* PPP echo request */#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 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 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#define STATE_STARTING 1#define STATE_CLOSED 2#define STATE_STOPPED 3#define STATE_CLOSING 4#define STATE_STOPPING 5#define STATE_REQ_SENT 6#define STATE_ACK_RCVD 7#define STATE_ACK_SENT 8#define STATE_OPENED 9struct ppp_header { u_char address; u_char control; u_short protocol;};#define PPP_HEADER_LEN sizeof (struct ppp_header)struct lcp_header { u_char type; u_char ident; u_short len;};#define LCP_HEADER_LEN sizeof (struct lcp_header)struct cisco_packet { u_long type; u_long par1; u_long par2; u_short rel; u_short time0; u_short time1;};#define CISCO_PACKET_LEN 18/* * We follow the spelling and capitalization of RFC 1661 here, to make * it easier comparing with the standard. Please refer to this RFC in * case you can't make sense out of these abbreviation; it will also * explain the semantics related to the various events and actions. */struct cp { u_short proto; /* PPP control protocol number */ u_char protoidx; /* index into state table in struct sppp */ u_char flags;#define CP_LCP 0x01 /* this is the LCP */#define CP_AUTH 0x02 /* this is an authentication protocol */#define CP_NCP 0x04 /* this is a NCP */#define CP_QUAL 0x08 /* this is a quality reporting protocol */ const char *name; /* name of this control protocol */ /* event handlers */ void (*Up)(struct sppp *sp); void (*Down)(struct sppp *sp); void (*Open)(struct sppp *sp); void (*Close)(struct sppp *sp); void (*TO)(void *sp); int (*RCR)(struct sppp *sp, struct lcp_header *h, int len); void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len); void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len); /* actions */ void (*tlu)(struct sppp *sp); void (*tld)(struct sppp *sp); void (*tls)(struct sppp *sp); void (*tlf)(struct sppp *sp); void (*scr)(struct sppp *sp);};static struct sppp *spppq;#if defined(__FreeBSD__) && __FreeBSD__ >= 3static struct callout_handle keepalive_ch;#endif#if defined(__FreeBSD__) && __FreeBSD__ >= 3#define SPP_FMT "%s%d: "#define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit#else#define SPP_FMT "%s: "#define SPP_ARGS(ifp) (ifp)->if_xname#endif/* * 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, 0, 21, 0, 23,};#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))/* almost every function needs these */#define STDDCL \ struct ifnet *ifp = &sp->pp_if; \ int debug = ifp->if_flags & IFF_DEBUGstatic 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);static void sppp_cisco_input(struct sppp *sp, struct mbuf *m);static void sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m);static void sppp_cp_send(struct sppp *sp, u_short proto, u_char type, u_char ident, u_short len, void *data);/* 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, unsigned int type, unsigned int 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);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);static void sppp_lcp_open(struct sppp *sp);static void sppp_lcp_close(struct sppp *sp);static void sppp_lcp_TO(void *sp);static int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len);static void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);static void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);static void sppp_lcp_tlu(struct sppp *sp);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_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);static void sppp_ipcp_down(struct sppp *sp);static void sppp_ipcp_open(struct sppp *sp);static void sppp_ipcp_close(struct sppp *sp);static void sppp_ipcp_TO(void *sp);static int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len);static void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);static void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);static void sppp_ipcp_tlu(struct sppp *sp);static void sppp_ipcp_tld(struct sppp *sp);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_dotted_quad(u_long addr);static const char *sppp_ipcp_opt_name(u_char opt);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, u_long 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 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_set_ip_addr(struct sppp *sp, u_long src);/* our control protocol descriptors */static const struct cp lcp = { PPP_LCP, IDX_LCP, CP_LCP, "lcp", sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close, sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak, sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf, sppp_lcp_scr};static const struct cp ipcp = { PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp", sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close, sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak, sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf, sppp_ipcp_scr};static 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};static 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};static const struct cp *cps[IDX_COUNT] = { &lcp, /* IDX_LCP */ &ipcp, /* IDX_IPCP */ &pap, /* IDX_PAP */ &chap, /* IDX_CHAP */};/* * Exported functions, comprising our interface to the lower layer. *//* * Process the received packet. */voidsppp_input(struct ifnet *ifp, struct mbuf *m){ struct ppp_header *h; struct ifqueue *inq = 0; int s; struct sppp *sp = (struct sppp *)ifp; int debug = ifp->if_flags & IFF_DEBUG; if (ifp->if_flags & IFF_UP) /* Count received bytes, add FCS and one flag */ ifp->if_ibytes += m->m_pkthdr.len + 3; if (m->m_pkthdr.len <= PPP_HEADER_LEN) { /* Too small packet, drop it. */ if (debug) log(LOG_DEBUG, SPP_FMT "input packet is too small, %d bytes\n", SPP_ARGS(ifp), m->m_pkthdr.len); drop: ++ifp->if_ierrors; ++ifp->if_iqdrops; m_freem (m); return; } /* Get PPP header. */ h = mtod (m, struct ppp_header*); m_adj (m, PPP_HEADER_LEN); switch (h->address) { case PPP_ALLSTATIONS: if (h->control != PPP_UI) goto invalid; if (sp->pp_flags & PP_CISCO) { if (debug) log(LOG_DEBUG, SPP_FMT "PPP packet in Cisco mode " "<addr=0x%x ctrl=0x%x proto=0x%x>\n", SPP_ARGS(ifp), h->address, h->control, ntohs(h->protocol)); goto drop; } switch (ntohs (h->protocol)) { default: if (sp->state[IDX_LCP] == STATE_OPENED) sppp_cp_send (sp, PPP_LCP, PROTO_REJ, ++sp->pp_seq, m->m_pkthdr.len + 2, &h->protocol); if (debug) log(LOG_DEBUG, SPP_FMT "invalid input protocol " "<addr=0x%x ctrl=0x%x proto=0x%x>\n", SPP_ARGS(ifp), h->address, h->control, ntohs(h->protocol)); ++ifp->if_noproto; goto drop; case PPP_LCP: 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, sp, m); m_freem (m); return; case PPP_IP: if (sp->state[IDX_IPCP] == STATE_OPENED) { schednetisr (NETISR_IP); inq = &ipintrq; } break;#endif#ifdef IPX case PPP_IPX: /* IPX IPXCP not implemented yet */ if (sp->pp_phase == PHASE_NETWORK) { schednetisr (NETISR_IPX); inq = &ipxintrq; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -