m_devget函数

来源:互联网 发布:mysql直接复制数据文件 编辑:程序博客网 时间:2024/05/18 13:41

当接收到一个以太网帧时,设备驱动程序调用函数m_devget来创建一个Mbuf链表,并把设备中帧复制到这个链表中。

struct mbuf *
m_devget(buf, totlen, off0, ifp, copy)
        char *buf;
        int totlen, off0;
        struct ifnet *ifp;
        void (*copy)();
{
        register struct mbuf *m;
        struct mbuf *top = 0, **mp = ⊤
        register int off = off0, len;
        register char *cp;
        char *epkt;

        cp = buf;
        epkt = cp + totlen;
        if (off) {
                /*
                 * If parameter(参数) 'off' is non-zero(is not zero), packet is trailer-encapsulated(跟踪压缩),
                 * so we have to skip(跳过) the type and length fields.
                 */
                cp += off + 2 * sizeof(u_int16_t);
                totlen -= 2 * sizeof(u_int16_t);
        }
        MGETHDR(m, M_DONTWAIT, MT_DATA);
        if (m == 0)
                return (0);
        m->m_pkthdr.rcvif = ifp;
        m->m_pkthdr.len = totlen;
        m->m_len = MHLEN;

        while (totlen > 0) {
                if (top) {
                        //MGET:allocates an mbuf and initializes it to contain internal data
                        MGET(m, M_DONTWAIT, MT_DATA);
                        if (m == 0) {
                                m_freem(top);
                                return (0);
                        }
                        m->m_len = MLEN;
                }
                len = min(totlen, epkt - cp);
                if (len >= MINCLSIZE) {        //数据长度大于或等于MINCLSIZE(20
                        MCLGET(m, M_DONTWAIT);        //分配一个簇
                        if (m->m_flags & M_EXT)
                                m->m_len = len = min(len, MCLBYTES);
                        else
                                len = m->m_len;
                } else {        //数据长度小于MINCLSIZE(20
                        /*
                         * Place initial small packet/header at end of mbuf.
                         */
                        if (len < m->m_len) { //第一种情况:0<数据长度<84
                                if (top == 0 && len + max_linkhdr <= m->m_len)
                                        m->m_data += max_linkhdr; //保留16个字节的空间
                                m->m_len = len;        //len = totlen
                        } else
                                len = m->m_len;
                }
                if (copy)
                        copy(cp, mtod(m, caddr_t), (unsigned)len);
                else
                        bcopy(cp, mtod(m, caddr_t), (unsigned)len);
                cp += len;
                *mp = m;
                mp = &m->m_next;
                totlen -= len;
                if (cp == epkt)
                        cp = buf;
        }
        return (top);
}