f_snd; /* output queue */
};
对输出队列的操作函数,simple and beauty
/*
* Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
* input routines have queues of messages stored on ifqueue structures
* (defined above). Entries are added to and deleted from these structures
* by these macros, which should be called with ipl raised to splimp().
*/
#define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen)
#define IF_DROP(ifq) ((ifq)->ifq_drops++)
#define IF_ENQUEUE(ifq, m) { \
(m)->m_nextpkt = 0; \
if ((ifq)->ifq_tail == 0) \
(ifq)->ifq_head = m; \
else \
(ifq)->ifq_tail->m_nextpkt = m; \
(ifq)->ifq_tail = m; \
(ifq)->ifq_len++; \
}
#define IF_PREPEND(ifq, m) { \
(m)->m_nextpkt = (ifq)->ifq_head; \
if ((ifq)->ifq_tail == 0) \
(ifq)->ifq_tail = (m); \
(ifq)->ifq_head = (m); \
(ifq)->ifq_len++; \
}
#define IF_DEQUEUE(ifq, m) { \
(m) = (ifq)->ifq_head; \
if (m) { \
if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \
(ifq)->ifq_tail = 0; \
(m)->m_nextpkt = 0; \
(ifq)->ifq_len--; \
} \
}
/*
* The ifaddr structure contains information about one address
* of an interface. They are maintained by the different address families,
* are allocated and attached when an address is set, and are linked
* together so all addresses for an interface can be located.
*/
struct ifaddr {
struct sockaddr *ifa_addr; /* address of interface */
struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
struct sockaddr *ifa_netmask; /* used to determine subnet */
struct ifnet *ifa_ifp; /* back-pointer to interface */
struct ifaddr *ifa_next; /* next address for interface */
void (*ifa_rtrequest)(); /* check or clean routes (+ or -)'d */
u_short ifa_flags; /* mostly rt_flags for cloning */
short ifa_refcnt; /* extra to malloc for link info */
int ifa_metric; /* cost of going out this interface */
#ifdef notdef
struct rtentry *ifa_rt; /* XXXX for ROUTETOIF */
#endif
};
以loop设备为例,其初始化函数为loopattach,相当于linux下的probe函数。
81 loopattach(n)
82 int n;
83 {
有专用的ifnet,其他的设备需要申请,并初始化
84 register struct ifnet *ifp = &loif;
85
86 #ifdef lint
87 n = n; /* Highlander: there can only be one... */
88 #endif
89 ifp->if_name = "lo";
90 ifp->if_mtu = LOMTU;
91 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
92 ifp->if_ioctl = loioctl;
93 ifp->if_output = looutput;
94 ifp->if_type = IFT_LOOP;
95 ifp->if_hdrlen = 0;
96 ifp->if_addrlen = 0;
注册给内核,相当于register_netdevice
97 if_attach(ifp);
98 #if NBPFILTER > 0
分组过滤相关,按下不表
99 bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
100 #endif
101 }
if_attach主要就是把ifp放到一个链表里,初始化后 找到组织了
void
if_attach(ifp)
struct ifnet *ifp;
{
unsigned socksize, ifasize;
int namelen, unitlen, masklen, ether_output();
char workbuf[12], *unitname;
全局的一个结构
register struct ifnet **p = &ifnet;
register struct sockaddr_dl *sdl;
register struct ifaddr *ifa;
static int if_indexlim = 8;
extern void link_rtrequest();
这个循环很有意思,看了半天才明白
p指向的是ifnet结构中的一个成员,这个成员是ifnet*,*P指向下一个结构。所以*P==NULL,说明P所指的成员所在的结构是最后一个ifnet,所以可以直接对*P,既ifnet->if_next赋值。
while (*p)
p = &((*p)->if_next);
*p = ifp;
增加全区的if_index,如果有接口删除了,占用的if_index也不能用了
ifp->if_index = ++if_index;
动态的扩充ifnet_addr的大小,方法不错
if (ifnet_addrs == 0 || if_index >= if_indexlim) {
unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
stru