IP层输入

来源:互联网 发布:淘宝怎么修改发票抬头 编辑:程序博客网 时间:2024/06/05 18:20
//在inet_init时,已经使用dev_add_pack(&ip_packet_type)向ptype_base中注册二层负载//IPv4报文处理回调,当netif_receive_skb进行二层包处理时,会遍历所有ptype_base列//表,找到对应的三层协议,并调用回调进行处理。这里ip_rcv就是IPV4的接收处理回调ip_rcv//如果目地MAC不是自身,则将包丢弃,不是自身通常都是从二层桥转发。if (skb->pkt_type == PACKET_OTHERHOST)goto drop;//如果skb是共享的,则先复制一份,复制失败则丢弃。if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);goto out;//检测当前skb的头部是否有ip头大小的有效空间。if (!pskb_may_pull(skb, sizeof(struct iphdr)))goto inhdr_error;iph = skb->nh.iph;//检测ip头长度是否小于最少20字节,或者不是ipv4版本if (iph->ihl < 5 || iph->version != 4)goto inhdr_error;//检测当前skb的头部是否有ip整个头(可能含ip选项)的有效空间。if (!pskb_may_pull(skb, iph->ihl*4))goto inhdr_error;iph = skb->nh.iph;//进行ip校验和检测if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))goto inhdr_error;//检测整个报文是否小于ip头记载的总长度,或者总长度小于IP头长度len = ntohs(iph->tot_len);if (skb->len < len || len < (iph->ihl*4))goto inhdr_error;//在二层传输时,很可能为了适应二层媒介(比如以太网帧最小必须是64字节)而//填充无效信息。这里检测是否含有填充信息,如果含有则修正skb的tail指向有效//数据的位置,跳过无效的填充。if (pskb_trim_rcsum(skb, len))IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);goto drop;//将sky的cb成员清空。memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));//进行netfileter的PRE_ROUTING链处理,这里不分析netfileter,假设没有被//netfilter拦截,则会触发ip_rcv_finish调用。NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish);--------------------------------------------------------------------------------------------------------------------ip_rcv_finish//没有目地对象,先进行路由模块查询,这里暂时先不去了解路由模块的处理机制//仅需要知道,如果路由模块判断出当前报文是本地报文,则将设置本地接收回调//为rth->u.dst.input= ip_local_deliver;if (skb->dst == NULL)ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,skb->dev);//如果ip头长度大于20字节,则表示有ip选项,则进行ip选项处理。if (iph->ihl > 5 && ip_rcv_options(skb))goto drop;//调用skb->dst->input回调进行本地接收处理,这个回调就是在上面ip_route_input中//设置的。如果回调函数的返回值为NET_XMIT_BYPASS,则循环接收处理。dst_input(skb);for (;;)err = skb->dst->input(skb);if (likely(err == 0))return err;if (unlikely(err != NET_XMIT_BYPASS))return err;----------------------------------------------------------------------------------------------------------------------ip_local_deliver//如果当前ip报是分片,则需要进行组装,在没有收到所有分片时,直接返回,ip//分片及组装待后面单独分析。if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET))skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER)if (!skb)return 0;//进行netfileter的LOCAL_IN链处理,这里不分析netfileter,假设没有被netfilter拦截,//则会触发ip_local_deliver_finish调用。NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,ip_local_deliver_finish);---------------------------------------------------------------------------------------------------------------------ip_local_deliver_finish//去除ip头,将skb->data指向ip负载。__skb_pull(skb, ihl);skb->h.raw = skb->data;//ip负载的协议号int protocol = skb->nh.iph->protocol;//查找是否有原始套接口需要处理此协议报文hash = protocol & (MAX_INET_PROTOS - 1);raw_sk = sk_head(&raw_v4_htable[hash]);//如果存在原始套接口在监听该协议报文,则调用原始套接口进行处理if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash))raw_sk = NULL;//检测当前内核是否注册了对应的四层协议处理对象,比如UDP协议是在//inet_init中使用inet_add_protocol(&udp_protocol, IPPROTO_UDP)加入了UDP//处理回调。if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL)//如果对应协议设置需要安全策略标记,则使用xfrm4_policy_check进行安全策略//处理,处理失败则将报文丢弃。暂不分析。if (!ipprot->no_policy)if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))kfree_skb(skb);goto out;nf_reset(skb);//调用对应的四层协议处理函数进行处理。暂不分析。ipprot->handler(skb);else//如果四层协议没有对应的内核模块处理,同时也没有原始套接口监听,则发送//ICMP错误。if (!raw_sk)if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))icmp_send(skb, ICMP_DEST_UNREACH,ICMP_PROT_UNREACH, 0);kfree_skb(skb);

0 0
原创粉丝点击