📄 if_ppp.c
字号:
if (sc->sc_xc_state != NULL) (*sc->sc_xcomp->comp_free)(sc->sc_xc_state); sc->sc_xcomp = *cp; /* entry points for compressor */ sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb); if (sc->sc_xc_state == NULL) { IOLogDbg("ppp%d: comp_alloc failed", if_unit(sc->sc_if)); error = ENOBUFS; } splimp(); sc->sc_flags &= ~SC_COMP_RUN; } else { if (sc->sc_rc_state != NULL) (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); sc->sc_rcomp = *cp; /* entry points for compressor */ sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb); if (sc->sc_rc_state == NULL) { IOLogDbg("ppp%d: decomp_alloc failed", if_unit(sc->sc_if)); error = ENOBUFS; } splimp(); sc->sc_flags &= ~SC_DECOMP_RUN; } splx(s); return (error); } IOLogDbg("ppp%d: no compressor for [%x %x %x], %x", if_unit(sc->sc_if), ccp_option[0], ccp_option[1], ccp_option[2], nb); return (EINVAL); /* no handler found */#endif /* PPP_COMPRESS */#ifdef HAS_BROKEN_TIOCSPGRP case TIOCSPGRP: tp->t_pgrp = *(int *)data; break;#endif case PPPIOCGNPMODE: case PPPIOCSNPMODE: npi = (struct npioctl *) data; switch (npi->protocol) { case PPP_IP: npx = NP_IP; break; default: return EINVAL; } if (cmd == PPPIOCGNPMODE) { npi->mode = sc->sc_npmode[npx]; } else { if (! suser()) return EPERM; if (npi->mode != sc->sc_npmode[npx]) { s = splimp(); sc->sc_npmode[npx] = npi->mode; if (npi->mode != NPMODE_QUEUE) { ppp_requeue(sc); (*sc->sc_start)(sc); } splx(s); } } break; case PPPIOCGIDLE: s = splimp();#if NS_TARGET >= 40 ns_time_to_timeval(clock_value(System), &tv_time); t = tv_time.tv_sec;#else t = time.tv_sec;#endif /* NS_TARGET */ ((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent; ((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv; splx(s); break; default: return (-1); } return (0);}intpppcontrol(ifp, cmd, data) netif_t ifp; const char *cmd; void *data;{ if (!strcmp(cmd, IFCONTROL_UNIXIOCTL)) { if_ioctl_t* ctl = (if_ioctl_t*)data; return pppsioctl(ifp, ctl->ioctl_command, ctl->ioctl_data); } else if (!strcmp(cmd, IFCONTROL_SETADDR)) { struct sockaddr_in *sin = (struct sockaddr_in *)data; if (sin->sin_family != AF_INET) return EAFNOSUPPORT; if_flags_set(ifp, if_flags(ifp) | IFF_UP); return 0; } /* * We implement this to allow iftab * to contain -AUTOMATIC- entries * without generating errors at boot time. * We do not, however, mark it as UP. */ else if (!strcmp(cmd, IFCONTROL_AUTOADDR)) { struct sockaddr_in *sin = (struct sockaddr_in *) data; if (sin->sin_family != AF_INET) return EAFNOSUPPORT; return 0; } else if (!strcmp(cmd, IFCONTROL_SETFLAGS)) { register union ifr_ifru *ifr = (union ifr_ifru *)data; if (!suser()) return EPERM; if_flags_set(ifp, ifr->ifru_flags); return 0; } /* * Under 3.2 developer, I don't know the symbol for this * new 3.3 command. So it is a constant for now. I don't * believe I need to do anything to support this at the moment. */ else if (strcmp(cmd, "add-multicast") == 0) { struct sockaddr_in *sin = (struct sockaddr_in *) data; if (sin->sin_family != AF_INET) return EAFNOSUPPORT; } else { IOLog("ppp%d: Invalid ppp control %s\n", if_unit(ifp), cmd); return EINVAL; }}/* * Process an ioctl request to the ppp network interface. */intpppsioctl(ifp, cmd, data) register netif_t ifp; int cmd; caddr_t data;{ register struct ppp_softc *sc = &ppp_softc[if_unit(ifp)]; register struct ifaddr *ifa = (struct ifaddr *)data; register struct ifreq *ifr = (struct ifreq *)data; struct ppp_stats *psp;#ifdef PPP_COMPRESS struct ppp_comp_stats *pcp;#endif int s = splimp(), error = 0; switch (cmd) { case SIOCSIFFLAGS: IOLog("ppp%d: pppioctl: SIOCSIFFLAGS called!\n", if_unit(ifp)); break; case SIOCSIFADDR: if (ifa->ifa_addr.sa_family != AF_INET) error = EAFNOSUPPORT; break; case SIOCSIFDSTADDR: if (ifa->ifa_addr.sa_family != AF_INET) error = EAFNOSUPPORT; break; case SIOCSIFMTU: if (!suser()) { error = EPERM; break; } if_mtu_set(sc->sc_if, ifr->ifr_mtu); nbq_flush(&sc->sc_freeq); /* get rid of old buffers */ pppsched(pppfillfreeq, sc); /* and make a queue of new ones */ pppgetm(sc); break; case SIOCGIFMTU: ifr->ifr_mtu = if_mtu(sc->sc_if); break; case SIOCGPPPSTATS: psp = &((struct ifpppstatsreq *) data)->stats; bzero(psp, sizeof(*psp)); psp->p.ppp_ibytes = sc->sc_bytesrcvd; psp->p.ppp_ipackets = if_ipackets(sc->sc_if); psp->p.ppp_ierrors = if_ierrors(sc->sc_if); psp->p.ppp_obytes = sc->sc_bytessent; psp->p.ppp_opackets = if_opackets(sc->sc_if); psp->p.ppp_oerrors = if_oerrors(sc->sc_if);#ifdef VJC psp->vj.vjs_packets = sc->sc_comp.stats.vjs_packets; psp->vj.vjs_compressed = sc->sc_comp.stats.vjs_compressed; psp->vj.vjs_searches = sc->sc_comp.stats.vjs_searches; psp->vj.vjs_misses = sc->sc_comp.stats.vjs_misses; psp->vj.vjs_uncompressedin = sc->sc_comp.stats.vjs_uncompressedin; psp->vj.vjs_compressedin = sc->sc_comp.stats.vjs_compressedin; psp->vj.vjs_errorin = sc->sc_comp.stats.vjs_errorin; psp->vj.vjs_tossed = sc->sc_comp.stats.vjs_tossed;#endif /* VJC */ break;#ifdef PPP_COMPRESS case SIOCGPPPCSTATS: pcp = &((struct ifpppcstatsreq *) data)->stats; bzero(pcp, sizeof(*pcp)); if (sc->sc_xc_state != NULL) (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c); if (sc->sc_rc_state != NULL) (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d); break;#endif /* PPP_COMPRESS */ default: error = EINVAL; } splx(s); return (error);}/* * Queue a packet. Start transmission if not active. * Packet is placed in Information field of PPP frame. * * This procedure MUST take an actual netbuf_t as input * since it may be called by procedures outside of us. * The buffer received must be in the same format as that * returned by pppgetbuf(). */intpppoutput(ifp, in_nb, arg) netif_t ifp; netbuf_t in_nb; void *arg;{ register struct ppp_softc *sc = &ppp_softc[if_unit(ifp)]; struct sockaddr *dst = (struct sockaddr *) arg; int protocol, address, control; u_char *cp; int s, error; mark_t flags = 0; struct ip *ip; struct nb_queue *ifq; enum NPmode mode; NETBUF_T m0; m0 = nb_TO_NB(in_nb); if (sc->sc_devp == NULL || (if_flags(ifp) & IFF_RUNNING) == 0 || (if_flags(ifp) & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) { error = ENETDOWN; /* sort of */ goto bad; } /* * Compute PPP header. */ flags &= ~M_HIGHPRI; switch (dst->sa_family) {#ifdef INET case AF_INET: address = PPP_ALLSTATIONS; control = PPP_UI; protocol = PPP_IP; mode = sc->sc_npmode[NP_IP]; /* * If this packet has the "low delay" bit set in the IP header, * or TCP and to an interactive port, put it on the fastq instead */ ip = mtod(m0, struct ip *); if (ip->ip_tos & IPTOS_LOWDELAY || ip->ip_p == IPPROTO_ICMP) goto urgent; else if (ip->ip_p == IPPROTO_TCP) { register u_short *p = (u_short *) &(((caddr_t) ip)[ip->ip_hl << 2]); if (INTERACTIVE(ntohs(p[0])) || INTERACTIVE(ntohs(p[1])))urgent: flags |= M_HIGHPRI; } break;#endif#ifdef NS case AF_NS: address = PPP_ALLSTATIONS; control = PPP_UI; protocol = PPP_XNS; mode = NPMODE_PASS; break;#endif case AF_UNSPEC: address = PPP_ADDRESS(dst->sa_data); control = PPP_CONTROL(dst->sa_data); protocol = PPP_PROTOCOL(dst->sa_data); mode = NPMODE_PASS; break; default: IOLog("ppp%d: af%d not supported\n", if_unit(ifp), dst->sa_family); error = EAFNOSUPPORT; goto bad; } /* * Drop this packet, or return an error, if necessary. */ if (mode == NPMODE_ERROR) { error = ENETDOWN; goto bad; } if (mode == NPMODE_DROP) { error = 0; goto bad; } /* * Add PPP header. */ NB_GROW_TOP(m0, PPP_HDRLEN); cp = mtod(m0, u_char *); *cp++ = address; *cp++ = control; *cp++ = protocol >> 8; *cp++ = protocol & 0xff; if (sc->sc_flags & SC_LOG_OUTPKT) { IOLog("ppp%d: output:\n", if_unit(ifp)); /* XXX */ pppdumpm(m0); } /* * Put the packet on the appropriate queue. */ s = splimp(); /* splnet should be OK now */ if (mode == NPMODE_QUEUE) { NB_SET_MARK(m0,flags); /* save priority */ /* XXX we should limit the number of packets on this queue */ nbq_enqueue(&sc->sc_npq, m0); /* XXX is this correct? */ } else { ifq = (flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_slowq; if (nbq_full(ifq) < 0) { nbq_drop(ifq); IOLog("ppp%d: output queue full\n", if_unit(sc->sc_if)); splx(s); incr_cnt(sc->sc_if, if_oerrors); error = ENOBUFS; goto bad; } nbq_enqueue(ifq, m0); } /* * If we don't have some compressed packets already * and we are not at interrupt priority, then do some compression. * * We need to be especially careful here. pppouput() is typically * called at 2 different priority levels. On a NeXT, neither of these * is the interrupt priority level. However, on Intel, one of them is. * I don't know about HPPA or Sparc. Simple fix is to just check. */ if(!sc->sc_compsched && s != ipltospl(IPLIMP)) { sc->sc_compsched = 1; splx(s); pppintr_comp(sc); /* Calls pppstart() */ } else { (*sc->sc_start)(sc); splx(s); } return (0);bad: NB_FREE(m0); return (error);}/* * After a change in the NPmode for some NP, move packets from the * npqueue to the send queue or the fast queue as appropriate. * Should be called at splimp (actually splnet would probably suffice). * Due to some of the uglies in the packet queueing system I have * implemented this without the mpp stuff. * PCF */static voidppp_requeue(sc) struct ppp_softc *sc;{ NETBUF_T m, lm, nm; struct nb_queue *ifq; enum NPmode mode; mark_t flags; lm = nm = NULL; for (m = sc->sc_npq.head; m; ) { NB_GET_NEXT(m,&nm); switch (PPP_PROTOCOL(mtod(m, u_char *))) { case PPP_IP: mode = sc->sc_npmode[NP_IP]; break; default: mode = NPMODE_PASS; } switch (mode) { case NPMODE_PASS: /* * This packet can now go on one of the queues to be sent. */ if(lm) NB_SET_NEXT(lm,nm); else sc->sc_npq.head = nm; NB_SET_NEXT(m,NULL); NB_GET_MARK(m,&flags); ifq = (flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_slowq; if (nbq_full(ifq)) { nbq_drop(ifq); incr_cnt(sc->sc_if, if_oerrors); NB_FREE(m); } else nbq_enqueue(ifq, m); sc->sc_npq.len--; break; case NPMODE_DROP: case NPMODE_ERROR: sc->sc_npq.len--; NB_FREE(m); break; case NPMODE_QUEUE: lm = m; break; } m = nm; } sc->sc_npq.tail = lm; /* anything further on has been sent ! */}/* * Get a packet to send. This procedure is intended to be called * at spltty()/splimp(), so it takes little time. If there isn't * a packet waiting to go out, it schedules a software interrupt * to prepare a new packet; the device start routine gets called * again when a packet is ready. */NETBUF_Tppp_dequeue(sc) struct ppp_softc *sc;{ NETBUF_T m; int error; m = nbq_dequeue(&sc->sc_compq); if (!sc->sc_compsched && (! nbq_empty(&sc->sc_slowq) || ! nbq_empty(&sc->sc_fastq))) { if ((error = pppsched(pppintr_comp, sc)) == KERN_SUCCESS) sc->sc_compsched = 1; else { IOLogDbg("ppp%d: compression callout failed returning %d\n", if_unit(sc->sc_if), error); } } return m;}/* * Takes all received input packets and uncompresses/hands_off. * Must not be reentrant and is called at normal priority. * Guaranteed Non-Reentrancy means we don't need to be at splnet(). * */voidpppintr_decomp(arg) void *arg;{ struct ppp_softc *sc = (struct ppp_softc *)arg; int s; NETBUF_T m; if (nbq_low(&sc->sc_freeq)) pppfillfreeq((void *) sc); decomp: for (;;) { m = nbq_dequeue(&sc->sc_rawq); if (m == NULL) break; ppp_inproc(sc, m); } /* * Now we have aparently emptied the queue. So, we try to reset the * synchronization flag that schedules callbacks. We check for the * possibility that an interrupt occurred before we finish this check. */ s = splimp(); if (!nbq_empty(&sc->sc_rawq)) { splx(s); goto decomp; } else { sc->sc_decompsched = 0; splx(s); }}/* * Readies the next few output packet from * the sc_fastq/sc_slowq. Will try to * precompress all packets on the fast * queue and at most one from the slow queue. */voidpppintr_comp(arg) void *arg;{ struct ppp_softc *sc = (struct ppp_softc *)arg; int s; NETBUF_T m; if (nbq_low(&sc->sc_freeq)) pppfillfreeq((void *) sc); while (!nbq_full(&sc->sc_compq) && !nbq_empty(&sc->sc_fastq)) ppp_outpkt(sc); if (!nbq_full(&sc->sc_compq) && !nbq_empty(&sc->sc_slowq)) ppp_outpkt(sc); sc->sc_compsched = 0;}/* * Grab another packet off a queue and apply VJ compression, * packet compression, address/control and/or protocol compression * if enabled. Should be called at splnet. */static voidppp_outpkt(sc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -