Linux内核分析 - 网络[十四]:IP选项
do_ip_setsockopt() 处理ip选项 根据optname来决定处理何种 类型的选项,决定setsockopt()中参数的optval如何解释。当是IP_OPTIONS时为IP选项,按IP选项来处理optval。 switch (optname) { case IP_OPTIONS: ip_options_get_from_use()根据用户传入值optval生成选项结构opt,xchg()这句将inet->opt 和opt进行了交换,即将opt赋值给了inet->opt,同时将inet->opt作为结果返回。 err = ip_options_get_from_user(sock_net(sk), &opt, optval, optlen); opt = xchg(&inet->opt, opt); kfree(opt); ip_options_get_from_user() 分配内存给IP选项,struct ip_options记录了选项相关的一些内部数据 结构,最后的属性__data[0]才指向真正的IP选项。因此在分配空间时是struct ip_options大小加上optlen大小,当然,还要做 4字节对齐。 struct ip_options *opt = ip_options_get_alloc(optlen); static struct ip_options *ip_options_get_alloc(const int optlen) { return kzalloc(sizeof(struct ip_options) + ((optlen + 3) & ~3), GFP_KERNEL); } 分配空间后,拷贝用户设置的IP选项到opt->__data中;最后调用ip_options_get_finish()完成选项的处理,包 括了用户传入选项的再处理、一些内部数据的填写,下面会进行详细讲解。 copy_from_user(opt->__data, data, optlen); return ip_options_get_finish(net, optp, opt, optlen); ip_options_get_finish() 选项头部的空字节用 IPOPT_NOOP来补齐,选项尾部的空字节用IPOPT_END来补齐,IPOPT_NOOP和IPOPT_END都占用1字节,因此optlen递增,记录选项 长度到opt中。然后调用ip_options_compile()。 while (optlen & 3) opt->__data[optlen++] = IPOPT_END; opt->optlen = optlen; ip_options_compile()实际完成选项的处理,它在两个地方被调用:生成带IP选项的报文 时被调用,此时处理的是用户传入的选项;接收带有IP选项的报文时被调用,此时处理的是报文中的IP选项,下面详细看下该函 数,以LSRR选项为例子。 ip_options_compile(net, opt, NULL); kfree(*optp); *optp = opt; ip_options_compile() 这里对应于该函数应用的两种情况: 1. 如果是生成带IP选项的报文,传入 的参数skb为空(此时skb还没有创建),optptr指向opt->__data,而上面已经看到用户设置的选项在函数 ip_options_get_from_user()中被拷贝到其中; 2. 如果接收到带IP选项的报文,传入skb不为空(收到报文时就创建了), optptr指向报文中IP选项的位置。iph指向IP报头的位置,当然,如果是生成选项,iph所指向的位置是没有意义的。 if (skb != NULL) { rt = skb_rtable(skb); optptr = (unsigned char *)&(ip_hdr(skb)[1]); } else optptr = opt->__data; iph = optptr - sizeof(struct iphdr); IP选项是按[code, len, ptr, data]这样的块排列的,每个块代表一个选项 内容,多个选项可以共存,每个块4字节对齐,不足的用IPOPT_NOOP补齐。for循环处理每个选项,其中IPOPT_END和IPOPT_ NOOP只是特殊的占位符,需要另外处理。然后按照选项块的格式,取出选项长度len到optlen,再根据选项的code分别进行处理 ,可以看到获取选项块长度的代码段在IPOPT_END和IPOPT_NOOP之后。 for (l = opt->optlen; l > 0; ) { switch (*optptr) { case IPOPT_END: …. case IPOPT_NOOP: ... …... optlen = optptr[1]; if (optlen<2 || optlen>l) { pp_ptr = optptr; goto error; } case …... …...// 处理代码段 } l -= optlen; optptr += optlen; } (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |