📄 if_spppsubr.c
字号:
#endif#ifdef NS case PPP_XNS: /* XNS IDPCP not implemented yet */ if (sp->pp_phase == PHASE_NETWORK) { schednetisr (NETISR_NS); inq = &nsintrq; } break;#endif#ifdef ISO case PPP_ISO: /* OSI NLCP not implemented yet */ if (sp->pp_phase == PHASE_NETWORK) { 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 (debug) log(LOG_DEBUG, SPP_FMT "Cisco packet in PPP 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: ++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 IPX case ETHERTYPE_IPX: schednetisr (NETISR_IPX); inq = &ipxintrq; break;#endif#ifdef NS case ETHERTYPE_NS: schednetisr (NETISR_NS); inq = &nsintrq; break;#endif } break; default: /* Invalid PPP packet. */ invalid: if (debug) log(LOG_DEBUG, SPP_FMT "invalid input packet " "<addr=0x%x ctrl=0x%x proto=0x%x>\n", SPP_ARGS(ifp), h->address, h->control, ntohs(h->protocol)); goto drop; } 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 (debug) log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n", SPP_ARGS(ifp)); goto drop; } IF_ENQUEUE(inq, m); splx(s);}/* * Enqueue transmit packet. */static intsppp_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, rv = 0; int debug = ifp->if_flags & IFF_DEBUG; s = splimp(); if ((ifp->if_flags & IFF_UP) == 0 || (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) { m_freem (m); splx (s); return (ENETDOWN); } if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) { /* * Interface is not yet running, but auto-dial. Need * to start LCP for it. */ ifp->if_flags |= IFF_RUNNING; splx(s); lcp.Open(sp); s = splimp(); } ifq = &ifp->if_snd;#ifdef INET if (dst->sa_family == AF_INET) { /* XXX Check mbuf length here? */ struct ip *ip = mtod (m, struct ip*); struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); /* * When using dynamic local IP address assignment by using * 0.0.0.0 as a local address, the first TCP session will * not connect because the local TCP checksum is computed * using 0.0.0.0 which will later become our real IP address * so the TCP checksum computed at the remote end will * become invalid. So we * - don't let packets with src ip addr 0 thru * - we flag TCP packets with src ip 0 as an error */ if(ip->ip_src.s_addr == INADDR_ANY) /* -hm */ { m_freem(m); splx(s); if(ip->ip_p == IPPROTO_TCP) return(EADDRNOTAVAIL); else return(0); } /* * Put low delay, telnet, rlogin and ftp control packets * in front of the queue. */ if (IF_QFULL (&sp->pp_fastq)) ; else if (ip->ip_tos & IPTOS_LOWDELAY) ifq = &sp->pp_fastq; else if (m->m_len < sizeof *ip + sizeof *tcp) ; else if (ip->ip_p != IPPROTO_TCP) ; else if (INTERACTIVE (ntohs (tcp->th_sport))) ifq = &sp->pp_fastq; else if (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 (debug) log(LOG_DEBUG, SPP_FMT "no memory for transmit header\n", SPP_ARGS(ifp)); ++ifp->if_oerrors; splx (s); return (ENOBUFS); } /* * May want to check size of packet * (albeit due to the implementation it's always enough) */ h = mtod (m, struct ppp_header*); if (sp->pp_flags & PP_CISCO) { h->address = CISCO_UNICAST; /* unicast 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 { /* * Don't choke with an ENETDOWN early. It's * possible that we just started dialing out, * so don't drop the packet immediately. If * we notice that we run out of buffer space * below, we will however remember that we are * not ready to carry IP packets, and return * ENETDOWN, as opposed to ENOBUFS. */ h->protocol = htons(PPP_IP); if (sp->state[IDX_IPCP] != STATE_OPENED) rv = 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 IPX case AF_IPX: /* Novell IPX Protocol */ h->protocol = htons ((sp->pp_flags & PP_CISCO) ? ETHERTYPE_IPX : PPP_IPX); break;#endif#ifdef ISO case AF_ISO: /* ISO OSI Protocol */ if (sp->pp_flags & PP_CISCO) goto nosupport; h->protocol = htons (PPP_ISO); break;nosupport:#endif default: m_freem (m); ++ifp->if_oerrors; 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); ++ifp->if_oerrors; splx (s); return (rv? rv: 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);}voidsppp_attach(struct ifnet *ifp){ struct sppp *sp = (struct sppp*) ifp; /* Initialize keepalive handler. */ if (! spppq) TIMEOUT(sppp_keepalive, 0, hz * 10, keepalive_ch); /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; spppq = sp; sp->pp_if.if_mtu = PP_MTU; sp->pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; sp->pp_if.if_type = IFT_PPP; sp->pp_if.if_output = sppp_output;#if 0 sp->pp_flags = PP_KEEPALIVE;#endif sp->pp_fastq.ifq_maxlen = 32; sp->pp_cpq.ifq_maxlen = 20; sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; sp->pp_seq = 0; sp->pp_rseq = 0; sp->pp_phase = PHASE_DEAD; sp->pp_up = lcp.Up; sp->pp_down = lcp.Down; sppp_lcp_init(sp); sppp_ipcp_init(sp); sppp_pap_init(sp); sppp_chap_init(sp);}voidsppp_detach(struct ifnet *ifp){ struct sppp **q, *p, *sp = (struct sppp*) ifp; int i; /* Remove the entry from the keepalive list. */ for (q = &spppq; (p = *q); q = &p->pp_next) if (p == sp) { *q = p->pp_next; break; } /* Stop keepalive handler. */ if (! spppq) 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);}/* * Flush the interface output queue. */voidsppp_flush(struct ifnet *ifp){ struct sppp *sp = (struct sppp*) ifp; sppp_qflush (&sp->pp_if.if_snd); sppp_qflush (&sp->pp_fastq); sppp_qflush (&sp->pp_cpq);}/* * Check if the output queue is empty. */intsppp_isempty(struct ifnet *ifp){ struct sppp *sp = (struct sppp*) ifp; int empty, s; s = splimp(); empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head && !sp->pp_if.if_snd.ifq_head; splx(s); return (empty);}/* * Get next packet to send. */struct mbuf *sppp_dequeue(struct ifnet *ifp){ struct sppp *sp = (struct sppp*) ifp; struct mbuf *m; int s; s = splimp(); /* * 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 && (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); } splx(s); return m;}/* * 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. */intsppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data){ struct ifreq *ifr = (struct ifreq*) data; struct sppp *sp = (struct sppp*) ifp; int s, rv, going_up, going_down, newmode; s = splimp(); rv = 0; switch (cmd) { case SIOCAIFADDR: case SIOCSIFDSTADDR: break; case SIOCSIFADDR: if_up(ifp); /* fall through... */ case SIOCSIFFLAGS: going_up = ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0; going_down = (ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING; newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE); if (newmode == (IFF_AUTO | IFF_PASSIVE)) { /* sanity */ newmode = IFF_PASSIVE; ifp->if_flags &= ~IFF_AUTO; } if (going_up || going_down) lcp.Close(sp); if (going_up && newmode == 0) { /* neither auto-dial nor passive */ ifp->if_flags |= IFF_RUNNING; if (!(sp->pp_flags & PP_CISCO)) lcp.Open(sp); } else if (going_down) { sppp_flush(ifp); ifp->if_flags &= ~IFF_RUNNING; } break;#ifdef SIOCSIFMTU#ifndef ifr_mtu#define ifr_mtu ifr_metric#endif case SIOCSIFMTU: if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru) return (EINVAL); ifp->if_mtu = ifr->ifr_mtu; break;#endif#ifdef SLIOCSETMTU case SLIOCSETMTU: if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru) return (EINVAL); ifp->if_mtu = *(short*)data; break;#endif#ifdef SIOCGIFMTU case SIOCGIFMTU: ifr->ifr_mtu = ifp->if_mtu; break;#endif#ifdef SLIOCGETMTU case SLIOCGETMTU: *(short*)data = ifp->if_mtu; break;#endif case SIOCADDMULTI: case SIOCDELMULTI: break; case SIOCGIFGENERIC: case SIOCSIFGENERIC: rv = sppp_params(sp, cmd, data); break; default: rv = ENOTTY; } splx(s); return rv;}/* * Cisco framing implementation. *//* * Handle incoming Cisco keepalive protocol packets. */static voidsppp_cisco_input(struct sppp *sp, struct mbuf *m){ STDDCL; struct cisco_packet *h; u_long me, mymask; if (m->m_pkthdr.len < CISCO_PACKET_LEN) { if (debug) log(LOG_DEBUG, SPP_FMT "cisco invalid packet length: %d bytes\n", SPP_ARGS(ifp), m->m_pkthdr.len); return; } h = mtod (m, struct cisco_packet*); if (debug) log(LOG_DEBUG, SPP_FMT "cisco input: %d bytes " "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", SPP_ARGS(ifp), m->m_pkthdr.len, (u_long)ntohl (h->type), (u_long)h->par1, (u_long)h->par2, (u_int)h->rel, (u_int)h->time0, (u_int)h->time1); switch (ntohl (h->type)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -