Chinaunix首页 | 论坛 | 博客
  • 博客访问: 818997
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 15:38:37

转:http://blog.csdn.net/nerdx/article/details/12495445
  1. //skb->pkt_type根据l2地址设置,在eth_type_trans(由驱动调用)中,如果数据帧的目的l2地址为接收接口的l2地址,设置为PACKET_HOST  
  2. //skb->rt->rt_type根据l3地址设置,在ip_route_input(由ip协议调用)中,如果数据帧的目的l3地址为本机配置的l3地址,设置为RTN_LOCAL  
  3.   
  4. //调用路径ip_rcv->ip_rcv_finish->ip_options_rcv_srr  
  5. //  1.skb->dst非本机ip,  
  6. //      1.1 严路由选项,向发送方返回错误  
  7. //      1.2 宽路由选项,直接返回,继续ip_rcv_finish后续处理  
  8. //  2.skb->dst本机ip,  
  9. //      寻找源路由选项ptr指示的下一个,非本机ip的单播地址,复制到ip报头,设置ip_changed使ip校验和失效。  
  10.   
  11. //根据源路由选项,选择下一跳地址,并更新skb->dst路由缓存  
  12. 1.1 int ip_options_rcv_srr(struct sk_buff *skb)  
  13. {  
  14.     struct ip_options *opt = &(IPCB(skb)->opt);//ip控制块,在ip_options_compile中被初始化  
  15.     int srrspace, srrptr;  
  16.     u32 nexthop;  
  17.     struct iphdr *iph = skb->nh.iph;  
  18.     unsigned char * optptr = skb->nh.raw + opt->srr;  
  19.     struct rtable *rt = (struct rtable*)skb->dst;  
  20.     struct rtable *rt2;  
  21.     int err;  
  22.   
  23.     if (!opt->srr)  
  24.         return 0;  
  25.   
  26.     if (skb->pkt_type != PACKET_HOST)//l2地址非本机  
  27.         return -EINVAL;  
  28.     if (rt->rt_type == RTN_UNICAST) {//l3地址非本机,但是可以到达  
  29.         if (!opt->is_strictroute)//非严源路由选项,可以跳过,不处理  
  30.             return 0;  
  31.         icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24));//否则通过icmp,报告发送主机,本机不在严路由ip列表中  
  32.         return -EINVAL;  
  33.     }  
  34.     if (rt->rt_type != RTN_LOCAL)//l3地址非主机,则返回错误  
  35.         return -EINVAL;  
  36.     //从ptr指示的起始位置,逐个遍历后续的路由ip,直到下一跳为非本机单播路由  
  37.     for (srrptr=optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) {  
  38.         if (srrptr + 3 > srrspace) {//不足4字节  
  39.             icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24));//报告错误  
  40.             return -EINVAL;  
  41.         }  
  42.         memcpy(&nexthop, &optptr[srrptr-1], 4);//从源路由选项中,复制下一跳的ip地址  
  43.   
  44.         rt = (struct rtable*)skb->dst;  
  45.         skb->dst = NULL;  
  46.         err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);//通过源路由选项提供的下一跳地址,路由查询  
  47.         rt2 = (struct rtable*)skb->dst;  
  48.         if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {//查询出现错误,或者下一跳地址非单播路由,并且非指向本地的路由  
  49.             ip_rt_put(rt2);  
  50.             skb->dst = &rt->u.dst;//使用之前的路由选项  
  51.             return -EINVAL;//返回错误  
  52.         }  
  53.         ip_rt_put(rt);  
  54.         if (rt2->rt_type != RTN_LOCAL)//找到非本机单播地址  
  55.             break;  
  56.         memcpy(&iph->daddr, &optptr[srrptr-1], 4);//修改ip报头的目的地址  
  57.         opt->is_changed = 1;  
  58.     }  
  59.     if (srrptr <= srrspace) {  
  60.         opt->srr_is_hit = 1;  
  61.         opt->is_changed = 1;  
  62.     }  
  63.     return 0;  
  64. }  
阅读(706) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~