1implement Dhcp; 2 3# 4# configure an interface using DHCP 5# 6 7include "sys.m"; 8 sys: Sys; 9 10include "draw.m"; 11 12include "ip.m"; 13 ip: IP; 14 IPv4off, IPaddrlen: import IP; 15 IPaddr: import ip; 16 get2, get4, put2, put4: import ip; 17 18include "dhcp.m"; 19 dhcpclient: Dhcpclient; 20 Bootconf, Lease: import dhcpclient; 21 22include "arg.m"; 23 24Dhcp: module 25{ 26 init: fn(nil: ref Draw->Context, nil: list of string); 27}; 28 29RetryTime: con 10*1000; # msec 30 31init(nil: ref Draw->Context, args: list of string) 32{ 33 sys = load Sys Sys->PATH; 34 ip = load IP IP->PATH; 35 dhcpclient = load Dhcpclient Dhcpclient->PATH; 36 37 sys->pctl(Sys->NEWFD|Sys->NEWPGRP, 0 :: 1 :: 2 :: nil); 38 39 arg := load Arg Arg->PATH; 40 arg->init(args); 41 arg->setusage("dhcp [-bdmnpr] [-g ipgw] [-h hostname] [-x /net] ifcdir [ip [ipmask]]"); 42 trace := 0; 43 pcfg := 0; 44 bootp := 0; 45 monitor := 0; 46 retry := 0; 47 noctl := 0; 48 netdir := "/net"; 49 cfg := Bootconf.new(); 50 while((o := arg->opt()) != 0) 51 case o { 52 'b' => bootp = 1; 53 'd' => trace++; 54 'g' => cfg.ipgw = arg->earg(); 55 'h' => cfg.puts(Dhcpclient->Ohostname, arg->earg()); 56 'm' => monitor = 1; 57 'n' => noctl = 1; 58 'p' => pcfg = 1; 59 'r' => retry = 1; 60 'x' => netdir = arg->earg(); 61 * => arg->usage(); 62 } 63 args = arg->argv(); 64 if(len args == 0) 65 arg->usage(); 66 67 ifcdir := hd args; 68 args = tl args; 69 if(args != nil){ 70 cfg.ip = hd args; 71 args = tl args; 72 if(args != nil){ 73 cfg.ipmask = hd args; 74 args = tl args; 75 if(args != nil) 76 arg->usage(); 77 } 78 } 79 arg = nil; 80 81 ifcctl: ref Sys->FD; 82 if(noctl == 0){ 83 ifcctl = sys->open(ifcdir+"/ctl", Sys->OWRITE); 84 if(ifcctl == nil) 85 err(sys->sprint("cannot open %s/ctl: %r", ifcdir)); 86 } 87 etherdir := finddev(ifcdir); 88 if(etherdir == nil) 89 err(sys->sprint("cannot find network device in %s/status: %r", ifcdir)); 90 if(etherdir[0] != '/' && etherdir[0] != '#') 91 etherdir = netdir+"/"+etherdir; 92 93 ip->init(); 94 dhcpclient->init(); 95 dhcpclient->tracing(trace); 96 e: string; 97 lease: ref Lease; 98 for(;;){ 99 if(bootp){ 100 (cfg, e) = dhcpclient->bootp(netdir, ifcctl, etherdir+"/addr", cfg); 101 if(e == nil){ 102 if(cfg != nil) 103 dhcpclient->applycfg(netdir, ifcctl, cfg); 104 if(pcfg) 105 printcfg(cfg); 106 break; 107 } 108 }else{ 109 (cfg, lease, e) = dhcpclient->dhcp(netdir, ifcctl, etherdir+"/addr", cfg, nil); # last is array of int options 110 if(e == nil){ 111 if(pcfg) 112 printcfg(cfg); 113 if(cfg.lease > 0 && monitor) 114 leasemon(lease.configs, pcfg); 115 break; 116 } 117 } 118 if(!retry) 119 err("failed to configure network: "+e); 120 sys->fprint(sys->fildes(2), "dhcp: failed to configure network: %s; retrying", e); 121 sys->sleep(RetryTime); 122 } 123} 124 125leasemon(configs: chan of (ref Bootconf, string), pcfg: int) 126{ 127 for(;;){ 128 (cfg, e) := <-configs; 129 if(e != nil) 130 sys->fprint(sys->fildes(2), "dhcp: %s", e); 131 if(pcfg) 132 printcfg(cfg); 133 } 134} 135 136printcfg(cfg: ref Bootconf) 137{ 138 sys->print("ip=%s ipmask=%s ipgw=%s iplease=%d\n", cfg.ip, cfg.ipmask, cfg.ipgw, cfg.lease); 139} 140 141finddev(ifcdir: string): string 142{ 143 fd := sys->open(ifcdir+"/status", Sys->OREAD); 144 if(fd == nil) 145 return nil; 146 buf := array[1024] of byte; 147 n := sys->read(fd, buf, len buf); 148 if(n < 0) 149 return nil; 150 (nf, l) := sys->tokenize(string buf[0:n], " \n"); 151 if(nf < 2){ 152 sys->werrstr("unexpected format for status file"); 153 return nil; 154 } 155 return hd tl l; 156} 157 158err(s: string) 159{ 160 sys->fprint(sys->fildes(2), "dhcp: %s\n", s); 161 raise "fail:error"; 162} 163