ip输入处理函数ip_input()小结

ip输入处理函数ip_input()小结
当有帧数据到达网络接口时,网络设备驱动程序会调用m_devget()函数创建一mbuf链表,将收到的帧的数据部分(从ip首部开始) 存放到该mbuf链中.然后调用eth_input(struct ifnet * ifp, struct ether_header *eh, struct mbuf *m)函数通知协议.如果识别到该帧的数据部分为ip分组(类型长度字段为0x0800),eth_input()会将指针m指向的mbuf链表作为ip分组插入到ip输入队列ipintrq中,并且通过软中断通知ip协议;否则,如果识别到该帧的数据部分为arp分组(类型长度字段为0x0806), eth_input()会将指针m指向的mbuf链表作为arp分组插入到arp输入队列arpintrq中,并且通过软中断通知arp协议.代码如下:
void ether_input(ifp, eh, m)
{
    struct ifqueue * inq;

    ........
    switch (eh->ether_type)
    {
       case ETHERTYPE_IP:
             schednetisr(NETISR_IP);
             inq = &ipintrq;
             break;
       case ETHERTYPE_ARP:
             schednetisr(NETISR_ARP);
             inq = &arpintrq;
             break;
       default:
             if (eh->ether_type > ETHERMTU)
             {
                   m_freem(m);
                   return;
             }
    }
    .......
    s = splimp();
    if (IF_QFULL(inq))
    {
          IF_DROP(inq);
          m_freem(m);
    }   else
             IF_ENQUEUE(inq, m);     //将m指向的链表插入到相应的协议输入队列中
    splx(s);
}

ip协议在收到软中断后,会调用ip层软中断处理函数void ipintr(void),net/3直接在ipintr里面处理ip分组, 而ecos则是在ipintr函数里调用了ip_input()函数来处理每一个ip分组:
static void ipintr(void)
{
    int s;
    struct mbuf *m;

    while(1) {
        s = splimp();
        IF_DEQUEUE(&ipintrq, m);
        splx(s);
        if (m == 0)
            return;
        ip_input(m);
    }
}
ip_input的原型很简单: void ip_input(struct mbuf * m),下面详细介绍一下ip_input函数所完成的工作:

(1)验证工作:首先验证主机系统上面的网络接口有没有配置了ip地址(验证in_ifaddr是否为空);其次,验证m指向的mbuf链的数据部分(即ip分组)有误错误,如:ip版本号是否为4,检验和是否正确,首部长度是否正确,等等.

(2)如果hlen标识分组首部长度>40,ip_input()函数就会去调用ip_dooption(struct mbuf *m)对首部选项进行处理.在ip_dooption()函数中,如果发现选项数据有误,则直接丢弃分组,或者发现由于选项中采用了源路由选项则转发分组,这两种情况下函数返回1,否则返回0.ip_input()检查ip_dooption()的返回值,如果发现返回值为1,则ip_input认为分组已经在ip_dooption函数里被处理完了,ip_input直接返回,继续下一个分组的处理;否则,当发现返回值为0时,继续对分组进行处理. 下面我们描述一下函数ip_dooption的处理过程:
    a.对源路由选项LSRR,SSRR选项的处理.需要注意的是,如果分组启动了源路由选项,那么分组的目的ip地址将会被选项中的下一跳ip地址替换.并且在确定分组已经到达目的主机后,所经过的路由选项会被备份在静态全局变量ip_srcrt中,所经过的路由器的跳数会被记录在ip_nhops中,以备传输层协议构造逆转路由.如果发现分组还没有到达最终的目的地址,那么ip_dooption在所有选项处理完毕后将会调用ip_forward(m,1)函数转发该分组.
    b.对记录路由选项的处理
    c.对时间戳选项的处理

(3)扫描本系统中in_ifaddr指向的ip地址链,判断本系统是否为分组所要到达的目的地址.首先检查所有接口的目的地址ia_addr,看是否有能与分组的目的地址匹配(单播); 其次检查分组到达的接口的广播地址,看是否与分组的目的地址匹配(广播). 如果地址链扫描完成后发现没有地址与分组的目的地址匹配,就去验证多播.如果还不匹配,最后检查分组是否为受限的特殊地址,如全1,或全0.
如果通过以上检查后,系统有地址与分组的目的地址匹配,则确定分组已经到达了最终目的地,否则分组需要被转发.当然,只有当系统被配置成路由器(全局变量ip_forward == 1)时才转发分组然后返回,否则直接丢弃分组后返回.

(4)如果分组已经到达最终目的地,则ip_input()此时会去检查分组的ip首部,以判断该分组是否为ip数据报的某个分片.如果确定该分组是某个ip数据报的某个分片,则ip_input将调用ip_reass()函数将到达的分片与以前的分片进行重装.这就涉及到一个重要的数据结构---重装表.

(5)如果到达的分片与以前的分片重装在一起,能组成一个完整的数据报,或者到达的分组本身就是一个完整的数据报,则ip层将通过ip首部所标识的协议类型调用相应的传输层函数.代码如下:
(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);

(6)函数返回.










  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值