⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_ppp.c

📁 unix and linux net driver
💻 C
📖 第 1 页 / 共 3 页
字号:
		    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 + -