📄 if_sl.c
字号:
} sc = &sl_softc[ifp->if_unit]; if (sc->sc_ttyp == NULL) { m_freem(m); return (ENETDOWN); /* sort of */ } if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { m_freem(m); return (EHOSTUNREACH); } ifq = &ifp->if_snd; if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { register int p = -1; if (m->m_len > sizeof(struct ip)) p = ((int *)ip)[ip->ip_hl]; if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) { ifq = &sc->sc_fastq; p = 1; } else p = 0; if (sc->sc_if.if_flags & IFF_D1) { /* * The last parameter turns off connection id * compression for background traffic: Since * fastq traffic can jump ahead of the background * traffic, we don't know what order packets will * go on the line. */ p = sl_compress_tcp(m, ip, &sc->sc_comp, p); *mtod(m, u_char *) |= p; } } else if ((sc->sc_if.if_flags & IFF_D3) && ip->ip_p == IPPROTO_ICMP) { m_freem(m); return (0); } s = splimp(); if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); sc->sc_if.if_oerrors++; return (ENOBUFS); } IF_ENQUEUE(ifq, m); if (sc->sc_ttyp->t_outq.c_cc == 0) { splx(s); slstart(sc->sc_ttyp); } else splx(s); return (0);}/* * Start output on interface. Get another datagram * to send from the interface queue and map it to * the interface before starting output. */slstart(tp) register struct tty *tp;{ register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; register struct mbuf *m; register u_char *cp; int s; struct mbuf *m2;#if !defined(ultrix) || defined(ULTRIX_3) extern int cfreecount;#endif for (;;) { /* * If there is more in the output queue, just send it now. * We are being called in lieu of ttstart and must do what * it would. */#ifdef vax s=splimp();#else#ifdef mips s=spltty(); /* Mips requires higher IPL than Vax */#endif mips#endif vax if (tp->t_outq.c_cc != 0) { (*tp->t_oproc)(tp); if (tp->t_outq.c_cc > SLIP_HIWAT) { splx(s); return; } } /* * This happens briefly when the line shuts down. */ if (sc == NULL) { splx(s); return; } /* * Get a packet and send it to the interface. */ IF_DEQUEUE(&sc->sc_fastq, m); if (m == NULL) IF_DEQUEUE(&sc->sc_if.if_snd, m);#if defined(SL_NIT) && defined(NIT) if (m && sl_donit && nitcb.ncb_next != &nitcb) { /* do nit processing if there's anyone listening */ static struct ether_header oheader = { { 1 }, { 2 } }; struct nit_ii nii; int len = 0; m2 = m; do { len += m2->m_len; } while (m2 = m2->m_next); oheader.ether_type = *mtod(m, u_char *); nii.nii_header = (caddr_t)&oheader; nii.nii_hdrlen = sizeof(oheader); nii.nii_type = oheader.ether_type; nii.nii_datalen = len; nii.nii_promisc = 0; nit_tap(&sc->sc_if, m, &nii); }#endif splx(s); if (m == NULL) return; /* * If system is getting low on clists, just flush our * output queue (if the stuff was important, it'll get * retransmitted). */#if !defined(ultrix) || defined(ULTIX_3) if (cfreecount < CLISTRESERVE + SLMTU) { m_freem(m); sc->sc_if.if_collisions++; continue; }#endif /* * The extra FRAME_END will start up a new packet, and thus * will flush any accumulated garbage. We do this whenever * the line may have been idle for some time. */ if (tp->t_outq.c_cc == 0) { ++sc->sc_bytessent; (void) putc(FRAME_END, &tp->t_outq); } while (m) { register u_char *ep; cp = mtod(m, u_char *); ep = cp + m->m_len; while (cp < ep) { /* * Find out how many bytes in the string we can * handle without doing something special. */ register u_char *bp = cp; while (cp < ep) { switch (*cp++) { case FRAME_ESCAPE: case FRAME_END: --cp; goto out; } } out: if (cp > bp) { /* * Put n characters at once * into the tty output queue. */ if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) break; sc->sc_bytessent += cp - bp; } /* * If there are characters left in the mbuf, * the first one must be special.. * Put it out in a different form. */ if (cp < ep) { if (putc(FRAME_ESCAPE, &tp->t_outq)) break; if (putc(*cp++ == FRAME_ESCAPE ? TRANS_FRAME_ESCAPE : TRANS_FRAME_END, &tp->t_outq)) { (void) unputc(&tp->t_outq); break; } sc->sc_bytessent += 2; } } MFREE(m, m2); m = m2; } if (putc(FRAME_END, &tp->t_outq)) { /* * Not enough room. Remove a char to make room * and end the packet normally. * If you get many collisions (more than one or two * a day) you probably do not have enough clists * and you should increase "nclist" in param.c. */ (void) unputc(&tp->t_outq); (void) putc(FRAME_END, &tp->t_outq); sc->sc_if.if_collisions++; } else { ++sc->sc_bytessent; sc->sc_if.if_opackets++; } }}/* * Copy data buffer to mbuf chain; add ifnet pointer. */static struct mbuf *sl_btom(sc, len) register struct sl_softc *sc; register int len;{ register u_char *cp; register struct mbuf *m; MGET(m, M_DONTWAIT, MT_DATA); if (m == NULL) return (NULL); /* * If we have more than MLEN bytes, it's cheaper to * queue the cluster we just filled & allocate a new one * for the input buffer. Otherwise, fill the mbuf we * allocated above. Note that code in the input routine * guarantees that packet + ifp will fit in a cluster and * initial setup left room for interface pointer. */ cp = sc->sc_buf;#if BSD==43 if (len >= MLEN - sizeof(struct ifnet *)) { MCLGET(m); if (m->m_len != MCLBYTES) { /* we couldn't get a cluster - if memory's this * low, it's time to start dropping packets. */ m_freem(m); return (NULL); } sc->sc_ep = mtod(m, u_char *) + (BUFOFFSET + SLMAX); m->m_off = (int)cp - (int)m - sizeof(struct ifnet *); } else { bcopy((caddr_t)cp, mtod(m, caddr_t) + sizeof(struct ifnet *), len); } m->m_len = len + sizeof(struct ifnet *); *mtod(m, struct ifnet **) = &sc->sc_if;#else#ifdef ultrix if (len >= MLEN) { struct mbuf *p; MCLGET(m,p); if (m->m_len != MCLBYTES) { /* we couldn't get a cluster - if memory's this * low, it's time to start dropping packets. */ m_freem(m); return (NULL); } m->m_clptr = (caddr_t)(sc->sc_ep - (SLMAX + BUFOFFSET)); sc->sc_ep = mtod(m, u_char *) + (BUFOFFSET + SLMAX); m->m_off = (int)cp; } else { bcopy((caddr_t)cp, mtod(m, caddr_t), len); } m->m_len = len;#ifdef ULTRIX_3 m->ifnetptr= (char *) &sc->sc_if;#else m->m_ifp = &sc->sc_if;#endif ULTRIX_3#else if (len >= MLEN) { MCLGET(m); if (m->m_len != MCLBYTES) { /* we couldn't get a cluster - if memory's this * low, it's time to start dropping packets. */ m_freem(m); return (NULL); } sc->sc_ep = mtod(m, u_char *) + (BUFOFFSET + SLMAX); m->m_off = (int)cp - (int)m; } else { bcopy((caddr_t)cp, mtod(m, caddr_t), len); } m->m_len = len;#endif#endif return (m);}/* * tty interface receiver interrupt. */slinput(c, tp) register int c; register struct tty *tp;{ register struct sl_softc *sc; register struct mbuf *m; register int len; int s;#if defined(ultrix) && defined(ULTRIX_4) struct ifqueue *inq;#endif tk_nin++; sc = (struct sl_softc *)tp->t_sc; if (sc == NULL) return; ++sc->sc_bytesrcvd; c &= 0xff; switch (c) { case TRANS_FRAME_ESCAPE: if (sc->sc_escape) c = FRAME_ESCAPE; break; case TRANS_FRAME_END: if (sc->sc_escape) c = FRAME_END; break; case FRAME_ESCAPE: sc->sc_escape = 1; return; case FRAME_END: len = sc->sc_mp - sc->sc_buf; if (len < 3) /* less than min length packet - ignore */ goto newpack;#if defined(SL_NIT) && defined(NIT) if (sl_donit && nitcb.ncb_next != &nitcb) { /* do nit processing if there's anyone listening */ static struct ether_header iheader = { { 2 }, { 1 } }; static struct mbuf mb; struct nit_ii nii; m = &mb; m->m_len = len; m->m_off = (int)sc->sc_buf - (int)m; iheader.ether_type = *sc->sc_buf; nii.nii_header = (caddr_t)&iheader; nii.nii_hdrlen = sizeof(iheader); nii.nii_type = iheader.ether_type; nii.nii_datalen = len; nii.nii_promisc = 0; nit_tap(&sc->sc_if, m, &nii); }#endif if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { if (c & 0x80) c = TYPE_COMPRESSED_TCP; else if (c == TYPE_UNCOMPRESSED_TCP) *sc->sc_buf &= 0x4f; /* * we've got something that's not an IP packet. * If compression is enabled, try to uncompress it. * Otherwise, if `auto-enable' compression is on and * it's a reasonable packet, uncompress it then * enable compression. Otherwise, drop it. */ if (sc->sc_if.if_flags & IFF_D1) { len = sl_uncompress_tcp(&sc->sc_buf, len, (u_int)c, &sc->sc_comp); if (len <= 0) goto error; } else if ((sc->sc_if.if_flags & IFF_D2) && c == TYPE_UNCOMPRESSED_TCP && len >= 40) { len = sl_uncompress_tcp(&sc->sc_buf, len, (u_int)c, &sc->sc_comp); if (len <= 0) goto error; sc->sc_if.if_flags |= IFF_D1; } else goto error; } m = sl_btom(sc, len); if (m == NULL) goto error; sc->sc_if.if_ipackets++; s = splimp();#if defined(ultrix) && defined(ULTRIX_4) inq = &ipintrq; smp_lock(&inq->lk_ifqueue, LK_RETRY);#endif if (IF_QFULL(&ipintrq)) { IF_DROP(&ipintrq); sc->sc_if.if_ierrors++; m_freem(m); } else { IF_ENQUEUE(&ipintrq, m); schednetisr(NETISR_IP); }#if defined(ultrix) && defined(ULTRIX_4) smp_unlock(&inq->lk_ifqueue);#endif splx(s); goto newpack; } if (sc->sc_mp < sc->sc_ep) { *sc->sc_mp++ = c; sc->sc_escape = 0; return; }error: sc->sc_if.if_ierrors++;newpack: sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; sc->sc_escape = 0;}/* * Process an ioctl request. */slioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ int s = splimp(), error = 0;#ifndef sun register struct ifaddr *ifa = (struct ifaddr *)data; switch (cmd) { case SIOCSIFADDR: if (ifa->ifa_addr.sa_family == AF_INET) ifp->if_flags |= IFF_UP; else error = EAFNOSUPPORT; break; case SIOCSIFDSTADDR: if (ifa->ifa_addr.sa_family != AF_INET) error = EAFNOSUPPORT; break; default: error = EINVAL; }#else switch (cmd) { case SIOCSIFADDR: if_rtdelete(ifp); ifp->if_addr = *(struct sockaddr *)data; ifp->if_net = in_netof(((struct sockaddr_in *)data)->sin_addr); ifp->if_flags |= IFF_UP|IFF_RUNNING; ifp->if_flags &=~ IFF_BROADCAST; /* set up routing table entry */ error = rtinit(&ifp->if_dstaddr, &ifp->if_addr, RTF_HOST|RTF_UP); ifp->if_flags |= IFF_ROUTE; break; case SIOCSIFDSTADDR: /* all the real work is done for us in ../net/if.c */ break; default: error = EINVAL; }#endif splx(s); return (error);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -