📄 if_tap.c
字号:
error = EINVAL; break; } splx(s); return (error);} /* tapifioctl *//*** tapifstart ** ** Queue packets from higher level ready to put out.*/static voidtapifstart(ifp) struct ifnet *ifp;{ struct tap_softc *tp = tapcntl[ifp->if_unit]; struct mbuf *m0; int s; TAPDEBUG(__FUNCTION__": %s%d starting...\n", ifp->if_name, ifp->if_unit); if ((tp->tap_flags & TAP_READY) != TAP_READY) { TAPDEBUG(__FUNCTION__": %s%d not ready. tap_flags = 0x%x\n", ifp->if_name, ifp->if_unit, tp->tap_flags); return; } s = splimp(); ifp->if_flags |= IFF_OACTIVE; for (;;) { IF_DEQUEUE(&ifp->if_snd, m0); if (!m0) { break; }#if NBPFILTER > 0 if (ifp->if_bpf) { bpf_mtap(ifp, m0); }#endif /* NBPFILTER */ if (IF_QFULL(&tp->if_rcv)) { IF_DROP(&tp->if_rcv); /* XXX: stat */ TAPDEBUG(__FUNCTION__": %s%d if_rcv queue is full. " \ "Dropping packet.\n", ifp->if_name, ifp->if_unit); splx(s); m_freem(m0); return; } IF_ENQUEUE(&tp->if_rcv, m0); } if (tp->tap_flags & TAP_RWAIT) { tp->tap_flags &= ~TAP_RWAIT; wakeup((caddr_t)tp); } if (tp->tap_flags & TAP_ASYNC && tp->tap_sigio) { pgsigio(tp->tap_sigio, SIGIO, 0); } selwakeup(&tp->tap_rsel); ifp->if_flags &= ~IFF_OACTIVE; splx(s);} /* tapifstart *//*** tapioctl**** the cdevsw interface is now pretty minimal.*/static inttapioctl(dev, cmd, data, flag, p) dev_t dev; u_long cmd; caddr_t data; int flag; struct proc *p;{ int unit = dev_val(minor(dev)), s; struct tap_softc *tp = tapcntl[unit]; struct ifnet *ifp = &tp->tap_if; struct tapinfo *tapp; switch (cmd) { case TAPSIFINFO: tapp = (struct tapinfo *)data; ifp->if_mtu = tapp->mtu; ifp->if_type = tapp->type; ifp->if_baudrate = tapp->baudrate; break; case TAPGIFINFO: tapp = (struct tapinfo *)data; tapp->mtu = ifp->if_mtu; tapp->type = ifp->if_type; tapp->baudrate = ifp->if_baudrate; break; case TAPSDEBUG: tapdebug = *(int *)data; break; case TAPGDEBUG: *(int *)data = tapdebug; break; case FIONBIO: break; case FIOASYNC: if (*(int *)data) { tp->tap_flags |= TAP_ASYNC; } else { tp->tap_flags &= ~TAP_ASYNC; } break; case FIONREAD: s = splimp(); if (tp->if_rcv.ifq_head) { struct mbuf *mb = tp->if_rcv.ifq_head; for(*(int *)data = 0; mb != 0; mb = mb->m_next) *(int *)data += mb->m_len; } else { *(int *)data = 0; } splx(s); break; case FIOSETOWN: return (fsetown(*(int *)data, &tp->tap_sigio)); case FIOGETOWN: *(int *)data = fgetown(tp->tap_sigio); return (0); /* This is deprecated, FIOSETOWN should be used instead. */ case TIOCSPGRP: return (fsetown(-(*(int *)data), &tp->tap_sigio)); /* This is deprecated, FIOGETOWN should be used instead. */ case TIOCGPGRP: *(int *)data = -fgetown(tp->tap_sigio); return (0); default: return (ENOTTY); } return (0);} /* tapioctl *//*** tapread**** The cdevsw read interface - reads a packet at a time, or at** least as much of a packet as can be read.*/static inttapread(dev, uio, flag) dev_t dev; struct uio *uio; int flag;{ int unit = dev_val(minor(dev)); struct tap_softc *tp = tapcntl[unit]; struct ifnet *ifp = &tp->tap_if; struct mbuf *m, *m0; int error = 0, len, s; TAPDEBUG(__FUNCTION__": %s%d reading...\n", ifp->if_name, ifp->if_unit); if ((tp->tap_flags & TAP_READY) != TAP_READY) { TAPDEBUG(__FUNCTION__": %s%d not ready. tap_flags = 0x%x\n", ifp->if_name, ifp->if_unit, tp->tap_flags); return (EHOSTDOWN); } tp->tap_flags &= ~TAP_RWAIT; /* sleep until we get a packet */ s = splimp(); do { IF_DEQUEUE(&tp->if_rcv, m0); if (m0 == 0) { if (flag & IO_NDELAY) { splx(s); return (EWOULDBLOCK); } tp->tap_flags |= TAP_RWAIT; if (error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1), "taprd", 0)) { splx(s); return (error); } } } while (m0 == 0); splx(s); /* xfer packet to user space */ while (m0 && uio->uio_resid > 0 && error == 0) { len = min(uio->uio_resid, m0->m_len); if (len == 0) { break; } error = uiomove(mtod(m0, caddr_t), len, uio); MFREE(m0, m); m0 = m; } if (m0) { TAPDEBUG(__FUNCTION__": %s%d Dropping mbuf\n", ifp->if_name, ifp->if_unit); m_freem(m0); } return (error);} /* tapread *//*** tapwrite**** the cdevsw write interface - an atomic write is a packet - or else!*/static inttapwrite(dev, uio, flag) dev_t dev; struct uio *uio; int flag;{ int unit = dev_val(minor(dev)); struct ifnet *ifp = &tapcntl[unit]->tap_if; struct mbuf *top, **mp, *m; int error = 0, tlen, mlen; struct ether_header *eh; TAPDEBUG(__FUNCTION__": %s%d writting..\n", ifp->if_name, ifp->if_unit); if (uio->uio_resid == 0) { return (0); /* do nothing */ } if (uio->uio_resid < 0 || uio->uio_resid > TAPMRU) { TAPDEBUG(__FUNCTION__": %s%d len = %d!\n", ifp->if_name, ifp->if_unit, uio->uio_resid); return (EIO); } tlen = uio->uio_resid; /* get a header mbuf */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { return (ENOBUFS); } mlen = MHLEN; top = 0; mp = ⊤ while (error == 0 && uio->uio_resid > 0) { m->m_len = min(mlen, uio->uio_resid); error = uiomove(mtod(m, caddr_t), m->m_len, uio); *mp = m; mp = &m->m_next; if (uio->uio_resid > 0) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { error = ENOBUFS; break; } mlen = MLEN; } } if (error) { if (top) { m_freem(top); } return (error); } top->m_pkthdr.len = tlen; top->m_pkthdr.rcvif = ifp; eh = mtod(top, struct ether_header *);#if NBPFILTER > 0 if (ifp->if_bpf) { bpf_mtap(ifp, top); }#endif /* NBPFILTER */#ifdef BRIDGE /* Ethernet bridge */ if (do_bridge) { struct ifnet *bdg_ifp; bdg_ifp = bridge_in(top); if (BDG_DROP == bdg_ifp) { /* drop it */ m_freem(top); top = 0; return (0); } if (BDG_LOCAL != bdg_ifp) { /* forward it */ bdg_forward(&top, bdg_ifp); } if (BDG_LOCAL == bdg_ifp || BDG_BCAST == bdg_ifp || BDG_MCAST == bdg_ifp) { goto getit; } /* drop it */ if (top) { m_freem(top); top = 0; } return (0); }getit:#endif /* BRIDGE */ /* adjust mbuf and give packet to the ether_input */ m_adj(top, sizeof(struct ether_header)); ether_input(ifp, eh, top); return (0);} /* tapwrite *//*** tappoll**** The poll interface, this is only useful on reads** really. The write detect always returns true, write never blocks** anyway, it either accepts the packet or drops it.*/static inttappoll(dev, events, p) dev_t dev; int events; struct proc *p;{ int unit = dev_val(minor(dev)), s; struct tap_softc *tp = tapcntl[unit]; struct ifnet *ifp = &tp->arpcom.ac_if; int revents = 0; s = splimp(); TAPDEBUG(__FUNCTION__": %s%d polling...\n", ifp->if_name, ifp->if_unit); if (events & (POLLIN | POLLRDNORM)) { if (tp->if_rcv.ifq_len > 0) { TAPDEBUG(__FUNCTION__": %s%d have data! q = %d\n", ifp->if_name, ifp->if_unit, tp->if_rcv.ifq_len); revents |= (events & (POLLIN | POLLRDNORM)); } else { TAPDEBUG(__FUNCTION__": %s%d waiting for data\n", ifp->if_name, ifp->if_unit); selrecord(p, &tp->tap_rsel); } } if (events & (POLLOUT | POLLWRNORM)) { revents |= (events & (POLLOUT | POLLWRNORM)); } splx(s); return (revents);} /* tappoll */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -