📄 if_spppsubr.c
字号:
/* * Synchronous PPP/Cisco link level subroutines. * Keepalive protocol implemented in both Cisco and PPP modes. * * Copyright (C) 1994 Cronyx Ltd. * Author: Serge Vakulenko, <vak@zebub.msk.su> * * 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. * * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */#undef DEBUG#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/mbuf.h>#include <net/if.h>#include <net/netisr.h>#include <net/if_types.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>#include <netinet/if_ether.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>#ifdef DEBUG#define print(s) printf s#else#define print(s) {/*void*/}#endif#define MAXALIVECNT 3 /* max. alive packets */#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_LCP 0xc021 /* Link Control Protocol */#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */#define LCP_CONF_REQ 1 /* PPP LCP configure request */#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */#define LCP_CONF_REJ 4 /* PPP LCP configure reject */#define LCP_TERM_REQ 5 /* PPP LCP terminate request */#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */#define LCP_CODE_REJ 7 /* PPP LCP code reject */#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */#define LCP_ECHO_REQ 9 /* PPP LCP echo request */#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */#define LCP_DISC_REQ 11 /* PPP LCP 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_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */#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 */struct 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 18struct sppp *spppq;/* * 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. */static u_short interactive_ports[8] = { 0, 513, 0, 0, 0, 21, 0, 23,};#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))/* * Timeout routine activation macros. */#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \ timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \ (p)->pp_flags |= PP_TIMO; }#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \ untimeout (sppp_cp_timeout, (void*) (p)); \ (p)->pp_flags &= ~PP_TIMO; }void sppp_keepalive (void *dummy);void sppp_cp_send (struct sppp *sp, u_short proto, u_char type, u_char ident, u_short len, void *data);void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);void sppp_lcp_input (struct sppp *sp, struct mbuf *m);void sppp_cisco_input (struct sppp *sp, struct mbuf *m);void sppp_ipcp_input (struct sppp *sp, struct mbuf *m);void sppp_lcp_open (struct sppp *sp);void sppp_ipcp_open (struct sppp *sp);int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, int len, u_long *magic);void sppp_cp_timeout (void *arg);char *sppp_lcp_type_name (u_char type);char *sppp_ipcp_type_name (u_char type);void sppp_print_bytes (u_char *p, u_short len);/* * Flush interface queue. */static void qflush (struct ifqueue *ifq){ struct mbuf *m, *n; n = ifq->ifq_head; while ((m = n)) { n = m->m_act; m_freem (m); } ifq->ifq_head = 0; ifq->ifq_tail = 0; ifq->ifq_len = 0;}/* * Process the received packet. */void sppp_input (struct ifnet *ifp, struct mbuf *m){ struct ppp_header *h; struct sppp *sp = (struct sppp*) ifp; struct ifqueue *inq = 0; int s; 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 (ifp->if_flags & IFF_DEBUG) printf ("%s%d: input packet is too small, %d bytes\n", ifp->if_name, ifp->if_unit, m->m_pkthdr.len);drop: ++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) { default: /* Invalid PPP packet. */invalid: if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid input packet <0x%x 0x%x 0x%x>\n", ifp->if_name, ifp->if_unit, h->address, h->control, ntohs (h->protocol)); goto drop; case PPP_ALLSTATIONS: if (h->control != PPP_UI) goto invalid; if (sp->pp_flags & PP_CISCO) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", ifp->if_name, ifp->if_unit, h->address, h->control, ntohs (h->protocol)); goto drop; } switch (ntohs (h->protocol)) { default: if (sp->lcp.state == LCP_STATE_OPENED) sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, ++sp->pp_seq, m->m_pkthdr.len + 2, &h->protocol); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n", ifp->if_name, ifp->if_unit, h->address, h->control, ntohs (h->protocol)); ++ifp->if_noproto; goto drop; case PPP_LCP: sppp_lcp_input ((struct sppp*) ifp, m); m_freem (m); return;#ifdef INET case PPP_IPCP: if (sp->lcp.state == LCP_STATE_OPENED) sppp_ipcp_input ((struct sppp*) ifp, m); m_freem (m); return; case PPP_IP: if (sp->ipcp.state == IPCP_STATE_OPENED) { schednetisr (NETISR_IP); inq = &ipintrq; } break;#endif#ifdef NS case PPP_XNS: /* XNS IDPCP not implemented yet */ if (sp->lcp.state == LCP_STATE_OPENED) { schednetisr (NETISR_NS); inq = &nsintrq; } break;#endif#ifdef ISO case PPP_ISO: /* OSI NLCP not implemented yet */ if (sp->lcp.state == LCP_STATE_OPENED) { schednetisr (NETISR_ISO); inq = &clnlintrq; } break;#endif } break; case CISCO_MULTICAST: case CISCO_UNICAST: /* Don't check the control field here (RFC 1547). */ if (! (sp->pp_flags & PP_CISCO)) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", ifp->if_name, ifp->if_unit, h->address, h->control, ntohs (h->protocol)); goto drop; } switch (ntohs (h->protocol)) { default: ++ifp->if_noproto; goto invalid; case CISCO_KEEPALIVE: sppp_cisco_input ((struct sppp*) ifp, m); m_freem (m); return;#ifdef INET case ETHERTYPE_IP: schednetisr (NETISR_IP); inq = &ipintrq; break;#endif#ifdef NS case ETHERTYPE_NS: schednetisr (NETISR_NS); inq = &nsintrq; break;#endif } break; } if (! (ifp->if_flags & IFF_UP) || ! inq) goto drop; /* Check queue. */ s = splimp (); if (IF_QFULL (inq)) { /* Queue overflow. */ IF_DROP (inq); splx (s); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: protocol queue overflow\n", ifp->if_name, ifp->if_unit); goto drop; } IF_ENQUEUE (inq, m); splx (s);}/* * Enqueue transmit packet. */int sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt){ struct sppp *sp = (struct sppp*) ifp; struct ppp_header *h; struct ifqueue *ifq; int s = splimp (); if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) { m_freem (m); splx (s); return (ENETDOWN); } ifq = &ifp->if_snd;#ifdef INET /* * Put low delay, telnet, rlogin and ftp control packets * in front of the queue. */ { struct ip *ip = mtod (m, struct ip*); struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); if (! IF_QFULL (&sp->pp_fastq) && ((ip->ip_tos & IPTOS_LOWDELAY) || ip->ip_p == IPPROTO_TCP && m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) && (INTERACTIVE (ntohs (tcp->th_sport)) || INTERACTIVE (ntohs (tcp->th_dport))))) ifq = &sp->pp_fastq; }#endif /* * Prepend general data packet PPP header. For now, IP only. */ M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); if (! m) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: no memory for transmit header\n", ifp->if_name, ifp->if_unit); splx (s); return (ENOBUFS); } h = mtod (m, struct ppp_header*); if (sp->pp_flags & PP_CISCO) { h->address = CISCO_MULTICAST; /* broadcast address */ h->control = 0; } else { h->address = PPP_ALLSTATIONS; /* broadcast address */ h->control = PPP_UI; /* Unnumbered Info */ } switch (dst->sa_family) {#ifdef INET case AF_INET: /* Internet Protocol */ if (sp->pp_flags & PP_CISCO) h->protocol = htons (ETHERTYPE_IP); else if (sp->ipcp.state == IPCP_STATE_OPENED) h->protocol = htons (PPP_IP); else { m_freem (m); splx (s); return (ENETDOWN); } break;#endif#ifdef NS case AF_NS: /* Xerox NS Protocol */ h->protocol = htons ((sp->pp_flags & PP_CISCO) ? ETHERTYPE_NS : PPP_XNS); break;#endif#ifdef ISO case AF_ISO: /* ISO OSI Protocol */ if (sp->pp_flags & PP_CISCO) goto nosupport; h->protocol = htons (PPP_ISO); break;#endifnosupport: default: m_freem (m); splx (s); return (EAFNOSUPPORT); } /* * Queue message on interface, and start output if interface * not yet active. */ if (IF_QFULL (ifq)) { IF_DROP (&ifp->if_snd); m_freem (m); splx (s); return (ENOBUFS); } IF_ENQUEUE (ifq, m); if (! (ifp->if_flags & IFF_OACTIVE)) (*ifp->if_start) (ifp); /* * Count output packets and bytes. * The packet length includes header, FCS and 1 flag, * according to RFC 1333. */ ifp->if_obytes += m->m_pkthdr.len + 3; splx (s); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -