一、接口的初始化
環回接口的作用是直接把輸出隊列的分組直接發送到輸入隊列。
沒用硬件設備,環回僞設備在main函數中通過環回接口的pdevinit結構中的pdev_attach指針直接調用loopatttach時初始化。
void
loopattach(n)
int n;
{
register struct ifnet *ifp = &loif;
#ifdef lint
n = n; /* Highlander: there can only be one... */
#endif
ifp->if_name = "lo";
ifp->if_mtu = LOMTU;
ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
ifp->if_ioctl = loioctl;
ifp->if_output = looutput;
ifp->if_type = IFT_LOOP;
ifp->if_hdrlen = 0; /* 環回接口沒有鏈路首部和硬件地址 */
ifp->if_addrlen = 0;
if_attach(ifp); /* 接口結構的初始化 */
#if NBPFILTER > 0
bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); /* 登記BPF的環回接口 */
#endif
}
二、環回接口的輸入和輸出
環回接口的if_output指向函數looutput,將輸出分組放置到分組的目的地址指明的協議的輸入隊列。
int
looutput(ifp, m, dst, rt)
struct ifnet *ifp;
register struct mbuf *m;
struct sockaddr *dst;
register struct rtentry *rt;
{
int s, isr;
register struct ifqueue *ifq = 0;
if ((m->m_flags & M_PKTHDR) == 0)
panic("looutput no HDR");
ifp->if_lastchange = time;
#if NBPFILTER > 0
if (loif.if_bpf) {
/*
* We need to prepend the address family as
* a four byte field. Cons up a dummy header
* to pacify bpf. This is safe because bpf
* will only read from the mbuf (i.e., it won't
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
u_int af = dst->sa_family;
m0.m_next = m;
m0.m_len = 4;
m0.m_data = (char *)⁡
/* 將加了目的地址的新mbuf鏈表傳遞給bpf_mtap */
bpf_mtap(loif.if_bpf, &m0);
}
#endif
/* 輸出環回到輸入 */
m->m_pkthdr.rcvif = ifp; /* 設置接收接口 */
/* 檢查路由是否允許 */
if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
m_freem(m);
return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
}
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
switch (dst->sa_family) {
/* 以下根據不同的協議類型分發數據到輸入隊列 */
#ifdef INET
case AF_INET:
ifq = &ipintrq;
isr = NETISR_IP;
break;
#endif
#ifdef NS
case AF_NS:
ifq = &nsintrq;
isr = NETISR_NS;
break;
#endif
#ifdef ISO
case AF_ISO:
ifq = &clnlintrq;
isr = NETISR_ISO;
break;
#endif
default:
printf("lo%d: can't handle af%d/n", ifp->if_unit,
dst->sa_family);
m_freem(m);
return (EAFNOSUPPORT);
}
s = splimp();
if (IF_QFULL(ifq)) {
IF_DROP(ifq);
m_freem(m);
splx(s);
return (ENOBUFS);
}
IF_ENQUEUE(ifq, m);
schednetisr(isr); /* 調用軟中斷觸發 */
ifp->if_ipackets++;
ifp->if_ibytes += m->m_pkthdr.len;
splx(s);
return (0);
}
/*****************************************************/
環回接口的處理較爲簡單,在這裏只作簡要分析。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/mythfish/archive/2008/11/23/3357666.aspx