免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3841 | 回复: 2
打印 上一主题 下一主题

in_ifinit函数的困惑 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-15 10:24 |只看该作者 |倒序浏览
in_control函数中有两处调用in_ifinit函数,一处是SIOCAIFADDR(添加多个地址)另一处是SIOCSIFADDR(设置一个接口地址)可是为什么在4.4BSD和FreeBSD6.2的网络代码中的in_ifinit函数中看不到处理SIOCAIFADDR命令的代码呢?在in_ifinit函数中一上来就先把接口的旧地址保存到一个变量中,然后就用传进来的新地址替换了老地址,然后是如果接口结构定义了if_ioctl函数就调用他的链路层处理,可是调用的时候仅仅是执行SIOCSIFADDR一个命令,( error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);  )再后就是一些路由和组播相关的代码.请高手指点小弟谢谢了.
int in_control(xxx){
     .....
     switch(cmd)
     case
     ........
     case SIOCAIFADDR:
                maskIsNew = 0;
                hostIsNew = 1;
                error = 0;
                if (ia->ia_addr.sin_family == AF_INET) {
                        if (ifra->ifra_addr.sin_len == 0) {                                                                                                        //新地址没有长度,认为不是一个新地址
                                ifra->ifra_addr = ia->ia_addr;
                                hostIsNew = 0;
                        } else if (ifra->ifra_addr.sin_addr.s_addr ==
                                               ia->ia_addr.sin_addr.s_addr)                                                                                        //新旧地址相等不算新地址
                                hostIsNew = 0;
                }
                if (ifra->ifra_mask.sin_len) {                                                                                                                                //新地址有掩码
                        in_ifscrub(ifp, ia);                                                                                                                                                                //删除接口存在的路由
                        ia->ia_sockmask = ifra->ifra_mask;                                                                                                        //设置掩码
                        ia->ia_sockmask.sin_family = AF_INET;
                        ia->ia_subnetmask =
                             ntohl(ia->ia_sockmask.sin_addr.s_addr);                                                                //设置子码
                        maskIsNew = 1;
                }
                if ((ifp->if_flags & IFF_POINTOPOINT) &&
                    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
                        in_ifscrub(ifp, ia);                                                                                                                                                                //删除接口存在的路由
                        ia->ia_dstaddr = ifra->ifra_dstaddr;                                                                                                //更新目的地址
                        maskIsNew  = 1; /* We lie; but the effect's the same */
                }
                if (ifra->ifra_addr.sin_family == AF_INET &&
                    (hostIsNew || maskIsNew))                                                                                                                                        //有新地址或新掩码
                        error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);                                                //调用in_ifinit执行操作 最后一个参数为0表示不必刷新所有路由
                if (error != 0 && iaIsNew)
                        break;

                if ((ifp->if_flags & IFF_BROADCAST) &&                                                                                                //如果接口支持广播
                    (ifra->ifra_broadaddr.sin_family == AF_INET))
                        ia->ia_broadaddr = ifra->ifra_broadaddr;                                                                                //设置广播地址
                if (error == 0)
                        EVENTHANDLER_INVOKE(ifaddr_event, ifp);
                return (error);
........
}



static int
in_ifinit(ifp, ia, sin, scrub)
        register struct ifnet *ifp;                                                                                                                                        //物理接口
        register struct in_ifaddr *ia;                                                                                                                        //物理接口的原地址结构
        struct sockaddr_in *sin;                                                                                                                                                //要加入或者删除的地址
        int scrub;                                                                                                                                                                                                        //接口改变后是否更新路由
{
        register u_long i = ntohl(sin->sin_addr.s_addr);
        struct sockaddr_in oldaddr;
        int s = splimp(), flags = RTF_UP, error = 0;

        oldaddr = ia->ia_addr;                                                                                                                                                        //保存老地址
        if (oldaddr.sin_family == AF_INET)
                LIST_REMOVE(ia, ia_hash);                                                                                                                                        //从hash表中删除老地址
        ia->ia_addr = *sin;
        if (ia->ia_addr.sin_family == AF_INET)
                LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
                    ia, ia_hash);                                                                                                                                                                        //加入新地址到hash接口的表中
        /*
         * Give the interface a chance to initialize
         * if this is its first address,
         * and to validate the address if necessary.
         */
        if (ifp->if_ioctl) {                                                                                                                                                                //如果定义了ioctl函数
                IFF_LOCKGIANT(ifp);
                error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);        //可能是leioctl,loioctl等链路层地址
                IFF_UNLOCKGIANT(ifp);
                if (error) {
                        splx(s);
                        /* LIST_REMOVE(ia, ia_hash) is done in in_control */
                        ia->ia_addr = oldaddr;                                                                                                                                        //有错误发生还原老地址
                        if (ia->ia_addr.sin_family == AF_INET)
                                LIST_INSERT_HEAD(INADDR_HASH(
                                    ia->ia_addr.sin_addr.s_addr), ia, ia_hash);                               
                        return (error);
                }
        }
        splx(s);
        if (scrub) {
                ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
                in_ifscrub(ifp, ia);                                                                                                                                                        //删除接口路由
                ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
        }
        if (IN_CLASSA(i))                                                                                                                                                                                //尝试网络掩码
                ia->ia_netmask = IN_CLASSA_NET;
        else if (IN_CLASSB(i))
                ia->ia_netmask = IN_CLASSB_NET;
        else
                ia->ia_netmask = IN_CLASSC_NET;
        /*
         * The subnet mask usually includes at least the standard network part,
         * but may may be smaller in the case of supernetting.
         * If it is set, we believe it.
         */
        if (ia->ia_subnetmask == 0) {                                                                                                                                //如果没有子网掩码就用尝试性的掩码
                ia->ia_subnetmask = ia->ia_netmask;
                ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
        } else                                                                                                                                                                                                                        //使用子网掩码
                ia->ia_netmask &= ia->ia_subnetmask;
        ia->ia_net = i & ia->ia_netmask;
        ia->ia_subnet = i & ia->ia_subnetmask;
        in_socktrim(&ia->ia_sockmask);
#ifdef DEV_CARP
        /*
         * XXX: carp(4) does not have interface route
         */
        if (ifp->if_type == IFT_CARP)
                return (0);
#endif
        /*
         * Add route for the network.
         */
        ia->ia_ifa.ifa_metric = ifp->if_metric;
        if (ifp->if_flags & IFF_BROADCAST) {
                ia->ia_broadaddr.sin_addr.s_addr =
                        htonl(ia->ia_subnet | ~ia->ia_subnetmask);
                ia->ia_netbroadcast.s_addr =
                        htonl(ia->ia_net | ~ ia->ia_netmask);
        } else if (ifp->if_flags & IFF_LOOPBACK) {
                ia->ia_dstaddr = ia->ia_addr;
                flags |= RTF_HOST;
        } else if (ifp->if_flags & IFF_POINTOPOINT) {
                if (ia->ia_dstaddr.sin_family != AF_INET)
                        return (0);
                flags |= RTF_HOST;
        }
        if ((error = in_addprefix(ia, flags)) != 0)
                return (error);

        /*
         * If the interface supports multicast, join the "all hosts"
         * multicast group on that interface.
         */
        if (ifp->if_flags & IFF_MULTICAST) {
                struct in_addr addr;

                addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
                in_addmulti(&addr, ifp);                                                                                                                                                                //加入所有主机组
        }
        return (error);
}

论坛徽章:
0
2 [报告]
发表于 2007-10-16 14:39 |只看该作者
原帖由 xiaoning188 于 2007-10-15 10:24 发表
in_control函数中有两处调用in_ifinit函数,一处是SIOCAIFADDR(添加多个地址)另一处是SIOCSIFADDR(设置一个接口地址)可是为什么在4.4BSD和FreeBSD6.2的网络代码中的in_ifinit函数中看不到处理SIOCAIFADDR命令的代 ...


从error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);往底层的部分,
对于添加第1个地址和添加第2、3、。。。个地址是没有区别的。ifconfig xxx
和ifconfig xxx alias的区别都体现在上述调用的外层。

论坛徽章:
0
3 [报告]
发表于 2007-10-17 08:46 |只看该作者
谢谢楼上的哥哥,是小弟疏忽了,多谢指点.打个比方如果是LAN以太网,也就是把地址保存在ifnet结构中的arpcom 和ifaddr结构数据中吧.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP