RS:Router Solicitation路由器请求
RA:Router Advertisement路由器公告
在Android系统中我们想要打开一个网络接口(比如eth0)的ipv6功能,用命令的话我们有如下两种办法:
1,echo 0 > /proc/sys/net/ipv6/conf/eth0/disable_ipv6
直接读写的内核proc文件
2,ndc interface ipv6 eth0 enable
用ndc命令,最终也是写内核proc文件
如上的操作proc文件就是触发网络终端发送RS报文的方式,接下来就记录一下内核中对应的代码流程:
写disable_ipv6文件对应的文件系统函数为:
addrconf_sysctl_disable
static
int addrconf_sysctl_disable(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int *valp = ctl->data;
int val = *valp;
loff_t pos = *ppos;
struct ctl_table lctl;
int ret;
/*
* ctl->data points to idev->cnf.disable_ipv6, we should
* not modify it until we get the rtnl lock.
*/
lctl = *ctl;
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
if (write)
ret = addrconf_disable_ipv6(ctl, valp, val);
if (ret)
*ppos = pos;
return ret;
}
接下来进入addrconf_disable_ipv6
static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf)
{
struct net *net;
int old;
if (!rtnl_trylock())
return restart_syscall();
net = (struct net *)table->extra2;
old = *p;
*p = newf;
//如果值不变则不作处理
if (p == &net->ipv6.devconf_dflt->disable_ipv6) {
rtnl_unlock();
return 0;
}
if (p == &net->ipv6.devconf_all->disable_ipv6) {
net->ipv6.devconf_dflt->disable_ipv6 = newf;
addrconf_disable_change(net, newf);
} else if ((!newf) ^ (!old)) //如果值发生变化则作处理
dev_disable_change((struct inet6_dev *)table->extra1);
rtnl_unlock();
return 0;
}
接下来进入dev_disable_change
static void dev_disable_change(struct inet6_dev *idev)
{
struct netdev_notifier_info info;
if (!idev || !idev->dev)
return;
netdev_notifier_info_init(&info, idev->dev);
if (idev->cnf.disable_ipv6)
addrconf_notify(NULL, NETDEV_DOWN, &info); //关闭ipv6
else
addrconf_notify(NULL, NETDEV_UP, &info); //开启ipv6
}
这里只看开启ipv6,所以接下来看addrconf_notify对NETDEV_UP的处理
case NETDEV_UP:
case NETDEV_CHANGE:
if (dev->flags & IFF_SLAVE)
break;
if (idev && idev->cnf.disable_ipv6)
break;
if (event == NETDEV_UP) { //NETDEV_UP
if (!addrconf_qdisc_ok(dev)) {
/* device is not ready yet. */
pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n",
dev->name);
break;
}
if (!idev && dev->mtu >= IPV6_MIN_MTU)
idev = ipv6_add_dev(dev); //将dev加入ipv6协议栈
if (!IS_ERR_OR_NULL(idev)) {
idev->if_flags |= IF_READY;
run_pending = 1;
}
} else {
if (!addrconf_qdisc_ok(dev)) {
/* device is still not ready. */
break;
}
if (idev) {
if (idev->if_flags & IF_READY)
/* device is already configured. */
break;
idev->if_flags |= IF_READY;
}
pr_info("ADDRCONF(NETDEV_CHANGE): %s: link becomes ready\n",
dev->name);
run_pending = 1;
}