/* * 从网卡上下载数据包,len是数据的长度,本地以太网头部被分开 */ static struct mbuf * elget(buf, totlen, ifp)/*由elread调用,buf是指向sc->el_pktbuf缓冲区,并且数据已经存在, totlen是整个数据包长度-sizeof(struct ether_header)即以太网头部的长度*/ caddr_t buf; int totlen; struct ifnet *ifp; { struct mbuf *top, **mp, *m; int len; register caddr_t cp; char *epkt; buf += sizeof(struct ether_header);/*调用前buf指向...请看下图 |--------------------------------整个数据----------------------------------------------| |--ether头部14字节----|--------IP或ARP或其他协议头部及数据-----------------------------| ^ 调用前buf指向这 ^ 执行之后buf指向这 因为在向上传递数据的过程是一层一层的剥,在本次要剥掉ether_header即以太网头部 */ cp = buf;/*放入寄存器中*/ epkt = cp + totlen;/*epkt在计算后指向数据的尾部*/ MGETHDR(m, M_DONTWAIT, MT_DATA);/*得到一标记了头部的mbuf*/ /*MGETHDR宏说明 #define MGETHDR(m, how, type) do { struct mbuf *_mm; int _mhow = (how); int _mtype = (type); int _ms = splimp(); 屏蔽中断 if (mmbfree == NULL) mmbfree是内存管理初始化时的全局变量,意思是还有可用的内存块吗? (void)m_mballoc(1, _mhow); 没有就分配一个,1代表分配一个MSIZE大小的块,该函数调用kmem_malloc核心内存分配函数,返回的可用mbuf指针在mmbfree中 _mm = mmbfree; if (_mm != NULL) { mmbfree = _mm->m_next; 如果上面的m_mballoc函数执行了,_mm->m_next肯定为NULL mbtypes[MT_FREE]--; _mm->m_type = _mtype; 看上下文可知,_mtype是MT_DATA mbtypes[_mtype]++; _mm->m_next = NULL; 从这开始是初始化mbuf一些指针 _mm->m_nextpkt = NULL; _mm->m_data = _mm->m_pktdat; _mm->m_flags = M_PKTHDR; 加入mbuf链首标志,即该链的第一个包,该宏和MGET的不同之处 _mm->m_pkthdr.rcvif = NULL; _mm->m_pkthdr.csum_flags = 0; _mm->m_pkthdr.aux = (struct mbuf *)NULL; (m) = _mm; splx(_ms); 恢复中断 } else { splx(_ms); _mm = m_retryhdr(_mhow, _mtype); 再来一次MGETHDR,不过m_retryhdr已经定义为空,防止死循环 if (_mm == NULL && _mhow == M_WAIT) 还为空 (m) = m_mballoc_wait(MGETHDR_C, _mtype); 强制用阻塞型 else (m) = _mm; } } while (0) */ if (m == 0) return (0); m->m_pkthdr.rcvif = ifp;/*指向接收该包的网络卡的ifp指针,后面好多协议要用到他*/ m->m_pkthdr.len = totlen;/*已经把以太网头部剥离,数据长度没算他了*/ m->m_len = MHLEN;/*该出是链首,所以该mbuf的长度是MHLEN,而不是MLEN*/ /* 这就是MHLEN #define MSIZE 256 /* mbuf的大小 * #define MLEN (MSIZE - sizeof(struct m_hdr)) /* 普通数据区的长度* #define MHLEN (MLEN - sizeof(struct pkthdr)) /* 链首数据区的长度 |