17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ip.h>
47dd7cddfSDavid du Colombier #include <bio.h>
57dd7cddfSDavid du Colombier #include <ndb.h>
67dd7cddfSDavid du Colombier #include "dat.h"
77dd7cddfSDavid du Colombier
82ddf2468SDavid du Colombier /*
92ddf2468SDavid du Colombier * ala rfc2131
102ddf2468SDavid du Colombier */
117dd7cddfSDavid du Colombier
120a84db5eSDavid du Colombier enum {
130a84db5eSDavid du Colombier Maxloglen = 1024,
140a84db5eSDavid du Colombier };
150a84db5eSDavid du Colombier
167dd7cddfSDavid du Colombier typedef struct Req Req;
177dd7cddfSDavid du Colombier struct Req
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier int fd; /* for reply */
207dd7cddfSDavid du Colombier Bootp *bp;
21f27a9a5aSDavid du Colombier Udphdr *up;
227dd7cddfSDavid du Colombier uchar *e; /* end of received message */
237dd7cddfSDavid du Colombier uchar *p; /* options pointer */
247dd7cddfSDavid du Colombier uchar *max; /* max end of reply */
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier /* expanded to v6 */
277dd7cddfSDavid du Colombier uchar ciaddr[IPaddrlen];
287dd7cddfSDavid du Colombier uchar giaddr[IPaddrlen];
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier /* parsed options */
312ddf2468SDavid du Colombier int p9request; /* flag: this is a bootp with plan9 options */
322ddf2468SDavid du Colombier int genrequest; /* flag: this is a bootp with generic options */
338ae63d3dSDavid du Colombier int broadcast; /* flag: request was broadcast */
347dd7cddfSDavid du Colombier int dhcptype; /* dhcp message type */
357dd7cddfSDavid du Colombier int leasetime; /* dhcp lease */
367dd7cddfSDavid du Colombier uchar ip[IPaddrlen]; /* requested address */
377dd7cddfSDavid du Colombier uchar server[IPaddrlen]; /* server address */
389a747e4fSDavid du Colombier char msg[ERRMAX]; /* error message */
397dd7cddfSDavid du Colombier char vci[32]; /* vendor class id */
407dd7cddfSDavid du Colombier char *id; /* client id */
417dd7cddfSDavid du Colombier uchar requested[32]; /* requested params */
427dd7cddfSDavid du Colombier uchar vendorclass[32];
437dd7cddfSDavid du Colombier char cputype[32-3];
447dd7cddfSDavid du Colombier
457dd7cddfSDavid du Colombier Info gii; /* about target network */
467dd7cddfSDavid du Colombier Info ii; /* about target system */
477dd7cddfSDavid du Colombier int staticbinding;
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier uchar buf[2*1024]; /* message buffer */
507dd7cddfSDavid du Colombier };
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier #define TFTP "/lib/tftpd"
532ddf2468SDavid du Colombier
547dd7cddfSDavid du Colombier char *blog = "ipboot";
557dd7cddfSDavid du Colombier char mysysname[64];
567dd7cddfSDavid du Colombier Ipifc *ipifcs;
577dd7cddfSDavid du Colombier int debug;
587dd7cddfSDavid du Colombier int nobootp;
597dd7cddfSDavid du Colombier long now;
60e183b1a6SDavid du Colombier int slowstat, slowdyn;
619a747e4fSDavid du Colombier char net[256];
627dd7cddfSDavid du Colombier
632ddf2468SDavid du Colombier int pptponly; /* only answer request that came from the pptp server */
64e183b1a6SDavid du Colombier int mute, mutestat;
657dd7cddfSDavid du Colombier int minlease = MinLease;
662ddf2468SDavid du Colombier int staticlease = StaticLease;
677dd7cddfSDavid du Colombier
68e47b3901SDavid du Colombier uvlong start;
693ff48bf5SDavid du Colombier
700a84db5eSDavid du Colombier static int v6opts;
710a84db5eSDavid du Colombier
727dd7cddfSDavid du Colombier /* option magic */
737dd7cddfSDavid du Colombier char plan9opt[4] = { 'p', '9', ' ', ' ' };
747dd7cddfSDavid du Colombier char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 };
757dd7cddfSDavid du Colombier
767dd7cddfSDavid du Colombier /* well known addresses */
777dd7cddfSDavid du Colombier uchar zeros[Maxhwlen];
787dd7cddfSDavid du Colombier
793ff48bf5SDavid du Colombier /* option debug buffer */
803ff48bf5SDavid du Colombier char optbuf[1024];
813ff48bf5SDavid du Colombier char *op;
823ff48bf5SDavid du Colombier char *oe = optbuf + sizeof(optbuf);
833ff48bf5SDavid du Colombier
843ff48bf5SDavid du Colombier char *optname[256] =
853ff48bf5SDavid du Colombier {
863ff48bf5SDavid du Colombier [OBend] "end",
873ff48bf5SDavid du Colombier [OBpad] "pad",
883ff48bf5SDavid du Colombier [OBmask] "mask",
893ff48bf5SDavid du Colombier [OBtimeoff] "timeoff",
903ff48bf5SDavid du Colombier [OBrouter] "router",
913ff48bf5SDavid du Colombier [OBtimeserver] "time",
923ff48bf5SDavid du Colombier [OBnameserver] "name",
933ff48bf5SDavid du Colombier [OBdnserver] "dns",
943ff48bf5SDavid du Colombier [OBlogserver] "log",
953ff48bf5SDavid du Colombier [OBcookieserver] "cookie",
963ff48bf5SDavid du Colombier [OBlprserver] "lpr",
973ff48bf5SDavid du Colombier [OBimpressserver] "impress",
983ff48bf5SDavid du Colombier [OBrlserver] "rl",
993ff48bf5SDavid du Colombier [OBhostname] "host",
1003ff48bf5SDavid du Colombier [OBbflen] "bflen",
1013ff48bf5SDavid du Colombier [OBdumpfile] "dumpfile",
1023ff48bf5SDavid du Colombier [OBdomainname] "dom",
1033ff48bf5SDavid du Colombier [OBswapserver] "swap",
1043ff48bf5SDavid du Colombier [OBrootpath] "rootpath",
1053ff48bf5SDavid du Colombier [OBextpath] "extpath",
1063ff48bf5SDavid du Colombier [OBipforward] "ipforward",
1073ff48bf5SDavid du Colombier [OBnonlocal] "nonlocal",
1083ff48bf5SDavid du Colombier [OBpolicyfilter] "policyfilter",
1093ff48bf5SDavid du Colombier [OBmaxdatagram] "maxdatagram",
1103ff48bf5SDavid du Colombier [OBttl] "ttl",
1113ff48bf5SDavid du Colombier [OBpathtimeout] "pathtimeout",
1123ff48bf5SDavid du Colombier [OBpathplateau] "pathplateau",
1133ff48bf5SDavid du Colombier [OBmtu] "mtu",
1143ff48bf5SDavid du Colombier [OBsubnetslocal] "subnetslocal",
1153ff48bf5SDavid du Colombier [OBbaddr] "baddr",
1163ff48bf5SDavid du Colombier [OBdiscovermask] "discovermask",
1173ff48bf5SDavid du Colombier [OBsupplymask] "supplymask",
1183ff48bf5SDavid du Colombier [OBdiscoverrouter] "discoverrouter",
1193ff48bf5SDavid du Colombier [OBrsserver] "rsserver",
1203ff48bf5SDavid du Colombier [OBstaticroutes] "staticroutes",
1213ff48bf5SDavid du Colombier [OBtrailerencap] "trailerencap",
1223ff48bf5SDavid du Colombier [OBarptimeout] "arptimeout",
1233ff48bf5SDavid du Colombier [OBetherencap] "etherencap",
1243ff48bf5SDavid du Colombier [OBtcpttl] "tcpttl",
1253ff48bf5SDavid du Colombier [OBtcpka] "tcpka",
1263ff48bf5SDavid du Colombier [OBtcpkag] "tcpkag",
1273ff48bf5SDavid du Colombier [OBnisdomain] "nisdomain",
1283ff48bf5SDavid du Colombier [OBniserver] "niserver",
1293ff48bf5SDavid du Colombier [OBntpserver] "ntpserver",
1303ff48bf5SDavid du Colombier [OBvendorinfo] "vendorinfo",
1313ff48bf5SDavid du Colombier [OBnetbiosns] "NBns",
1323ff48bf5SDavid du Colombier [OBnetbiosdds] "NBdds",
1333ff48bf5SDavid du Colombier [OBnetbiostype] "NBtype",
1343ff48bf5SDavid du Colombier [OBnetbiosscope] "NBscope",
1353ff48bf5SDavid du Colombier [OBxfontserver] "xfont",
1363ff48bf5SDavid du Colombier [OBxdispmanager] "xdisp",
1373ff48bf5SDavid du Colombier [OBnisplusdomain] "NPdomain",
1383ff48bf5SDavid du Colombier [OBnisplusserver] "NP",
1393ff48bf5SDavid du Colombier [OBhomeagent] "homeagent",
1403ff48bf5SDavid du Colombier [OBsmtpserver] "smtp",
1413ff48bf5SDavid du Colombier [OBpop3server] "pop3",
1423ff48bf5SDavid du Colombier [OBnntpserver] "nntp",
1433ff48bf5SDavid du Colombier [OBwwwserver] "www",
1443ff48bf5SDavid du Colombier [OBfingerserver] "finger",
1453ff48bf5SDavid du Colombier [OBircserver] "ircserver",
1463ff48bf5SDavid du Colombier [OBstserver] "stserver",
1473ff48bf5SDavid du Colombier [OBstdaserver] "stdaserver",
1483ff48bf5SDavid du Colombier
1493ff48bf5SDavid du Colombier /* dhcp options */
1503ff48bf5SDavid du Colombier [ODipaddr] "ip",
1513ff48bf5SDavid du Colombier [ODlease] "leas",
1523ff48bf5SDavid du Colombier [ODoverload] "overload",
1533ff48bf5SDavid du Colombier [ODtype] "typ",
1543ff48bf5SDavid du Colombier [ODserverid] "sid",
1553ff48bf5SDavid du Colombier [ODparams] "params",
1563ff48bf5SDavid du Colombier [ODmessage] "message",
1573ff48bf5SDavid du Colombier [ODmaxmsg] "maxmsg",
1583ff48bf5SDavid du Colombier [ODrenewaltime] "renewaltime",
1593ff48bf5SDavid du Colombier [ODrebindingtime] "rebindingtime",
1603ff48bf5SDavid du Colombier [ODvendorclass] "vendorclass",
1613ff48bf5SDavid du Colombier [ODclientid] "cid",
1623ff48bf5SDavid du Colombier [ODtftpserver] "tftpserver",
1633ff48bf5SDavid du Colombier [ODbootfile] "bf",
1643ff48bf5SDavid du Colombier };
1653ff48bf5SDavid du Colombier
1667dd7cddfSDavid du Colombier void addropt(Req*, int, uchar*);
1677dd7cddfSDavid du Colombier void addrsopt(Req*, int, uchar**, int);
1687dd7cddfSDavid du Colombier void arpenter(uchar*, uchar*);
1697dd7cddfSDavid du Colombier void bootp(Req*);
1707dd7cddfSDavid du Colombier void byteopt(Req*, int, uchar);
1717dd7cddfSDavid du Colombier void dhcp(Req*);
1727dd7cddfSDavid du Colombier void fatal(int, char*, ...);
1737dd7cddfSDavid du Colombier void hexopt(Req*, int, char*);
1742ddf2468SDavid du Colombier void logdhcp(Req*);
1752ddf2468SDavid du Colombier void logdhcpout(Req *, char *);
1767dd7cddfSDavid du Colombier void longopt(Req*, int, long);
1773ff48bf5SDavid du Colombier void maskopt(Req*, int, uchar*);
1787dd7cddfSDavid du Colombier void miscoptions(Req*, uchar*);
1797dd7cddfSDavid du Colombier int openlisten(char *net);
1800a84db5eSDavid du Colombier void p9addrsopt(Req *rp, int t, uchar **ip, int i);
1817dd7cddfSDavid du Colombier void parseoptions(Req*);
1827dd7cddfSDavid du Colombier void proto(Req*, int);
1837dd7cddfSDavid du Colombier void rcvdecline(Req*);
1847dd7cddfSDavid du Colombier void rcvdiscover(Req*);
1857dd7cddfSDavid du Colombier void rcvinform(Req*);
1867dd7cddfSDavid du Colombier void rcvrelease(Req*);
1877dd7cddfSDavid du Colombier void rcvrequest(Req*);
1882ddf2468SDavid du Colombier int readlast(int, uchar*, int);
1897dd7cddfSDavid du Colombier char* readsysname(void);
1907dd7cddfSDavid du Colombier void remrequested(Req*, int);
1917dd7cddfSDavid du Colombier void sendack(Req*, uchar*, int, int);
1927dd7cddfSDavid du Colombier void sendnak(Req*, char*);
1937dd7cddfSDavid du Colombier void sendoffer(Req*, uchar*, int);
1947dd7cddfSDavid du Colombier void stringopt(Req*, int, char*);
1957dd7cddfSDavid du Colombier void termopt(Req*);
1967dd7cddfSDavid du Colombier int validip(uchar*);
1977dd7cddfSDavid du Colombier void vectoropt(Req*, int, uchar*, int);
1987dd7cddfSDavid du Colombier void warning(int, char*, ...);
1993ff48bf5SDavid du Colombier
2003ff48bf5SDavid du Colombier void
timestamp(char * tag)2013ff48bf5SDavid du Colombier timestamp(char *tag)
2023ff48bf5SDavid du Colombier {
203e47b3901SDavid du Colombier uvlong t;
2043ff48bf5SDavid du Colombier
2053ff48bf5SDavid du Colombier t = nsec()/1000;
206e47b3901SDavid du Colombier syslog(0, blog, "%s %lludµs", tag, t - start);
2073ff48bf5SDavid du Colombier }
2087dd7cddfSDavid du Colombier
2097dd7cddfSDavid du Colombier void
usage(void)2107dd7cddfSDavid du Colombier usage(void)
2117dd7cddfSDavid du Colombier {
2122ddf2468SDavid du Colombier fprint(2, "usage: dhcp [-dmnprsSZ] [-f directory] [-M minlease] "
2132ddf2468SDavid du Colombier "[-x netmtpt] [-Z staticlease] addr n [addr n] ...\n");
2147dd7cddfSDavid du Colombier exits("usage");
2157dd7cddfSDavid du Colombier }
2167dd7cddfSDavid du Colombier
2177dd7cddfSDavid du Colombier void
main(int argc,char ** argv)2187dd7cddfSDavid du Colombier main(int argc, char **argv)
2197dd7cddfSDavid du Colombier {
2203ff48bf5SDavid du Colombier int i, n, fd;
2217dd7cddfSDavid du Colombier uchar ip[IPaddrlen];
2227dd7cddfSDavid du Colombier Req r;
2237dd7cddfSDavid du Colombier
2242ddf2468SDavid du Colombier setnetmtpt(net, sizeof net, nil);
2257dd7cddfSDavid du Colombier
2269a747e4fSDavid du Colombier fmtinstall('E', eipfmt);
2279a747e4fSDavid du Colombier fmtinstall('I', eipfmt);
2289a747e4fSDavid du Colombier fmtinstall('V', eipfmt);
2299a747e4fSDavid du Colombier fmtinstall('M', eipfmt);
2307dd7cddfSDavid du Colombier ARGBEGIN {
2310a84db5eSDavid du Colombier case '6':
2320a84db5eSDavid du Colombier v6opts = 1;
2330a84db5eSDavid du Colombier break;
2347dd7cddfSDavid du Colombier case 'd':
2357dd7cddfSDavid du Colombier debug = 1;
2367dd7cddfSDavid du Colombier break;
2377dd7cddfSDavid du Colombier case 'f':
2382ddf2468SDavid du Colombier ndbfile = EARGF(usage());
2397dd7cddfSDavid du Colombier break;
2402ddf2468SDavid du Colombier case 'm':
2412ddf2468SDavid du Colombier mute = 1;
242e183b1a6SDavid du Colombier break;
2432ddf2468SDavid du Colombier case 'M':
2442ddf2468SDavid du Colombier minlease = atoi(EARGF(usage()));
2452ddf2468SDavid du Colombier if(minlease <= 0)
2462ddf2468SDavid du Colombier minlease = MinLease;
2477dd7cddfSDavid du Colombier break;
2487dd7cddfSDavid du Colombier case 'n':
2497dd7cddfSDavid du Colombier nobootp = 1;
2507dd7cddfSDavid du Colombier break;
2517dd7cddfSDavid du Colombier case 'p':
2527dd7cddfSDavid du Colombier pptponly = 1;
2537dd7cddfSDavid du Colombier break;
254e183b1a6SDavid du Colombier case 'r':
255e183b1a6SDavid du Colombier mutestat = 1;
256e183b1a6SDavid du Colombier break;
2572ddf2468SDavid du Colombier case 's':
2582ddf2468SDavid du Colombier slowstat = 1;
2597dd7cddfSDavid du Colombier break;
2602ddf2468SDavid du Colombier case 'S':
2612ddf2468SDavid du Colombier slowdyn = 1;
2622ddf2468SDavid du Colombier break;
2632ddf2468SDavid du Colombier case 'x':
2642ddf2468SDavid du Colombier setnetmtpt(net, sizeof net, EARGF(usage()));
2652ddf2468SDavid du Colombier break;
2662ddf2468SDavid du Colombier case 'Z':
2672ddf2468SDavid du Colombier staticlease = atoi(EARGF(usage()));
2682ddf2468SDavid du Colombier if(staticlease <= 0)
2692ddf2468SDavid du Colombier staticlease = StaticLease;
2702ddf2468SDavid du Colombier break;
2712ddf2468SDavid du Colombier default:
2727dd7cddfSDavid du Colombier usage();
2737dd7cddfSDavid du Colombier break;
2747dd7cddfSDavid du Colombier } ARGEND;
2757dd7cddfSDavid du Colombier
2767dd7cddfSDavid du Colombier while(argc > 1){
2777dd7cddfSDavid du Colombier parseip(ip, argv[0]);
2787dd7cddfSDavid du Colombier if(!validip(ip))
2797dd7cddfSDavid du Colombier usage();
2807dd7cddfSDavid du Colombier n = atoi(argv[1]);
2817dd7cddfSDavid du Colombier if(n <= 0)
2827dd7cddfSDavid du Colombier usage();
2837dd7cddfSDavid du Colombier initbinding(ip, n);
2847dd7cddfSDavid du Colombier argc -= 2;
2857dd7cddfSDavid du Colombier argv += 2;
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier
2883ff48bf5SDavid du Colombier /* for debugging */
2893ff48bf5SDavid du Colombier for(i = 0; i < 256; i++)
2903ff48bf5SDavid du Colombier if(optname[i] == 0)
2913ff48bf5SDavid du Colombier optname[i] = smprint("%d", i);
2923ff48bf5SDavid du Colombier
2937dd7cddfSDavid du Colombier /* what is my name? */
2942ddf2468SDavid du Colombier strcpy(mysysname, readsysname());
2957dd7cddfSDavid du Colombier
2967dd7cddfSDavid du Colombier /* put process in background */
2970a84db5eSDavid du Colombier if(!debug)
2980a84db5eSDavid du Colombier switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
2997dd7cddfSDavid du Colombier case -1:
3007dd7cddfSDavid du Colombier fatal(1, "fork");
3017dd7cddfSDavid du Colombier case 0:
3027dd7cddfSDavid du Colombier break;
3037dd7cddfSDavid du Colombier default:
3047dd7cddfSDavid du Colombier exits(0);
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier
307ea58ad6fSDavid du Colombier if (chdir(TFTP) < 0)
308ea58ad6fSDavid du Colombier warning(1, "can't change directory to %s", TFTP);
3097dd7cddfSDavid du Colombier fd = openlisten(net);
3107dd7cddfSDavid du Colombier
3117dd7cddfSDavid du Colombier for(;;){
3127dd7cddfSDavid du Colombier memset(&r, 0, sizeof(r));
3137dd7cddfSDavid du Colombier r.fd = fd;
3143ff48bf5SDavid du Colombier n = readlast(r.fd, r.buf, sizeof(r.buf));
315f27a9a5aSDavid du Colombier if(n < Udphdrsize)
3167dd7cddfSDavid du Colombier fatal(1, "error reading requests");
3173ff48bf5SDavid du Colombier start = nsec()/1000;
3183ff48bf5SDavid du Colombier op = optbuf;
3193ff48bf5SDavid du Colombier *op = 0;
3207dd7cddfSDavid du Colombier proto(&r, n);
3217dd7cddfSDavid du Colombier if(r.id != nil)
3227dd7cddfSDavid du Colombier free(r.id);
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier
3267dd7cddfSDavid du Colombier void
proto(Req * rp,int n)3277dd7cddfSDavid du Colombier proto(Req *rp, int n)
3287dd7cddfSDavid du Colombier {
3297dd7cddfSDavid du Colombier uchar relip[IPaddrlen];
3307dd7cddfSDavid du Colombier char buf[64];
3317dd7cddfSDavid du Colombier
3327dd7cddfSDavid du Colombier now = time(0);
3337dd7cddfSDavid du Colombier
3347dd7cddfSDavid du Colombier rp->e = rp->buf + n;
3357dd7cddfSDavid du Colombier rp->bp = (Bootp*)rp->buf;
336f27a9a5aSDavid du Colombier rp->up = (Udphdr*)rp->buf;
3378ae63d3dSDavid du Colombier if (ipcmp(rp->up->laddr, IPv4bcast) == 0){
338decede3dSDavid du Colombier ipmove(rp->up->laddr, rp->up->ifcaddr);
3398ae63d3dSDavid du Colombier rp->broadcast = 1;
3408ae63d3dSDavid du Colombier }
341f27a9a5aSDavid du Colombier rp->max = rp->buf + Udphdrsize + MINSUPPORTED - IPUDPHDRSIZE;
3427dd7cddfSDavid du Colombier rp->p = rp->bp->optdata;
3437dd7cddfSDavid du Colombier v4tov6(rp->giaddr, rp->bp->giaddr);
3447dd7cddfSDavid du Colombier v4tov6(rp->ciaddr, rp->bp->ciaddr);
3457dd7cddfSDavid du Colombier
3467dd7cddfSDavid du Colombier if(pptponly && rp->bp->htype != 0)
3477dd7cddfSDavid du Colombier return;
3487dd7cddfSDavid du Colombier
3499a747e4fSDavid du Colombier ipifcs = readipifc(net, ipifcs, -1);
3507dd7cddfSDavid du Colombier if(validip(rp->giaddr))
3517dd7cddfSDavid du Colombier ipmove(relip, rp->giaddr);
3527dd7cddfSDavid du Colombier else if(validip(rp->up->raddr))
3537dd7cddfSDavid du Colombier ipmove(relip, rp->up->raddr);
3547dd7cddfSDavid du Colombier else
3557dd7cddfSDavid du Colombier ipmove(relip, rp->up->laddr);
3567dd7cddfSDavid du Colombier if(rp->e < (uchar*)rp->bp->sname){
3577dd7cddfSDavid du Colombier warning(0, "packet too short");
3587dd7cddfSDavid du Colombier return;
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier if(rp->bp->op != Bootrequest){
3617dd7cddfSDavid du Colombier warning(0, "not bootrequest");
3627dd7cddfSDavid du Colombier return;
3637dd7cddfSDavid du Colombier }
3647dd7cddfSDavid du Colombier
3657dd7cddfSDavid du Colombier if(rp->e >= rp->bp->optdata){
3667dd7cddfSDavid du Colombier if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0)
3677dd7cddfSDavid du Colombier rp->p9request = 1;
3687dd7cddfSDavid du Colombier if(memcmp(rp->bp->optmagic, genericopt, sizeof(rp->bp->optmagic)) == 0) {
3697dd7cddfSDavid du Colombier rp->genrequest = 1;
3707dd7cddfSDavid du Colombier parseoptions(rp);
3713ff48bf5SDavid du Colombier }
3723ff48bf5SDavid du Colombier }
3737dd7cddfSDavid du Colombier rp->p = rp->bp->optdata;
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier /* If no id is specified, make one from the hardware address
3767dd7cddfSDavid du Colombier * of the target. We assume all zeros is not a hardware address
3777dd7cddfSDavid du Colombier * which could be a mistake.
3787dd7cddfSDavid du Colombier */
3797dd7cddfSDavid du Colombier if(rp->id == nil){
3807dd7cddfSDavid du Colombier if(rp->bp->hlen > Maxhwlen){
3817dd7cddfSDavid du Colombier warning(0, "hlen %d", rp->bp->hlen);
3827dd7cddfSDavid du Colombier return;
3837dd7cddfSDavid du Colombier }
3847dd7cddfSDavid du Colombier if(memcmp(zeros, rp->bp->chaddr, rp->bp->hlen) == 0){
3857dd7cddfSDavid du Colombier warning(0, "no chaddr");
3867dd7cddfSDavid du Colombier return;
3877dd7cddfSDavid du Colombier }
3887dd7cddfSDavid du Colombier sprint(buf, "hwa%2.2ux_", rp->bp->htype);
3897dd7cddfSDavid du Colombier rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen);
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier
3927dd7cddfSDavid du Colombier /* info about gateway */
3933ff48bf5SDavid du Colombier if(lookupip(relip, &rp->gii, 1) < 0){
3947dd7cddfSDavid du Colombier warning(0, "lookupip failed");
3957dd7cddfSDavid du Colombier return;
3967dd7cddfSDavid du Colombier }
3977dd7cddfSDavid du Colombier
3987dd7cddfSDavid du Colombier /* info about target system */
3997dd7cddfSDavid du Colombier if(lookup(rp->bp, &rp->ii, &rp->gii) == 0)
4007dd7cddfSDavid du Colombier if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0)
4017dd7cddfSDavid du Colombier rp->staticbinding = 1;
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier if(rp->dhcptype)
4047dd7cddfSDavid du Colombier dhcp(rp);
4057dd7cddfSDavid du Colombier else
4067dd7cddfSDavid du Colombier bootp(rp);
4073ff48bf5SDavid du Colombier timestamp("done");
4087dd7cddfSDavid du Colombier }
4097dd7cddfSDavid du Colombier
4108ae63d3dSDavid du Colombier /*
4118ae63d3dSDavid du Colombier * since we are single-threaded, this causes us to effectively
412*588d0145SDavid du Colombier * stop listening while we sleep.
4138ae63d3dSDavid du Colombier */
414e183b1a6SDavid du Colombier static void
slowdelay(Req * rp)415e183b1a6SDavid du Colombier slowdelay(Req *rp)
416e183b1a6SDavid du Colombier {
417e183b1a6SDavid du Colombier if(slowstat && rp->staticbinding || slowdyn && !rp->staticbinding)
418*588d0145SDavid du Colombier sleep(1000);
419e183b1a6SDavid du Colombier }
420e183b1a6SDavid du Colombier
4217dd7cddfSDavid du Colombier void
dhcp(Req * rp)4227dd7cddfSDavid du Colombier dhcp(Req *rp)
4237dd7cddfSDavid du Colombier {
4247dd7cddfSDavid du Colombier logdhcp(rp);
4257dd7cddfSDavid du Colombier
4267dd7cddfSDavid du Colombier switch(rp->dhcptype){
4277dd7cddfSDavid du Colombier case Discover:
428e183b1a6SDavid du Colombier slowdelay(rp);
4297dd7cddfSDavid du Colombier rcvdiscover(rp);
4307dd7cddfSDavid du Colombier break;
4317dd7cddfSDavid du Colombier case Request:
4327dd7cddfSDavid du Colombier rcvrequest(rp);
4337dd7cddfSDavid du Colombier break;
4347dd7cddfSDavid du Colombier case Decline:
4357dd7cddfSDavid du Colombier rcvdecline(rp);
4367dd7cddfSDavid du Colombier break;
4377dd7cddfSDavid du Colombier case Release:
4387dd7cddfSDavid du Colombier rcvrelease(rp);
4397dd7cddfSDavid du Colombier break;
4407dd7cddfSDavid du Colombier case Inform:
4417dd7cddfSDavid du Colombier rcvinform(rp);
4427dd7cddfSDavid du Colombier break;
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier
4467dd7cddfSDavid du Colombier void
rcvdiscover(Req * rp)4477dd7cddfSDavid du Colombier rcvdiscover(Req *rp)
4487dd7cddfSDavid du Colombier {
4497dd7cddfSDavid du Colombier Binding *b, *nb;
4507dd7cddfSDavid du Colombier
4517dd7cddfSDavid du Colombier if(rp->staticbinding){
4522ddf2468SDavid du Colombier sendoffer(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease));
4537dd7cddfSDavid du Colombier return;
4547dd7cddfSDavid du Colombier }
4557dd7cddfSDavid du Colombier
4567dd7cddfSDavid du Colombier /*
4577dd7cddfSDavid du Colombier * first look for an outstanding offer
4587dd7cddfSDavid du Colombier */
4597dd7cddfSDavid du Colombier b = idtooffer(rp->id, &rp->gii);
4607dd7cddfSDavid du Colombier
4617dd7cddfSDavid du Colombier /*
4627dd7cddfSDavid du Colombier * rfc2131 says:
4637dd7cddfSDavid du Colombier * If an address is available, the new address
4647dd7cddfSDavid du Colombier * SHOULD be chosen as follows:
4657dd7cddfSDavid du Colombier *
4667dd7cddfSDavid du Colombier * o The client's current address as recorded in the client's current
4677dd7cddfSDavid du Colombier * binding, ELSE
4687dd7cddfSDavid du Colombier *
4697dd7cddfSDavid du Colombier * o The client's previous address as recorded in the client's (now
4707dd7cddfSDavid du Colombier * expired or released) binding, if that address is in the server's
4717dd7cddfSDavid du Colombier * pool of available addresses and not already allocated, ELSE
4727dd7cddfSDavid du Colombier *
4737dd7cddfSDavid du Colombier * o The address requested in the 'Requested IP Address' option, if that
4747dd7cddfSDavid du Colombier * address is valid and not already allocated, ELSE
4757dd7cddfSDavid du Colombier *
4767dd7cddfSDavid du Colombier * o A new address allocated from the server's pool of available
4777dd7cddfSDavid du Colombier * addresses; the address is selected based on the subnet from which
4787dd7cddfSDavid du Colombier * the message was received (if 'giaddr' is 0) or on the address of
4797dd7cddfSDavid du Colombier * the relay agent that forwarded the message ('giaddr' when not 0).
4807dd7cddfSDavid du Colombier */
4817dd7cddfSDavid du Colombier if(b == nil){
4827dd7cddfSDavid du Colombier b = idtobinding(rp->id, &rp->gii, 1);
4837dd7cddfSDavid du Colombier if(b && b->boundto && strcmp(b->boundto, rp->id) != 0)
4847dd7cddfSDavid du Colombier if(validip(rp->ip) && samenet(rp->ip, &rp->gii)){
4857dd7cddfSDavid du Colombier nb = iptobinding(rp->ip, 0);
4867dd7cddfSDavid du Colombier if(nb && nb->lease < now)
4877dd7cddfSDavid du Colombier b = nb;
4887dd7cddfSDavid du Colombier }
4897dd7cddfSDavid du Colombier }
4907dd7cddfSDavid du Colombier if(b == nil){
4913ff48bf5SDavid du Colombier warning(0, "!Discover(%s via %I): no binding %I",
4923ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip);
4937dd7cddfSDavid du Colombier return;
4947dd7cddfSDavid du Colombier }
4957dd7cddfSDavid du Colombier mkoffer(b, rp->id, rp->leasetime);
4967dd7cddfSDavid du Colombier sendoffer(rp, b->ip, b->offer);
4977dd7cddfSDavid du Colombier }
4987dd7cddfSDavid du Colombier
4997dd7cddfSDavid du Colombier void
rcvrequest(Req * rp)5007dd7cddfSDavid du Colombier rcvrequest(Req *rp)
5017dd7cddfSDavid du Colombier {
5027dd7cddfSDavid du Colombier Binding *b;
5037dd7cddfSDavid du Colombier
5047dd7cddfSDavid du Colombier if(validip(rp->server)){
5057dd7cddfSDavid du Colombier /* this is a reply to an offer - SELECTING */
5067dd7cddfSDavid du Colombier
5077dd7cddfSDavid du Colombier /* check for hard assignment */
5087dd7cddfSDavid du Colombier if(rp->staticbinding){
5097dd7cddfSDavid du Colombier if(forme(rp->server))
5100a84db5eSDavid du Colombier sendack(rp, rp->ii.ipaddr,
5110a84db5eSDavid du Colombier (staticlease > minlease? staticlease:
5120a84db5eSDavid du Colombier minlease), 1);
5137dd7cddfSDavid du Colombier else
5143ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): for server %I not me",
5153ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->server);
5167dd7cddfSDavid du Colombier return;
5177dd7cddfSDavid du Colombier }
5187dd7cddfSDavid du Colombier
5197dd7cddfSDavid du Colombier b = idtooffer(rp->id, &rp->gii);
5207dd7cddfSDavid du Colombier
5217dd7cddfSDavid du Colombier /* if we don't have an offer, nak */
5227dd7cddfSDavid du Colombier if(b == nil){
5233ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): no offer",
5247dd7cddfSDavid du Colombier rp->id, rp->gii.ipaddr);
5257dd7cddfSDavid du Colombier if(forme(rp->server))
5267dd7cddfSDavid du Colombier sendnak(rp, "no offer for you");
5277dd7cddfSDavid du Colombier return;
5287dd7cddfSDavid du Colombier }
5297dd7cddfSDavid du Colombier
5307dd7cddfSDavid du Colombier /* if not for me, retract offer */
5317dd7cddfSDavid du Colombier if(!forme(rp->server)){
5327dd7cddfSDavid du Colombier b->expoffer = 0;
5333ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): for server %I not me",
5343ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->server);
5357dd7cddfSDavid du Colombier return;
5367dd7cddfSDavid du Colombier }
5377dd7cddfSDavid du Colombier
5387dd7cddfSDavid du Colombier /*
5397dd7cddfSDavid du Colombier * if the client is confused about what we offered, nak.
5407dd7cddfSDavid du Colombier * client really shouldn't be specifying this when selecting
5417dd7cddfSDavid du Colombier */
5427dd7cddfSDavid du Colombier if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){
5433ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): requests %I, not %I",
5447dd7cddfSDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip, b->ip);
5457dd7cddfSDavid du Colombier sendnak(rp, "bad ip address option");
5467dd7cddfSDavid du Colombier return;
5477dd7cddfSDavid du Colombier }
5487dd7cddfSDavid du Colombier if(commitbinding(b) < 0){
5493ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): can't commit %I",
5503ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, b->ip);
5517dd7cddfSDavid du Colombier sendnak(rp, "can't commit binding");
5527dd7cddfSDavid du Colombier return;
5537dd7cddfSDavid du Colombier }
5547dd7cddfSDavid du Colombier sendack(rp, b->ip, b->offer, 1);
5557dd7cddfSDavid du Colombier } else if(validip(rp->ip)){
5567dd7cddfSDavid du Colombier /*
5577dd7cddfSDavid du Colombier * checking address/net - INIT-REBOOT
5587dd7cddfSDavid du Colombier *
5593ff48bf5SDavid du Colombier * This is a rebooting client that remembers its old
5603ff48bf5SDavid du Colombier * address.
5617dd7cddfSDavid du Colombier */
5627dd7cddfSDavid du Colombier /* check for hard assignment */
5637dd7cddfSDavid du Colombier if(rp->staticbinding){
5647dd7cddfSDavid du Colombier if(memcmp(rp->ip, rp->ii.ipaddr, IPaddrlen) != 0){
5653ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): %I not valid for %E",
5663ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr);
5677dd7cddfSDavid du Colombier sendnak(rp, "not valid");
5687dd7cddfSDavid du Colombier }
5690a84db5eSDavid du Colombier sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
5700a84db5eSDavid du Colombier staticlease: minlease), 1);
5717dd7cddfSDavid du Colombier return;
5727dd7cddfSDavid du Colombier }
5737dd7cddfSDavid du Colombier
5747dd7cddfSDavid du Colombier /* make sure the network makes sense */
5757dd7cddfSDavid du Colombier if(!samenet(rp->ip, &rp->gii)){
5763ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): bad forward of %I",
5773ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip);
5787dd7cddfSDavid du Colombier sendnak(rp, "wrong network");
5797dd7cddfSDavid du Colombier return;
5807dd7cddfSDavid du Colombier }
5817dd7cddfSDavid du Colombier b = iptobinding(rp->ip, 0);
5827dd7cddfSDavid du Colombier if(b == nil){
5830a84db5eSDavid du Colombier warning(0, "!Request(%s via %I): no binding for %I",
5843ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip);
5857dd7cddfSDavid du Colombier return;
5867dd7cddfSDavid du Colombier }
5877dd7cddfSDavid du Colombier if(memcmp(rp->ip, b->ip, IPaddrlen) != 0 || now > b->lease){
5883ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): %I not valid",
5893ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip);
5907dd7cddfSDavid du Colombier sendnak(rp, "not valid");
5917dd7cddfSDavid du Colombier return;
5927dd7cddfSDavid du Colombier }
5937dd7cddfSDavid du Colombier b->offer = b->lease - now;
5947dd7cddfSDavid du Colombier sendack(rp, b->ip, b->offer, 1);
5957dd7cddfSDavid du Colombier } else if(validip(rp->ciaddr)){
5963ff48bf5SDavid du Colombier /*
5973ff48bf5SDavid du Colombier * checking address - RENEWING or REBINDING
5983ff48bf5SDavid du Colombier *
5993ff48bf5SDavid du Colombier * these states are indistinguishable in our action. The only
6003ff48bf5SDavid du Colombier * difference is how close to lease expiration the client is.
6013ff48bf5SDavid du Colombier * If it is really close, it broadcasts the request hoping that
6023ff48bf5SDavid du Colombier * some server will answer.
6033ff48bf5SDavid du Colombier */
6047dd7cddfSDavid du Colombier
6057dd7cddfSDavid du Colombier /* check for hard assignment */
6067dd7cddfSDavid du Colombier if(rp->staticbinding){
6077dd7cddfSDavid du Colombier if(ipcmp(rp->ciaddr, rp->ii.ipaddr) != 0){
6083ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): %I not valid",
6093ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ciaddr);
6107dd7cddfSDavid du Colombier sendnak(rp, "not valid");
6117dd7cddfSDavid du Colombier }
6120a84db5eSDavid du Colombier sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
6130a84db5eSDavid du Colombier staticlease: minlease), 1);
6147dd7cddfSDavid du Colombier return;
6157dd7cddfSDavid du Colombier }
6167dd7cddfSDavid du Colombier
6177dd7cddfSDavid du Colombier /* make sure the network makes sense */
6187dd7cddfSDavid du Colombier if(!samenet(rp->ciaddr, &rp->gii)){
6193ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): bad forward of %I",
6203ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip);
6217dd7cddfSDavid du Colombier sendnak(rp, "wrong network");
6227dd7cddfSDavid du Colombier return;
6237dd7cddfSDavid du Colombier }
6247dd7cddfSDavid du Colombier b = iptobinding(rp->ciaddr, 0);
6257dd7cddfSDavid du Colombier if(b == nil){
6263ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): no binding for %I",
6273ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ciaddr);
6287dd7cddfSDavid du Colombier return;
6297dd7cddfSDavid du Colombier }
6307dd7cddfSDavid du Colombier if(ipcmp(rp->ciaddr, b->ip) != 0){
6313ff48bf5SDavid du Colombier warning(0, "!Request(%I via %s): %I not valid",
6323ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ciaddr);
6337dd7cddfSDavid du Colombier sendnak(rp, "invalid ip address");
6347dd7cddfSDavid du Colombier return;
6357dd7cddfSDavid du Colombier }
6367dd7cddfSDavid du Colombier mkoffer(b, rp->id, rp->leasetime);
6377dd7cddfSDavid du Colombier if(commitbinding(b) < 0){
6383ff48bf5SDavid du Colombier warning(0, "!Request(%s via %I): can't commit %I",
6393ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, b->ip);
6407dd7cddfSDavid du Colombier sendnak(rp, "can't commit binding");
6417dd7cddfSDavid du Colombier return;
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier sendack(rp, b->ip, b->offer, 1);
6447dd7cddfSDavid du Colombier }
6457dd7cddfSDavid du Colombier }
6467dd7cddfSDavid du Colombier
6477dd7cddfSDavid du Colombier void
rcvdecline(Req * rp)6487dd7cddfSDavid du Colombier rcvdecline(Req *rp)
6497dd7cddfSDavid du Colombier {
6507dd7cddfSDavid du Colombier Binding *b;
6517dd7cddfSDavid du Colombier char buf[64];
6527dd7cddfSDavid du Colombier
6537dd7cddfSDavid du Colombier if(rp->staticbinding)
6547dd7cddfSDavid du Colombier return;
6557dd7cddfSDavid du Colombier
6567dd7cddfSDavid du Colombier b = idtooffer(rp->id, &rp->gii);
6577dd7cddfSDavid du Colombier if(b == nil){
6583ff48bf5SDavid du Colombier warning(0, "!Decline(%s via %I): no binding",
6597dd7cddfSDavid du Colombier rp->id, rp->gii.ipaddr);
6607dd7cddfSDavid du Colombier return;
6617dd7cddfSDavid du Colombier }
6627dd7cddfSDavid du Colombier
6637dd7cddfSDavid du Colombier /* mark ip address as in use */
6647dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "declined by %s", rp->id);
6657dd7cddfSDavid du Colombier mkoffer(b, buf, 0x7fffffff);
6667dd7cddfSDavid du Colombier commitbinding(b);
6677dd7cddfSDavid du Colombier }
6687dd7cddfSDavid du Colombier
6697dd7cddfSDavid du Colombier void
rcvrelease(Req * rp)6707dd7cddfSDavid du Colombier rcvrelease(Req *rp)
6717dd7cddfSDavid du Colombier {
6727dd7cddfSDavid du Colombier Binding *b;
6737dd7cddfSDavid du Colombier
6747dd7cddfSDavid du Colombier if(rp->staticbinding)
6757dd7cddfSDavid du Colombier return;
6767dd7cddfSDavid du Colombier
6777dd7cddfSDavid du Colombier b = idtobinding(rp->id, &rp->gii, 0);
6787dd7cddfSDavid du Colombier if(b == nil){
6793ff48bf5SDavid du Colombier warning(0, "!Release(%s via %I): no binding",
6807dd7cddfSDavid du Colombier rp->id, rp->gii.ipaddr);
6817dd7cddfSDavid du Colombier return;
6827dd7cddfSDavid du Colombier }
6837dd7cddfSDavid du Colombier if(strcmp(rp->id, b->boundto) != 0){
6843ff48bf5SDavid du Colombier warning(0, "!Release(%s via %I): invalid release of %I",
6853ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip);
6867dd7cddfSDavid du Colombier return;
6877dd7cddfSDavid du Colombier }
6883ff48bf5SDavid du Colombier warning(0, "Release(%s via %I): releasing %I", b->boundto, rp->gii.ipaddr, b->ip);
6897dd7cddfSDavid du Colombier if(releasebinding(b, rp->id) < 0)
6907dd7cddfSDavid du Colombier warning(0, "release: couldn't release");
6917dd7cddfSDavid du Colombier }
6927dd7cddfSDavid du Colombier
6937dd7cddfSDavid du Colombier void
rcvinform(Req * rp)6947dd7cddfSDavid du Colombier rcvinform(Req *rp)
6957dd7cddfSDavid du Colombier {
6967dd7cddfSDavid du Colombier Binding *b;
6977dd7cddfSDavid du Colombier
6987dd7cddfSDavid du Colombier if(rp->staticbinding){
6997dd7cddfSDavid du Colombier sendack(rp, rp->ii.ipaddr, 0, 0);
7007dd7cddfSDavid du Colombier return;
7017dd7cddfSDavid du Colombier }
7027dd7cddfSDavid du Colombier
7037dd7cddfSDavid du Colombier b = iptobinding(rp->ciaddr, 0);
7047dd7cddfSDavid du Colombier if(b == nil){
7053ff48bf5SDavid du Colombier warning(0, "!Inform(%s via %I): no binding for %I",
7063ff48bf5SDavid du Colombier rp->id, rp->gii.ipaddr, rp->ip);
7077dd7cddfSDavid du Colombier return;
7087dd7cddfSDavid du Colombier }
7097dd7cddfSDavid du Colombier sendack(rp, b->ip, 0, 0);
7107dd7cddfSDavid du Colombier }
7117dd7cddfSDavid du Colombier
71259cc4ca5SDavid du Colombier int
setsiaddr(uchar * siaddr,uchar * saddr,uchar * laddr)7133ff48bf5SDavid du Colombier setsiaddr(uchar *siaddr, uchar *saddr, uchar *laddr)
71459cc4ca5SDavid du Colombier {
7153ff48bf5SDavid du Colombier if(ipcmp(saddr, IPnoaddr) != 0){
7163ff48bf5SDavid du Colombier v6tov4(siaddr, saddr);
71759cc4ca5SDavid du Colombier return 0;
71859cc4ca5SDavid du Colombier } else {
71959cc4ca5SDavid du Colombier v6tov4(siaddr, laddr);
72059cc4ca5SDavid du Colombier return 1;
72159cc4ca5SDavid du Colombier }
72259cc4ca5SDavid du Colombier }
72359cc4ca5SDavid du Colombier
724e183b1a6SDavid du Colombier int
ismuted(Req * rp)725e183b1a6SDavid du Colombier ismuted(Req *rp)
726e183b1a6SDavid du Colombier {
727e183b1a6SDavid du Colombier return mute || (mutestat && rp->staticbinding);
728e183b1a6SDavid du Colombier }
729e183b1a6SDavid du Colombier
7307dd7cddfSDavid du Colombier void
sendoffer(Req * rp,uchar * ip,int offer)7317dd7cddfSDavid du Colombier sendoffer(Req *rp, uchar *ip, int offer)
7327dd7cddfSDavid du Colombier {
7337dd7cddfSDavid du Colombier int n;
7347dd7cddfSDavid du Colombier ushort flags;
7357dd7cddfSDavid du Colombier Bootp *bp;
736f27a9a5aSDavid du Colombier Udphdr *up;
7377dd7cddfSDavid du Colombier
7387dd7cddfSDavid du Colombier bp = rp->bp;
7397dd7cddfSDavid du Colombier up = rp->up;
7407dd7cddfSDavid du Colombier
7417dd7cddfSDavid du Colombier /*
7427dd7cddfSDavid du Colombier * set destination
7437dd7cddfSDavid du Colombier */
7447dd7cddfSDavid du Colombier flags = nhgets(bp->flags);
7457dd7cddfSDavid du Colombier if(validip(rp->giaddr)){
7467dd7cddfSDavid du Colombier ipmove(up->raddr, rp->giaddr);
7477dd7cddfSDavid du Colombier hnputs(up->rport, 67);
7487dd7cddfSDavid du Colombier } else if(flags & Fbroadcast){
7497dd7cddfSDavid du Colombier ipmove(up->raddr, IPv4bcast);
7507dd7cddfSDavid du Colombier hnputs(up->rport, 68);
7517dd7cddfSDavid du Colombier } else {
7527dd7cddfSDavid du Colombier ipmove(up->raddr, ip);
7537dd7cddfSDavid du Colombier if(bp->htype == 1)
7547dd7cddfSDavid du Colombier arpenter(up->raddr, bp->chaddr);
7557dd7cddfSDavid du Colombier hnputs(up->rport, 68);
7567dd7cddfSDavid du Colombier }
7577dd7cddfSDavid du Colombier
7587dd7cddfSDavid du Colombier /*
7597dd7cddfSDavid du Colombier * fill in standard bootp part
7607dd7cddfSDavid du Colombier */
7617dd7cddfSDavid du Colombier bp->op = Bootreply;
7627dd7cddfSDavid du Colombier bp->hops = 0;
7637dd7cddfSDavid du Colombier hnputs(bp->secs, 0);
7647dd7cddfSDavid du Colombier memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
76580ee5cbfSDavid du Colombier v6tov4(bp->giaddr, rp->giaddr);
7667dd7cddfSDavid du Colombier v6tov4(bp->yiaddr, ip);
7673ff48bf5SDavid du Colombier setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
7687dd7cddfSDavid du Colombier strncpy(bp->sname, mysysname, sizeof(bp->sname));
7697dd7cddfSDavid du Colombier strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
7707dd7cddfSDavid du Colombier
7717dd7cddfSDavid du Colombier /*
7727dd7cddfSDavid du Colombier * set options
7737dd7cddfSDavid du Colombier */
7747dd7cddfSDavid du Colombier byteopt(rp, ODtype, Offer);
7757dd7cddfSDavid du Colombier longopt(rp, ODlease, offer);
7767dd7cddfSDavid du Colombier addropt(rp, ODserverid, up->laddr);
7777dd7cddfSDavid du Colombier miscoptions(rp, ip);
7787dd7cddfSDavid du Colombier termopt(rp);
7797dd7cddfSDavid du Colombier
7803ff48bf5SDavid du Colombier logdhcpout(rp, "Offer");
7817dd7cddfSDavid du Colombier
7827dd7cddfSDavid du Colombier /*
7837dd7cddfSDavid du Colombier * send
7847dd7cddfSDavid du Colombier */
7857dd7cddfSDavid du Colombier n = rp->p - rp->buf;
786e183b1a6SDavid du Colombier if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
7877dd7cddfSDavid du Colombier warning(0, "offer: write failed: %r");
7887dd7cddfSDavid du Colombier }
7897dd7cddfSDavid du Colombier
7907dd7cddfSDavid du Colombier void
sendack(Req * rp,uchar * ip,int offer,int sendlease)7917dd7cddfSDavid du Colombier sendack(Req *rp, uchar *ip, int offer, int sendlease)
7927dd7cddfSDavid du Colombier {
7937dd7cddfSDavid du Colombier int n;
7947dd7cddfSDavid du Colombier ushort flags;
7957dd7cddfSDavid du Colombier Bootp *bp;
796f27a9a5aSDavid du Colombier Udphdr *up;
7977dd7cddfSDavid du Colombier
7987dd7cddfSDavid du Colombier bp = rp->bp;
7997dd7cddfSDavid du Colombier up = rp->up;
8007dd7cddfSDavid du Colombier
8017dd7cddfSDavid du Colombier /*
8027dd7cddfSDavid du Colombier * set destination
8037dd7cddfSDavid du Colombier */
8047dd7cddfSDavid du Colombier flags = nhgets(bp->flags);
8057dd7cddfSDavid du Colombier if(validip(rp->giaddr)){
8067dd7cddfSDavid du Colombier ipmove(up->raddr, rp->giaddr);
8077dd7cddfSDavid du Colombier hnputs(up->rport, 67);
8087dd7cddfSDavid du Colombier } else if(flags & Fbroadcast){
8097dd7cddfSDavid du Colombier ipmove(up->raddr, IPv4bcast);
8107dd7cddfSDavid du Colombier hnputs(up->rport, 68);
8117dd7cddfSDavid du Colombier } else {
8127dd7cddfSDavid du Colombier ipmove(up->raddr, ip);
8137dd7cddfSDavid du Colombier if(bp->htype == 1)
8147dd7cddfSDavid du Colombier arpenter(up->raddr, bp->chaddr);
8157dd7cddfSDavid du Colombier hnputs(up->rport, 68);
8167dd7cddfSDavid du Colombier }
8177dd7cddfSDavid du Colombier
8187dd7cddfSDavid du Colombier /*
8197dd7cddfSDavid du Colombier * fill in standard bootp part
8207dd7cddfSDavid du Colombier */
8217dd7cddfSDavid du Colombier bp->op = Bootreply;
8227dd7cddfSDavid du Colombier bp->hops = 0;
8237dd7cddfSDavid du Colombier hnputs(bp->secs, 0);
82480ee5cbfSDavid du Colombier v6tov4(bp->giaddr, rp->giaddr);
8257dd7cddfSDavid du Colombier v6tov4(bp->yiaddr, ip);
8263ff48bf5SDavid du Colombier setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
8277dd7cddfSDavid du Colombier strncpy(bp->sname, mysysname, sizeof(bp->sname));
8287dd7cddfSDavid du Colombier strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
8297dd7cddfSDavid du Colombier
8307dd7cddfSDavid du Colombier /*
8317dd7cddfSDavid du Colombier * set options
8327dd7cddfSDavid du Colombier */
8337dd7cddfSDavid du Colombier byteopt(rp, ODtype, Ack);
8343ff48bf5SDavid du Colombier if(sendlease){
8357dd7cddfSDavid du Colombier longopt(rp, ODlease, offer);
8363ff48bf5SDavid du Colombier }
8377dd7cddfSDavid du Colombier addropt(rp, ODserverid, up->laddr);
8387dd7cddfSDavid du Colombier miscoptions(rp, ip);
8397dd7cddfSDavid du Colombier termopt(rp);
8407dd7cddfSDavid du Colombier
8413ff48bf5SDavid du Colombier logdhcpout(rp, "Ack");
8427dd7cddfSDavid du Colombier
8437dd7cddfSDavid du Colombier /*
8447dd7cddfSDavid du Colombier * send
8457dd7cddfSDavid du Colombier */
8467dd7cddfSDavid du Colombier n = rp->p - rp->buf;
847e183b1a6SDavid du Colombier if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
8487dd7cddfSDavid du Colombier warning(0, "ack: write failed: %r");
8497dd7cddfSDavid du Colombier }
8507dd7cddfSDavid du Colombier
8517dd7cddfSDavid du Colombier void
sendnak(Req * rp,char * msg)8527dd7cddfSDavid du Colombier sendnak(Req *rp, char *msg)
8537dd7cddfSDavid du Colombier {
8547dd7cddfSDavid du Colombier int n;
8557dd7cddfSDavid du Colombier Bootp *bp;
856f27a9a5aSDavid du Colombier Udphdr *up;
8577dd7cddfSDavid du Colombier
8587dd7cddfSDavid du Colombier bp = rp->bp;
8597dd7cddfSDavid du Colombier up = rp->up;
8607dd7cddfSDavid du Colombier
8617dd7cddfSDavid du Colombier /*
8627dd7cddfSDavid du Colombier * set destination (always broadcast)
8637dd7cddfSDavid du Colombier */
8647dd7cddfSDavid du Colombier if(validip(rp->giaddr)){
8657dd7cddfSDavid du Colombier ipmove(up->raddr, rp->giaddr);
8667dd7cddfSDavid du Colombier hnputs(up->rport, 67);
8677dd7cddfSDavid du Colombier } else {
8687dd7cddfSDavid du Colombier ipmove(up->raddr, IPv4bcast);
8697dd7cddfSDavid du Colombier hnputs(up->rport, 68);
8707dd7cddfSDavid du Colombier }
8717dd7cddfSDavid du Colombier
8727dd7cddfSDavid du Colombier /*
8737dd7cddfSDavid du Colombier * fill in standard bootp part
8747dd7cddfSDavid du Colombier */
8757dd7cddfSDavid du Colombier bp->op = Bootreply;
8767dd7cddfSDavid du Colombier bp->hops = 0;
8777dd7cddfSDavid du Colombier hnputs(bp->secs, 0);
87880ee5cbfSDavid du Colombier v6tov4(bp->giaddr, rp->giaddr);
8797dd7cddfSDavid du Colombier memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
8807dd7cddfSDavid du Colombier memset(bp->yiaddr, 0, sizeof(bp->yiaddr));
8817dd7cddfSDavid du Colombier memset(bp->siaddr, 0, sizeof(bp->siaddr));
8827dd7cddfSDavid du Colombier
8837dd7cddfSDavid du Colombier /*
8847dd7cddfSDavid du Colombier * set options
8857dd7cddfSDavid du Colombier */
8867dd7cddfSDavid du Colombier byteopt(rp, ODtype, Nak);
8877dd7cddfSDavid du Colombier addropt(rp, ODserverid, up->laddr);
8887dd7cddfSDavid du Colombier if(msg)
8897dd7cddfSDavid du Colombier stringopt(rp, ODmessage, msg);
8907dd7cddfSDavid du Colombier if(strncmp(rp->id, "id", 2) == 0)
8917dd7cddfSDavid du Colombier hexopt(rp, ODclientid, rp->id+2);
8927dd7cddfSDavid du Colombier termopt(rp);
8937dd7cddfSDavid du Colombier
8943ff48bf5SDavid du Colombier logdhcpout(rp, "Nak");
8953ff48bf5SDavid du Colombier
8967dd7cddfSDavid du Colombier /*
8977dd7cddfSDavid du Colombier * send nak
8987dd7cddfSDavid du Colombier */
8997dd7cddfSDavid du Colombier n = rp->p - rp->buf;
900e183b1a6SDavid du Colombier if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
9017dd7cddfSDavid du Colombier warning(0, "nak: write failed: %r");
9027dd7cddfSDavid du Colombier }
9037dd7cddfSDavid du Colombier
9047dd7cddfSDavid du Colombier void
bootp(Req * rp)9057dd7cddfSDavid du Colombier bootp(Req *rp)
9067dd7cddfSDavid du Colombier {
9077dd7cddfSDavid du Colombier int n;
9087dd7cddfSDavid du Colombier Bootp *bp;
909f27a9a5aSDavid du Colombier Udphdr *up;
9107dd7cddfSDavid du Colombier ushort flags;
9119a747e4fSDavid du Colombier Iplifc *lifc;
9127dd7cddfSDavid du Colombier Info *iip;
9137dd7cddfSDavid du Colombier
9148ae63d3dSDavid du Colombier warning(0, "bootp %s %I->%I from %s via %I, file %s %s",
9153ff48bf5SDavid du Colombier rp->genrequest? "generic": (rp->p9request? "p9": ""),
9167dd7cddfSDavid du Colombier rp->up->raddr, rp->up->laddr,
917da51d93aSDavid du Colombier rp->id, rp->gii.ipaddr,
9188ae63d3dSDavid du Colombier rp->bp->file, rp->broadcast? "broadcast": "unicast");
9197dd7cddfSDavid du Colombier
9207dd7cddfSDavid du Colombier if(nobootp)
9217dd7cddfSDavid du Colombier return;
9227dd7cddfSDavid du Colombier
9237dd7cddfSDavid du Colombier bp = rp->bp;
9247dd7cddfSDavid du Colombier up = rp->up;
9257dd7cddfSDavid du Colombier iip = &rp->ii;
9267dd7cddfSDavid du Colombier
9277dd7cddfSDavid du Colombier if(rp->staticbinding == 0){
9287dd7cddfSDavid du Colombier warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr);
9297dd7cddfSDavid du Colombier return;
9307dd7cddfSDavid du Colombier }
9317dd7cddfSDavid du Colombier
9327dd7cddfSDavid du Colombier /* ignore if not for us */
9337dd7cddfSDavid du Colombier if(*bp->sname){
9347dd7cddfSDavid du Colombier if(strcmp(bp->sname, mysysname) != 0){
9357dd7cddfSDavid du Colombier bp->sname[20] = 0;
9367dd7cddfSDavid du Colombier warning(0, "bootp for server %s", bp->sname);
9377dd7cddfSDavid du Colombier return;
9387dd7cddfSDavid du Colombier }
939e183b1a6SDavid du Colombier } else
940e183b1a6SDavid du Colombier slowdelay(rp);
9417dd7cddfSDavid du Colombier
9427dd7cddfSDavid du Colombier /* ignore if we don't know what file to load */
9437dd7cddfSDavid du Colombier if(*bp->file == 0){
9440a84db5eSDavid du Colombier if(rp->genrequest && *iip->bootf2) /* if not plan 9 & have alternate file... */
9453ff48bf5SDavid du Colombier strncpy(bp->file, iip->bootf2, sizeof(bp->file));
9463ff48bf5SDavid du Colombier else if(*iip->bootf)
9477dd7cddfSDavid du Colombier strncpy(bp->file, iip->bootf, sizeof(bp->file));
9487dd7cddfSDavid du Colombier else if(*bp->sname) /* if we were asked, respond no matter what */
9497dd7cddfSDavid du Colombier bp->file[0] = '\0';
9507dd7cddfSDavid du Colombier else {
9517dd7cddfSDavid du Colombier warning(0, "no bootfile for %I", iip->ipaddr);
9527dd7cddfSDavid du Colombier return;
9537dd7cddfSDavid du Colombier }
9547dd7cddfSDavid du Colombier }
9557dd7cddfSDavid du Colombier
9567dd7cddfSDavid du Colombier /* ignore if the file is unreadable */
9573ff48bf5SDavid du Colombier if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){
9589a747e4fSDavid du Colombier warning(0, "inaccessible bootfile1 %s", bp->file);
9597dd7cddfSDavid du Colombier return;
9607dd7cddfSDavid du Colombier }
9617dd7cddfSDavid du Colombier
9627dd7cddfSDavid du Colombier bp->op = Bootreply;
9637dd7cddfSDavid du Colombier v6tov4(bp->yiaddr, iip->ipaddr);
9647dd7cddfSDavid du Colombier if(rp->p9request){
9657dd7cddfSDavid du Colombier warning(0, "p9bootp: %I", iip->ipaddr);
9667dd7cddfSDavid du Colombier memmove(bp->optmagic, plan9opt, 4);
9677dd7cddfSDavid du Colombier if(iip->gwip == 0)
9687dd7cddfSDavid du Colombier v4tov6(iip->gwip, bp->giaddr);
9697dd7cddfSDavid du Colombier rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip,
9707dd7cddfSDavid du Colombier iip->auip, iip->gwip);
9713ff48bf5SDavid du Colombier sprint(optbuf, "%s", (char*)(bp->optmagic));
9727dd7cddfSDavid du Colombier } else if(rp->genrequest){
9737dd7cddfSDavid du Colombier warning(0, "genericbootp: %I", iip->ipaddr);
9747dd7cddfSDavid du Colombier memmove(bp->optmagic, genericopt, 4);
9757dd7cddfSDavid du Colombier miscoptions(rp, iip->ipaddr);
9767dd7cddfSDavid du Colombier termopt(rp);
9777dd7cddfSDavid du Colombier } else if(iip->vendor[0] != 0) {
9787dd7cddfSDavid du Colombier warning(0, "bootp vendor field: %s", iip->vendor);
9797dd7cddfSDavid du Colombier memset(rp->p, 0, 128-4);
9807dd7cddfSDavid du Colombier rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor);
9817dd7cddfSDavid du Colombier } else {
9827dd7cddfSDavid du Colombier memset(rp->p, 0, 128-4);
9837dd7cddfSDavid du Colombier rp->p += 128-4;
9847dd7cddfSDavid du Colombier }
9857dd7cddfSDavid du Colombier
9867dd7cddfSDavid du Colombier /*
9877dd7cddfSDavid du Colombier * set destination
9887dd7cddfSDavid du Colombier */
9897dd7cddfSDavid du Colombier flags = nhgets(bp->flags);
9907dd7cddfSDavid du Colombier if(validip(rp->giaddr)){
9917dd7cddfSDavid du Colombier ipmove(up->raddr, rp->giaddr);
9927dd7cddfSDavid du Colombier hnputs(up->rport, 67);
9937dd7cddfSDavid du Colombier } else if(flags & Fbroadcast){
9947dd7cddfSDavid du Colombier ipmove(up->raddr, IPv4bcast);
9957dd7cddfSDavid du Colombier hnputs(up->rport, 68);
9967dd7cddfSDavid du Colombier } else {
9977dd7cddfSDavid du Colombier v4tov6(up->raddr, bp->yiaddr);
9987dd7cddfSDavid du Colombier if(bp->htype == 1)
9997dd7cddfSDavid du Colombier arpenter(up->raddr, bp->chaddr);
10007dd7cddfSDavid du Colombier hnputs(up->rport, 68);
10017dd7cddfSDavid du Colombier }
10027dd7cddfSDavid du Colombier
10037dd7cddfSDavid du Colombier /*
10047dd7cddfSDavid du Colombier * select best local address if destination is directly connected
10057dd7cddfSDavid du Colombier */
10069a747e4fSDavid du Colombier lifc = findlifc(up->raddr);
10079a747e4fSDavid du Colombier if(lifc)
10089a747e4fSDavid du Colombier ipmove(up->laddr, lifc->ip);
10097dd7cddfSDavid du Colombier
10107dd7cddfSDavid du Colombier /*
10117dd7cddfSDavid du Colombier * our identity
10127dd7cddfSDavid du Colombier */
10137dd7cddfSDavid du Colombier strncpy(bp->sname, mysysname, sizeof(bp->sname));
10143ff48bf5SDavid du Colombier
10153ff48bf5SDavid du Colombier /*
10163ff48bf5SDavid du Colombier * set tftp server
10173ff48bf5SDavid du Colombier */
10183ff48bf5SDavid du Colombier setsiaddr(bp->siaddr, iip->tftp, up->laddr);
10193ff48bf5SDavid du Colombier if(rp->genrequest && *iip->bootf2)
10203ff48bf5SDavid du Colombier setsiaddr(bp->siaddr, iip->tftp2, up->laddr);
102159cc4ca5SDavid du Colombier
10227dd7cddfSDavid du Colombier /*
10237dd7cddfSDavid du Colombier * RFC 1048 says that we must pad vendor field with
10247dd7cddfSDavid du Colombier * zeros until we have a 64 byte field.
10257dd7cddfSDavid du Colombier */
10267dd7cddfSDavid du Colombier n = rp->p - rp->bp->optdata;
10277dd7cddfSDavid du Colombier if(n < 64-4) {
10287dd7cddfSDavid du Colombier memset(rp->p, 0, (64-4)-n);
10297dd7cddfSDavid du Colombier rp->p += (64-4)-n;
10307dd7cddfSDavid du Colombier }
10317dd7cddfSDavid du Colombier
10327dd7cddfSDavid du Colombier /*
10337dd7cddfSDavid du Colombier * send
10347dd7cddfSDavid du Colombier */
10357dd7cddfSDavid du Colombier n = rp->p - rp->buf;
1036e183b1a6SDavid du Colombier if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
10377dd7cddfSDavid du Colombier warning(0, "bootp: write failed: %r");
10383ff48bf5SDavid du Colombier
10393ff48bf5SDavid du Colombier warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s",
10403ff48bf5SDavid du Colombier up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags),
10413ff48bf5SDavid du Colombier bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr,
10423ff48bf5SDavid du Colombier optbuf);
10437dd7cddfSDavid du Colombier }
10447dd7cddfSDavid du Colombier
10457dd7cddfSDavid du Colombier void
parseoptions(Req * rp)10467dd7cddfSDavid du Colombier parseoptions(Req *rp)
10477dd7cddfSDavid du Colombier {
10487dd7cddfSDavid du Colombier int n, c, code;
10497dd7cddfSDavid du Colombier uchar *o, *p;
10507dd7cddfSDavid du Colombier
10517dd7cddfSDavid du Colombier p = rp->p;
10527dd7cddfSDavid du Colombier
10537dd7cddfSDavid du Colombier while(p < rp->e){
10547dd7cddfSDavid du Colombier code = *p++;
10557dd7cddfSDavid du Colombier if(code == 255)
10567dd7cddfSDavid du Colombier break;
10577dd7cddfSDavid du Colombier if(code == 0)
10587dd7cddfSDavid du Colombier continue;
10597dd7cddfSDavid du Colombier
10607dd7cddfSDavid du Colombier /* ignore anything that's too long */
10617dd7cddfSDavid du Colombier n = *p++;
10627dd7cddfSDavid du Colombier o = p;
10637dd7cddfSDavid du Colombier p += n;
10647dd7cddfSDavid du Colombier if(p > rp->e)
10657dd7cddfSDavid du Colombier return;
10667dd7cddfSDavid du Colombier
10677dd7cddfSDavid du Colombier switch(code){
10687dd7cddfSDavid du Colombier case ODipaddr: /* requested ip address */
10697dd7cddfSDavid du Colombier if(n == IPv4addrlen)
10707dd7cddfSDavid du Colombier v4tov6(rp->ip, o);
10717dd7cddfSDavid du Colombier break;
10727dd7cddfSDavid du Colombier case ODlease: /* requested lease time */
10737dd7cddfSDavid du Colombier rp->leasetime = nhgetl(o);
107480ee5cbfSDavid du Colombier if(rp->leasetime > MaxLease || rp->leasetime < 0)
10757dd7cddfSDavid du Colombier rp->leasetime = MaxLease;
10767dd7cddfSDavid du Colombier break;
10777dd7cddfSDavid du Colombier case ODtype:
10787dd7cddfSDavid du Colombier c = *o;
10797dd7cddfSDavid du Colombier if(c < 10 && c > 0)
10807dd7cddfSDavid du Colombier rp->dhcptype = c;
10817dd7cddfSDavid du Colombier break;
10827dd7cddfSDavid du Colombier case ODserverid:
10837dd7cddfSDavid du Colombier if(n == IPv4addrlen)
10847dd7cddfSDavid du Colombier v4tov6(rp->server, o);
10857dd7cddfSDavid du Colombier break;
10867dd7cddfSDavid du Colombier case ODmessage:
10879a747e4fSDavid du Colombier if(n > sizeof rp->msg-1)
10889a747e4fSDavid du Colombier n = sizeof rp->msg-1;
10897dd7cddfSDavid du Colombier memmove(rp->msg, o, n);
10907dd7cddfSDavid du Colombier rp->msg[n] = 0;
10917dd7cddfSDavid du Colombier break;
10927dd7cddfSDavid du Colombier case ODmaxmsg:
10937dd7cddfSDavid du Colombier c = nhgets(o);
10947dd7cddfSDavid du Colombier c -= 28;
1095f27a9a5aSDavid du Colombier c += Udphdrsize;
10967dd7cddfSDavid du Colombier if(c > 0)
10977dd7cddfSDavid du Colombier rp->max = rp->buf + c;
10987dd7cddfSDavid du Colombier break;
10997dd7cddfSDavid du Colombier case ODclientid:
11007dd7cddfSDavid du Colombier if(n <= 1)
11017dd7cddfSDavid du Colombier break;
11027dd7cddfSDavid du Colombier rp->id = toid( o, n);
11037dd7cddfSDavid du Colombier break;
11047dd7cddfSDavid du Colombier case ODparams:
11057dd7cddfSDavid du Colombier if(n > sizeof(rp->requested))
11067dd7cddfSDavid du Colombier n = sizeof(rp->requested);
11077dd7cddfSDavid du Colombier memmove(rp->requested, o, n);
11087dd7cddfSDavid du Colombier break;
11097dd7cddfSDavid du Colombier case ODvendorclass:
11107dd7cddfSDavid du Colombier if(n >= sizeof(rp->vendorclass))
11117dd7cddfSDavid du Colombier n = sizeof(rp->vendorclass)-1;
11127dd7cddfSDavid du Colombier memmove(rp->vendorclass, o, n);
11137dd7cddfSDavid du Colombier rp->vendorclass[n] = 0;
11147dd7cddfSDavid du Colombier if(strncmp((char*)rp->vendorclass, "p9-", 3) == 0)
11157dd7cddfSDavid du Colombier strcpy(rp->cputype, (char*)rp->vendorclass+3);
11167dd7cddfSDavid du Colombier break;
11177dd7cddfSDavid du Colombier case OBend:
11187dd7cddfSDavid du Colombier return;
11197dd7cddfSDavid du Colombier }
11207dd7cddfSDavid du Colombier }
11217dd7cddfSDavid du Colombier }
11227dd7cddfSDavid du Colombier
11237dd7cddfSDavid du Colombier void
remrequested(Req * rp,int opt)11247dd7cddfSDavid du Colombier remrequested(Req *rp, int opt)
11257dd7cddfSDavid du Colombier {
11267dd7cddfSDavid du Colombier uchar *p;
11277dd7cddfSDavid du Colombier
11287dd7cddfSDavid du Colombier p = memchr(rp->requested, opt, sizeof(rp->requested));
11297dd7cddfSDavid du Colombier if(p != nil)
11307dd7cddfSDavid du Colombier *p = OBpad;
11317dd7cddfSDavid du Colombier }
11327dd7cddfSDavid du Colombier
11337dd7cddfSDavid du Colombier void
miscoptions(Req * rp,uchar * ip)11347dd7cddfSDavid du Colombier miscoptions(Req *rp, uchar *ip)
11357dd7cddfSDavid du Colombier {
11360a84db5eSDavid du Colombier int i, j, na;
11370a84db5eSDavid du Colombier uchar x[2*IPaddrlen], vopts[Maxoptlen];
11387dd7cddfSDavid du Colombier uchar *op, *omax;
11390a84db5eSDavid du Colombier uchar *addrs[2];
11400a84db5eSDavid du Colombier char *p;
11413ff48bf5SDavid du Colombier char *attr[100], **a;
11423ff48bf5SDavid du Colombier Ndbtuple *t;
11437dd7cddfSDavid du Colombier
11447dd7cddfSDavid du Colombier addrs[0] = x;
11457dd7cddfSDavid du Colombier addrs[1] = x+IPaddrlen;
11467dd7cddfSDavid du Colombier
11477dd7cddfSDavid du Colombier /* always supply these */
11483ff48bf5SDavid du Colombier maskopt(rp, OBmask, rp->gii.ipmask);
11497dd7cddfSDavid du Colombier if(validip(rp->gii.gwip)){
11507dd7cddfSDavid du Colombier remrequested(rp, OBrouter);
11517dd7cddfSDavid du Colombier addropt(rp, OBrouter, rp->gii.gwip);
11527dd7cddfSDavid du Colombier } else if(validip(rp->giaddr)){
11537dd7cddfSDavid du Colombier remrequested(rp, OBrouter);
11547dd7cddfSDavid du Colombier addropt(rp, OBrouter, rp->giaddr);
11557dd7cddfSDavid du Colombier }
11567dd7cddfSDavid du Colombier
11572ddf2468SDavid du Colombier /*
11582ddf2468SDavid du Colombier * OBhostname for the HP4000M switches
11592ddf2468SDavid du Colombier * (this causes NT to log infinite errors - tough shit)
11602ddf2468SDavid du Colombier */
11619a747e4fSDavid du Colombier if(*rp->ii.domain){
11629a747e4fSDavid du Colombier remrequested(rp, OBhostname);
11639a747e4fSDavid du Colombier stringopt(rp, OBhostname, rp->ii.domain);
11649a747e4fSDavid du Colombier }
11653ff48bf5SDavid du Colombier if(*rp->ii.rootpath)
11669a747e4fSDavid du Colombier stringopt(rp, OBrootpath, rp->ii.rootpath);
11673ff48bf5SDavid du Colombier
11683ff48bf5SDavid du Colombier /* figure out what we need to lookup */
11693ff48bf5SDavid du Colombier na = 0;
11703ff48bf5SDavid du Colombier a = attr;
11713ff48bf5SDavid du Colombier if(*rp->ii.domain == 0)
11723ff48bf5SDavid du Colombier a[na++] = "dom";
11733ff48bf5SDavid du Colombier for(i = 0; i < sizeof(rp->requested); i++)
11743ff48bf5SDavid du Colombier switch(rp->requested[i]){
11753ff48bf5SDavid du Colombier case OBrouter:
11763ff48bf5SDavid du Colombier a[na++] = "@ipgw";
11773ff48bf5SDavid du Colombier break;
11783ff48bf5SDavid du Colombier case OBdnserver:
11793ff48bf5SDavid du Colombier a[na++] = "@dns";
11803ff48bf5SDavid du Colombier break;
11813ff48bf5SDavid du Colombier case OBnetbiosns:
11823ff48bf5SDavid du Colombier a[na++] = "@wins";
11833ff48bf5SDavid du Colombier break;
11843ff48bf5SDavid du Colombier case OBsmtpserver:
11853ff48bf5SDavid du Colombier a[na++] = "@smtp";
11863ff48bf5SDavid du Colombier break;
11873ff48bf5SDavid du Colombier case OBpop3server:
11883ff48bf5SDavid du Colombier a[na++] = "@pop3";
11893ff48bf5SDavid du Colombier break;
11903ff48bf5SDavid du Colombier case OBwwwserver:
11913ff48bf5SDavid du Colombier a[na++] = "@www";
11923ff48bf5SDavid du Colombier break;
11933ff48bf5SDavid du Colombier case OBntpserver:
11943ff48bf5SDavid du Colombier a[na++] = "@ntp";
11953ff48bf5SDavid du Colombier break;
11963ff48bf5SDavid du Colombier case OBtimeserver:
11973ff48bf5SDavid du Colombier a[na++] = "@time";
11983ff48bf5SDavid du Colombier break;
11999a747e4fSDavid du Colombier }
12003ff48bf5SDavid du Colombier if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
12013ff48bf5SDavid du Colombier || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
12023ff48bf5SDavid du Colombier a[na++] = "@fs";
12033ff48bf5SDavid du Colombier a[na++] = "@auth";
12043ff48bf5SDavid du Colombier }
12053ff48bf5SDavid du Colombier t = lookupinfo(ip, a, na);
12069a747e4fSDavid du Colombier
12077dd7cddfSDavid du Colombier /* lookup anything we might be missing */
12087dd7cddfSDavid du Colombier if(*rp->ii.domain == 0)
12093ff48bf5SDavid du Colombier lookupname(rp->ii.domain, t);
12107dd7cddfSDavid du Colombier
12117dd7cddfSDavid du Colombier /* add any requested ones that we know about */
12127dd7cddfSDavid du Colombier for(i = 0; i < sizeof(rp->requested); i++)
12137dd7cddfSDavid du Colombier switch(rp->requested[i]){
12143ff48bf5SDavid du Colombier case OBrouter:
12153ff48bf5SDavid du Colombier j = lookupserver("ipgw", addrs, t);
12163ff48bf5SDavid du Colombier addrsopt(rp, OBrouter, addrs, j);
12173ff48bf5SDavid du Colombier break;
12187dd7cddfSDavid du Colombier case OBdnserver:
12193ff48bf5SDavid du Colombier j = lookupserver("dns", addrs, t);
12207dd7cddfSDavid du Colombier addrsopt(rp, OBdnserver, addrs, j);
12217dd7cddfSDavid du Colombier break;
12227dd7cddfSDavid du Colombier case OBhostname:
12237dd7cddfSDavid du Colombier if(*rp->ii.domain)
12247dd7cddfSDavid du Colombier stringopt(rp, OBhostname, rp->ii.domain);
12257dd7cddfSDavid du Colombier break;
12267dd7cddfSDavid du Colombier case OBdomainname:
12277dd7cddfSDavid du Colombier p = strchr(rp->ii.domain, '.');
12287dd7cddfSDavid du Colombier if(p)
12297dd7cddfSDavid du Colombier stringopt(rp, OBdomainname, p+1);
12307dd7cddfSDavid du Colombier break;
12317dd7cddfSDavid du Colombier case OBnetbiosns:
12323ff48bf5SDavid du Colombier j = lookupserver("wins", addrs, t);
12337dd7cddfSDavid du Colombier addrsopt(rp, OBnetbiosns, addrs, j);
12347dd7cddfSDavid du Colombier break;
12357dd7cddfSDavid du Colombier case OBnetbiostype:
12367dd7cddfSDavid du Colombier /* p-node: peer to peer WINS queries */
12377dd7cddfSDavid du Colombier byteopt(rp, OBnetbiostype, 0x2);
12387dd7cddfSDavid du Colombier break;
12397dd7cddfSDavid du Colombier case OBsmtpserver:
12403ff48bf5SDavid du Colombier j = lookupserver("smtp", addrs, t);
12417dd7cddfSDavid du Colombier addrsopt(rp, OBsmtpserver, addrs, j);
12427dd7cddfSDavid du Colombier break;
12437dd7cddfSDavid du Colombier case OBpop3server:
12443ff48bf5SDavid du Colombier j = lookupserver("pop3", addrs, t);
12457dd7cddfSDavid du Colombier addrsopt(rp, OBpop3server, addrs, j);
12467dd7cddfSDavid du Colombier break;
12477dd7cddfSDavid du Colombier case OBwwwserver:
12483ff48bf5SDavid du Colombier j = lookupserver("www", addrs, t);
12497dd7cddfSDavid du Colombier addrsopt(rp, OBwwwserver, addrs, j);
12507dd7cddfSDavid du Colombier break;
12517dd7cddfSDavid du Colombier case OBntpserver:
12523ff48bf5SDavid du Colombier j = lookupserver("ntp", addrs, t);
12537dd7cddfSDavid du Colombier addrsopt(rp, OBntpserver, addrs, j);
12547dd7cddfSDavid du Colombier break;
12557dd7cddfSDavid du Colombier case OBtimeserver:
12563ff48bf5SDavid du Colombier j = lookupserver("time", addrs, t);
12577dd7cddfSDavid du Colombier addrsopt(rp, OBtimeserver, addrs, j);
12587dd7cddfSDavid du Colombier break;
12597dd7cddfSDavid du Colombier case OBttl:
12607dd7cddfSDavid du Colombier byteopt(rp, OBttl, 255);
12617dd7cddfSDavid du Colombier break;
12627dd7cddfSDavid du Colombier }
12637dd7cddfSDavid du Colombier
12642ddf2468SDavid du Colombier /* add plan9 specific options */
12657dd7cddfSDavid du Colombier if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
12667dd7cddfSDavid du Colombier || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
12672ddf2468SDavid du Colombier /* point to temporary area */
12687dd7cddfSDavid du Colombier op = rp->p;
12697dd7cddfSDavid du Colombier omax = rp->max;
12700a84db5eSDavid du Colombier /* stash encoded options in vopts */
12717dd7cddfSDavid du Colombier rp->p = vopts;
12727dd7cddfSDavid du Colombier rp->max = vopts + sizeof(vopts) - 1;
12737dd7cddfSDavid du Colombier
12740a84db5eSDavid du Colombier /* emit old v4 addresses first to make sure that they fit */
12750a84db5eSDavid du Colombier addrsopt(rp, OP9fsv4, addrs, lookupserver("fs", addrs, t));
12760a84db5eSDavid du Colombier addrsopt(rp, OP9authv4, addrs, lookupserver("auth", addrs, t));
12777dd7cddfSDavid du Colombier
12780a84db5eSDavid du Colombier p9addrsopt(rp, OP9fs, addrs, lookupserver("fs", addrs, t));
12790a84db5eSDavid du Colombier p9addrsopt(rp, OP9auth, addrs, lookupserver("auth", addrs, t));
12800a84db5eSDavid du Colombier p9addrsopt(rp, OP9ipaddr, addrs, lookupserver("ip", addrs, t));
12810a84db5eSDavid du Colombier p9addrsopt(rp, OP9ipmask, addrs, lookupserver("ipmask", addrs, t));
12820a84db5eSDavid du Colombier p9addrsopt(rp, OP9ipgw, addrs, lookupserver("ipgw", addrs, t));
12830a84db5eSDavid du Colombier
12840a84db5eSDavid du Colombier /* point back to packet, encapsulate vopts into packet */
12857dd7cddfSDavid du Colombier j = rp->p - vopts;
12867dd7cddfSDavid du Colombier rp->p = op;
12877dd7cddfSDavid du Colombier rp->max = omax;
12887dd7cddfSDavid du Colombier vectoropt(rp, OBvendorinfo, vopts, j);
12897dd7cddfSDavid du Colombier }
12907dd7cddfSDavid du Colombier
12913ff48bf5SDavid du Colombier ndbfree(t);
12927dd7cddfSDavid du Colombier }
12937dd7cddfSDavid du Colombier
12947dd7cddfSDavid du Colombier int
openlisten(char * net)12957dd7cddfSDavid du Colombier openlisten(char *net)
12967dd7cddfSDavid du Colombier {
12977dd7cddfSDavid du Colombier int fd, cfd;
12982ddf2468SDavid du Colombier char data[128], devdir[40];
12997dd7cddfSDavid du Colombier
13007dd7cddfSDavid du Colombier sprint(data, "%s/udp!*!bootp", net);
13017dd7cddfSDavid du Colombier cfd = announce(data, devdir);
13027dd7cddfSDavid du Colombier if(cfd < 0)
13037dd7cddfSDavid du Colombier fatal(1, "can't announce");
13047dd7cddfSDavid du Colombier if(fprint(cfd, "headers") < 0)
13057dd7cddfSDavid du Colombier fatal(1, "can't set header mode");
13067dd7cddfSDavid du Colombier
13077dd7cddfSDavid du Colombier sprint(data, "%s/data", devdir);
13087dd7cddfSDavid du Colombier fd = open(data, ORDWR);
13097dd7cddfSDavid du Colombier if(fd < 0)
13107dd7cddfSDavid du Colombier fatal(1, "open udp data");
13117dd7cddfSDavid du Colombier return fd;
13127dd7cddfSDavid du Colombier }
13137dd7cddfSDavid du Colombier
13147dd7cddfSDavid du Colombier void
fatal(int syserr,char * fmt,...)13157dd7cddfSDavid du Colombier fatal(int syserr, char *fmt, ...)
13167dd7cddfSDavid du Colombier {
13170a84db5eSDavid du Colombier char buf[Maxloglen];
13187dd7cddfSDavid du Colombier va_list arg;
13197dd7cddfSDavid du Colombier
13207dd7cddfSDavid du Colombier va_start(arg, fmt);
13219a747e4fSDavid du Colombier vseprint(buf, buf+sizeof(buf), fmt, arg);
13227dd7cddfSDavid du Colombier va_end(arg);
13237dd7cddfSDavid du Colombier if(syserr)
13243ff48bf5SDavid du Colombier syslog(1, blog, "%s: %r", buf);
13257dd7cddfSDavid du Colombier else
13263ff48bf5SDavid du Colombier syslog(1, blog, "%s", buf);
13277dd7cddfSDavid du Colombier exits(buf);
13287dd7cddfSDavid du Colombier }
13297dd7cddfSDavid du Colombier
13300a84db5eSDavid du Colombier void
warning(int syserr,char * fmt,...)13317dd7cddfSDavid du Colombier warning(int syserr, char *fmt, ...)
13327dd7cddfSDavid du Colombier {
13330a84db5eSDavid du Colombier char buf[Maxloglen];
13347dd7cddfSDavid du Colombier va_list arg;
13357dd7cddfSDavid du Colombier
13367dd7cddfSDavid du Colombier va_start(arg, fmt);
13379a747e4fSDavid du Colombier vseprint(buf, buf+sizeof(buf), fmt, arg);
13387dd7cddfSDavid du Colombier va_end(arg);
13397dd7cddfSDavid du Colombier if(syserr){
13403ff48bf5SDavid du Colombier syslog(0, blog, "%s: %r", buf);
13417dd7cddfSDavid du Colombier if(debug)
13423ff48bf5SDavid du Colombier fprint(2, "%s: %r\n", buf);
13437dd7cddfSDavid du Colombier } else {
13443ff48bf5SDavid du Colombier syslog(0, blog, "%s", buf);
13457dd7cddfSDavid du Colombier if(debug)
13463ff48bf5SDavid du Colombier fprint(2, "%s\n", buf);
13477dd7cddfSDavid du Colombier }
13487dd7cddfSDavid du Colombier }
13497dd7cddfSDavid du Colombier
13507dd7cddfSDavid du Colombier char*
readsysname(void)13517dd7cddfSDavid du Colombier readsysname(void)
13527dd7cddfSDavid du Colombier {
13539a747e4fSDavid du Colombier static char name[128];
13547dd7cddfSDavid du Colombier char *p;
13557dd7cddfSDavid du Colombier int n, fd;
13567dd7cddfSDavid du Colombier
13577dd7cddfSDavid du Colombier fd = open("/dev/sysname", OREAD);
13587dd7cddfSDavid du Colombier if(fd >= 0){
13597dd7cddfSDavid du Colombier n = read(fd, name, sizeof(name)-1);
13607dd7cddfSDavid du Colombier close(fd);
13617dd7cddfSDavid du Colombier if(n > 0){
13627dd7cddfSDavid du Colombier name[n] = 0;
13637dd7cddfSDavid du Colombier return name;
13647dd7cddfSDavid du Colombier }
13657dd7cddfSDavid du Colombier }
13667dd7cddfSDavid du Colombier p = getenv("sysname");
13679a747e4fSDavid du Colombier if(p == nil || *p == 0)
13689a747e4fSDavid du Colombier return "unknown";
13697dd7cddfSDavid du Colombier return p;
13707dd7cddfSDavid du Colombier }
13717dd7cddfSDavid du Colombier
13727dd7cddfSDavid du Colombier extern int
validip(uchar * ip)13737dd7cddfSDavid du Colombier validip(uchar *ip)
13747dd7cddfSDavid du Colombier {
13757dd7cddfSDavid du Colombier if(ipcmp(ip, IPnoaddr) == 0)
13767dd7cddfSDavid du Colombier return 0;
13777dd7cddfSDavid du Colombier if(ipcmp(ip, v4prefix) == 0)
13787dd7cddfSDavid du Colombier return 0;
13797dd7cddfSDavid du Colombier return 1;
13807dd7cddfSDavid du Colombier }
13817dd7cddfSDavid du Colombier
13827dd7cddfSDavid du Colombier void
longopt(Req * rp,int t,long v)13837dd7cddfSDavid du Colombier longopt(Req *rp, int t, long v)
13847dd7cddfSDavid du Colombier {
13857dd7cddfSDavid du Colombier if(rp->p + 6 > rp->max)
13867dd7cddfSDavid du Colombier return;
13877dd7cddfSDavid du Colombier *rp->p++ = t;
13887dd7cddfSDavid du Colombier *rp->p++ = 4;
13897dd7cddfSDavid du Colombier hnputl(rp->p, v);
13907dd7cddfSDavid du Colombier rp->p += 4;
13913ff48bf5SDavid du Colombier
13923ff48bf5SDavid du Colombier op = seprint(op, oe, "%s(%ld)", optname[t], v);
13937dd7cddfSDavid du Colombier }
13947dd7cddfSDavid du Colombier
13957dd7cddfSDavid du Colombier void
addropt(Req * rp,int t,uchar * ip)13967dd7cddfSDavid du Colombier addropt(Req *rp, int t, uchar *ip)
13977dd7cddfSDavid du Colombier {
13987dd7cddfSDavid du Colombier if(rp->p + 6 > rp->max)
13997dd7cddfSDavid du Colombier return;
14000a84db5eSDavid du Colombier if (!isv4(ip)) {
14010a84db5eSDavid du Colombier if (debug)
14020a84db5eSDavid du Colombier warning(0, "not a v4 %s server: %I", optname[t], ip);
14030a84db5eSDavid du Colombier return;
14040a84db5eSDavid du Colombier }
14057dd7cddfSDavid du Colombier *rp->p++ = t;
14067dd7cddfSDavid du Colombier *rp->p++ = 4;
14077dd7cddfSDavid du Colombier memmove(rp->p, ip+IPv4off, 4);
14087dd7cddfSDavid du Colombier rp->p += 4;
14093ff48bf5SDavid du Colombier
14103ff48bf5SDavid du Colombier op = seprint(op, oe, "%s(%I)", optname[t], ip);
14113ff48bf5SDavid du Colombier }
14123ff48bf5SDavid du Colombier
14133ff48bf5SDavid du Colombier void
maskopt(Req * rp,int t,uchar * ip)14143ff48bf5SDavid du Colombier maskopt(Req *rp, int t, uchar *ip)
14153ff48bf5SDavid du Colombier {
14163ff48bf5SDavid du Colombier if(rp->p + 6 > rp->max)
14173ff48bf5SDavid du Colombier return;
14183ff48bf5SDavid du Colombier *rp->p++ = t;
14193ff48bf5SDavid du Colombier *rp->p++ = 4;
14203ff48bf5SDavid du Colombier memmove(rp->p, ip+IPv4off, 4);
14213ff48bf5SDavid du Colombier rp->p += 4;
14223ff48bf5SDavid du Colombier
14233ff48bf5SDavid du Colombier op = seprint(op, oe, "%s(%M)", optname[t], ip);
14247dd7cddfSDavid du Colombier }
14257dd7cddfSDavid du Colombier
14267dd7cddfSDavid du Colombier void
addrsopt(Req * rp,int t,uchar ** ip,int i)14277dd7cddfSDavid du Colombier addrsopt(Req *rp, int t, uchar **ip, int i)
14287dd7cddfSDavid du Colombier {
14290a84db5eSDavid du Colombier int v4s, n;
14300a84db5eSDavid du Colombier
14317dd7cddfSDavid du Colombier if(i <= 0)
14327dd7cddfSDavid du Colombier return;
14337dd7cddfSDavid du Colombier if(rp->p + 2 + 4*i > rp->max)
14347dd7cddfSDavid du Colombier return;
14350a84db5eSDavid du Colombier v4s = 0;
14360a84db5eSDavid du Colombier for(n = i; n-- > 0; )
14370a84db5eSDavid du Colombier if (isv4(ip[n]))
14380a84db5eSDavid du Colombier v4s++;
14390a84db5eSDavid du Colombier if (v4s <= 0) {
14400a84db5eSDavid du Colombier if (debug)
14410a84db5eSDavid du Colombier warning(0, "no v4 %s servers", optname[t]);
14420a84db5eSDavid du Colombier return;
14430a84db5eSDavid du Colombier }
14447dd7cddfSDavid du Colombier *rp->p++ = t;
14450a84db5eSDavid du Colombier *rp->p++ = 4*v4s;
14463ff48bf5SDavid du Colombier op = seprint(op, oe, " %s(", optname[t]);
14477dd7cddfSDavid du Colombier while(i-- > 0){
14480a84db5eSDavid du Colombier if (!isv4(*ip)) {
14490a84db5eSDavid du Colombier op = seprint(op, oe, " skipping %I ", *ip);
14500a84db5eSDavid du Colombier continue;
14510a84db5eSDavid du Colombier }
14527dd7cddfSDavid du Colombier v6tov4(rp->p, *ip);
14537dd7cddfSDavid du Colombier rp->p += 4;
14543ff48bf5SDavid du Colombier op = seprint(op, oe, "%I", *ip);
14557dd7cddfSDavid du Colombier ip++;
14563ff48bf5SDavid du Colombier if(i > 0)
14573ff48bf5SDavid du Colombier op = seprint(op, oe, " ");
14587dd7cddfSDavid du Colombier }
14593ff48bf5SDavid du Colombier op = seprint(op, oe, ")");
14607dd7cddfSDavid du Colombier }
14617dd7cddfSDavid du Colombier
14627dd7cddfSDavid du Colombier void
p9addrsopt(Req * rp,int t,uchar ** ip,int i)14630a84db5eSDavid du Colombier p9addrsopt(Req *rp, int t, uchar **ip, int i)
14640a84db5eSDavid du Colombier {
14650a84db5eSDavid du Colombier char *pkt, *payload;
14660a84db5eSDavid du Colombier
14670a84db5eSDavid du Colombier if(i <= 0 || !v6opts)
14680a84db5eSDavid du Colombier return;
14690a84db5eSDavid du Colombier pkt = (char *)rp->p;
14700a84db5eSDavid du Colombier *pkt++ = t; /* option */
14710a84db5eSDavid du Colombier pkt++; /* fill in payload length below */
14720a84db5eSDavid du Colombier payload = pkt;
14730a84db5eSDavid du Colombier *pkt++ = i; /* plan 9 address count */
14740a84db5eSDavid du Colombier op = seprint(op, oe, " %s(", optname[t]);
14750a84db5eSDavid du Colombier while(i-- > 0){
14760a84db5eSDavid du Colombier pkt = seprint(pkt, (char *)rp->max, "%I", *ip);
14770a84db5eSDavid du Colombier if ((uchar *)pkt+1 >= rp->max) {
14780a84db5eSDavid du Colombier op = seprint(op, oe, "<out of mem1>)");
14790a84db5eSDavid du Colombier return;
14800a84db5eSDavid du Colombier }
14810a84db5eSDavid du Colombier pkt++; /* leave NUL as terminator */
14820a84db5eSDavid du Colombier op = seprint(op, oe, "%I", *ip);
14830a84db5eSDavid du Colombier ip++;
14840a84db5eSDavid du Colombier if(i > 0)
14850a84db5eSDavid du Colombier op = seprint(op, oe, " ");
14860a84db5eSDavid du Colombier }
14870a84db5eSDavid du Colombier if ((uchar *)pkt - rp->p > 0377) {
14880a84db5eSDavid du Colombier op = seprint(op, oe, "<out of mem2>)");
14890a84db5eSDavid du Colombier return;
14900a84db5eSDavid du Colombier }
14910a84db5eSDavid du Colombier op = seprint(op, oe, ")");
14920a84db5eSDavid du Colombier rp->p[1] = pkt - payload; /* payload length */
14930a84db5eSDavid du Colombier rp->p = (uchar *)pkt;
14940a84db5eSDavid du Colombier }
14950a84db5eSDavid du Colombier
14960a84db5eSDavid du Colombier void
byteopt(Req * rp,int t,uchar v)14977dd7cddfSDavid du Colombier byteopt(Req *rp, int t, uchar v)
14987dd7cddfSDavid du Colombier {
14997dd7cddfSDavid du Colombier if(rp->p + 3 > rp->max)
15007dd7cddfSDavid du Colombier return;
15017dd7cddfSDavid du Colombier *rp->p++ = t;
15027dd7cddfSDavid du Colombier *rp->p++ = 1;
15037dd7cddfSDavid du Colombier *rp->p++ = v;
15043ff48bf5SDavid du Colombier
15053ff48bf5SDavid du Colombier op = seprint(op, oe, "%s(%d)", optname[t], v);
15067dd7cddfSDavid du Colombier }
15077dd7cddfSDavid du Colombier
15087dd7cddfSDavid du Colombier void
termopt(Req * rp)15097dd7cddfSDavid du Colombier termopt(Req *rp)
15107dd7cddfSDavid du Colombier {
15117dd7cddfSDavid du Colombier if(rp->p + 1 > rp->max)
15127dd7cddfSDavid du Colombier return;
15137dd7cddfSDavid du Colombier *rp->p++ = OBend;
15147dd7cddfSDavid du Colombier }
15157dd7cddfSDavid du Colombier
15167dd7cddfSDavid du Colombier void
stringopt(Req * rp,int t,char * str)15177dd7cddfSDavid du Colombier stringopt(Req *rp, int t, char *str)
15187dd7cddfSDavid du Colombier {
15197dd7cddfSDavid du Colombier int n;
15207dd7cddfSDavid du Colombier
15217dd7cddfSDavid du Colombier n = strlen(str);
15227dd7cddfSDavid du Colombier if(n > 255)
15237dd7cddfSDavid du Colombier n = 255;
15247dd7cddfSDavid du Colombier if(rp->p+n+2 > rp->max)
15257dd7cddfSDavid du Colombier return;
15267dd7cddfSDavid du Colombier *rp->p++ = t;
15277dd7cddfSDavid du Colombier *rp->p++ = n;
15287dd7cddfSDavid du Colombier memmove(rp->p, str, n);
15297dd7cddfSDavid du Colombier rp->p += n;
15303ff48bf5SDavid du Colombier
15313ff48bf5SDavid du Colombier op = seprint(op, oe, "%s(%s)", optname[t], str);
15327dd7cddfSDavid du Colombier }
15337dd7cddfSDavid du Colombier
15347dd7cddfSDavid du Colombier void
vectoropt(Req * rp,int t,uchar * v,int n)15357dd7cddfSDavid du Colombier vectoropt(Req *rp, int t, uchar *v, int n)
15367dd7cddfSDavid du Colombier {
15373ff48bf5SDavid du Colombier int i;
15383ff48bf5SDavid du Colombier
15390a84db5eSDavid du Colombier if(n > 255) {
15407dd7cddfSDavid du Colombier n = 255;
15410a84db5eSDavid du Colombier op = seprint(op, oe, "vectoropt len %d > 255 ", n);
15420a84db5eSDavid du Colombier }
15437dd7cddfSDavid du Colombier if(rp->p+n+2 > rp->max)
15447dd7cddfSDavid du Colombier return;
15457dd7cddfSDavid du Colombier *rp->p++ = t;
15467dd7cddfSDavid du Colombier *rp->p++ = n;
15477dd7cddfSDavid du Colombier memmove(rp->p, v, n);
15487dd7cddfSDavid du Colombier rp->p += n;
15493ff48bf5SDavid du Colombier
15503ff48bf5SDavid du Colombier op = seprint(op, oe, "%s(", optname[t]);
15513ff48bf5SDavid du Colombier if(n > 0)
15520a84db5eSDavid du Colombier op = seprint(op, oe, "%ud", v[0]);
15533ff48bf5SDavid du Colombier for(i = 1; i < n; i++)
15543ff48bf5SDavid du Colombier op = seprint(op, oe, " %ud", v[i]);
15550a84db5eSDavid du Colombier op = seprint(op, oe, ")");
15567dd7cddfSDavid du Colombier }
15577dd7cddfSDavid du Colombier
15587dd7cddfSDavid du Colombier int
fromhex(int x)15597dd7cddfSDavid du Colombier fromhex(int x)
15607dd7cddfSDavid du Colombier {
15617dd7cddfSDavid du Colombier if(x >= '0' && x <= '9')
15627dd7cddfSDavid du Colombier return x - '0';
15637dd7cddfSDavid du Colombier return x - 'a';
15647dd7cddfSDavid du Colombier }
15657dd7cddfSDavid du Colombier
15667dd7cddfSDavid du Colombier void
hexopt(Req * rp,int t,char * str)15677dd7cddfSDavid du Colombier hexopt(Req *rp, int t, char *str)
15687dd7cddfSDavid du Colombier {
15697dd7cddfSDavid du Colombier int n;
15707dd7cddfSDavid du Colombier
15717dd7cddfSDavid du Colombier n = strlen(str);
15727dd7cddfSDavid du Colombier n /= 2;
15737dd7cddfSDavid du Colombier if(n > 255)
15747dd7cddfSDavid du Colombier n = 255;
15757dd7cddfSDavid du Colombier if(rp->p+n+2 > rp->max)
15767dd7cddfSDavid du Colombier return;
15777dd7cddfSDavid du Colombier *rp->p++ = t;
15787dd7cddfSDavid du Colombier *rp->p++ = n;
15797dd7cddfSDavid du Colombier while(n-- > 0){
15807dd7cddfSDavid du Colombier *rp->p++ = (fromhex(str[0])<<4)|fromhex(str[1]);
15817dd7cddfSDavid du Colombier str += 2;
15827dd7cddfSDavid du Colombier }
15833ff48bf5SDavid du Colombier
15843ff48bf5SDavid du Colombier op = seprint(op, oe, "%s(%s)", optname[t], str);
15857dd7cddfSDavid du Colombier }
15867dd7cddfSDavid du Colombier
15877dd7cddfSDavid du Colombier void
arpenter(uchar * ip,uchar * ether)15887dd7cddfSDavid du Colombier arpenter(uchar *ip, uchar *ether)
15897dd7cddfSDavid du Colombier {
15907dd7cddfSDavid du Colombier int f;
15917dd7cddfSDavid du Colombier char buf[256];
15927dd7cddfSDavid du Colombier
15937dd7cddfSDavid du Colombier sprint(buf, "%s/arp", net);
15947dd7cddfSDavid du Colombier f = open(buf, OWRITE);
15957dd7cddfSDavid du Colombier if(f < 0){
15967dd7cddfSDavid du Colombier syslog(debug, blog, "open %s: %r", buf);
15977dd7cddfSDavid du Colombier return;
15987dd7cddfSDavid du Colombier }
15997dd7cddfSDavid du Colombier fprint(f, "add ether %I %E", ip, ether);
16007dd7cddfSDavid du Colombier close(f);
16017dd7cddfSDavid du Colombier }
16027dd7cddfSDavid du Colombier
16037dd7cddfSDavid du Colombier char *dhcpmsgname[] =
16047dd7cddfSDavid du Colombier {
16057dd7cddfSDavid du Colombier [Discover] "Discover",
16067dd7cddfSDavid du Colombier [Offer] "Offer",
16077dd7cddfSDavid du Colombier [Request] "Request",
16087dd7cddfSDavid du Colombier [Decline] "Decline",
16097dd7cddfSDavid du Colombier [Ack] "Ack",
16107dd7cddfSDavid du Colombier [Nak] "Nak",
16117dd7cddfSDavid du Colombier [Release] "Release",
16127dd7cddfSDavid du Colombier [Inform] "Inform",
16137dd7cddfSDavid du Colombier };
16147dd7cddfSDavid du Colombier
16157dd7cddfSDavid du Colombier void
logdhcp(Req * rp)16167dd7cddfSDavid du Colombier logdhcp(Req *rp)
16177dd7cddfSDavid du Colombier {
16187dd7cddfSDavid du Colombier char buf[4096];
16197dd7cddfSDavid du Colombier char *p, *e;
16207dd7cddfSDavid du Colombier int i;
16217dd7cddfSDavid du Colombier
16227dd7cddfSDavid du Colombier p = buf;
16237dd7cddfSDavid du Colombier e = buf + sizeof(buf);
16247dd7cddfSDavid du Colombier if(rp->dhcptype > 0 && rp->dhcptype <= Inform)
16253ff48bf5SDavid du Colombier p = seprint(p, e, "%s(", dhcpmsgname[rp->dhcptype]);
16267dd7cddfSDavid du Colombier else
16273ff48bf5SDavid du Colombier p = seprint(p, e, "%d(", rp->dhcptype);
16283ff48bf5SDavid du Colombier p = seprint(p, e, "%I->%I) xid(%ux)flag(%ux)", rp->up->raddr, rp->up->laddr,
16293ff48bf5SDavid du Colombier nhgetl(rp->bp->xid), nhgets(rp->bp->flags));
16307dd7cddfSDavid du Colombier if(rp->bp->htype == 1)
16313ff48bf5SDavid du Colombier p = seprint(p, e, "ea(%E)", rp->bp->chaddr);
16323ff48bf5SDavid du Colombier if(validip(rp->ciaddr))
16333ff48bf5SDavid du Colombier p = seprint(p, e, "ci(%I)", rp->ciaddr);
16343ff48bf5SDavid du Colombier if(validip(rp->giaddr))
16353ff48bf5SDavid du Colombier p = seprint(p, e, "gi(%I)", rp->giaddr);
16363ff48bf5SDavid du Colombier if(validip(rp->ip))
16373ff48bf5SDavid du Colombier p = seprint(p, e, "ip(%I)", rp->ip);
16383ff48bf5SDavid du Colombier if(rp->id != nil)
16393ff48bf5SDavid du Colombier p = seprint(p, e, "id(%s)", rp->id);
16403ff48bf5SDavid du Colombier if(rp->leasetime)
16413ff48bf5SDavid du Colombier p = seprint(p, e, "leas(%d)", rp->leasetime);
16423ff48bf5SDavid du Colombier if(validip(rp->server))
16433ff48bf5SDavid du Colombier p = seprint(p, e, "sid(%I)", rp->server);
16443ff48bf5SDavid du Colombier p = seprint(p, e, "need(");
16457dd7cddfSDavid du Colombier for(i = 0; i < sizeof(rp->requested); i++)
16467dd7cddfSDavid du Colombier if(rp->requested[i] != 0)
16473ff48bf5SDavid du Colombier p = seprint(p, e, "%s ", optname[rp->requested[i]]);
16487dd7cddfSDavid du Colombier p = seprint(p, e, ")");
16498ae63d3dSDavid du Colombier p = seprint(p, e, " %s", rp->broadcast? "broadcast": "unicast");
16507dd7cddfSDavid du Colombier USED(p);
16517dd7cddfSDavid du Colombier syslog(0, blog, "%s", buf);
16527dd7cddfSDavid du Colombier }
16533ff48bf5SDavid du Colombier
16543ff48bf5SDavid du Colombier void
logdhcpout(Req * rp,char * type)16553ff48bf5SDavid du Colombier logdhcpout(Req *rp, char *type)
16563ff48bf5SDavid du Colombier {
16573ff48bf5SDavid du Colombier syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s",
16583ff48bf5SDavid du Colombier type, rp->up->laddr, rp->up->raddr, rp->id,
16593ff48bf5SDavid du Colombier rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf);
16603ff48bf5SDavid du Colombier }
16613ff48bf5SDavid du Colombier
16623ff48bf5SDavid du Colombier /*
16633ff48bf5SDavid du Colombier * if we get behind, it's useless to try answering since the sender
16643ff48bf5SDavid du Colombier * will probably have retransmitted with a differnt sequence number.
16650a84db5eSDavid du Colombier * So dump all but the last message in the queue.
16663ff48bf5SDavid du Colombier */
16670a84db5eSDavid du Colombier void
ding(void *,char * msg)16680a84db5eSDavid du Colombier ding(void*, char *msg)
16693ff48bf5SDavid du Colombier {
16703ff48bf5SDavid du Colombier if(strstr(msg, "alarm"))
16713ff48bf5SDavid du Colombier noted(NCONT);
16723ff48bf5SDavid du Colombier else
16733ff48bf5SDavid du Colombier noted(NDFLT);
16743ff48bf5SDavid du Colombier }
16753ff48bf5SDavid du Colombier
16763ff48bf5SDavid du Colombier int
readlast(int fd,uchar * buf,int len)16773ff48bf5SDavid du Colombier readlast(int fd, uchar *buf, int len)
16783ff48bf5SDavid du Colombier {
16793ff48bf5SDavid du Colombier int lastn, n;
16803ff48bf5SDavid du Colombier
16813ff48bf5SDavid du Colombier notify(ding);
16823ff48bf5SDavid du Colombier
16833ff48bf5SDavid du Colombier lastn = 0;
16843ff48bf5SDavid du Colombier for(;;){
16853ff48bf5SDavid du Colombier alarm(20);
16863ff48bf5SDavid du Colombier n = read(fd, buf, len);
16873ff48bf5SDavid du Colombier alarm(0);
16883ff48bf5SDavid du Colombier if(n < 0){
16893ff48bf5SDavid du Colombier if(lastn > 0)
16903ff48bf5SDavid du Colombier return lastn;
16913ff48bf5SDavid du Colombier break;
16923ff48bf5SDavid du Colombier }
16933ff48bf5SDavid du Colombier lastn = n;
16943ff48bf5SDavid du Colombier }
16953ff48bf5SDavid du Colombier return read(fd, buf, len);
16963ff48bf5SDavid du Colombier }
1697