//调用路径ip_queue_xmit->ip_options_build //函数主要任务: // 1.非分片ip报文,向ip报头填充ip选项,ip选项在创建socket时设置 // 2.分片ip报文,将record route选项,time stamp选项设置为NOP // daddr,ip接收方的地址 1.1 void ip_options_build(struct sk_buff * skb, struct ip_options * opt, u32 daddr, struct rtable *rt, int is_frag) { unsigned char * iph = skb->nh.raw; memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));//将socket中提供的ip选项拷贝到skb->cb中 memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);//复制ip选项到ip报头后 opt = &(IPCB(skb)->opt); opt->is_data = 0; if (opt->srr)//将目标地址拷贝到源路由选项列表中的最后一个位置上 memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); if (!is_frag) {//在ip_queue_xmit->ip_options_build调用路径上,is_frag为0 if (opt->rr_needaddr)//record route选项 ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt);//获取路由的首选源地址填充到选项ptr所指的位置 if (opt->ts_needaddr)//time stamp选项 ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt); if (opt->ts_needtime) { struct timeval tv; __u32 midtime; do_gettimeofday(&tv);//通过do_gettimeofday获取系统时间,填充当天的ms midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); } return; } //ip分片中的选项 if (opt->rr) { memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]);//设置record route为NOP opt->rr = 0; opt->rr_needaddr = 0; } if (opt->ts) { memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]);//设置time stamp为NOP opt->ts = 0; opt->ts_needaddr = opt->ts_needtime = 0; } }