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