#!/bin/sh
<?
include "/htdocs/phplib/trace.php";
include "/htdocs/phplib/xnode.php";
function cmd($cmd) {echo $cmd."\n";}
function msg($msg) {cmd("echo ".$msg." > /dev/console");}
/*****************************************/
function add_each($list, $path, $node)
{
//echo "# add_each(".$list.",".$path.",".$node.")\n";
$i = 0;
$cnt = scut_count($list, "");
while ($i < $cnt)
{
$val = scut($list, $i, "");
if ($val!="") add($path."/".$node, $val);
$i++;
}
return $cnt;
}
/*****************************************/
function add_route($ipaddr,$prefix,$gw,$metric,$inf)
{
$base = "/runtime/dynamic/route6";
$cnt = query($base."/entry#");
if($cnt=="") $cnt=0;
$cnt++;
$ip = query($base."/entry:".$cnt."/ipaddr");
if($ip == "")
{
set($base."/entry:".$cnt."/ipaddr", $ipaddr);
set($base."/entry:".$cnt."/prefix", $prefix);
set($base."/entry:".$cnt."/gateway", $gw);
set($base."/entry:".$cnt."/metric", $metric);
set($base."/entry:".$cnt."/inf", $inf);
}
}
/*****************************************/
function remove_route($ipaddr,$prefix,$gw)
{
$base = "/runtime/dynamic/route6";
$cnt = query($base."/entry#");
//msg('remove route: ip:'.$ipaddr.',prefix:'.$prefix.',gw:'.$gw);
$i=1;
while($i<=$cnt)
{
$dest = query($base."/entry:".$i."/ipaddr");
$pfx = query($base."/entry:".$i."/prefix");
$via = query($base."/entry:".$i."/gateway");
//msg('route entry:'.$i.', dest:'.$dest.',pfx:'.$pfx.',via:'.$via);
if($ipaddr==$dest && $prefix==$pfx && $gw==$via)
{
del($base."/entry:".$i);
}
$i++;
}
}
/*****************************************/
function dev_detach($hasevent)
{
$sts = XNODE_getpathbytarget("/runtime", "inf", "uid", $_GLOBALS["INF"], 0);
if ($sts=="") return $_GLOBALS["INF"]." has no runtime nodes.";
if (query($sts."/inet/addrtype")!="ipv6") return $_GLOBALS["INF"]." is not ipv6.";
if (query($sts."/inet/ipv6/valid")!=1) return $_GLOBALS["INF"]." is not active.";
$devnam = query($sts."/devnam");
if ($devnam=="") return $_GLOBALS["INF"]." has no device name.";
anchor($sts."/inet/ipv6");
$mode = query("mode");
$ipaddr = query("ipaddr");
$prefix = query("prefix");
$gw = query("gateway");
$dhcpopt= query("dhcpopt");
$defrt = query($sts."/defaultroute");
//$blackholepfx = query($sts."/blackhole/prefix"); //IOL test
$blackholecnt = query($sts."/blackhole/count"); //IOL test
/* default route */
if ($defrt!="" && $defrt>0)
{
if ($gw!="")
{
cmd("ip -6 route del ::/0 via ".$gw." dev ".$devnam);
remove_route("::","0",$gw);
}
else if ($mode!="TSP")
{
cmd("ip -6 route del ::/0 dev ".$devnam);
remove_route("::","0","");
}
}
else cmd("ip -6 route flush table ".$_GLOBALS["INF"]);
/* TSPC will destroy the tunnel, so we don't need to detach. */
if ($mode != "TSP")
{
/* peer-to-peer */
if ($prefix==128 && $gw!="") cmd("ip -6 route del ".$gw."/128 dev ".$devnam);
/* detach */
if ($mode=="LL") msg($_GLOBALS["INF"].' a is link local interface.');
else if ($mode=="STATEFUL" && $dhcpopt!="IA-PD")
{
msg($_GLOBALS["INF"].' is a stateful-IANA interface.');
$netid = ipv6networkid($ipaddr, $prefix);
remove_route($netid, $prefix, "::");
}
else if ($mode=="STATELESS")
{
msg($_GLOBALS["INF"].' is a stateless interface.');
$netid = ipv6networkid($ipaddr, $prefix);
remove_route($netid, $prefix, "::");
}
else
{
/* check if the $ipaddr is our link-local address */
$phyinf = query($sts."/phyinf");
$path = XNODE_getpathbytarget("/runtime", "phyinf", "uid", $phyinf, 0);
$llipaddr = query($path."/ipv6/link/ipaddr");
$netid = ipv6networkid($ipaddr, $prefix);
//cmd("ip -6 addr del ".$ipaddr."/".$prefix." dev ".$devnam);
if($ipaddr!=$llipaddr)
{
cmd("ip -6 route del ".$netid."/".$prefix." dev ".$devnam);
remove_route($netid, $prefix, "::");
cmd("ip -6 addr del ".$ipaddr."/".$prefix." dev ".$devnam);
}
else msg($ipaddr.' is our link-local address.');
}
}
/* remove blackhole rule if needed */
//if ($blackholepfx != "")
//{
// $blackholeplen = query($sts."/blackhole/plen");
// cmd("ip -6 route del blackhole ".$blackholepfx."/".$blackholeplen." dev lo");
// del($sts."/blackhole");
//}
if($hasevent>0)
{
if ($blackholecnt != "" && $blackholecnt != "0")
{
foreach($sts."/blackhole/entry")
{
if($InDeX > $blackholecnt) break;
$blackholepfx = query($sts."/blackhole/entry:".$InDeX."/prefix");
$blackholeplen = query($sts."/blackhole/entry:".$InDeX."/plen");
cmd("ip -6 route del blackhole ".$blackholepfx."/".$blackholeplen." dev lo");
}
del($sts."/blackhole");
}
if($mode=="STATEFUL") cmd("event WANPORT.LINKUP remove V6CONFIRM");
}
if ($hasevent>0)
{
cmd("rm -f /var/run/".$_GLOBALS["INF"].".UP");
cmd("event ".$_GLOBALS["INF"].".DOWN");
}
del($sts."/inet");
del($sts."/devnam");
del($sts."/pdhint");
//$childip = query($sts."/child/ipaddr");
//$childuid = query($sts."/child/uid");
//if($childip!="") del($sts."/child");
if($hasevent>0)
{
$childip = query($sts."/child/ipaddr");
$childgzip = query($sts."/childgz/ipaddr");
//$childuid = query($sts."/child/uid");
if($childip!="") del($sts."/child");
if($childgzip!="") del($sts."/childgz");
}
}
function dev_attach($hasevent)
{
$cfg = XNODE_getpathbytarget("", "inf", "uid", $_GLOBALS["INF"], 0);
if ($cfg=="") return $_GLOBALS["INF"]." does not exist!";
/* The runtime node of INF should already be created when starting INET service.
* Set the create flag to make sure is will always be created. */
$sts = XNODE_getpathbytarget("/runtime", "inf", "uid", $_GLOBALS["INF"], 1);
/* Just in case the device is still alive. */
if (query($sts."/inet/ipv6/valid")==1) dev_detach(0);
/* Set Child variables */
$child = query($sts."/child/uid");
//msg('child is '.$child);
if ($child!="")
{
$ipaddr = query($sts."/child/ipaddr");
$prefix = query($sts."/child/prefix");
$pdnetwork = query($sts."/child/pdnetwork");
$pdprefix = query($sts."/child/pdprefix");
if ($ipaddr!="" && $prefix!="") $addrtype="ipv6";
XNODE_set_var($child."_ADDRTYPE", $addrtype);
XNODE_set_var($child."_IPADDR", $ipaddr);
XNODE_set_var($child."_PREFIX", $prefix);
XNODE_set_var($child."_PDNETWORK", $pdnetwork);
XNODE_set_var($child."_PDPREFIX", $pdprefix);
}
/* Set guest zone child variables */
$childgz = query($sts."/childgz/uid");
//msg('child guest zone is '.$childgz);
if ($childgz!="")
{
$ipaddr = query($sts."/childgz/ipaddr");
$prefix = query($sts."/childgz/prefix");
$pdnetwork = query($sts."/childgz/pdnetwork");
$pdprefix = query($sts."/childgz/pdprefix");
if ($ipaddr!="" && $prefix!="") $addrtype="ipv6";
XNODE_set_var($childgz."_ADDRTYPE", $addrtype);
XNODE_set_var($childgz."_IPADDR", $ipaddr);
XNODE_set_var($childgz."_PREFIX", $prefix);
XNODE_set_var($childgz."_PDNETWORK", $pdnetwork);
XNODE_set_var($childgz."_PDPREFIX", $pdprefix);
}
/* Get the default metric from config. */
$defrt = query($cfg."/defaultroute");
/***********************************************/
/* Update Status */
$M = $_GLOBALS["MODE"];
anchor($sts);
set("defaultroute", $defrt);
set("devnam", $_GLOBALS["DEVNAM"]);
set("inet/uid", query($cfg."/inet"));
set("inet/addrtype", "ipv6");
set("inet/uptime", query("/runtime/device/uptime"));
set("inet/ipv6/valid", "1");
/* INET */
anchor($sts."/inet/ipv6");
set("mode", $M);
set("ipaddr", $_GLOBALS["IPADDR"]);
set("prefix", $_GLOBALS["PREFIX"]);
set("gateway", $_GLOBALS["GATEWAY"]);
set("routerlft",$_GLOBALS["ROUTERLFT"]);
set("preferlft",$_GLOBALS["PREFERLFT"]);
set("validlft", $_GLOBALS["VALIDLFT"]);
/* DNS & ROUTING */
add_each($_GLOBALS["DNS"], $sts."/inet/ipv6", "dns");
/***********************************************/
/* attach */
$dhcpopt = query("dhcpopt");
if ($M=="LL") msg($_GLOBALS["INF"].' a is link local interface.');
else if ($M=="STATELESS") msg($_GLOBALS["INF"].' is a self-configured interface.');
else if ($M=="STATEFUL" && $dhcpopt!="IA-PD") msg($_GLOBALS["INF"].' is a stateful-IANA interface.');
else cmd("ip -6 addr add ".$_GLOBALS["IPADDR"]."/".$_GLOBALS["PREFIX"]." dev ".$_GLOBALS["DEVNAM"]);
/* IOL test */
$pidfile = "/var/servd/".$_GLOBALS["INF"]."-dhcp6c.pid";
if($M=="STATEFUL")
cmd('event WANPORT.LINKUP insert V6CONFIRM:"kill -SIGUSR1 `cat '.$pidfile.'`"');
if($M!="LL")
{
$rtnetid = ipv6networkid($_GLOBALS["IPADDR"], $_GLOBALS["PREFIX"]);
if($rtnetid!="fe80::")
add_route($rtnetid, $_GLOBALS["PREFIX"], "::", "256", $_GLOBALS["INF"]);
}
/* Handle the peer-to-peer connection. */
if ($_GLOBALS["PREFIX"]==128 && $_GLOBALS["GATEWAY"]!="")
cmd("ip -6 route add ".$_GLOBALS["GATEWAY"]."/128 dev ".$_GLOBALS["DEVNAM"]);
/* gateway */
if ($defrt!="" && $defrt>0)
{
if ($_GLOBALS["GATEWAY"]!="")
{
cmd("ip -6 route add ::/0 via ".$_GLOBALS["GATEWAY"]." dev ".$_GLOBALS["DEVNAM"]." metric ".$defrt);
add_route("::", "0", $_GLOBALS["GATEWAY"], $defrt, $_GLOBALS["INF"]);
}
}
else
{
$netid = ipv6networkid($_GLOBALS["IPADDR"], $_GLOBALS["PREFIX"]);
cmd("ip -6 route add ".$netid."/".$_GLOBALS["PREFIX"]." dev ".$_GLOBALS["DEVNAM"].
" src ".$_GLOBALS["IPADDR"]." table ".$_GLOBALS["INF"]);
}
/* Routing */
// Currently, the INF specific routing table is not used. by David.
//$hasroute=0;
//if ($hasroute>0) echo "ip -6 rule add table ".$_GLOBALS["INF"]." prio 30000\n";
if ($hasevent>0)
{
cmd("event ".$_GLOBALS["INF"].".UP");
cmd("echo 1 > /var/run/".$_GLOBALS["INF"].".UP");
}
}
function main_entry()
{
if ($_GLOBALS["INF"]=="") return "No INF !!";
if ($_GLOBALS["ACTION"]=="ATTACH") return dev_attach(1);
else if ($_GLOBALS["ACTION"]=="DETACH") return dev_detach(1);
return "Unknown action - ".$_GLOBALS["ACTION"];
}
/*****************************************/
/* Required variables:
*
* ACTION: ATTACH/DETACH
* MODE: IPv6 mode
* INF: Interface UID
* DEVNAM: device name
* IPADDR: IP address
* PREFIX: Prefix length
* GATEWAY: Gateway
* ROUTERLFT: Router lift time
* PREFERLFT: Prefer lift time
* VALIDLFT: Valid lift time
* DNS: DNS servers
*/
$ret = main_entry();
if ($ret!="") cmd("# ".$ret."\nexit 9\n");
else cmd("exit 0\n");
?>