BSD net源碼分析(4)──環回接口

一、接口的初始化
環回接口的作用是直接把輸出隊列的分組直接發送到輸入隊列。
沒用硬件設備,環回僞設備在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

發佈了30 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章