]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/dhcpd/dhcpd.c
socksd: setnetmtpt
[plan9front.git] / sys / src / cmd / ip / dhcpd / dhcpd.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <bio.h>
5 #include <ndb.h>
6 #include "dat.h"
7
8 /*
9  *      ala rfc2131
10  */
11
12 enum {
13         Maxloglen = 1024,
14 };
15
16 typedef struct Req Req;
17 struct Req
18 {
19         int     fd;                     /* for reply */
20         Bootp   *bp;
21         Udphdr  *up;
22         uchar   *e;                     /* end of received message */
23         uchar   *p;                     /* options pointer */
24         uchar   *max;                   /* max end of reply */
25
26         /* expanded to v6 */
27         uchar   ciaddr[IPaddrlen];
28         uchar   giaddr[IPaddrlen];
29
30         /* parsed options */
31         int     p9request;              /* flag: this is a bootp with plan9 options */
32         int     genrequest;             /* flag: this is a bootp with generic options */
33         int     dhcptype;               /* dhcp message type */
34         int     leasetime;              /* dhcp lease */
35         uchar   ip[IPaddrlen];          /* requested address */
36         uchar   server[IPaddrlen];      /* server address */
37         char    msg[ERRMAX];            /* error message */
38         char    vci[32];                /* vendor class id */
39         char    *id;                    /* client id */
40         uchar   requested[32];          /* requested params */
41         uchar   vendorclass[32];
42         char    cputype[32-3];
43
44         Info    gii;                    /* about target network */
45         Info    ii;                     /* about target system */
46         int     staticbinding;
47
48         uchar buf[2*1024];              /* message buffer */
49 };
50
51 #define TFTP "/lib/tftpd"
52
53 char    *blog = "ipboot";
54 char    mysysname[64];
55 Ipifc   *ipifcs;
56 int     debug;
57 int     nobootp;
58 long    now;
59 int     slowstat, slowdyn;
60 char    net[256];
61
62 int     pptponly;       /* only answer request that came from the pptp server */
63 int     mute, mutestat;
64 int     minlease = MinLease;
65 int     staticlease = StaticLease;
66
67 uvlong  start;
68
69 static int v6opts;
70
71 /* option magic */
72 char plan9opt[4] = { 'p', '9', ' ', ' ' };
73 char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 };
74
75 /* well known addresses */
76 uchar zeros[Maxhwlen];
77
78 /* option debug buffer */
79 char optbuf[1024];
80 char *op;
81 char *oe = optbuf + sizeof(optbuf);
82
83 char *optname[256] =
84 {
85 [OBend]                 "end",
86 [OBpad]                 "pad",
87 [OBmask]                "mask",
88 [OBtimeoff]             "timeoff",
89 [OBrouter]              "router",
90 [OBtimeserver]          "time",
91 [OBnameserver]          "name",
92 [OBdnserver]            "dns",
93 [OBlogserver]           "log",
94 [OBcookieserver]        "cookie",
95 [OBlprserver]           "lpr",
96 [OBimpressserver]       "impress",
97 [OBrlserver]            "rl",
98 [OBhostname]            "host",
99 [OBbflen]               "bflen",
100 [OBdumpfile]            "dumpfile",
101 [OBdomainname]          "dom",
102 [OBswapserver]          "swap",
103 [OBrootpath]            "rootpath",
104 [OBextpath]             "extpath",
105 [OBipforward]           "ipforward",
106 [OBnonlocal]            "nonlocal",
107 [OBpolicyfilter]        "policyfilter",
108 [OBmaxdatagram]         "maxdatagram",
109 [OBttl]                 "ttl",
110 [OBpathtimeout]         "pathtimeout",
111 [OBpathplateau]         "pathplateau",
112 [OBmtu]                 "mtu",
113 [OBsubnetslocal]        "subnetslocal",
114 [OBbaddr]               "baddr",
115 [OBdiscovermask]        "discovermask",
116 [OBsupplymask]          "supplymask",
117 [OBdiscoverrouter]      "discoverrouter",
118 [OBrsserver]            "rsserver",
119 [OBstaticroutes]        "staticroutes",
120 [OBtrailerencap]        "trailerencap",
121 [OBarptimeout]          "arptimeout",
122 [OBetherencap]          "etherencap",
123 [OBtcpttl]              "tcpttl",
124 [OBtcpka]               "tcpka",
125 [OBtcpkag]              "tcpkag",
126 [OBnisdomain]           "nisdomain",
127 [OBniserver]            "niserver",
128 [OBntpserver]           "ntpserver",
129 [OBvendorinfo]          "vendorinfo",
130 [OBnetbiosns]           "NBns",
131 [OBnetbiosdds]          "NBdds",
132 [OBnetbiostype]         "NBtype",
133 [OBnetbiosscope]        "NBscope",
134 [OBxfontserver]         "xfont",
135 [OBxdispmanager]        "xdisp",
136 [OBnisplusdomain]       "NPdomain",
137 [OBnisplusserver]       "NP",
138 [OBhomeagent]           "homeagent",
139 [OBsmtpserver]          "smtp",
140 [OBpop3server]          "pop3",
141 [OBnntpserver]          "nntp",
142 [OBwwwserver]           "www",
143 [OBfingerserver]        "finger",
144 [OBircserver]           "ircserver",
145 [OBstserver]            "stserver",
146 [OBstdaserver]          "stdaserver",
147
148 /* dhcp options */
149 [ODipaddr]              "ip",
150 [ODlease]               "leas",
151 [ODoverload]            "overload",
152 [ODtype]                "typ",
153 [ODserverid]            "sid",
154 [ODparams]              "params",
155 [ODmessage]             "message",
156 [ODmaxmsg]              "maxmsg",
157 [ODrenewaltime]         "renewaltime",
158 [ODrebindingtime]       "rebindingtime",
159 [ODvendorclass]         "vendorclass",
160 [ODclientid]            "cid",
161 [ODtftpserver]          "tftpserver",
162 [ODbootfile]            "bf",
163 };
164
165 void    addropt(Req*, int, uchar*);
166 void    addrsopt(Req*, int, uchar**, int);
167 void    arpenter(uchar*, uchar*);
168 void    bootp(Req*);
169 void    byteopt(Req*, int, uchar);
170 void    dhcp(Req*);
171 void    fatal(int, char*, ...);
172 void    hexopt(Req*, int, char*);
173 void    logdhcp(Req*);
174 void    logdhcpout(Req *, char *);
175 void    longopt(Req*, int, long);
176 void    maskopt(Req*, int, uchar*);
177 void    miscoptions(Req*, uchar*);
178 int     openlisten(char *net);
179 void    p9addrsopt(Req *rp, int t, uchar **ip, int i);
180 void    parseoptions(Req*);
181 void    proto(Req*, int);
182 void    rcvdecline(Req*);
183 void    rcvdiscover(Req*);
184 void    rcvinform(Req*);
185 void    rcvrelease(Req*);
186 void    rcvrequest(Req*);
187 int     readlast(int, uchar*, int);
188 char*   readsysname(void);
189 void    remrequested(Req*, int);
190 void    sendack(Req*, uchar*, int, int);
191 void    sendnak(Req*, char*);
192 void    sendoffer(Req*, uchar*, int);
193 void    stringopt(Req*, int, char*);
194 void    termopt(Req*);
195 int     validip(uchar*);
196 void    vectoropt(Req*, int, uchar*, int);
197 void    warning(int, char*, ...);
198
199 void
200 timestamp(char *tag)
201 {
202         uvlong t;
203
204         t = nsec()/1000;
205         syslog(0, blog, "%s %lludµs", tag, t - start);
206 }
207
208 void
209 usage(void)
210 {
211         fprint(2, "usage: dhcp [-dmnprsSZ] [-f directory] [-M minlease] "
212                 "[-x netmtpt] [-Z staticlease] addr n [addr n] ...\n");
213         exits("usage");
214 }
215
216 void
217 main(int argc, char **argv)
218 {
219         int i, n, fd;
220         uchar ip[IPaddrlen];
221         Req r;
222
223         setnetmtpt(net, sizeof net, nil);
224
225         fmtinstall('E', eipfmt);
226         fmtinstall('I', eipfmt);
227         fmtinstall('V', eipfmt);
228         fmtinstall('M', eipfmt);
229         ARGBEGIN {
230         case '6':
231                 v6opts = 1;
232                 break;
233         case 'd':
234                 debug = 1;
235                 break;
236         case 'f':
237                 ndbfile = EARGF(usage());
238                 break;
239         case 'm':
240                 mute = 1;
241                 break;
242         case 'M':
243                 minlease = atoi(EARGF(usage()));
244                 if(minlease <= 0)
245                         minlease = MinLease;
246                 break;
247         case 'n':
248                 nobootp = 1;
249                 break;
250         case 'p':
251                 pptponly = 1;
252                 break;
253         case 'r':
254                 mutestat = 1;
255                 break;
256         case 's':
257                 slowstat = 1;
258                 break;
259         case 'S':
260                 slowdyn = 1;
261                 break;
262         case 'x':
263                 setnetmtpt(net, sizeof net, EARGF(usage()));
264                 break;
265         case 'Z':
266                 staticlease = atoi(EARGF(usage()));
267                 if(staticlease <= 0)
268                         staticlease = StaticLease;
269                 break;
270         default:
271                 usage();
272                 break;
273         } ARGEND;
274
275         while(argc > 1){
276                 parseip(ip, argv[0]);
277                 if(!validip(ip))
278                         usage();
279                 n = atoi(argv[1]);
280                 if(n <= 0)
281                         usage();
282                 initbinding(ip, n);
283                 argc -= 2;
284                 argv += 2;
285         }
286
287         /* for debugging */
288         for(i = 0; i < 256; i++)
289                 if(optname[i] == 0)
290                         optname[i] = smprint("%d", i);
291
292         /* what is my name? */
293         strcpy(mysysname, readsysname());
294
295         /* put process in background */
296         if(!debug)
297         switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
298         case -1:
299                 fatal(1, "fork");
300         case 0:
301                 break;
302         default:
303                 exits(0);
304         }
305
306         if (chdir(TFTP) < 0)
307                 warning(1, "can't change directory to %s", TFTP);
308         fd = openlisten(net);
309
310         for(;;){
311                 memset(&r, 0, sizeof(r));
312                 r.fd = fd;
313                 n = readlast(r.fd, r.buf, sizeof(r.buf));
314                 if(n < Udphdrsize)
315                         fatal(1, "error reading requests");
316                 start = nsec()/1000;
317                 op = optbuf;
318                 *op = 0;
319                 proto(&r, n);
320                 if(r.id != nil)
321                         free(r.id);
322         }
323 }
324
325 void
326 proto(Req *rp, int n)
327 {
328         uchar relip[IPaddrlen];
329         char buf[64];
330
331         now = time(0);
332
333         rp->e = rp->buf + n;
334         rp->bp = (Bootp*)rp->buf;
335         rp->up = (Udphdr*)rp->buf;
336         if (ipcmp(rp->up->laddr, IPv4bcast) == 0)
337                 ipmove(rp->up->laddr, rp->up->ifcaddr);
338         rp->max = rp->buf + Udphdrsize + MINSUPPORTED - IPUDPHDRSIZE;
339         rp->p = rp->bp->optdata;
340         v4tov6(rp->giaddr, rp->bp->giaddr);
341         v4tov6(rp->ciaddr, rp->bp->ciaddr);
342
343         if(pptponly && rp->bp->htype != 0)
344                 return;
345
346         ipifcs = readipifc(net, ipifcs, -1);
347         if(validip(rp->giaddr))
348                 ipmove(relip, rp->giaddr);
349         else if(validip(rp->up->raddr))
350                 ipmove(relip, rp->up->raddr);
351         else
352                 ipmove(relip, rp->up->laddr);
353         if(rp->e < (uchar*)rp->bp->sname){
354                 warning(0, "packet too short");
355                 return;
356         }
357         if(rp->bp->op != Bootrequest){
358                 warning(0, "not bootrequest");
359                 return;
360         }
361
362         if(rp->e >= rp->bp->optdata){
363                 if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0)
364                         rp->p9request = 1;
365                 if(memcmp(rp->bp->optmagic, genericopt, sizeof(rp->bp->optmagic)) == 0) {
366                         rp->genrequest = 1;
367                         parseoptions(rp);
368                 }
369         }
370         rp->p = rp->bp->optdata;
371
372         /*  If no id is specified, make one from the hardware address
373          *  of the target.  We assume all zeros is not a hardware address
374          *  which could be a mistake.
375          */
376         if(rp->id == nil){
377                 if(rp->bp->hlen > Maxhwlen){
378                         warning(0, "hlen %d", rp->bp->hlen);
379                         return;
380                 }
381                 if(memcmp(zeros, rp->bp->chaddr, rp->bp->hlen) == 0){
382                         warning(0, "no chaddr");
383                         return;
384                 }
385                 sprint(buf, "hwa%2.2ux_", rp->bp->htype);
386                 rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen);
387         }
388
389         /* info about gateway */
390         if(lookupip(relip, &rp->gii, 1) < 0){
391                 warning(0, "lookupip failed");
392                 return;
393         }
394
395         /* info about target system */
396         if(lookup(rp->bp, &rp->ii, &rp->gii) == 0)
397                 if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0)
398                         rp->staticbinding = 1;
399
400         if(rp->dhcptype)
401                 dhcp(rp);
402         else
403                 bootp(rp);
404         timestamp("done");
405 }
406
407 static void
408 slowdelay(Req *rp)
409 {
410         if(slowstat && rp->staticbinding || slowdyn && !rp->staticbinding)
411                 sleep(2000);
412 }
413
414 void
415 dhcp(Req *rp)
416 {
417         logdhcp(rp);
418
419         switch(rp->dhcptype){
420         case Discover:
421                 slowdelay(rp);
422                 rcvdiscover(rp);
423                 break;
424         case Request:
425                 rcvrequest(rp);
426                 break;
427         case Decline:
428                 rcvdecline(rp);
429                 break;
430         case Release:
431                 rcvrelease(rp);
432                 break;
433         case Inform:
434                 rcvinform(rp);
435                 break;
436         }
437 }
438
439 void
440 rcvdiscover(Req *rp)
441 {
442         Binding *b, *nb;
443
444         if(rp->staticbinding){
445                 sendoffer(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease));
446                 return;
447         }
448
449         /*
450          *  first look for an outstanding offer
451          */
452         b = idtooffer(rp->id, &rp->gii);
453
454         /*
455          * rfc2131 says:
456          *   If an address is available, the new address
457          *   SHOULD be chosen as follows:
458          *
459          *      o The client's current address as recorded in the client's current
460          *        binding, ELSE
461          *
462          *      o The client's previous address as recorded in the client's (now
463          *        expired or released) binding, if that address is in the server's
464          *        pool of available addresses and not already allocated, ELSE
465          *
466          *      o The address requested in the 'Requested IP Address' option, if that
467          *        address is valid and not already allocated, ELSE
468          *
469          *      o A new address allocated from the server's pool of available
470          *        addresses; the address is selected based on the subnet from which
471          *        the message was received (if 'giaddr' is 0) or on the address of
472          *        the relay agent that forwarded the message ('giaddr' when not 0).
473          */
474         if(b == nil){
475                 b = idtobinding(rp->id, &rp->gii, 1);
476                 if(b && b->boundto && strcmp(b->boundto, rp->id) != 0)
477                 if(validip(rp->ip) && samenet(rp->ip, &rp->gii)){
478                         nb = iptobinding(rp->ip, 0);
479                         if(nb && nb->lease < now)
480                                 b = nb;
481                 }
482         }
483         if(b == nil){
484                 warning(0, "!Discover(%s via %I): no binding %I",
485                         rp->id, rp->gii.ipaddr, rp->ip);
486                 return;
487         }
488         mkoffer(b, rp->id, rp->leasetime);
489         sendoffer(rp, b->ip, b->offer);
490 }
491
492 void
493 rcvrequest(Req *rp)
494 {
495         Binding *b;
496
497         if(validip(rp->server)){
498                 /* this is a reply to an offer - SELECTING */
499
500                 /* check for hard assignment */
501                 if(rp->staticbinding){
502                         if(forme(rp->server))
503                                 sendack(rp, rp->ii.ipaddr,
504                                         (staticlease > minlease? staticlease:
505                                         minlease), 1);
506                         else
507                                 warning(0, "!Request(%s via %I): for server %I not me",
508                                         rp->id, rp->gii.ipaddr, rp->server);
509                         return;
510                 }
511
512                 b = idtooffer(rp->id, &rp->gii);
513
514                 /* if we don't have an offer, nak */
515                 if(b == nil){
516                         warning(0, "!Request(%s via %I): no offer",
517                                 rp->id, rp->gii.ipaddr);
518                         if(forme(rp->server))
519                                 sendnak(rp, "no offer for you");
520                         return;
521                 }
522
523                 /* if not for me, retract offer */
524                 if(!forme(rp->server)){
525                         b->expoffer = 0;
526                         warning(0, "!Request(%s via %I): for server %I not me",
527                                 rp->id, rp->gii.ipaddr, rp->server);
528                         return;
529                 }
530
531                 /*
532                  *  if the client is confused about what we offered, nak.
533                  *  client really shouldn't be specifying this when selecting
534                  */
535                 if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){
536                         warning(0, "!Request(%s via %I): requests %I, not %I",
537                                 rp->id, rp->gii.ipaddr, rp->ip, b->ip);
538                         sendnak(rp, "bad ip address option");
539                         return;
540                 }
541                 if(commitbinding(b) < 0){
542                         warning(0, "!Request(%s via %I): can't commit %I",
543                                 rp->id, rp->gii.ipaddr, b->ip);
544                         sendnak(rp, "can't commit binding");
545                         return;
546                 }
547                 sendack(rp, b->ip, b->offer, 1);
548         } else if(validip(rp->ip)){
549                 /*
550                  *  checking address/net - INIT-REBOOT
551                  *
552                  *  This is a rebooting client that remembers its old
553                  *  address.
554                  */
555                 /* check for hard assignment */
556                 if(rp->staticbinding){
557                         if(memcmp(rp->ip, rp->ii.ipaddr, IPaddrlen) != 0){
558                                 warning(0, "!Request(%s via %I): %I not valid for %E",
559                                         rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr);
560                                 sendnak(rp, "not valid");
561                         }
562                         sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
563                                 staticlease: minlease), 1);
564                         return;
565                 }
566
567                 /* make sure the network makes sense */
568                 if(!samenet(rp->ip, &rp->gii)){
569                         warning(0, "!Request(%s via %I): bad forward of %I",
570                                 rp->id, rp->gii.ipaddr, rp->ip);
571                         sendnak(rp, "wrong network");
572                         return;
573                 }
574                 b = iptobinding(rp->ip, 0);
575                 if(b == nil){
576                         warning(0, "!Request(%s via %I): no binding for %I",
577                                 rp->id, rp->gii.ipaddr, rp->ip);
578                         return;
579                 }
580                 if(memcmp(rp->ip, b->ip, IPaddrlen) != 0 || now > b->lease){
581                         warning(0, "!Request(%s via %I): %I not valid",
582                                 rp->id, rp->gii.ipaddr, rp->ip);
583                         sendnak(rp, "not valid");
584                         return;
585                 }
586                 b->offer = b->lease - now;
587                 sendack(rp, b->ip, b->offer, 1);
588         } else if(validip(rp->ciaddr)){
589                 /*
590                  *  checking address - RENEWING or REBINDING
591                  *
592                  *  these states are indistinguishable in our action.  The only
593                  *  difference is how close to lease expiration the client is.
594                  *  If it is really close, it broadcasts the request hoping that
595                  *  some server will answer.
596                  */
597
598                 /* check for hard assignment */
599                 if(rp->staticbinding){
600                         if(ipcmp(rp->ciaddr, rp->ii.ipaddr) != 0){
601                                 warning(0, "!Request(%s via %I): %I not valid",
602                                         rp->id, rp->gii.ipaddr, rp->ciaddr);
603                                 sendnak(rp, "not valid");
604                         }
605                         sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
606                                 staticlease: minlease), 1);
607                         return;
608                 }
609
610                 /* make sure the network makes sense */
611                 if(!samenet(rp->ciaddr, &rp->gii)){
612                         warning(0, "!Request(%s via %I): bad forward of %I",
613                                 rp->id, rp->gii.ipaddr, rp->ip);
614                         sendnak(rp, "wrong network");
615                         return;
616                 }
617                 b = iptobinding(rp->ciaddr, 0);
618                 if(b == nil){
619                         warning(0, "!Request(%s via %I): no binding for %I",
620                                 rp->id, rp->gii.ipaddr, rp->ciaddr);
621                         return;
622                 }
623                 if(ipcmp(rp->ciaddr, b->ip) != 0){
624                         warning(0, "!Request(%I via %s): %I not valid",
625                                 rp->id, rp->gii.ipaddr, rp->ciaddr);
626                         sendnak(rp, "invalid ip address");
627                         return;
628                 }
629                 mkoffer(b, rp->id, rp->leasetime);
630                 if(commitbinding(b) < 0){
631                         warning(0, "!Request(%s via %I): can't commit %I",
632                                 rp->id, rp->gii.ipaddr, b->ip);
633                         sendnak(rp, "can't commit binding");
634                         return;
635                 }
636                 sendack(rp, b->ip, b->offer, 1);
637         }
638 }
639
640 void
641 rcvdecline(Req *rp)
642 {
643         Binding *b;
644         char buf[64];
645
646         if(rp->staticbinding)
647                 return;
648
649         b = idtooffer(rp->id, &rp->gii);
650         if(b == nil){
651                 warning(0, "!Decline(%s via %I): no binding",
652                         rp->id, rp->gii.ipaddr);
653                 return;
654         }
655
656         /* mark ip address as in use */
657         snprint(buf, sizeof(buf), "declined by %s", rp->id);
658         mkoffer(b, buf, 0x7fffffff);
659         commitbinding(b);
660 }
661
662 void
663 rcvrelease(Req *rp)
664 {
665         Binding *b;
666
667         if(rp->staticbinding)
668                 return;
669
670         b = idtobinding(rp->id, &rp->gii, 0);
671         if(b == nil){
672                 warning(0, "!Release(%s via %I): no binding",
673                         rp->id, rp->gii.ipaddr);
674                 return;
675         }
676         if(strcmp(rp->id, b->boundto) != 0){
677                 warning(0, "!Release(%s via %I): invalid release of %I",
678                         rp->id, rp->gii.ipaddr, rp->ip);
679                 return;
680         }
681         warning(0, "Release(%s via %I): releasing %I", b->boundto, rp->gii.ipaddr, b->ip);
682         if(releasebinding(b, rp->id) < 0)
683                 warning(0, "release: couldn't release");
684 }
685
686 void
687 rcvinform(Req *rp)
688 {
689         Binding *b;
690
691         if(rp->staticbinding){
692                 sendack(rp, rp->ii.ipaddr, 0, 0);
693                 return;
694         }
695
696         b = iptobinding(rp->ciaddr, 0);
697         if(b == nil){
698                 warning(0, "!Inform(%s via %I): no binding for %I",
699                         rp->id, rp->gii.ipaddr, rp->ip);
700                 return;
701         }
702         sendack(rp, b->ip, 0, 0);
703 }
704
705 int
706 setsiaddr(uchar *siaddr, uchar *saddr, uchar *laddr)
707 {
708         if(ipcmp(saddr, IPnoaddr) != 0){
709                 v6tov4(siaddr, saddr);
710                 return 0;
711         } else {
712                 v6tov4(siaddr, laddr);
713                 return 1;
714         }
715 }
716
717 int
718 ismuted(Req *rp)
719 {
720         return mute || (mutestat && rp->staticbinding);
721 }
722
723 void
724 sendoffer(Req *rp, uchar *ip, int offer)
725 {
726         int n;
727         ushort flags;
728         Bootp *bp;
729         Udphdr *up;
730
731         bp = rp->bp;
732         up = rp->up;
733
734         /*
735          *  set destination
736          */
737         flags = nhgets(bp->flags);
738         if(validip(rp->giaddr)){
739                 ipmove(up->raddr, rp->giaddr);
740                 hnputs(up->rport, 67);
741         } else if(flags & Fbroadcast){
742                 ipmove(up->raddr, IPv4bcast);
743                 hnputs(up->rport, 68);
744         } else {
745                 ipmove(up->raddr, ip);
746                 if(bp->htype == 1)
747                         arpenter(up->raddr, bp->chaddr);
748                 hnputs(up->rport, 68);
749         }
750
751         /*
752          *  fill in standard bootp part
753          */
754         bp->op = Bootreply;
755         bp->hops = 0;
756         hnputs(bp->secs, 0);
757         memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
758         v6tov4(bp->giaddr, rp->giaddr);
759         v6tov4(bp->yiaddr, ip);
760         setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
761         strncpy(bp->sname, mysysname, sizeof(bp->sname));
762         strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
763
764         /*
765          *  set options
766          */
767         byteopt(rp, ODtype, Offer);
768         longopt(rp, ODlease, offer);
769         addropt(rp, ODserverid, up->laddr);
770         miscoptions(rp, ip);
771         termopt(rp);
772
773         logdhcpout(rp, "Offer");
774
775         /*
776          *  send
777          */
778         n = rp->p - rp->buf;
779         if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
780                 warning(0, "offer: write failed: %r");
781 }
782
783 void
784 sendack(Req *rp, uchar *ip, int offer, int sendlease)
785 {
786         int n;
787         ushort flags;
788         Bootp *bp;
789         Udphdr *up;
790
791         bp = rp->bp;
792         up = rp->up;
793
794         /*
795          *  set destination
796          */
797         flags = nhgets(bp->flags);
798         if(validip(rp->giaddr)){
799                 ipmove(up->raddr, rp->giaddr);
800                 hnputs(up->rport, 67);
801         } else if(flags & Fbroadcast){
802                 ipmove(up->raddr, IPv4bcast);
803                 hnputs(up->rport, 68);
804         } else {
805                 ipmove(up->raddr, ip);
806                 if(bp->htype == 1)
807                         arpenter(up->raddr, bp->chaddr);
808                 hnputs(up->rport, 68);
809         }
810
811         /*
812          *  fill in standard bootp part
813          */
814         bp->op = Bootreply;
815         bp->hops = 0;
816         hnputs(bp->secs, 0);
817         v6tov4(bp->giaddr, rp->giaddr);
818         v6tov4(bp->yiaddr, ip);
819         setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr);
820         strncpy(bp->sname, mysysname, sizeof(bp->sname));
821         strncpy(bp->file, rp->ii.bootf, sizeof(bp->file));
822
823         /*
824          *  set options
825          */
826         byteopt(rp, ODtype, Ack);
827         if(sendlease){
828                 longopt(rp, ODlease, offer);
829         }
830         addropt(rp, ODserverid, up->laddr);
831         miscoptions(rp, ip);
832         termopt(rp);
833
834         logdhcpout(rp, "Ack");
835
836         /*
837          *  send
838          */
839         n = rp->p - rp->buf;
840         if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
841                 warning(0, "ack: write failed: %r");
842 }
843
844 void
845 sendnak(Req *rp, char *msg)
846 {
847         int n;
848         Bootp *bp;
849         Udphdr *up;
850
851         bp = rp->bp;
852         up = rp->up;
853
854         /*
855          *  set destination (always broadcast)
856          */
857         if(validip(rp->giaddr)){
858                 ipmove(up->raddr, rp->giaddr);
859                 hnputs(up->rport, 67);
860         } else {
861                 ipmove(up->raddr, IPv4bcast);
862                 hnputs(up->rport, 68);
863         }
864
865         /*
866          *  fill in standard bootp part
867          */
868         bp->op = Bootreply;
869         bp->hops = 0;
870         hnputs(bp->secs, 0);
871         v6tov4(bp->giaddr, rp->giaddr);
872         memset(bp->ciaddr, 0, sizeof(bp->ciaddr));
873         memset(bp->yiaddr, 0, sizeof(bp->yiaddr));
874         memset(bp->siaddr, 0, sizeof(bp->siaddr));
875
876         /*
877          *  set options
878          */
879         byteopt(rp, ODtype, Nak);
880         addropt(rp, ODserverid, up->laddr);
881         if(msg)
882                 stringopt(rp, ODmessage, msg);
883         if(strncmp(rp->id, "id", 2) == 0)
884                 hexopt(rp, ODclientid, rp->id+2);
885         termopt(rp);
886
887         logdhcpout(rp, "Nak");
888
889         /*
890          *  send nak
891          */
892         n = rp->p - rp->buf;
893         if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
894                 warning(0, "nak: write failed: %r");
895 }
896
897 void
898 bootp(Req *rp)
899 {
900         int n;
901         Bootp *bp;
902         Udphdr *up;
903         ushort flags;
904         Iplifc *lifc;
905         Info *iip;
906
907         warning(0, "bootp %s %I->%I from %s via %I, file %s",
908                 rp->genrequest? "generic": (rp->p9request? "p9": ""),
909                 rp->up->raddr, rp->up->laddr,
910                 rp->id, rp->gii.ipaddr,
911                 rp->bp->file);
912
913         if(nobootp)
914                 return;
915
916         bp = rp->bp;
917         up = rp->up;
918         iip = &rp->ii;
919
920         if(rp->staticbinding == 0){
921                 warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr);
922                 return;
923         }
924
925         /* ignore if not for us */
926         if(*bp->sname){
927                 if(strcmp(bp->sname, mysysname) != 0){
928                         bp->sname[20] = 0;
929                         warning(0, "bootp for server %s", bp->sname);
930                         return;
931                 }
932         } else
933                 slowdelay(rp);
934
935         /* ignore if we don't know what file to load */
936         if(*bp->file == 0){
937                 if(rp->genrequest && *iip->bootf2) /* if not plan 9 & have alternate file... */
938                         strncpy(bp->file, iip->bootf2, sizeof(bp->file));
939                 else if(*iip->bootf)
940                         strncpy(bp->file, iip->bootf, sizeof(bp->file));
941                 else if(*bp->sname) /* if we were asked, respond no matter what */
942                         bp->file[0] = '\0';
943                 else {
944                         warning(0, "no bootfile for %I", iip->ipaddr);
945                         return;
946                 }
947         }
948
949         /* ignore if the file is unreadable */
950         if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){
951                 warning(0, "inaccessible bootfile1 %s", bp->file);
952                 return;
953         }
954
955         bp->op = Bootreply;
956         v6tov4(bp->yiaddr, iip->ipaddr);
957         if(rp->p9request){
958                 warning(0, "p9bootp: %I", iip->ipaddr);
959                 memmove(bp->optmagic, plan9opt, 4);
960                 if(iip->gwip == 0)
961                         v4tov6(iip->gwip, bp->giaddr);
962                 rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip,
963                                 iip->auip, iip->gwip);
964                 sprint(optbuf, "%s", (char*)(bp->optmagic));
965         } else if(rp->genrequest){
966                 warning(0, "genericbootp: %I", iip->ipaddr);
967                 memmove(bp->optmagic, genericopt, 4);
968                 miscoptions(rp, iip->ipaddr);
969                 termopt(rp);
970         } else if(iip->vendor[0] != 0) {
971                 warning(0, "bootp vendor field: %s", iip->vendor);
972                 memset(rp->p, 0, 128-4);
973                 rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor);
974         } else {
975                 memset(rp->p, 0, 128-4);
976                 rp->p += 128-4;
977         }
978
979         /*
980          *  set destination
981          */
982         flags = nhgets(bp->flags);
983         if(validip(rp->giaddr)){
984                 ipmove(up->raddr, rp->giaddr);
985                 hnputs(up->rport, 67);
986         } else if(flags & Fbroadcast){
987                 ipmove(up->raddr, IPv4bcast);
988                 hnputs(up->rport, 68);
989         } else {
990                 v4tov6(up->raddr, bp->yiaddr);
991                 if(bp->htype == 1)
992                         arpenter(up->raddr, bp->chaddr);
993                 hnputs(up->rport, 68);
994         }
995
996         /*
997          *  select best local address if destination is directly connected
998          */
999         lifc = findlifc(up->raddr);
1000         if(lifc)
1001                 ipmove(up->laddr, lifc->ip);
1002
1003         /*
1004          *  our identity
1005          */
1006         strncpy(bp->sname, mysysname, sizeof(bp->sname));
1007
1008         /*
1009          *  set tftp server
1010          */
1011         setsiaddr(bp->siaddr, iip->tftp, up->laddr);
1012         if(rp->genrequest && *iip->bootf2)
1013                 setsiaddr(bp->siaddr, iip->tftp2, up->laddr);
1014
1015         /*
1016          * RFC 1048 says that we must pad vendor field with
1017          * zeros until we have a 64 byte field.
1018          */
1019         n = rp->p - rp->bp->optdata;
1020         if(n < 64-4) {
1021                 memset(rp->p, 0, (64-4)-n);
1022                 rp->p += (64-4)-n;
1023         }
1024
1025         /*
1026          *  send
1027          */
1028         n = rp->p - rp->buf;
1029         if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n)
1030                 warning(0, "bootp: write failed: %r");
1031
1032         warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s",
1033                         up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags),
1034                         bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr,
1035                         optbuf);
1036 }
1037
1038 void
1039 parseoptions(Req *rp)
1040 {
1041         int n, c, code;
1042         uchar *o, *p;
1043
1044         p = rp->p;
1045
1046         while(p < rp->e){
1047                 code = *p++;
1048                 if(code == 255)
1049                         break;
1050                 if(code == 0)
1051                         continue;
1052
1053                 /* ignore anything that's too long */
1054                 n = *p++;
1055                 o = p;
1056                 p += n;
1057                 if(p > rp->e)
1058                         return;
1059
1060                 switch(code){
1061                 case ODipaddr:  /* requested ip address */
1062                         if(n == IPv4addrlen)
1063                                 v4tov6(rp->ip, o);
1064                         break;
1065                 case ODlease:   /* requested lease time */
1066                         rp->leasetime = nhgetl(o);
1067                         if(rp->leasetime > MaxLease || rp->leasetime < 0)
1068                                 rp->leasetime = MaxLease;
1069                         break;
1070                 case ODtype:
1071                         c = *o;
1072                         if(c < 10 && c > 0)
1073                                 rp->dhcptype = c;
1074                         break;
1075                 case ODserverid:
1076                         if(n == IPv4addrlen)
1077                                 v4tov6(rp->server, o);
1078                         break;
1079                 case ODmessage:
1080                         if(n > sizeof rp->msg-1)
1081                                 n = sizeof rp->msg-1;
1082                         memmove(rp->msg, o, n);
1083                         rp->msg[n] = 0;
1084                         break;
1085                 case ODmaxmsg:
1086                         c = nhgets(o);
1087                         c -= 28;
1088                         c += Udphdrsize;
1089                         if(c > 0)
1090                                 rp->max = rp->buf + c;
1091                         break;
1092                 case ODclientid:
1093                         if(n <= 1)
1094                                 break;
1095                         rp->id = toid( o, n);
1096                         break;
1097                 case ODparams:
1098                         if(n > sizeof(rp->requested))
1099                                 n = sizeof(rp->requested);
1100                         memmove(rp->requested, o, n);
1101                         break;
1102                 case ODvendorclass:
1103                         if(n >= sizeof(rp->vendorclass))
1104                                 n = sizeof(rp->vendorclass)-1;
1105                         memmove(rp->vendorclass, o, n);
1106                         rp->vendorclass[n] = 0;
1107                         if(strncmp((char*)rp->vendorclass, "p9-", 3) == 0)
1108                                 strcpy(rp->cputype, (char*)rp->vendorclass+3);
1109                         break;
1110                 case OBend:
1111                         return;
1112                 }
1113         }
1114 }
1115
1116 void
1117 remrequested(Req *rp, int opt)
1118 {
1119         uchar *p;
1120
1121         p = memchr(rp->requested, opt, sizeof(rp->requested));
1122         if(p != nil)
1123                 *p = OBpad;
1124 }
1125
1126 void
1127 miscoptions(Req *rp, uchar *ip)
1128 {
1129         int i, j, na;
1130         uchar x[2*IPaddrlen], vopts[Maxoptlen];
1131         uchar *op, *omax;
1132         uchar *addrs[2];
1133         char *p;
1134         char *attr[100], **a;
1135         Ndbtuple *t;
1136
1137         addrs[0] = x;
1138         addrs[1] = x+IPaddrlen;
1139
1140         /* always supply these */
1141         maskopt(rp, OBmask, rp->gii.ipmask);
1142         if(validip(rp->gii.gwip)){
1143                 remrequested(rp, OBrouter);
1144                 addropt(rp, OBrouter, rp->gii.gwip);
1145         } else if(validip(rp->giaddr)){
1146                 remrequested(rp, OBrouter);
1147                 addropt(rp, OBrouter, rp->giaddr);
1148         }
1149
1150         /*
1151          * OBhostname for the HP4000M switches
1152          * (this causes NT to log infinite errors - tough shit)
1153          */
1154         if(*rp->ii.domain){
1155                 remrequested(rp, OBhostname);
1156                 stringopt(rp, OBhostname, rp->ii.domain);
1157         }
1158         if(*rp->ii.rootpath)
1159                 stringopt(rp, OBrootpath, rp->ii.rootpath);
1160
1161         /* figure out what we need to lookup */
1162         na = 0;
1163         a = attr;
1164         if(*rp->ii.domain == 0)
1165                 a[na++] = "dom";
1166         for(i = 0; i < sizeof(rp->requested); i++)
1167                 switch(rp->requested[i]){
1168                 case OBrouter:
1169                         a[na++] = "@ipgw";
1170                         break;
1171                 case OBdnserver:
1172                         a[na++] = "@dns";
1173                         break;
1174                 case OBnetbiosns:
1175                         a[na++] = "@wins";
1176                         break;
1177                 case OBsmtpserver:
1178                         a[na++] = "@smtp";
1179                         break;
1180                 case OBpop3server:
1181                         a[na++] = "@pop3";
1182                         break;
1183                 case OBwwwserver:
1184                         a[na++] = "@www";
1185                         break;
1186                 case OBntpserver:
1187                         a[na++] = "@ntp";
1188                         break;
1189                 case OBtimeserver:
1190                         a[na++] = "@time";
1191                         break;
1192                 }
1193         if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
1194         || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
1195                 a[na++] = "@fs";
1196                 a[na++] = "@auth";
1197         }
1198         t = lookupinfo(ip, a, na);
1199
1200         /* lookup anything we might be missing */
1201         if(*rp->ii.domain == 0)
1202                 lookupname(rp->ii.domain, t);
1203
1204         /* add any requested ones that we know about */
1205         for(i = 0; i < sizeof(rp->requested); i++)
1206                 switch(rp->requested[i]){
1207                 case OBrouter:
1208                         j = lookupserver("ipgw", addrs, t);
1209                         addrsopt(rp, OBrouter, addrs, j);
1210                         break;
1211                 case OBdnserver:
1212                         j = lookupserver("dns", addrs, t);
1213                         addrsopt(rp, OBdnserver, addrs, j);
1214                         break;
1215                 case OBhostname:
1216                         if(*rp->ii.domain)
1217                                 stringopt(rp, OBhostname, rp->ii.domain);
1218                         break;
1219                 case OBdomainname:
1220                         p = strchr(rp->ii.domain, '.');
1221                         if(p)
1222                                 stringopt(rp, OBdomainname, p+1);
1223                         break;
1224                 case OBnetbiosns:
1225                         j = lookupserver("wins", addrs, t);
1226                         addrsopt(rp, OBnetbiosns, addrs, j);
1227                         break;
1228                 case OBnetbiostype:
1229                         /* p-node: peer to peer WINS queries */
1230                         byteopt(rp, OBnetbiostype, 0x2);
1231                         break;
1232                 case OBsmtpserver:
1233                         j = lookupserver("smtp", addrs, t);
1234                         addrsopt(rp, OBsmtpserver, addrs, j);
1235                         break;
1236                 case OBpop3server:
1237                         j = lookupserver("pop3", addrs, t);
1238                         addrsopt(rp, OBpop3server, addrs, j);
1239                         break;
1240                 case OBwwwserver:
1241                         j = lookupserver("www", addrs, t);
1242                         addrsopt(rp, OBwwwserver, addrs, j);
1243                         break;
1244                 case OBntpserver:
1245                         j = lookupserver("ntp", addrs, t);
1246                         addrsopt(rp, OBntpserver, addrs, j);
1247                         break;
1248                 case OBtimeserver:
1249                         j = lookupserver("time", addrs, t);
1250                         addrsopt(rp, OBtimeserver, addrs, j);
1251                         break;
1252                 case OBttl:
1253                         byteopt(rp, OBttl, 255);
1254                         break;
1255                 }
1256
1257         /* add plan9 specific options */
1258         if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
1259         || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
1260                 /* point to temporary area */
1261                 op = rp->p;
1262                 omax = rp->max;
1263                 /* stash encoded options in vopts */
1264                 rp->p = vopts;
1265                 rp->max = vopts + sizeof(vopts) - 1;
1266
1267                 /* emit old v4 addresses first to make sure that they fit */
1268                 addrsopt(rp, OP9fsv4, addrs, lookupserver("fs", addrs, t));
1269                 addrsopt(rp, OP9authv4, addrs, lookupserver("auth", addrs, t));
1270
1271                 p9addrsopt(rp, OP9fs, addrs, lookupserver("fs", addrs, t));
1272                 p9addrsopt(rp, OP9auth, addrs, lookupserver("auth", addrs, t));
1273                 p9addrsopt(rp, OP9ipaddr, addrs, lookupserver("ip", addrs, t));
1274                 p9addrsopt(rp, OP9ipmask, addrs, lookupserver("ipmask", addrs, t));
1275                 p9addrsopt(rp, OP9ipgw, addrs, lookupserver("ipgw", addrs, t));
1276
1277                 /* point back to packet, encapsulate vopts into packet */
1278                 j = rp->p - vopts;
1279                 rp->p = op;
1280                 rp->max = omax;
1281                 vectoropt(rp, OBvendorinfo, vopts, j);
1282         }
1283
1284         ndbfree(t);
1285 }
1286
1287 int
1288 openlisten(char *net)
1289 {
1290         int fd, cfd;
1291         char data[128], devdir[40];
1292
1293         sprint(data, "%s/udp!*!bootp", net);
1294         cfd = announce(data, devdir);
1295         if(cfd < 0)
1296                 fatal(1, "can't announce");
1297         if(fprint(cfd, "headers") < 0)
1298                 fatal(1, "can't set header mode");
1299
1300         sprint(data, "%s/data", devdir);
1301         fd = open(data, ORDWR);
1302         if(fd < 0)
1303                 fatal(1, "open udp data");
1304         return fd;
1305 }
1306
1307 void
1308 fatal(int syserr, char *fmt, ...)
1309 {
1310         char buf[Maxloglen];
1311         va_list arg;
1312
1313         va_start(arg, fmt);
1314         vseprint(buf, buf+sizeof(buf), fmt, arg);
1315         va_end(arg);
1316         if(syserr)
1317                 syslog(1, blog, "%s: %r", buf);
1318         else
1319                 syslog(1, blog, "%s", buf);
1320         exits(buf);
1321 }
1322
1323 void
1324 warning(int syserr, char *fmt, ...)
1325 {
1326         char buf[Maxloglen];
1327         va_list arg;
1328
1329         va_start(arg, fmt);
1330         vseprint(buf, buf+sizeof(buf), fmt, arg);
1331         va_end(arg);
1332         if(syserr){
1333                 syslog(0, blog, "%s: %r", buf);
1334                 if(debug)
1335                         fprint(2, "%s: %r\n", buf);
1336         } else {
1337                 syslog(0, blog, "%s", buf);
1338                 if(debug)
1339                         fprint(2, "%s\n", buf);
1340         }
1341 }
1342
1343 char*
1344 readsysname(void)
1345 {
1346         static char name[128];
1347         char *p;
1348         int n, fd;
1349
1350         fd = open("/dev/sysname", OREAD);
1351         if(fd >= 0){
1352                 n = read(fd, name, sizeof(name)-1);
1353                 close(fd);
1354                 if(n > 0){
1355                         name[n] = 0;
1356                         return name;
1357                 }
1358         }
1359         p = getenv("sysname");
1360         if(p == nil || *p == 0)
1361                 return "unknown";
1362         return p;
1363 }
1364
1365 extern int
1366 validip(uchar *ip)
1367 {
1368         if(ipcmp(ip, IPnoaddr) == 0)
1369                 return 0;
1370         if(ipcmp(ip, v4prefix) == 0)
1371                 return 0;
1372         return 1;
1373 }
1374
1375 void
1376 longopt(Req *rp, int t, long v)
1377 {
1378         if(rp->p + 6 > rp->max)
1379                 return;
1380         *rp->p++ = t;
1381         *rp->p++ = 4;
1382         hnputl(rp->p, v);
1383         rp->p += 4;
1384
1385         op = seprint(op, oe, "%s(%ld)", optname[t], v);
1386 }
1387
1388 void
1389 addropt(Req *rp, int t, uchar *ip)
1390 {
1391         if(rp->p + 6 > rp->max)
1392                 return;
1393         if (!isv4(ip)) {
1394                 if (debug)
1395                         warning(0, "not a v4 %s server: %I", optname[t], ip);
1396                 return;
1397         }
1398         *rp->p++ = t;
1399         *rp->p++ = 4;
1400         memmove(rp->p, ip+IPv4off, 4);
1401         rp->p += 4;
1402
1403         op = seprint(op, oe, "%s(%I)", optname[t], ip);
1404 }
1405
1406 void
1407 maskopt(Req *rp, int t, uchar *ip)
1408 {
1409         if(rp->p + 6 > rp->max)
1410                 return;
1411         *rp->p++ = t;
1412         *rp->p++ = 4;
1413         memmove(rp->p, ip+IPv4off, 4);
1414         rp->p += 4;
1415
1416         op = seprint(op, oe, "%s(%M)", optname[t], ip);
1417 }
1418
1419 void
1420 addrsopt(Req *rp, int t, uchar **ip, int i)
1421 {
1422         int v4s, n;
1423
1424         if(i <= 0)
1425                 return;
1426         if(rp->p + 2 + 4*i > rp->max)
1427                 return;
1428         v4s = 0;
1429         for(n = i; n-- > 0; )
1430                 if (isv4(ip[n]))
1431                         v4s++;
1432         if (v4s <= 0) {
1433                 if (debug)
1434                         warning(0, "no v4 %s servers", optname[t]);
1435                 return;
1436         }
1437         *rp->p++ = t;
1438         *rp->p++ = 4*v4s;
1439         op = seprint(op, oe, " %s(", optname[t]);
1440         while(i-- > 0){
1441                 if (!isv4(*ip)) {
1442                         op = seprint(op, oe, " skipping %I ", *ip);
1443                         continue;
1444                 }
1445                 v6tov4(rp->p, *ip);
1446                 rp->p += 4;
1447                 op = seprint(op, oe, "%I", *ip);
1448                 ip++;
1449                 if(i > 0)
1450                         op = seprint(op, oe, " ");
1451         }
1452         op = seprint(op, oe, ")");
1453 }
1454
1455 void
1456 p9addrsopt(Req *rp, int t, uchar **ip, int i)
1457 {
1458         char *pkt, *payload;
1459
1460         if(i <= 0 || !v6opts)
1461                 return;
1462         pkt = (char *)rp->p;
1463         *pkt++ = t;                     /* option */
1464         pkt++;                          /* fill in payload length below */
1465         payload = pkt;
1466         *pkt++ = i;                     /* plan 9 address count */
1467         op = seprint(op, oe, " %s(", optname[t]);
1468         while(i-- > 0){
1469                 pkt = seprint(pkt, (char *)rp->max, "%I", *ip);
1470                 if ((uchar *)pkt+1 >= rp->max) {
1471                         op = seprint(op, oe, "<out of mem1>)");
1472                         return;
1473                 }
1474                 pkt++;                  /* leave NUL as terminator */
1475                 op = seprint(op, oe, "%I", *ip);
1476                 ip++;
1477                 if(i > 0)
1478                         op = seprint(op, oe, " ");
1479         }
1480         if ((uchar *)pkt - rp->p > 0377) {
1481                 op = seprint(op, oe, "<out of mem2>)");
1482                 return;
1483         }
1484         op = seprint(op, oe, ")");
1485         rp->p[1] = pkt - payload;       /* payload length */
1486         rp->p = (uchar *)pkt;
1487 }
1488
1489 void
1490 byteopt(Req *rp, int t, uchar v)
1491 {
1492         if(rp->p + 3 > rp->max)
1493                 return;
1494         *rp->p++ = t;
1495         *rp->p++ = 1;
1496         *rp->p++ = v;
1497
1498         op = seprint(op, oe, "%s(%d)", optname[t], v);
1499 }
1500
1501 void
1502 termopt(Req *rp)
1503 {
1504         if(rp->p + 1 > rp->max)
1505                 return;
1506         *rp->p++ = OBend;
1507 }
1508
1509 void
1510 stringopt(Req *rp, int t, char *str)
1511 {
1512         int n;
1513
1514         n = strlen(str);
1515         if(n > 255)
1516                 n = 255;
1517         if(rp->p+n+2 > rp->max)
1518                 return;
1519         *rp->p++ = t;
1520         *rp->p++ = n;
1521         memmove(rp->p, str, n);
1522         rp->p += n;
1523
1524         op = seprint(op, oe, "%s(%s)", optname[t], str);
1525 }
1526
1527 void
1528 vectoropt(Req *rp, int t, uchar *v, int n)
1529 {
1530         int i;
1531
1532         if(n > 255) {
1533                 n = 255;
1534                 op = seprint(op, oe, "vectoropt len %d > 255 ", n);
1535         }
1536         if(rp->p+n+2 > rp->max)
1537                 return;
1538         *rp->p++ = t;
1539         *rp->p++ = n;
1540         memmove(rp->p, v, n);
1541         rp->p += n;
1542
1543         op = seprint(op, oe, "%s(", optname[t]);
1544         if(n > 0)
1545                 op = seprint(op, oe, "%ud", v[0]);
1546         for(i = 1; i < n; i++)
1547                 op = seprint(op, oe, " %ud", v[i]);
1548         op = seprint(op, oe, ")");
1549 }
1550
1551 int
1552 fromhex(int x)
1553 {
1554         if(x >= '0' && x <= '9')
1555                 return x - '0';
1556         return x - 'a';
1557 }
1558
1559 void
1560 hexopt(Req *rp, int t, char *str)
1561 {
1562         int n;
1563
1564         n = strlen(str);
1565         n /= 2;
1566         if(n > 255)
1567                 n = 255;
1568         if(rp->p+n+2 > rp->max)
1569                 return;
1570         *rp->p++ = t;
1571         *rp->p++ = n;
1572         while(n-- > 0){
1573                 *rp->p++ = (fromhex(str[0])<<4)|fromhex(str[1]);
1574                 str += 2;
1575         }
1576
1577         op = seprint(op, oe, "%s(%s)", optname[t], str);
1578 }
1579
1580 void
1581 arpenter(uchar *ip, uchar *ether)
1582 {
1583         int f;
1584         char buf[256];
1585
1586         sprint(buf, "%s/arp", net);
1587         f = open(buf, OWRITE);
1588         if(f < 0){
1589                 syslog(debug, blog, "open %s: %r", buf);
1590                 return;
1591         }
1592         fprint(f, "add ether %I %E", ip, ether);
1593         close(f);
1594 }
1595
1596 char *dhcpmsgname[] =
1597 {
1598         [Discover]      "Discover",
1599         [Offer]         "Offer",
1600         [Request]       "Request",
1601         [Decline]       "Decline",
1602         [Ack]           "Ack",
1603         [Nak]           "Nak",
1604         [Release]       "Release",
1605         [Inform]        "Inform",
1606 };
1607
1608 void
1609 logdhcp(Req *rp)
1610 {
1611         char buf[4096];
1612         char *p, *e;
1613         int i;
1614
1615         p = buf;
1616         e = buf + sizeof(buf);
1617         if(rp->dhcptype > 0 && rp->dhcptype <= Inform)
1618                 p = seprint(p, e, "%s(", dhcpmsgname[rp->dhcptype]);
1619         else
1620                 p = seprint(p, e, "%d(", rp->dhcptype);
1621         p = seprint(p, e, "%I->%I) xid(%ux)flag(%ux)", rp->up->raddr, rp->up->laddr,
1622                 nhgetl(rp->bp->xid), nhgets(rp->bp->flags));
1623         if(rp->bp->htype == 1)
1624                 p = seprint(p, e, "ea(%E)", rp->bp->chaddr);
1625         if(validip(rp->ciaddr))
1626                 p = seprint(p, e, "ci(%I)", rp->ciaddr);
1627         if(validip(rp->giaddr))
1628                 p = seprint(p, e, "gi(%I)", rp->giaddr);
1629         if(validip(rp->ip))
1630                 p = seprint(p, e, "ip(%I)", rp->ip);
1631         if(rp->id != nil)
1632                 p = seprint(p, e, "id(%s)", rp->id);
1633         if(rp->leasetime)
1634                 p = seprint(p, e, "leas(%d)", rp->leasetime);
1635         if(validip(rp->server))
1636                 p = seprint(p, e, "sid(%I)", rp->server);
1637         p = seprint(p, e, "need(");
1638         for(i = 0; i < sizeof(rp->requested); i++)
1639                 if(rp->requested[i] != 0)
1640                         p = seprint(p, e, "%s ", optname[rp->requested[i]]);
1641         p = seprint(p, e, ")");
1642
1643         USED(p);
1644         syslog(0, blog, "%s", buf);
1645 }
1646
1647 void
1648 logdhcpout(Req *rp, char *type)
1649 {
1650         syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s",
1651                 type, rp->up->laddr, rp->up->raddr, rp->id,
1652                 rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf);
1653 }
1654
1655 /*
1656  *  if we get behind, it's useless to try answering since the sender
1657  *  will probably have retransmitted with a differnt sequence number.
1658  *  So dump all but the last message in the queue.
1659  */
1660 void
1661 ding(void*, char *msg)
1662 {
1663         if(strstr(msg, "alarm"))
1664                 noted(NCONT);
1665         else
1666                 noted(NDFLT);
1667 }
1668
1669 int
1670 readlast(int fd, uchar *buf, int len)
1671 {
1672         int lastn, n;
1673
1674         notify(ding);
1675
1676         lastn = 0;
1677         for(;;){
1678                 alarm(20);
1679                 n = read(fd, buf, len);
1680                 alarm(0);
1681                 if(n < 0){
1682                         if(lastn > 0)
1683                                 return lastn;
1684                         break;
1685                 }
1686                 lastn = n;
1687         }
1688         return read(fd, buf, len);
1689 }