BSD net源码分析(4)──环回接口

来源:互联网 发布:养老保险的算法 编辑:程序博客网 时间:2024/05/21 22:32

一、接口的初始化
环回接口的作用是直接把输出队列的分组直接发送到输入队列。
没用硬件设备,环回伪设备在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

原创粉丝点击