📄 if_ppp.c
字号:
snit_intr(ifp, mb, &nif); }#endif/* * For Digital UNIX, there's space set aside in the header mbuf * for the interface info. * * For Sun it's smuggled around via a pointer at the front of the mbuf. */#ifdef __osf__ mb->m_pkthdr.rcvif = ifp; mb->m_pkthdr.len = len;#else mb->m_off -= sizeof(struct ifnet *); mb->m_len += sizeof(struct ifnet *); *mtod(mb, struct ifnet **) = ifp;#endif inq = 0; switch (proto) { case PPP_IP: inq = &ipintrq; schednetisr(NETISR_IP); } if (inq != 0) { s = splhigh(); if (IF_QFULL(inq)) { IF_DROP(inq); ++ifp->if_ierrors; if (sp->flags & DBGLOG) printf("if_ppp: inq full, proto=%x\n", proto); m_freem(mb); } else { IF_ENQUEUE(inq, mb); } splx(s); } else { if (sp->flags & DBGLOG) printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto); ++ifp->if_ierrors; m_freem(mb); } break; default: putnext(q, mp); } return 0;}/* * Network code wants to output a packet. * Turn it into a STREAMS message and send it down. */static intif_ppp_output(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst;{ mblk_t *mp; int proto, s; if_ppp_t *sp; u_char *p; if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m0); return ENETDOWN; } if ((unsigned)ifp->if_unit >= ppp_nalloc) {#ifdef DEBUG printf("if_ppp_output: unit %d?\n", ifp->if_unit);#endif m_freem(m0); return EINVAL; } sp = states[ifp->if_unit]; if (sp == 0) {#ifdef DEBUG printf("if_ppp_output: no queue?\n");#endif m_freem(m0); return ENETDOWN; } if (sp->flags & DBGLOG) { p = mtod(m0, u_char *); printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n", ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], sp->q); } switch (dst->sa_family) { case AF_INET: proto = PPP_IP;#ifdef SNIT_SUPPORT if (ifp->if_flags & IFF_PROMISC) { struct nit_if nif; struct mbuf *m; int len; for (len = 0, m = m0; m != NULL; m = m->m_next) len += m->m_len; nif.nif_header = (caddr_t) &snit_ehdr; nif.nif_hdrlen = sizeof(snit_ehdr); nif.nif_bodylen = len; nif.nif_promisc = 0; snit_intr(ifp, m0, &nif); }#endif break; default: m_freem(m0); return EAFNOSUPPORT; } ++ifp->if_opackets; mp = make_message(m0, PPP_HDRLEN); m_freem(m0); if (mp == 0) { ++ifp->if_oerrors; return ENOBUFS; } mp->b_rptr -= PPP_HDRLEN; mp->b_rptr[0] = PPP_ALLSTATIONS; mp->b_rptr[1] = PPP_UI; mp->b_rptr[2] = proto >> 8; mp->b_rptr[3] = proto; s = splstr(); if (sp->flags & DBGLOG) printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n", sp->q, mp, mp->b_rptr, mp->b_wptr, proto); putnext(sp->q, mp); splx(s); return 0;}/* * Socket ioctl routine for ppp interfaces. */static intif_ppp_ioctl(ifp, cmd, data) struct ifnet *ifp; u_int cmd; caddr_t data;{ int s, error; struct ifreq *ifr = (struct ifreq *) data; struct ifaddr *ifa = (struct ifaddr *) data; u_short mtu; error = 0; s = splimp(); switch (cmd) { case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_RUNNING) == 0) ifp->if_flags &= ~IFF_UP; break; case SIOCSIFADDR: if (IFA_ADDR(ifa).sa_family != AF_INET) error = EAFNOSUPPORT; break; case SIOCSIFDSTADDR: if (IFA_ADDR(ifa).sa_family != AF_INET) error = EAFNOSUPPORT; break; case SIOCSIFMTU: if ((error = NOTSUSER()) != 0) break;#ifdef __osf__ /* this hack is necessary because ifioctl checks ifr_data * in 4.0 and 5.0, but ifr_data and ifr_metric overlay each * other in the definition of struct ifreq so pppd can't set both. */ bcopy(ifr->ifr_data, &mtu, sizeof (u_short)); ifr->ifr_mtu = mtu;#endif if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) { error = EINVAL; break; } ifp->if_mtu = ifr->ifr_mtu; break; case SIOCGIFMTU: ifr->ifr_mtu = ifp->if_mtu; break; case SIOCADDMULTI: case SIOCDELMULTI: switch(ifr->ifr_addr.sa_family) { case AF_INET: break; default: error = EAFNOSUPPORT; break; } break; default: error = EINVAL; } splx(s); return (error);}/* * Turn a STREAMS message into an mbuf chain. */static struct mbuf *make_mbufs(mp, off) mblk_t *mp; int off;{ struct mbuf *head, **prevp, *m; int len, space, n; unsigned char *cp, *dp; len = msgdsize(mp); if (len == 0) return 0; prevp = &head; space = 0; cp = mp->b_rptr;#ifdef __osf__ MGETHDR(m, M_DONTWAIT, MT_DATA); m->m_len = 0; space = MHLEN; *prevp = m; prevp = &m->m_next; dp = mtod(m, unsigned char *); len -= space; off = 0;#endif for (;;) { while (cp >= mp->b_wptr) { mp = mp->b_cont; if (mp == 0) { *prevp = 0; return head; } cp = mp->b_rptr; } n = mp->b_wptr - cp; if (space == 0) { MGET(m, M_DONTWAIT, MT_DATA); *prevp = m; if (m == 0) { if (head != 0) m_freem(head); return 0; } if (len + off > 2 * MLEN) {#ifdef __osf__ MCLGET(m, M_DONTWAIT);#else MCLGET(m);#endif }#ifdef __osf__ space = ((m->m_flags & M_EXT) ? MCLBYTES : MLEN);#else space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off; m->m_off += off;#endif m->m_len = 0; len -= space; dp = mtod(m, unsigned char *); off = 0; prevp = &m->m_next; } if (n > space) n = space; bcopy(cp, dp, n); cp += n; dp += n; space -= n; m->m_len += n; }}/* * Turn an mbuf chain into a STREAMS message. */#define ALLOCB_MAX 4096static mblk_t *make_message(m, off) struct mbuf *m; int off;{ mblk_t *head, **prevp, *mp; int len, space, n, nb; unsigned char *cp, *dp; struct mbuf *nm; len = 0; for (nm = m; nm != 0; nm = nm->m_next) len += nm->m_len; prevp = &head; space = 0; cp = mtod(m, unsigned char *); nb = m->m_len; for (;;) { while (nb <= 0) { m = m->m_next; if (m == 0) { *prevp = 0; return head; } cp = mtod(m, unsigned char *); nb = m->m_len; } if (space == 0) { space = len + off; if (space > ALLOCB_MAX) space = ALLOCB_MAX; mp = allocb(space, BPRI_LO); *prevp = mp; if (mp == 0) { if (head != 0) freemsg(head); return 0; } dp = mp->b_rptr += off; space -= off; len -= space; off = 0; prevp = &mp->b_cont; } n = nb < space? nb: space; bcopy(cp, dp, n); cp += n; dp += n; nb -= n; space -= n; mp->b_wptr = dp; }}/* * Digital UNIX doesn't allow for removing ifnet structures * from the list. But then we're not using this as a loadable * module anyway, so that's OK. * * Under SunOS, this should allow the module to be unloaded. * Unfortunately, it doesn't seem to detach all the references, * so your system may well crash after you unload this module :-( */#ifndef __osf__/* * Remove an interface from the system. * This routine contains magic. */#include <net/route.h>#include <netinet/in_pcb.h>#include <netinet/ip_var.h>#include <netinet/tcp.h>#include <netinet/tcp_timer.h>#include <netinet/tcp_var.h>#include <netinet/udp.h>#include <netinet/udp_var.h>static voidppp_if_detach(ifp) struct ifnet *ifp;{ int s; struct inpcb *pcb; struct ifaddr *ifa; struct in_ifaddr **inap; struct ifnet **ifpp; s = splhigh(); /* * Clear the interface from any routes currently cached in * TCP or UDP protocol control blocks. */ for (pcb = tcb.inp_next; pcb != &tcb; pcb = pcb->inp_next) if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp) in_losing(pcb); for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next) if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp) in_losing(pcb); /* * Delete routes through all addresses of the interface. */ for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->ifa_next) { rtinit(ifa, ifa, SIOCDELRT, RTF_HOST); rtinit(ifa, ifa, SIOCDELRT, 0); } /* * Unlink the interface's address(es) from the in_ifaddr list. */ for (inap = &in_ifaddr; *inap != 0; ) { if ((*inap)->ia_ifa.ifa_ifp == ifp) *inap = (*inap)->ia_next; else inap = &(*inap)->ia_next; } /* * Delete the interface from the ifnet list. */ for (ifpp = &ifnet; (*ifpp) != 0; ) { if (*ifpp == ifp) break; ifpp = &(*ifpp)->if_next; } if (*ifpp == 0) printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit); else *ifpp = ifp->if_next; splx(s);}#endif /* __osf__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -