if (m0->m_len == 0) { MFREE(m0, m); m0 = m; continue; }
tunread(dev, uio, ioflag)	dev_t		dev;	struct uio	*uio;	int		ioflag;{	int		unit;	struct tun_softc *tp;	struct ifnet	*ifp;	struct mbuf	*m, *m0;	int		error = 0, len, s;	if ((unit = minor(dev)) >= ntun)		return (ENXIO);	tp = &tunctl[unit];	ifp = &tp->tun_if;	TUNDEBUG(("%s: read\n", ifp->if_xname));	if ((tp->tun_flags & TUN_READY) != TUN_READY) {		TUNDEBUG(("%s: not ready 0%o\n", ifp->if_xname,			  tp->tun_flags));		return EHOSTDOWN;	}	tp->tun_flags &= ~TUN_RWAIT;	s = splimp();	do {		while ((tp->tun_flags & TUN_READY) != TUN_READY)			if ((error = tsleep((caddr_t)tp,			    (PZERO+1)|PCATCH, "tunread", 0)) != 0) {				splx(s);				return (error);			}		IFQ_DEQUEUE(&ifp->if_snd, m0);		if (m0 == 0) {			if (tp->tun_flags & TUN_NBIO && ioflag & IO_NDELAY) {				splx(s);				return EWOULDBLOCK;			}			tp->tun_flags |= TUN_RWAIT;			if ((error = tsleep((caddr_t)tp,			    (PZERO + 1)|PCATCH, "tunread", 0)) != 0) {				splx(s);				return (error);			}		}	} while (m0 == 0);	splx(s);	while (m0 && uio->uio_resid > 0 && error == 0) {		if (m0->m_len == 0) {			MFREE(m0, m);			m0 = m;			continue;		}		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) {		TUNDEBUG(("Dropping mbuf\n"));		m_freem(m0);	}	if (error)		ifp->if_ierrors++;	return error;}