获取MATCH版本信息出错IPT_SO_GET_REVISION_MATCH,errno=92

1320阅读 0评论2013-09-25 shaohui973
分类:嵌入式

背景:
    我们这个项目需要做软件的网络地址转换NAT,由于是嵌入式产品,且只需要操作NAT表,且SDK中没有提供NAT相关的库。
    故没有考虑使用现成的库,该用直接使用socket接口操作kernel的NAT表。
     
    socketId = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    getsockopt(g_IptableSocketId, IPPROTO_IP, IPT_SO_GET_REVISION_MATCH, &g_stUdpMatchRevision, &dwOptLen);
     
现象:
   程序交叉编译后,下到目标板运行时,上述的getsockopt返回失败,errno=92.   why?
    
原因分析:
   1.当socket()创建socket时,
   SYSCALL_DEFINE3(socket) --->sock_create()--->__sock_create()--(AF_INET)-> inet_create()
    
   inet_create()
   {
         //关注该函数所挂载在socket上的ops和prot。在我的程序里,这里挂载的分别是inet_sockraw_ops和raw_prot
   }
    
   2.当getsockopt()时,
   SYSCALL_DEFINE5(getsockopt)--->sock_common_getsockopt()--->raw_getsockopt()
    
   static int raw_getsockopt(struct sock *sk, int level, int optname,
              char __user *optval, int __user *optlen)
    {
        if (level != SOL_RAW)
            return ip_getsockopt(sk, level, optname, optval, optlen);
        return do_raw_getsockopt(sk, level, optname, optval, optlen);
    }
    
    我们的level是IPROTO_IP,故这里进入ip_getsockopt()
    
    int ip_getsockopt(struct sock *sk, int level,
          int optname, char __user *optval, int __user *optlen)
 {
     int err;
 
     err = do_ip_getsockopt(sk, level, optname, optval, optlen);
 #ifdef CONFIG_NETFILTER
     /* we need to exclude all possible ENOPROTOOPTs except default case */
     if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
            !ip_mroute_opt(optname)) {
        int len;
 
        if (get_user(len, optlen))
            return -EFAULT;
 
        lock_sock(sk);
        err = nf_getsockopt(sk, PF_INET, optname, optval,
                &len);
        release_sock(sk);
        if (err >= 0)
            err = put_user(len, optlen);
        return err;
      }
  #endif
    return err;
 }
 
 函数do_ip_getsockopt()的switch...case中没有我们的IPT_SO_GET_REVISION_MATCH,故进入default后会返回-ENOPROTOOPT(92)。
 假设我们打开了CONFIG_NETFILTER,则会进入nf_getsockopt()去处理我们的IPT_SO_GET_REVISION_MATCH请求。
 
 所以,基本上已经看出来了问题所在。很可能就是kernel的CONFIG_NETFILTER没有配置。
 于是返回linux kernel source中查看.config文件。果然,这个CONFIG_NETFILTER没有配置。
 
 至此,该问题已经解决。
上一篇:powerpc处理器u-boot启动
下一篇:NAT地址转换原理全攻略