Loading...
墨滴

流年树

2021/03/06  阅读:17  主题:默认主题

test

//从这里进入L4传输层
/*
 * ip_local_deliver_finish()将输入数据包从网络层传递
 * 到传输层。过程如下:
 * 1)首先,在数据包传递给传输层之前,去掉IP首部
 * 2)接着,如果是RAW套接字接收数据包,则需要
 * 复制一份副本,输入到接收该数据包的套接字。
 * 3)最后,通过传输层的接收例程,将数据包传递
 * 到传输层,由传输层进行处理。
 */
 /* 
 ip 层处理报文过程中,回复制一份报文到raw_socket中去;有的是IPPROTO_TCP/IPPROTO_RAW
 当 socket(AF_INET, SOCK_RAW, IPPROTO_RAW)时,它会接收所有协议的数据包,并且
IP_HDRINCL 是默认打开的,即是说应用层要提供 L3 和 L4 层的头。再如,如果是
IPPROTO_TCP 时,它只接收到 TCP 包。而 IP_HDRINCL 是默认不打开的,即系统会处理 L3
的头部
*/
static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
/*
  * 在数据包传递给传输层之前,先去掉
  * IP首部。
  */
 __skb_pull(skb, skb_network_header_len(skb));

 rcu_read_lock();
 {
  int protocol = ip_hdr(skb)->protocol;
  const struct net_protocol *ipprot;
  int raw;
/*
   * 处理RAW套接字,先根据传输层协议号
   * 得到哈希值,然后查看raw_v4_htable散列表
   * 中以该值为关键字的哈希桶是否为空,
   * 如果不为空,则说明创建了RAW套接字,
   * 复制该数据包的副本输入到注册到
   * 该桶中的所有套接字。
   */
   /*
ip_local_deliver_finish函数会先检查哈希表raw_v4_htable。
因为在创建 socket时,inet_create会把协议号IPPROTO_ICMP的值赋给socket的成员num,
并以num为键值,把socket存入哈 项表raw_v4_htable?瑀aw_v4_htable[IPPROTO_ICMP&(MAX_INET_PROTOS-1)]上即存放了 这个socket,实际上是一个socket的链表,
如果其它还有socket要处理这个回显应答,也会被放到这里,组成一个链 表,
ip_local_deliver_finish收到数据报后,取出这个socket链表(目前实际上只有一项),
调用raw_v4_input,把 skb交给每一个socket进行处理。
然后,还需要把数据报交给inet_protos[IPPROTO_ICMP& (MAX_INET_PROTOS-1)],即icmp_rcv处理,
因为对于icmp报文,每一个都是需要经过协议栈处理的,
但对回显应 答,icmp_rcv只是简单丢弃,并未实际处理。
*/
 resubmit:
 //之前开巨帧的时候,icmp不通就是在这里面的函数中sock_queue_rcv_skb丢的
  raw = raw_local_deliver(skb, protocol);
//如果是raw套接字,则则该函数里面会复制一份skb,然后送到  ,例如用ping 1.2.2.2的时候,会走这里面,不会走icmp_recv*/
  ipprot = rcu_dereference(inet_protos[protocol]);
  if (ipprot) {
   int ret;
/*
   * 通过查找inet_portos数组,确定是否
   * 注册了与IP首部中传输层协议号
   * 一致的传输层协议。若查找命中,
   * 则执行对应的传输层协议例程。
   */
   if (!ipprot->no_policy) {
    if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
     kfree_skb(skb);
     goto out;
    }
    nf_reset(skb);
   }
   ret = ipprot->handler(skb);//这里面会进入udp tcp传输层
   if (ret < 0) {
    protocol = -ret;
    goto resubmit;
   }
   __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
  } else {
   if (!raw) {
    /*
    * 如果没有响应的协议传输层接收该数据包,
    * 则释放该数据包。在释放前,如果是RAW
    * 套接字没有接收或接收异常,则还需产生
    * 一个目的不可达ICMP报文给发送方。表示该包raw没有接收并且inet_protos中没有注册该协议
    */
    if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
     __IP_INC_STATS(net, IPSTATS_MIB_INUNKNOWNPROTOS);
     icmp_send(skb, ICMP_DEST_UNREACH,
        ICMP_PROT_UNREACH, 0);
    }
    kfree_skb(skb);
   } else {
    __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
    consume_skb(skb);
   }
  }
 }
 out:
 rcu_read_unlock();

 return 0;
}

流年树

2021/03/06  阅读:17  主题:默认主题

作者介绍

流年树